teamon.eu

Webrat for [your language]

04 lutego 2010

Będzie szybko.

Webrat został napisany z myślą o Railsach. A co jeśli piszemy aplikacje w czymś innym? Odp. - Webrat! ;]

Wymagania: Ruby

Instalacja:

gem install mechanize webrat

Już.

Tworzymy sobie plik test.rb i wrzucamy:

 
require "webrat"
 
Webrat.configure do |config|
  config.mode = :mechanize
end
 
class MechanizeWorld < Webrat::MechanizeAdapter
  include Webrat::Matchers
  include Webrat::Methods
 
  Webrat::Methods.delegate_to_session :response_code, :response_body
end
 
Spec::Runner.configure do |config|
  include Webrat::Methods
end
 
# Tu sie zaczynaja testy
 
describe "Awesome system" do
  it "should work" do
    visit "http://0.0.0.0:8080"
    click_link "Login"
    fill_in "Username", :with => "teamon"
    click_button "Login"
    response_body.should include "Wrong password"
  end
end
 

Odpalamy przez

spec test.rb
(opcjonalnie:
spec --color --format=specdoc test.rb

 
% spec --color --format=specdoc test.rb
 
Awesome system
- should work
 
Finished in 0.060042 seconds
 
1 example, 0 failures
 

Bangla. Ale jest brzydko. Osobiście wole taka strukturę:

path/to/tests/spec_helper.rb
 
require "webrat"
 
Webrat.configure do |config|
  config.mode = :mechanize
end
 
class MechanizeWorld < Webrat::MechanizeAdapter
  include Webrat::Matchers
  include Webrat::Methods
 
  Webrat::Methods.delegate_to_session :response_code, :response_body
end
 
Spec::Runner.configure do |config|
  include Webrat::Methods
end
 
path/to/tests/spec.opts
 
--color
--format specdoc
 
path/to/tests/login_spec.rb
 
require File.join( File.dirname(__FILE__), "spec_helper" )
 
describe "Login system" do
  it "should not let me in" do
    visit "http://0.0.0.0:8080"
    click_link "Login"
    fill_in "Username", :with => "teamon"
    click_button "Login"
    response_body.should include "Wrong password"
  end
end
 
Rakefile
 
desc "Run specs"
task :spec do
  system("spec path/to/tests -O path/to/tests/spec.opts")
end
 

Odpalane oczywiście poprzez

rake spec

Pozostaje tylko pisać testy :)

Dodaj komentarz

merb + db4o

29 lipca 2009

Mini tutorial o tym jak skorzystać z obiektowej bazy db4o w merbie - takie małe proof of concept.

Wymagania & instalacja

  • JRuby - Przykład instalacji można znaleźć na przykład w jednym z poprzednich postów
  • db4o - .jar dostępny razem z rdb4o
  • merb - gem install merb-core
  • rdb4o
    git clone git://github.com/teamon/rdb4o.git
    cd rdb4o
    rake install
  • merbrdb4o
    git clone git://github.com/teamon/merb_rdb4o.git
    cd merb_rdb4o
    rake jruby:install
Więcej... Dodaj komentarz

Ruby - bound/unbound method, inherited, included, extended

03 czerwca 2009

Bound i unbound method

Ruby pozwala na "wyciągnięcie" pojedynczej metody z obiektu w postaci obiektu Method, który można później wywołać. Ruby dostarcza dwa rodzaje metod - Method oraz UnboundMethod. Podstawową różnicą między tymi dwoma jest to, że Method możemy wywołać, a UnboundMethod nie. Spowodowane jest to tym, iż obiekt UnboundMethod nie ma zadeklarowanego odbiorcy metody. Obiekt UnboundMethod można oczywiście "przypiąć" do odpowiedniego obiektu, ale o tym za chwilę.

Na początek prosty przykład.

 
class Timmy
  attr_accessor :age
 
  def say
    "Timmy!"
  end
 
  def move(x)
    "Moved #{x} meters"
  end
end
 
timmy = Timmy.new
 
say_method = timmy.method(:say) # => #<Method: Timmy#say>
move_method = timmy.method(:move) # => #<Method: Timmy#move>
 

Metoda method(sym) jest zdefiniowana w klasie Object i dostępna we wszystkich obiektach. Zwraca obiekt Method z metodą o podanej nazwie. Metoda ma zadeklarowanego odbiorcę, tak więc można ją wykonać. Metody wykonuje się tak samo jak obiekty Proc czyli poprzez call(parametry).

 
say_method.call # => "Timmy!"
move_method.call(4) # => "Moved 4 meters"
 

Taki obiekt metody można "odczepić" od odbiorcy:

 
unbound_say = say_method.unbind # => #<UnboundMethod: Timmy#say>
 

