Quick tip #2: Memoizable 2

Posted by wijet
on Wednesday, April 22

Gdy jakaś metoda wykonuje kosztowne obliczenia, a jej wyniku używamy wielokrotnie, rozsądnym jest obliczenia wykonać raz, a wynik zapamietać, tzw. cachowanie za pomoca zmiennych instancji. W takim wypadku, najczęsciej używamy idiomu "||="

class Bar
  def foo
    @foo ||= lambda {
      # jakies kosztowne obliczenia
      ...
    }.call
  end
end

Od railsów 2.2 możemy korzystać z metody :memoize, należy dodać metody z modułu ActiveSupport::Memoizable jako metody klasy.

class Bar
  extend ActiveSupport::Memoizable

  def foo
    # jakies kosztowne obliczenia
    ...
  end

  memoize :foo
end

Spowoduje to że za pierwszym wywołaniem metody :foo, metoda ta faktycznie zostanie wywołana, a wartość przez nią zwrócona zapamiętana (dziala to tak jak cachowanie w zmiennej instancji, czyli tylko w obrebie danego obiektu).

Każde następne wywołanie metody :foo, na tym konkretnym obiekcie, spowoduje zwrócenie zapamiętanej wartośći.

Jeśli chcemy wymusić wywołanie metody (tzn. bez cachu), jako ostatni parametr należy podać wartość true.

Linki

Module ActiveSupport::Memoizable

Memo-what? - A Guide to Memoization

Railscasts: Memoization

What's New in Edge Rails: Easy Memoization

Quick tip #1: tap i returning 3

Posted by wijet
on Saturday, April 11

Tym postem chcę rozpocząć serię którkich wpisów, o konkretnych metodach/konstrukcjach dostępnych w railsach, lub w samym Ruby, Za pomocą których możemy zrobić coś krócej, ładniej, bardziej ruby way.

Czasami pojawia się potrzeba wykonania na obiekcie pewnych operacji, a następnie zwrócenie go.

def foo(name)
  product = Product.find_or_initialize_by_name(name)
  # tu cos mieszamy z produktem
  ...
  # zapisujemy
  product.save
  product
end

jak widać na końcu musi być 'product' aby metoda zwracała product, inaczej :foo zwrociła by nam prawde lub fałsz, czyli wynik product.save

Możemy to bardzo elegancko, zastapić, poniższa konstrukcją

returning

def foo(name)
  returning Product.find_or_initialize_by_name(name) do |product|
    # tu cos mieszamy z produktem
    ...
    # zapisujemy
    product.save
  end
end

:returning przyjmuje obiekt, przekazuje go do bloku który otrzymuje, a następnie zwraca ten obiekt

tap

Za pomocą :tap możemy zrobić to samo, w troche inny sposob:

def foo(name)
  Product.find_or_initialize_by_name(name).tap do |product|
    # tu cos mieszamy z produktem
    ...
    # zapisujemy
    product.save
  end
end

Metoda :tap przyjmuje blok do którego przekazuje self (obiekt na którym została wywołana), a następnie po wykonaniu bloku zwraca self.

Obydwie metody sa dostepne w railsach. Warto wiedzieć że metoda :tap została włączona do Ruby w wersji 1.9.

Za pomocą metody :tap mozemy nawet wiecej poczarować, polecam przejrzenie poniższych linków:

Linki

Eavesdropping on Expressions

Tapping method chains with Ruby 1.9

Rails ActiveSupport returning Method

Mining ActiveSupport: Object#returning

Named scopes w ActiveRecord 3

Posted by wijet
on Thursday, April 02

Od railsów 2.1 możemy korzystać z dobrodziejstw named_scopes, za pomocą których możemy definiować w łatwy sposób findery. Mowiąc prościej, możemy budować zapytania do bazy danych. Nie są to jednak zwykłe metody ktore wyszukują nam coś w bazie, zamiast prostego zbioru wyników, zwracany jest scope (zakres).

Aby rzucić więcej swiatła na sprawę, zacznijmy od przykładu:

class Product < ActiveRecord::Base
  named_scope :available, :conditions => "amount > 0"
  named_scope :featured, :conditions => {:featured => true}
