Długo zbierałem się z tą decyzją, ale ostatecznie ją podjąłem. Wznawiam moją aktywność blogową jednak na nowym, angielskojęzycznym blogu: michalorman.com. Zapraszam wszystkich do śledzenia mojego nowego bloga.
Nowy blog, nowy start
22 Mar 2012 · general · Komentuj
Unobtrusive CSS
18 Oct 2011 · ruby · Komentuj
Bardzo modnym ostatnio terminem jest Unobtrusive JavaScript
. Ideą tego
podejścia jest nie umieszczanie wywołań JavaScript w plikach HTML
(np. w zdarzeniach onclick czy onblur) a przypinanie ich z poziomu
samych JavaScriptów za pomocą odpowiednich selektorów (a jeszcze lepiej
z wykorzystaniem np. jQuery). Mało jednak się
mówi iż ten sam paradygmat tyczy się CSS-a, a w jego przypadku sprawa
jest trochę mniej oczywista.
Zacznijmy od trywialnego przykładu, na początek w Javie, a konkretniej JSF. Któż z nas nie spotkał się z czymś podobnym:
<ice:panelGrid columns="3" style="width:100%" cellpadding="0" cellspacing="0"
columnClasses="col15 firstcol, col35 lastcol, col50 lastcol">
<!-- ... -->
</ice:panelGrid>
Jaki jest sens tworzenia klas typu col50? Czym to się różni od
ustawienia style="width: 50%" prosto w plikach JSF? Oczywiście w przypadku JSF i
komponentu panelGrid nie da się ustawić stylu dla poszczególnych
kolumn, A jedynie klasy, ale niewiele to zmienia.
Przejdźmy jednak do mniej oczywistego przypadku, na który ja się
ostatnio złapałem. Tworzyłem formularz, który w odróżnieniu od
pozostałych, zamiast każde pole renderować w kolejnym wierszu cały
renderował się w jednym. Pomyślałem, tak jak pewnie wiele osób by
pomyślało, zrobię klasę inline-form. Wtedy do każdego formularzu,
który ma być renderowany "w linii" dodam tę klasę i będzie śmigać. No i
powstał taki kod:
= simple_form_for @language, :html => { class: 'inline-form' } do |f|
= f.input :name, :label => false
= f.input :level, :label => false
= f.submit
I arkusz styli:
.inline-form {
overflow: hidden;
input {
float: left;
}
}
W arkuszu stylów standard, jakiś float, jakiś overflow.
Im dłużej się przyglądałem temu formularzowi tym bardziej mi się to
przestawało podobać. Czym to się właściwie różni od "niesławnych"
col35 czy col50 z poprzedniego przykładu? Idea jest
dokładnie ta sama. Jakiś fragment CSS-a zamykamy w klasie i ją
umieszczamy w HTML-u. Po prostu mamy mniej klepnięć w klawiaturę, no i
reużycie kodu prawda?
Style powinniśmy w dokumentach HTML umieszczać w sposób unobtrusive. Aby to osiągnąć, podobnie jak w przypadku JavaScript-u, powinniśmy w arkuszu stylów odpowiednim selektorem wybrać interesujący nas formularz i zdefiniować jak on powinien wyglądać. Nie potrzebujemy żadnej klasy.
Niestety sam CSS jest zbyt ograniczony, aby osiągnąć ten efekt jednocześnie nie duplikując kodu. Jeżeli chcielibyśmy posiadać wiele takich formularzy musielibyśmy skopiować kod stylu dla każdego formularza. Dlatego warto zamiast czystego CSS-a skorzystać z takich języków jak Sass). W Sass możemy bardzo łatwo osiągnąć ten sam efekt bez dublowania kodu:
@mixin inline-form {
overflow: hidden;
input {
float: left;
}
}
#new_language {
@include inline-form;
}
Po co ta cała zabawa? Po to aby nie mieszać odpowiedzialności (SRP?). HTML mówi co znajduje się w dokumencie, CSS określa jak wygląda a JavaScript jak się zachowuje. Zarówno JavaScript jak i CSS powinny być łączone z dokumentem HTML w sposób unobtrusive.
Testowanie operacji na plikach z FakeFS
16 Sep 2011 · ruby · Komentuj
Testowanie operacji na plikach może być problematyczne. Z jednej strony nie chcemy zaśmiecać swojego systemu jakimiś plikami generowanymi przez testy i martwić się, aby posprzątać po testach, z drugiej mockowanie klas I/O może być uciążliwe, oraz powoduje, że testy są bardzo wrażliwe na zmianę implementacji (nawet jeśli działanie metody pozostało bez zmian). Testując operacje na plikach na prawdę chcielibyśmy tworzyć te pliki, sprawdzać ich istnienie, atrybuty czy zawartość.
Rozwiązaniem tego problemu jest FakeFS. Biblioteka ta tworzy nam sztuczny system plików w pamięci operacyjnej. Dzięki FakeFS możemy tworzyć i testować pliki jednocześnie nie zaśmiecając sobie dysku.
Ponieważ biblioteka ta modyfikuje działanie biblioteki I/O możemy
natknąć się na problemy jeżeli nasz test powinien otworzyć plik z
prawdziwego systemu pliku. Na szczęście FakeFS pozwala nam aktywować i
deaktywować w dowolnym momencie sztuczny system plików. Przykładowo
testując za pomocą Cucumber'a do pliku env
możemy dodać coś takiego:
Before '@fakefs' do
FakeFS.activate!
end
After '@fakefs' do
FakeFS.deactivate!
end
Wtedy każdy scenariusz oznaczony przez @fakefs będzie wykonywany z
użyciem sztucznego systemu plików.
Używając tej biblioteki nie potrzebujemy korzystać z jakiegoś dodatkowego API, tworzyć jakiś magicznych obiektów itp. Operujemy na plikach po prostu korzystając z biblioteki I/O.
HTTP Basic Auth w Rails 3.1
05 Sep 2011 · ruby · Komentuj
Rails 3.1 pojawiło się na horyzoncie przynosząc nam wiele zmian (czasem dość kontrowersyjnych), a także wiele uproszeń, w tym dotyczących uwierzytelniania (ang. authentication). Teraz jeżeli chcemy część naszych widoków ukryć tylko dla administratora, możemy w prosty sposób zadeklarować uwierzytelnianie metodą HTTP Basic. Wystarczy w kontrolerze dodać:
http_basic_authenticate_with :name => "admin", :password => "secret"
I już. Dla pełności powinniśmy dodać force_ssl aby połączenie było
szyfrowane. Możemy również użyć parametrów only oraz except
znanych z filtrów.
To proste podejście jest jednak mało interesujące dla tych, którzy implementują jakiejś REST-owo-JSON-owe API w oparciu o Rails. W takim przypadku powinniśmy zdefiniować w kontrolerze filtr:
before_filter :authenticate!
private
def authenticate!
authenticated = authenticate_with_http_basic do |username, passwd|
# Tutaj proces uwierzytelniania...
end
request_http_basic_authentication unless authenticated
end
W ten sposób możemy posiadać bazę wielu użytkowników i uwierzytelniać ich metodą HTTP Basic. Rails czarną robotę zrobi za nas.
Spinner z Simple Form
30 May 2011 · ruby · Komentuj
Załóżmy, że w naszej aplikacji tworzymy widok na którym zawartość jednej listy wyboru zmienia się w zależności od tego co wybierzemy w drugiej. Opcje listy przeładowywane są oczywiście z pomocą AJAX-a. Załóżmy również, że chcemy użytkownika poinformować o owym żądaniu wyświetlając odpowiedni obrazek postępu (tzw. spinner) tuż obok listy, która ma zostać przeładowana. Oczywiście nic nie powinno stać na przeszkodzie, aby takich list mieć wiele na jednym formularzu. Na koniec załóżmy, że aplikację tworzymy w frameworku Rails z użyciem simple_form. Jak zatem dodać spinner to pola formularza? Okazuje się, że korzystając z tej instrukcji jest to niezwykle proste.
To co chciałbym osiągnąć, to aby nasz spinner można było deklaratywnie dodawać do pola formularza (podobnie jak pozostałe komponenty):
f.association :subcategory, :spinner => true
Zatem podążając zgodnie z instrukcją modyfikujemy najpierw
konfigurację /config/initializers/simple_form.rb:
SimpleForm.setup do |config|
config.components = [ :placeholder, :label_input, :spinner, :hint, :error ]
end
require 'simple_form/spinner'
W konfiguracji tej musimy dodać nowy komponent spinner który będzie
renderowany dla każdego pola formularza.
Następnie tworzymy plik /lib/simple_form/spinner.rb:
module SimpleForm
module Components
module Spinner
def spinner
if options[:spinner]
spinner_tag(attribute_name)
end
end
private
def spinner_tag(attribute)
template.image_tag 'spinner.gif', :id => "#{attribute}-spinner", :class => "spinner", :style => "display: none"
end
end
end
module Inputs
class Base
include SimpleForm::Components::Spinner
end
end
end
I to w zasadzie tyle. W metodzie spinner dla każdego pola, które
posiada opcję spinner = true tworzymy spinner_tag, który jest
zwyczajnym obrazkiem z unikalnym identyfikatorem. Spinner domyślnie
jest ukryty i musimy go przy odpowiednim zdarzeniu (np. zmianie
nadrzędnej listy) wyświetlić (np. metodą toggle z jQuery). Moduł
Spinner musimy jeszcze dołączyć do klasy
SimpleForm::Inputs::Base skąd będzie dostępny dla wszystkich pól
formularza.
Gotowy skrypt jest dostępny tutaj: https://github.com/michalorman/simple_form_spinner.
Jest w nim też kilka drobnych usprawnień konfiguracyjnych.