Bawię się ;)

Zainspirowany serwisem Kiedy Będzie Wielkanoc by Marcin Kaszyński, zrobiłem sobie bardziej ogólną zabawkę ;) Moja wersja pokazuje najbliższy dzień wolny – uwzględnia weekendy i święta (według listy z Wikipedii) :) Jeśli ktoś chce, to może kliknięciem sobie wyłączyć wyliczanie dla sobót i/lub niedziel (prawy górny róg), ale nie jest to na razie zapamiętywane (będzie pewnie w ciachu). I tyle ;)

Dostępne pod: ZaIleWolne.pl – enjoy! ;)


Dawno tu nie pisałem… No cóż, (bardzo) dużo pracy, życie osobiste i takie tam – to odstrasza od blogowania ;) Jeśli już, to od czasu do czasu coś publikuję jeśli chodzi o zdjęcia, a sprawy “kodowe” to raczej “robię” niż o nich piszę :)

Jako że od kilka dni jestem na L4, to się ostro opierdzielam, ale dopiero dziś jestem w stanie podjąć jakikolwiek intelektualny wysiłek… No to popatrzyłem sobie m.in. na GoldenLine. Dziś na forum PHPowym ktoś poruszył dość banalny problem, ktoś inny podrzucił rozwiązanie (preg_replace_callback (), a ja zacząłem się zastanawiać czemu wszyscy w PHP tak napierają na regexpy (rozumiem w Perlu, ale PHP?). Jak zacząłem się zastanawiać jak to zrobić bez regexpów, to zacząłem się bawić w zakodowanie tego ;)

Najpierw zrobiłem dość banalną wersję, przy użyciu strlen (), strpos () i substr (), i chciałem ją podać jako wersję hardcore ;) Wtedy pomyślałem sobie, że prawdziwa wersja hardcore, to byłaby bez użycia tychże funkcji… najprostsza postać tego to zastąpienie tychże funkcji swoimi ;) I o ile substr () i strpos () są dość banalne, o tyle dla mnie prawdziwym hardcorem jest strlen () ;)

Oczywiście nie są to najbardziej optymalne wydajne rozwiązania (a jeśli są to tylko przypadkiem), bo jeśli chodzi o optymalizację, to trzeba by używać wersji natywnych to trzeba by się najpierw zastanowić i sprawdzić czy jest co optymalizować… :) A całość warto potraktować stricte jako zabawę, którą dla mnie było pisanie tego :)

W całym “problemie” chodziło o zastąpienie w tekście wystąpień “[userId]ID[/userId]” tym, co zostanie wyplute przez dodatkową funkcję której podajemy zawartość tego co jest między znacznikami. Użycie preg_replace_callback () jest chyba najbardziej intuicyjnym rozwiązaniem, ale nie jedynym… :) Poniżej obydwie wersje: hardcore i bardziej hardcore – enjoy ;)

hardcore

function replace_user_id ($str, $fn) {
    $tags = array ('start' => '[userId]', 'end' => '[/userId]');
    $tag_len = array (
        'start' => strlen ($tags['start']),
        'end'   => strlen ($tags['end'])
    );
    $offset = $pos_end = 0;
    $ret    = '';
    $strlen = strlen ($str);

    while ($pos_end < $strlen) {
        if (
            ($pos_start = strpos ($str, $tags['start'], $pos_end)) !== false &&
            ($pos_end   = strpos ($str, $tags['end'], $pos_start)) !== false
        ) {
            $ret .= substr ($str, $offset, $pos_start - $offset);
            $pos_start += $tag_len['start'];

            $ret .= $fn (substr ($str, $pos_start, $pos_end - $pos_start));

            $pos_end += $tag_len['end'];
            $offset = $pos_end;
        }
        else {
            break;
        }
    }

    return $ret;
}

bardziej hardcore

class __mstrlen__ErrH {
    private static $error = false;
    private function __construct () {}
    static public function errh ($errno, $errstr, $errfile = '', $errline = 0, $errctx = array ()) {
        if ($errno != E_NOTICE) {
            return false;
        }

        $expected = 'Uninitialized string offset';
        for ($i=0; $i<26; ++$i) {
            if ($expected[$i] != $errstr[$i]) {
                return false;
            }
        }

        self::$error = true;
    }
    public static function isError () {
        return self::$error;
    }
    public static function zero () {
        self::$error = false;
    }
}

function mstrlen ($str) {
    $str = (string) $str;

    $len = -1;
    __mstrlen__ErrH::zero ();
    set_error_handler (array ('__mstrlen__ErrH', 'errh'), E_NOTICE);
    while (__mstrlen__ErrH::isError () === false) {
        ++$len;
        $q = $str[$len];
    }

    restore_error_handler ();
    return $len < 0 ? 0 : $len;
}