end

Daj się policzyć! 0

Posted by wijet
on Friday, December 14

Firma OpenLogic przeprowadza pierwszy na świecie spis programów open source. Jak wiadomo trudno jest policzyć wolne oprogramowanie, jest masa mirrorów, bardzo często oprogramowanie jest dostarczane razem z systemami operacyjnymi np linuksem, rozdawane na wszelakich konferencjach. Aby wdziąć udział w akcji należy ściągnąć program który przeskanuje nasz komputer w poszukiwaniu oprogramowania open source. Aplikacja wymaga interpretera Ruby przynajmniej w wersji 1.8.5. Pozostaje tylko czekać na pierwsze analizy wyników.

Dziwne zachowanie ||= 3

Posted by wijet
on Sunday, November 04

Do tej pory myślałem o boo ||= "foo" jako naturalnym(lepszym) zamienniku dla instrukcji

boo = "foo" if boo.nil?

Czyli do zmiennej boo przypisujemy "foo" jeśli boo jest nil'em. Fakt ten jest opisany na wielu stronach, także w książce "Programowanie w Języku Ruby" czytamy:

words[key] ||= []

"...jeśli wpis w tablicy asocjacyjnej words dla klucza key nie istnieje(nil), wartością zwracaną przez || będzie drugi operand, > czyli nowa pusta tablica. Dlatego ten wiersz kodu przypisze tablice elementowi tablicy asocjacyjnej który nie ma jeszcze > wartości..."

I w takiej świadomości dość długo żyłem, dlatego metoda typu

def foo(options = {})
  options[:boo] ||= true
  options[:bar] ||= "r"
end

wydawała mi się całkowicie poprawna.

Niestety tak nie jest, przekazanie do metody :boo => false i tak powodowało ustawienie options[:boo] na true, z początku myślałem ze w nocy ktoś mi podmienił interpreter. Zajrzałem na strone (bardzo dobre źródło wiedzy o idiomach ruby) "Ruby: idmioms":http://www.rubygarden.org/ruby/page/show/RubyIdioms i moje wątpliwosci zostaly rozwiane

bq. You can also use the ||= operator to assign a value to a variable if it evaluates to false.

Do tej pory dałbym sobie rękę uciąć że ||= przypisuje wartość tylko gdy zmienna jest nil'em, i "...bym teraz k** ręki nie miał".

Łatwe pobieranie screencastow z Railscasts.com 2

Posted by wijet
on Wednesday, August 15

Na stronie Railscasts znajduje się masa screencastów o railsach, trochę irytowało mnie osobne ściąganie plików, sprawdzanie które już mam a których nie, wiec napisałem kawałek kodu. Skrypt pakujemy do katalogu w którym chcemy gromadzić filmiki, odpalamy, dostajemy listę dostępnych na stronie screencastow (pobrane są oznaczane na zielone, niepobrane na czerwono), następnie wpisujemy oddzielone spacjami numery screencastow do pobrania. Może komuś przypadkiem się przyda :)

#!/usr/bin/ruby
require 'open-uri'
require 'rss/2.0'
 
