Archiwum

Archiwum dla ‘Różne’ Kategoria

Obiektowy JavaScript cz.2. – klasa sama w sobie

Marzec 2nd, 2010 reinmar Brak komentarzy

GąsienicaOpublikowane na licencji CC przez Trufflepig.

W poprzednim artykule o obiektach w JavaScriptcie poruszyłem kwestię ich tworzenia, dostępu do właściwości, kontekstu wywoływania metod oraz wspomniałem o kilku cechach. Czyste literały obiektów same w sobie są już w tym języku bardzo przydatne — przekonał się pewnie o tym każdy kto korzystał z jakiejś biblioteki typu MooTools czy Prototype. Pozwalają na przykład w dość wygodny sposób na podanie dowolnej liczby nazwanych argumentów funkcji:

new Ajax.Request('/your/url', {
	parameters: { id: 12, action: 'sth' },

	onSuccess: function (transport) {
		alert(transport.responseText);
	},

	evalJS: false
});

Pisałem ostatnio o tym, że w JavaScriptcie nie ma klas. Skąd więc w przykładzie słówko kluczowe new, które w typowym języku służy do tworzenia instancji obiektu na bazie jakiejś klasy? Otóż okazuje się, że w JavaScriptcie wprowadzono twór zwany konstruktorami obiektów.

Konstruktor obiektu

Zwyczajnie zaczyna się od definiowania klasy jakiegoś kotka, samochodu, czy figury geometrycznej. Nudy. Chciałem wymyślić coś bardziej konstruktywnego i spośród wszystkich dostępnych na moim biurku obiektów wybrałem butelkę po miodzie pitnym (pustą niestety). Myślę, że konstruktory dla napoju alkoholowego i butelki będą wystarczająco oryginalne :). Do dzieła:

var Alkohol = function (nazwa, ilosc_procentow, kolor) {

	this.nazwa = nazwa;
	this.ilosc_procentow = ilosc_procentow;

	this.kolor = kolor;
};
var ButelkaAlkoholu = function (alkohol, pojemnosc, rok_produkcji, kraj_produkcji) {

	this.alkohol = alkohol;
	this.pojemnosc = pojemnosc;

	this.rok_produkcji = rok_produkcji;
	this.kraj_produkcji = kraj_produkcji;

};

Oj tak. JavaScript to dziwoląg. Miały być konstruktory obiektów, a tu znowu pojawiły się funkcje. Z drugiej strony pojawiło się też słowo kluczowe this, więc cały przykład przypomina dwa wycięte z definicji klas napisanych w normalnym języku konstruktory. Na szczęście obiekty tworzymy już normalnie:

var miod = new Alkohol('Miód pitny', 13, '#850');

var butelka_miodu = new ButelkaAlkoholu(miod, 750, 2009, 'Polska');

 
console.dir(miod); // -> screenshot poniżej
console.dir(butelka_miodu); // -> screenshot poniżej

 
butelka_miodu.alkohol.nazwa; // -> "Miód pitny"

Obiekty miód i butelka miodu

Utworzyliśmy w ten sposób dwa obiekty, których struktura została wylistowana przy pomocy Firebuga i którą przedstawiłem na screenie.

W poprzedniej części artykułu pisałem o tym, że obiekt może mieć swoje metody (inaczej funkcje przypisane jako właściwości obiektu). Musi więc być sposób aby w konstruktorze obiektu zdefiniować takie metody. Dodajmy więc kilka linii do konstruktora ButelkaAlkohol:

var ButelkaAlkoholu = function (alkohol, pojemnosc, rok_produkcji, kraj_produkcji) {

	//...
	this.pelna = true;
	this.oproznij = function () {

		this.pelna = false;
	};
};
 
var butelka_miodu = new ButelkaAlkoholu(miod, 750, 2009, 'Polska');

butelka_miodu.pelna; // -> true
butelka_miodu.oproznij();
butelka_miodu.pelna; // -> false

Jak widać, aby utworzyć coś co możemy nazwać metodą, musimy przypisać funkcję do właściwości przyszłego obiektu. Uczulam znowu na działanie słowa this, o czym pisałem już poprzednim razem.

Alternatywna metoda tworzenia konstruktorów obiektów

Naszym celem jest utworzenie obiektu o zadanych przez nas wartościach właściwości. Pamiętając, że najprostszym sposobem na utworzenie obiektu jest skorzystanie z literału możemy dojść do następującej konstrukcji: stwórzmy funkcję zwracającją obiekt zapisany za pomocą literału:

var Alkohol2 = function (nazwa, ilosc_procentow, kolor) {

	var obj = {
		nazwa: nazwa,
		ilosc_procentow: ilosc_procentow,

		kolor: kolor,
		pelna: true,
		oproznij: function () { this.pelna = false; }

	};
 
	return obj;
};
 
var piwo = Alkohol2('piwo Tyskie', 5.6, '#FE3');

piwo; // -> Object nazwa=piwo Tyskie ilosc_procentow=5.6 kolor=#FE3

Tak więc skorzystaliśmy z funkcji w jej czysto funkcyjnym wymiarze. To jednak nie koniec. Dawno już nie było mowy o żadnym JavaScriptowym dziwactwie. Pora na następne. Otóż ten zapis również zadziała:

var piwo2 = new Alkohol2('piwo Tyskie', 5.6, '#FE3');

piwo2; // -> Object nazwa=piwo Tyskie ilosc_procentow=5.6 kolor=#FE3

Zonk.

Anegdota o użyciu new z funkcją

Kiedy dowiedziałem się o powyższym od razu zacząłem się zastanawiać jak w zasadzie JavaScript traktuje new w kontekście funkcji. Pierwsze co ciśnie się na palce, to modyfikacja przykładu z konstruktorem Alkohol2 tak by zwracał „nieobiekt”:

var Cons = function () {

	return 5;
};
var obj = new Cons();

obj; // -> Object

Nic ciekawego — jakiś pusty obiekt otrzymaliśmy. Dodajmy więc właściwość (pierwszy sposób tworzenia konstruktorów):

var Cons = function () {

	this.a = 'a';
	return 5;
};

var obj = new Cons();
obj; // -> Object a=a

Ciekawe, choć do wytłumaczenia — return 5 jest pomijane. Połączmy teraz dwa sposoby tworzenia konstruktorów:

var Cons = function () {

	this.a = 'a';
	return { b: 'b' };

};
var obj = new Cons();
obj; // -> Object b=b

Uups. JavaScript pomija właściwości zadeklarowane przy użyciu słowa this. W ten sposób dochodzimy do algorytmu, którym kieruje się ten język (a przynajmniej Firefox — może komuś się chce zajrzeć do specyfikacji? :):

  1. Jeśli zwracana przez funkcję wartość jest obiektem, to wyrażenie new Cons() zwraca ten obiekt.
  2. W przeciwnym wypadku wyrażenie to zwraca obiekt z właściwościami ustalonymi przy pomocy słowa this.

Porównując obydwa sposoby pisania konstruktorów można dojść do wniosku, że lepsza jest ta druga, (ze zwracaniem gotowego obiektu), ponieważ działa na obydwa sposoby: new Cons() i Cons(). Osobiście uważam jednak, że ta metoda jest gorsza — dlaczego? O tym później w tej i w następnej części artykułu.

Elementy programowania obiektowego

Umiemy już tworzyć konstruktory obiektów, które można porównać do klas w zwyczajnym języku. Obiekty tworzone za ich pomocą posiadały do tej pory jednak tylko publiczne właściwości i metody. JavaScript nie udostępnia mechanizmu modyfikatorów dostępu, można jednak skorzystać z jego cech aby oprogramować w prosty sposób podobne konstrukcje.

Właściwości prywatne

var Cons = function () {
    var private = 'jestem prywatna';

    this.getPrivate = function () { return private; };

};
 
var obj = new Cons();
obj.getPrivate(); // -> "jestem prywatna"

obj.private; // -> undefined

Dlaczego to działa? Wszystko opiera się o kolejny dziwoląg, czyli JavaScriptowego scope’a, a także o closures (BTW. fajne tematy na kolejne artykuły). W skrócie — funkcja zadeklarowana w innej funkcji ma dostęp do zmiennych dostępnych w swoim „rodzicu”. Do tego mechanizm domknięć powoduje, że funkcja getPrivate „zapamiętuje” środowisko, w którym została zadeklarowana.

Właściwości statyczne

var Cons = function () {
    this.nonstatic = 'nie jestem statyczna';

};
Cons.static = 'jestem statyczna';
 
Cons.static; // -> "jestem statyczna"

Cons.nonstatic; // -> undefined

Chyba nic nie trzeba wyjaśniać. Konstruktor Cons jak każda funkcja jest obiektem, więc można dodawać mu właściwości, co robimy w czwartej linii.

Dla jasności dodam, że w identyczny sposób tworzymy prywatne i statyczne metody obiektów i klas.

Dostęp z obiektu do konstruktora

Każdy obiekt posiada właściwość constructor, która daje dostęp do konstruktora (porównywalne do Javowego Object.getClass()):