function mstrpos ($str, $seek, $offset=0) {
    if (!is_int ($offset) || $offset < 0) {
        $offset = 0;
    }

    $str_len = mstrlen ($str);
    if ($offset > $str_len) {
        return false;
    }

    $seek_len = mstrlen ($seek);
    for ($i=$offset; $i < $str_len; ++$i) {
        for ($j=0; $j < $seek_len; ++$j) {
            if ($str[$i + $j] != $seek[$j]) {
                break;
            }
        }

        if ($j == $seek_len) {
            return $i;
        }
    }
    return false;
}

function msubstr ($str, $start, $length = null) {
    $str_len = mstrlen ($str);
    if (!is_int ($start)) {
        trigger_error ('Incorrect offset');
    }
    else if ($start >= $str_len) {
        return false;
    }
    else if ($start < 0) {
        $start = $str_len + $start;
    }

    if (!is_int ($length)) {
        $length = $str_len - $start;
    }
    else if ($length < 0) {
        $length = $str_len + $length - $start;
    }
    else if ($length + $start > $str_len) {
        $length = $str_len - $start;
    }

    $ret = '';
    for ($i=0; $i < $length; ++$i) {
        $ret .= $str[$i + $start];
    }

    return $ret;
}

function replace_user_id2 ($str, $fn) {
    $tags = array ('start' => '[userId]', 'end' => '[/userId]');
    $tag_len = array (
        'start' => mstrlen ($tags['start']),
        'end'   => mstrlen ($tags['end'])
    );
    $offset = $pos_end = 0;
    $ret    = '';
    $strlen = mstrlen ($str);

    while ($pos_end < $strlen) {
        if (
            ($pos_start = mstrpos ($str, $tags['start'], $pos_end)) !== false &&
            ($pos_end   = mstrpos ($str, $tags['end'], $pos_start)) !== false
        ) {
            $ret .= msubstr ($str, $offset, $pos_start - $offset);
            $pos_start += $tag_len['start'];

            $ret .= $fn (msubstr ($str, $pos_start, $pos_end - $pos_start));

            $pos_end += $tag_len['end'];
            $offset = $pos_end;
        }
        else {
            break;
        }
    }

    return $ret;
}

Od jakiegoś czasu wymyślam sobie różne udoskonalenia dla Vima, i piszę je zazwyczaj w Pythonie :) Niedawno opisywałem jak wyświetlić listę funkcji z edytowanego pliku, później zrobiłem sobie wygodne komentowanie kodu (wersje które znalazłem na sieci nie satysfakcjonowały mnie), teraz przyszedł czas na sprytne (w sensie: wygodne) uruchamianie właśnie edytowanego skryptu/programu :)

Do niedawna używałem prostego Pythonowego skryptu, który wywoływem z Vima:

!$ %

Wykrzyknik to polecenie wywołania programu z shella, $ to nazwa skryptu, a % jest rozwijany przez Vima do pełnej ścieżki bieżącego pliku. Było to o tyle wygodne, że nieważne w jakim języku pisałny był skrypt/program, $ uruchamiał odpowiedni interpreter, ze skonfigurowanymi parametrami i wyświetlał wyjście. Tą funkcjonalność oczywiście potrzebowałem zachować, ale wykonywanie zewnętrznego programu jest strasznie niewygodne ;) Więc zrobiłem sobie wygodniejszą, i nieco bardziej rozbudowaną wersję. Inne założenia to możliwość przekazywania parametrów do wykonywanego programu, oraz dla niektórych języków możliwość wcześniejszej, automatycznej kompilacji.

Przejdź do reszty tego wpisu »


Jakiś czas temu napisałem artykuł o setterach i getterach w PHP5. Może warto poruszyć podobny temat dotyczący Pythona? :)

Przede wszystkim, model obiektowy Pythona jest zupełnie inny niż PHP. Nie będę go tu omawiał, ponieważ to temat na dość obszerną książkę :) Generalnie obiektówka Pythona jest pełniejsza, ma większe możliwości przeciążania zarówno metod, jak i operatorów (których w PHP przeciążyć nie można).

Przejdź do reszty tego wpisu »


Już od jakiegoś czasu deweloperzy Pythona przygotowują nową, niekompatybilną z poprzednimi, wersję Pythona. Python, gdyby ktoś nie wiedział, to jeden z najfajniejszych języków jakie wymyślono ;) (oczywiście to mocno subiektywne uczucie, ale może kogoś zachęci ;) ). Napiszę tutaj o dwóch ważnych zmianach, co do których nie byłem zupełnie przekonany (a konkretnie: w ogóle nie byłem przekonany), a które spodobały mi się po dzisiejszej krótkiej zabawie z wersją alpha3 Pythona 3000 :)

Przejdź do reszty tego wpisu »


Developerzy PHP, projektując “nową” implementację OOP (nową w cudzysłowiu, bo raz że to było już kilka lat temu, a dwa, że dotyczy tylko i wyłącznie samego PHP), dość mocno wzorowali się na Javie. Czy to dobrze czy to źle to kwestia gustu, jednak wynika z tego kilka znaczących drobiazgów. Jednym z nich jest jednodziedziczenie (czyli że jedna klasa w PHP może mieć tylko jedną klasę bazową). Od zawsze uważałem to za dużą niewygodę ;) Jak widać, nie tylko ja.