module RSS
  class Rss
    class Channel
      class Item
        def file_name
          @file_name ||= self.enclosure.url.split(/\//).last
        end
        def file_number
          file_name.split(/_/).first.to_i
        end
        def file_size
          self.enclosure.length.to_f / 1024 / 1024
        end
      end
    end
  end
end
 
rss_content = ""
open("http://feeds.feedburner.com/railscasts") do |f|
  rss_content = f.read
end
 
rss = RSS::Parser.parse(rss_content,false)
rss.items.reverse.each do |item|
  if File.exists?(item.file_name)
    printf "\e[32m%s (%.2f MB)\e[0m\n", item.title, item.file_size
  else
    printf "\e[31m%s (%.2f MB)\e[0m\n", item.title, item.file_size
  end
end
 
puts "Podaj numery screencastow do pobrania"
numbers = STDIN.gets
 
numbers.split(' ').each do |n|
  item = rss.items.detect{|i| i.file_number == n.to_i}
  unless item.nil? or File.exists?(item.file_name)
    system "wget -c #{item.enclosure.url}" 
  end
end

Symbole w Ruby 3

Posted by wijet
on Tuesday, August 07

W dobrze napisanym kodzie Ruby często możemy spotkać symbole, nic dziwnego – w wielu miejscach użycie symboli zamiast stringów wpływa pozytywnie na wydajności programu a także należy do dobrego stylu programowania. Na początku przygody z Rubim zrozumienie symboli może sprawić kłopot.

Postawy YAML’a, czyli łatwe serializowanie i deserializowanie obiektów 3

Posted by wijet
on Wednesday, July 11

YAML jest prostym językiem służącym do opisu danych. Obiekty są przedstawiane za pomocą czystego tekstu, łatwego do czytania i edycji. YAML pozwala na składowanie zarówno pojedynczych obiektów jak i różnych zbiorów obiektów. Istnieje wiele implementacje YAML’a m.in. dla php, python, ruby, pozwala to na przenoszenie danych pomiędzy aplikacjami napisanymi w rożnych językach. Dzięki formatowi plików YAML nadaje się przede wszystkim do przechowywania konfiguracji, logów a także tworzenia prostych raportów.

Własne gemy - jak instalować gemy bez łaski root’a 0

Posted by wijet
on Wednesday, June 27

Najlepszym sposobem używania bibliotek ruby są gemy, bardzo prosta instalacja aktualizacja, rubygems także rozwiązuje problem zależności miedzy bibliotekami. Standardowo tylko administrator może dokonywać operacji na gemach. Możemy tak skonfigurować rubygems by korzystać z tych zainstalowanych już w systemie, a także instalować własne.

Tworzymy katalog dla gemów, następnie sprawdzamy gdzie w systemie są instalowane gemy domyślnie.

gem environment

Spisujemy ścieżki pod GEM PATH. Tworzymy w katalogu domowym plik .gemrc do którego pakujemy te ścieżki plus ścieżkę w której chcemy instalować własne gemy, plik będzie wyglądać mniej więcej tak:

gempath:
 - /usr/lib/ruby/gems/1.8
 - /home/wijet/gems

Istotny jest format pliku, ponieważ jest interpretowany jako plik YAML.

Już możemy instalować własne gemy:

gem install rails -i /home/wijet/gems

Bardzo często wychodzą nowe wersje gemów, możemy hurtem przeprowadzać update gemów bez zawracania głowy adminowi.

gem update -i /home/wijet/gems

Markaby - pisz w Ruby, wyświetlaj html 4

Posted by wijet
on Thursday, May 03

Pisząc mój serwer http w rubym, chciałem skorzystać z jakiegoś systemu szablonów, wybrałem ERB który jest chyba najprostszy i był najbliżej, bo w standardowej bibliotece języka. Pliki templatow ERB to wymieszany HTML z kodem ruby umieszczonym miedzy znacznikami, który następnie jest wykonywany. Taki format templatow jest średnio czytelny. Przeglądając kod micro frameworka Camping’a natknąłem się na "Markaby":http://code.whytheluckystiff.net/markaby/ (Markup as Ruby), czyli szablony w czystym ruby!.

Sortowanie prawie optymalne 3

Posted by wijet
on Saturday, April 28

Temat sortowania aktualny ponieważ na zajęciach z algorytmów i struktur danych omawiamy właśnie sposoby sortowania. Dowiedziałem sie jakoś,czy ktoś mi powiedział, czy usłyszałem gdzieś o głupim sortowaniu, jako przykład chyba najbardziej nieefektywnego sposobu sortowania. Z ciekawości poszukałem i napisałem trochę kodu.

Dobierz sobie kolor 3

Posted by wijet
on Thursday, April 05

ColorBlender

Ostatnio przeglądając forum.php.pl przypadkowo znalazłem bardzo przydatna stronkę ColorBlender . Jestem totalny antytalenciem jeśli chodzi o grafikę i dobieranie kolorów, a tu mieszając suwakami mam 6 dobranych do siebie kolorów, pewnie nie jest to idealne dobranie barw, ale jest na pewno lepsze niż zdał bym się na własny gust.