var Cons = function () {

    this.sth = 'sth';
};
 
var obj = new Cons();

obj.constructor; // -> function()
obj.constructor.toString(); // -> "function () { this.sth = "sth"; }"

A teraz niespodzianka. Dlaczego drugi sposób tworzenia konstruktorów (przez literał obiektu) uważam za gorszy? O to jeden z powodów:

var Cons2 = function () {
    return { sth: 'sth' };

};
var obj2 = Cons2();
var obj3 = new Cons2();

 
obj2.constructor; // -> Object()
obj3.constructor; // -> Object()

obj2.constructor.toString(); // -> "function Object() { [native code] }"
obj3.constructor.toString(); // -> "function Object() { [native code] }"

Zdefiniowaliśmy konstruktor, który teoretycznie działa jak ten z poprzedniego przykładu (zwraca obiekt o tej samej właściwości). Okazuje się jednak, że kiedy spróbujemy dostać się do konstruktora tego obiektu, to nie jest nim funkcja Cons2, a zwykła, natywna Object. Dla porównania:

({}).constructor.toString(); // -> "function Object() { [native code] }"

Co dalej?

Umiemy już posługiwać się obiektami. Umiemy też tworzyć ich konstruktory. Pora więc na dziedziczenie. O tym za czas jakiś w następnej części :)

Artykuł został opublikowany także na moim blogu prywatnym.

Kategorie:Różne Tagi:

Naj- opisy zmian w kodzie

Maj 19th, 2009 zergu 4 comments

Najgłupsze, najśmieszniejsze, najbardziej bezsensowne, najciekawsze pełne opisy zmian wgranego kodu w Subversion jakie udało nam się przyuważyć:

  • poprawka po zergu. Wstydź się :P
  • cos
  • refaktoryzacja hahaha
  • nie pamiętam co to
  • tagusie na dole
  • coby hmora taguf smigala jak na waSseLinie
  • Debile z PHP nie potrafią nawet gramatyki języka sensownie zrobić.
  • coby sie firebug nie denerwowal
  • Cichaczem zmieniłem Reinmarowi CSS-a.
  • redesign layoutu. O kurwa
  • dopieszczanko
  • Fix Knorra
  • Firefix.
  • cosie
  • haaa!
  • jkopytko
  • stylusie dla panelusia administratorka
  • dopieszczanie zdzicha
  • 3h meki z textilem i nadal nikt nie wie dlaczego niedziala. Ihaha
  • Szukarko
  • Polska sie pisze z duzej litery
  • musk mię boli
  • glupia opera
  • Zergu, kocham Cię
  • +glebogryzarka
  • Forms w Syffony to jakiś żart.
  • boze , ja nie moge =)
  • kod :)
  • la la la layout
  • Ominięcie buga PHP, który autorzy nazywają ficzerem.
  • Tao w kodzie
  •  
  • Teraz jest dobrze
Kategorie:Różne Tagi:,

Jak przycinać i skalować obrazki?

Kwiecień 17th, 2009 eshaem 1 komentarz

Odwiecznym problemem przy wyświetlaniu obrazków użytkowników jest przycinanie i skalowanie ich w taki sposób, który pasuje do wyglądu serwisu. Problem na pierwszy rzut oka może wydawać się dość trudny ze względu na różnorodność obrazków, które może wysłać użytkownik, posiada on jednak proste i eleganckie rozwiązanie.

lena

Lena - obiekt naszych testów

Na potrzeby wypisu założmy, że zajmujemy się przeskalowaniem powyższego obrazka z rozmiarów 300 x 300 px na 200 x 100 px. Można pomyśleć o najprostszym rozwiązaniu, czyli przeskalowaniu albo wycięciu odpowiedniego kawłka z oryginalnego obrazka. Żadne z tych rozwiązań nie jest jednak dobre, pierwsze nie poradzi sobie z plikami, w których stosunek szerokości do długości jest inny niż docelowy, drugą metodą wytniemy jedynie fragment z obrazka pomijając być może istotną część interesującą użytkowników naszego serwisu. (W szczególności problem pojawia się problem przy dużych obrazkach, którą część wycinać? Przedstawiony poniżej przykład jest nieco tendecyncyjny ze względu na małą wielkość obrazka.)

Skalowanie

Skalowanie

Wycinanie

Wycinanie