Tak "odczepionej" metody nie można już wywołać:

 
unbound_say.call
NoMethodError: undefined method `call' for #<UnboundMethod: Timmy#say>
	from (irb):30

Innym sposobem na uzyskanie obiektu UnboundMethod jest pobranie metody proste z klasy.

 
unbound_method = Timmy.instance_method(:say) # => #<UnboundMethod: Timmy#say>
 

Taki obiekt można teraz "przypiąć" do odpowiedniego obiektu:

 
tim = Timmy.new
unbound_method.bind(tim) # => #<Method: Timmy#say>
 

Jednak przypinanie metody z klasy do obiektu tej samej klasy ma trochę mały sens. Jednak można to wykorzystać na przykład w celu wywołania metody nadnadklasy:

 
class Person
  def say
    "HELLO"
  end
end
 
class Kid < Person
  def say
    "Hi"
  end
end
 
class Jimmy < Kid
  def say
    "Jimmy!"
  end
end
 
jim = Jimmy.new
jim.say # => "Jimmy!"
jim.class.superclass.superclass.instance_method(:say).bind(jim).call # => "HELLO"
 

included, extended, inherited

Metody included, extended oraz inherited są (jak można się domyślić) wywoływane kiedy korzystamy z include, extend albo dziedziczenia.

Kiedy dziedziczymy po jakiejś klasie, wywoływana jest na niej metoda inherited (o ile została zadeklarowana):

 
class Car
  def self.inherited(base)
    puts "#{base} inherits from Car"
  end
end
 
class Mercedes < Car; end
class Audi < Car; end
class BMW < Car; end
 
# >> Mercedes inherits from Car
# >> Audi inherits from Car
# >> BMW inherits from Car
 

Daje to większe możliwości operacji na klasach pochodnych i pozwala na wykonanie dodatkowych operacji.

Kolejną i chyba najczęściej wykorzystywaną metodą jest included. Metoda ta dotyczy modułu, który jest "includowany". Dzięki temu zamiast pisać:

 
class Audi
  include Fast::InstanceMethods
  extend Fast::ClassMethods
end
 

można to uprościć do zapisu:

 
class Audi
  include Fast
end
 

a całą resztę pozostawić modułowi:

 
module Fast
  def self.included(base)
    puts "#{base} includes Fast"
    base.send(:include, InstanceMethods)
    base.extend(ClassMethods)
  end
 
  module InstanceMethods
    def go
      "Goooooo #{self}"
    end
  end
 
  module ClassMethods
    def describe
      "I`m #{self}"
    end
  end
end
 
class Audi
  include Fast
end
 
class BMW
  include Fast
end
 
# >> Audi includes Fast
# >> BMW includes Fast
 
Audi.describe # => "I`m Audi"
BMW.describe # => "I`m BMW"
Audi.new.go # => "Goooooo #<Audi:0x241bc>"
BMW.new.go # => "Goooooo #<BMW:0x24090>"
 
 

Ostatnią metodą jest extended, która jest praktycznie identyczna w działaniu jak included z tym że jest wywoływana podczas użycia extend:

 
module Slow
  def self.extended(base)
    puts "Slow extends #{base}"
  end
 
  def describe
    "I`m slow #{self}"
  end
end
 
class Mercedes
  extend Slow
end
 
# >> Slow extends Mercedes
 
Mercedes.describe # => "I`m slow Mercedes"
 

Zarówno inherited jak i included są często wykorzystywane w przeróżnych bibliotekach. Przewagą dołączania modułu nad korzystaniem z dziedziczenia jest to, że moduł możną dołączyć praktycznie zawsze, podczas gdy ustawienie nadklasy nie zawsze jest możliwe.

2 komentarze

rubber - wersja testowa

29 maja 2009

Czyli edytor szablonów Joggera i menadżer plików z wbudowanym serwerem.

Lista ficzerów:

  • Dodawanie, usuwanie plików z folderu files
  • Edycja szablonów wpisów, komentarzy, logowania
  • Edycja szablonów stron
  • Serwer upakowujący szablony w przykładową treść - nie ma potrzeby męczenia się w panelu Joggera żeby sprawdzić jak coś będzie wyglądać.
  • Podgląd nowego wpisu

Wymagania

Jedynym wymaganiem do uruchomienia programu jest zainstalowany interpreter Ruby

W chwili obecnej zaimplementowana jest większość tagów szablonowych, które są opisane na Wiki. Poniżej krótki opis użycia.

Instalacja i konfiguracja

Instalacja sprowadza się do zainstalowania gema z githuba

 
gem sources -a http://gems.github.com
sudo gem install teamon-rubber
 

Ustawienie loginu i hasła (hasło jest przechowywane w zakodowanej formie)

 
mkdir my_jogger
cd my_jogger
rubber configure
 

Zarządzanie plikami

Pobranie plików z Joggera

rubber download

Wysłanie zmodyfikowanych plików

 
rubber upload files/my_file.html
rubber upload Szablon_koemntarzy.html
 

Wysłanie wszystkich plików

rubber upload files/*

Uruchomienie serwera

rubber server

Twój jogger będzie dostępny pod adresem http://localhost:1337. Przykładowe treści można zmienić w pliku content.yml. Zmiana w pliku szablonu będzie od razu widoczna po odświeżeniu przeglądarki (nie ma potrzeby restartowania serwera).

Podgląd nowego wpisu

Dodając plik do folderu posty o nazwie np. "nowy post.html" będzie on dostępny pod adresem http://localhost:1337/nowy%20post

Wszelkie propozycje i uwagi są bardzo mile widziane.

Kod oczywiście dostępny na githubie

2 komentarze

Pokaż swoje gemy!

10 maja 2009
Gem graph

Wpadłem dzisiaj na posta o pluginach to rubygems. Jednym z nich jest graph. Korzystając z języka dot (o którym możecie sobie przeczytać na jednym z joggerów) tworzy on graf zainstalowanych gemów połączonych zależnościami.

Wszystko co trzeba zrobić sprowadza się do:

 
sudo gem install graph
gem graph
 

Szczerze powiedziawszy jak zobaczyłem mój graf to trochę się przeraziłem...(gemów mam 195)

Swoją droga rails wypada bardzo biednie przy merb+dm :]

A jaki jest twój graf? :P

6 komentarzy