Padła propozycja dołączenia systemu “Cech” (ang. Traits) do PHP (podejrzewam że do wersji 6, ale to tylko moje zgadywanie – w każdym bądź razie są gotowe łatki m.in. do 5.2 i 5.3). Do czego służą Traitsy? W sumie… do obejście problemu jednodziedziczenia, czyli do wprowadzenia wielodziedziczenia.

Trzeba pamiętać, że ten mechanizm został podobno (nie sprawdzałem osobiście) sportowany także do Javy i C#, natomiast nie istnieje jeszcze ofiacjalna wersja dla PHP. Sam “wygląd” kodu, słowa kluczowe etc nie są jeszcze ustalone, ale to tylko szczegóły.

Szczegóły są dostępne w oficjalnym RFC: stefan-marr.de/artikel/rfc-traits-for-php.html. Ja tylko powiem, że da się często obejść niedogodność wynikajacą z braku wielodziedziczenia, ale problem leży właśnie w konieczności obchodzenia braków w języku (tak, wiem, to akurat jedna z typowych wojen wyższości jednych świąt nad drugimi ;) ale to akurat moje zdanie ;) ). Prostszym wyjściem byłoby wprowadzenie po prostu możliwości posiadania kilku klas bazowych, ale w to nie wnikam. Ja ogólnie jestem na tak.


Stwierdziłem niedawno, że brakuje mi w Vimie takiego drobiazgu jak wyświetlanie listy funkcji z edytowanego właśnie pliku. Można z jednej strony wykorzystać ctags, ale (pewien nie jestem, nie jestem znawcą tagsów ani ich obsługi w Vimie) po dodaniu funkcji/metody/czegokolwiek innego co można by nazwać tagiem trzeba by od nowa generować listę tagów. Nie jest to problemem takim bardzo dużym, do momentu gdy ciągle pracuje się nad różnymi projektami, z czego sporej części nie mam na dysku (tylko wykorzystując plugin netrw pracuję via ftp). W tym momencie moja znajomość systemu ctags podpowiada mi że robi się ciężko…

Postanowiłem więc napisać sobie prosty skrypt do tego, a że język wewnętrzny Vima mnie nieco odrzuca, postawiłem na Pythona ;) Żeby jakikolwiek skrypt pythona (jak ktoś lubi, można użyć też np perla) mógł zadziałać w Vimie, ten ostatni musi być skompilowany z jego obsługą. W Ubuntu wystarczy zainstalować pakiet vim-full. Łatwo sprawdzić czy Vim ma wkompilowaną obsługę pythona:

Przejdź do reszty tego wpisu »


Twórcy Blip!a wydali wersję 0.02 API, więc zrobiłem co w mojej mocy aby skończyć moją PeHaPową bilbiotekę do tegoż ;) Zmian dużo, do wersji API 0.01 była ona mocno testowa, i w sumie nie jest poprawnie zrobiona, są w niej błędy etc, których nie zamierzam już poprawiać. Wersja 0.02.4 niesie z sobą pełną obsługę protokołu, wykorzystując wszystko co producenci dali, szczegóły w oficjalnej dokumentacji Blip!a.

Szczegóły numeracji biblioteki: pierwszą część stanowi wersja API (w tym wyapdku 0.02), drugą – odsłona samej biblioteki (w tym wypadku 4).

BlipApi.php można używać na dwa sposoby:

  1. wywołując metodę BlipApi::execute(), gdzie pierwszym parametrem jest nazwa komendy do wykonania (spis komend w oficjalnej dokumentacji, jedyną różnicą jest dirmsg zamiast directed_messages), a następnie dostępne parametry metody (szczegóły w pliku klasy i w oficjalnej dokumentacji Blip!a), np.:

    $bapi = new BlipApi ('login', 'haslo');
    $bapi->connect ();
    $bapi->execute ('update_read', null, 'mysz');

    Pobierze ostatnie 10 statusów użytkownika mysz.

  2. wywołując komendę jako konkretną metodą obiektu BlipApi:

    $bapi->update_read (null, 'mysz');

    Powyższe dwa wywołania są sobie równoważne.

Jeśli ktoś znajdzie jakieś błędy, lub ma uwagi co do samej biblioteki, proszę o komentarze tutaj, lub kontakt mailowy: urzenia.net/email. Z góry dziękuję za feedback ;)

Bibliotekę można pobrać/obejrzeć z: repo.urzenia.net/files/blipapi-0.02.phps. W tej chwili nie ma skąd pobrać samej biblioteki, jako że usunąłem repo.urzenia.net. Dołączona jest za to do pakietu WP Blip!, skąd można ją “ręcznie” wyciągnąć :) Przepraszam za kłopot :)