Potrzebujemy więc rozwiązanie, które pozwoli uwzględnić różny stosunek wysokości do szerokości obrazka dostarczonego przez użytkownika, oraz umożliwi pokazanie jego jak największej zawartości. Najlepiej więc będzie jeżeli będziemy tylko ścinać obraz z góry i dołu, lub lewej i prawej a następnie skalować go do żądanego rozmiaru. Niech iw i ih oznaczają odpowiednio szerokość i wysokość obrazka wejściowego, natomiast ow i oh analogicznie dla obrazka wyjściowego. Obliczamy stosunki szerokości do wysokości dla obrazków:

  • Ri = iw/ih – w naszym przypadku wynosi on 300/300 = 1
  • Ro = ow/oh – w naszym przypadku wynosi on 200/100 = 2

Ponieważ Ro jest większy niż Ri, czyli w obrazku wyjściowym przypada więcej pikseli szerokości na piksel wysokości, to powinniśmy wyciąć możliwe najmniejszy kawałek góry i dołu z oryginalnego obrazka tak aby uzyskać w nim współczynnik Ro. Wymiary pasów, które powinniśmy wyciąć obliczamy następująco:

  • dh = iw/ro – w naszym przypadku 300/2 = 150

Ponieważ sumaryczna szerokość pasa wynosi 150, to przytniemy z góry i dołu pasy o szerokości 300 i wysokości 75 i skalujemy to co zostało do rozmiaru 200 x 100 px, przyjmując optymistycznie, że na skraju obrazka znajdują się zawsze najmniej istotne treści.

Fragment obrazka do przeskalowania

Fragment obrazka do przeskalowania

Wynik działania metody

Wynik działania metody

Sytuacja gdy Ro jest mniejsze od Ri jest analogiczna, nie będę więc jej omawiał. Przedstawiony algorytm jest bardzo prosty i w pseudokodzie wygląda następująco:

Ri = iw / ih
Ro = ow / oh

if (Ri  <= Ro)
{
new_h = ow / Ro
segment = (ih-newh)/2
zetnij pas o wysokości segment z góry i dołu i przeskaluj do rozmiarów ow x oh px
}
else
{
neww = Ro * ih
segment = (iw – neww) / 2
zetnij pas o szerokości segment z lewej i prawej i przeskaluj do rozmiarów ow x oh px
}

Przy implementacji  powyższego rozwiązania w języku PHP do ścinania i skalowania przydatna może okazać się funkcja imagecopyresampled().

Uruchamiamy PrawaWolna.pl

Marzec 9th, 2009 zergu Brak komentarzy

Dzisiaj wpis zupełnie nietechniczny. Chcieliśmy się jedynie pochwalić, że startujemy jeden z naszych serwisów: PrawaWolna.pl

Jest to serwis skierowany do wszelkiej maści kierowców i przez nich tworzony. Na stronie można znaleźć między innymi:

Zapraszamy! Wszelkie opinie, komentarze, zgłoszenia błędów są bardzo mile widziane.

Kategorie:Różne Tagi:

Refaktoryzacja CSS — jednak coś można

Marzec 5th, 2009 zergu 2 comments

Mówi się, i to raczej nie bez powodu, że refaktoryzowanie arkuszy stylów jest bardzo trudne. Jednak na szczęcie da się znaleźć przynajmniej jedno narzędzie bardzo usprawniające ten proces. Zwie się ono Dust-Me Selectors i jest dostarczane jako rozszerzenie do Firefoksa.

Dust-Me Selectors robi właściwie „tylko” jedną rzecz — znajduje nieużywane selektory CSS. Jednak właśnie jest to jedna z najtrudniejszych rzeczy do wykonania manualnie, szczególnie w przypadku dużych, długo rozwijanych projektów.

Rozszerzenie może działać na dwa sposoby:

  • przeszukiwanie jednej strony (przydatne raczej w niewielu przypadkach),
  • tzw. Spider Search, czyli przeszukiwanie wszystkich linków z mapy strony.

Mapa strony może być stroną HTML lub sitemapą w XML zgodną ze standardem. W tym pierwszym przypadku są pewne ograniczenia. Otóż domyślnie potrafi on wyskoczyć na inne, zewnętrzne domeny i je sprawdzać. Nie udało nam się znaleźć opcji zabraniającej tego, jedynie da się ograniczyć omijanie odnośników z rel=”external” i/lub rel=”nofollow”. Problem jest, gdy nasz serwis na to nie jest przygotowany. Wtedy pozostaje wygenerowanie lub napisanie sitemapy (która przecież i tak się przyda).

Samo działanie programu już jest bardzo proste. Wybieramy „Automation → Spider Search”, podajemy adres sitemapy lub strony HTML i czekamy na wyniki, które wyglądają na przykład tak:

Okno wyników Dust-me Selectors

Okno wyników Dust-me Selectors

Oczywiście znalezione selektory nie powinny trafiać od razu do kosza, bo narzędzie nie potrafi (i raczej wątpliwe żeby kiedykolwiek potrafiło) wziąć pod uwagę manipulacji dokonywanych przez JavaScript. Ponadto mogą istnieć specyficzne widoki, które nie będą mogły się znaleźć w mapie strony. Dlatego też wyniki należy traktować tylko jako listę podejrzanych. Warto dodać, że narzędzie pomogło nam szybko pozbyć się prawie dwustu linii z arkuszy CSS (przy kolejnych do dokładniejszego sprawdzenia).

Kategorie:Różne Tagi:,

Dostosowanie grep-a do SVN i Symfony

Luty 16th, 2009 zergu Brak komentarzy

Jednym z nieocenionych narzędzi podczas programowania jest grep, który (jakby ktoś nie wiedział) służy do wyszukiwania treści w plikach tekstowych.

Jednak, jak każde narzędzie, warto go dostosować do własnych potrzeb. Ja najczęściej stosuję go do przeszukiwania projektów będących pod kontrolą Subversion (SVN), poprzez taką instrukcję:

grep -RIin "szukane" * --exclude-dir=\.svn

Dla wyjaśnienia: -R — szukanie rekursywne w podkatalogach, -I — pomijanie plików binarnych, -i — niewrażliwość na wielkość znaków, -n — wyświetlenie nr linii w wyniku.

Oczywiście wpisywanie tego za każdym razem nie ma nic wspólnego z wygodą, dlatego warto sobie utworzyć funkcję dla powłoki np. w pliku .profile (średniki na końcu są wymagana dla Basha, Zsh ich nie potrzebuje):

function g { grep -RIn $1 * --exclude-dir=\.svn ; }
function gi { grep -RIin $1 * --exclude-dir=\.svn ; }

Dzięki czemu wystarczy wykonać:


[src]> g fuck
arch/i386/kernel/cpu/cpufreq/powernow-k7.c:558: * Some Athlon laptops have really fucked PST tables.
arch/i386/kernel/cpu/mtrr/generic.c:70:/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
…

Z racji tego, że większość projektów piszę w Symfony, stworzyłem sobie dodatkową wersję tej funkcji:

function sfg { grep -RIn $1 lib/model apps/ --exclude-dir=\.svn ; }

Odpalając ją w głównym katalogu projektu, można łatwo przeszukać wszystkie warstwy aplikacji (model, widoki, kontrolery i przy okazji parę innych).

Jest też możliwość włączenia „na stałe” niektórych opcji, poprzez wyeksportowanie zmiennej środowiskowej o nazwie GREP_OPTIONS, np.:

export GREP_OPTIONS="--exclude-dir=\.svn"

Ale ja osobiście tego nie stosuję.

Kategorie:Różne Tagi:, ,

Connection: close + Apache Benchmark

Grudzień 19th, 2008 Mistrz Wu Brak komentarzy

Testowanie apache-benchmarkiem (/usr/sbin/ab) jest niewątpliwie łatwe, proste i przyjemne, nie licząc rozczarowania wynikami. Znakomicie spisuje się w przypadku Rails (nie mam pojęcia dlaczego), ale w aplikacyjach PHP może nieco zaskoczyć.

Też nie wiem dlaczego, ale wydaje mi się, że jest prawdopodobnym iż…

Otóż PHP, słusznie zresztą, przy braku nagłówka Connection czeka na kolejne zapytania na tym samym połączeniu (zakłada domyślnie: keep-alive), a ab sam z siebie go nie wysyła i… zwiesza się na iluś tam otwartych połączeniach, na których nic się nie dzieje (ab chyba czeka aż to serwer się rozłączy). Niezbyt miło, bo to zaniża wyniki benczmarku i pogarsza i tak już złe samopoczucie.

Dlategoż zawsze dla pewniejszych wyników (i dobrego samopoczucia) warto dodawać ab opcje -H 'Connection: close'. Manual mówi nawet, że przełącznikiem -H można też inne nagłówki wysyłać, gdyby komuś zależało.

Czy to jednak znaczy, że Rails w wersji cokolwiek starej, bo 2.1.1, domyślnie zakłada Connection: close? To by było niesłuszne, lecz może być wytłumaczone jednowątkowością Rails. Tego niestety, już mi się nie chciało inwestygować, bo święta idą.

Tak więc szczęśliwego nowego jajka i co tam jeszcze!

Kategorie:Różne Tagi:, , ,