2013-03-24 13 views
17

Jaki jest najlepszy sposób na odrobinę SUCHY w przepisie na szefa kuchni? To znaczy. po prostu wyłóż małe fragmenty kodu Ruby, więc nie kopiuję wklejania go w kółko.DRY w ramach przepisu Szefa Kuchni

Poniższa nie oczywiście z:

NoMethodError: undefined method `connect_root' for Chef::Resource::RubyBlock 

mogę mieć wiele ruby_blocks w jednym przepisie, jak robią różne rzeczy i trzeba mieć różny not_if blokuje się Truley idempotent.

def connect_root(root_password) 
    m = Mysql.new("localhost", "root", root_password) 
    begin 
    yield m 
    ensure 
    m.close 
    end 
end 

ruby_block "set readonly" do 
    block do 
    connect_root node[:mysql][:server_root_password] do |connection| 
     command = 'SET GLOBAL read_only = ON' 
     Chef::Log.info "#{command}" 
     connection.query(command) 
    end 
    end 
    not_if do 
    ro = nil 
    connect_root node[:mysql][:server_root_password] do |connection| 
     connection.query("SELECT @@read_only as ro") {|r| r.each_hash {|h| 
     ro = h['ro'] 
     } } 
    end 
    ro 
    end 
end 

Odpowiedz

23

Jak już ustaliłeś, nie możesz definiować funkcji w przepisach. Dla tych bibliotek są dostarczane. należy utworzyć plik (np mysql_helper.rb) wewnątrz bibliotek folder w swojej książce kucharskiej z następujących czynności:

module MysqlHelper 
    def self.connect_root(root_password) 
    m = Mysql.new("localhost", "root", root_password) 
    begin 
     yield m 
    ensure 
     m.close 
    end 
    end 
end 

To musi być moduł, a nie klasa. Zauważ również, że definiujemy go jako statyczny (używając self.method_name). Wtedy będziesz mógł używać funkcji zdefiniowanych w tym module w twoich przepisach, używając nazwy modułu z nazwą metody:

MysqlHelper.connect_root node[:mysql][:server_root_password] do |connection| 
    [...] 
end 
+0

Nie próbowałem, ale jest to pełna odpowiedź, z przykładem. Dzięki! Przykro mi, że muszę stworzyć całą książkę kucharską kucharza dla jednej małej funkcji, która nie będzie używana nigdzie indziej. Ale cokolwiek. – DragonFax

+1

Jeśli chcesz używać metod instancji, aby nie trzeba było poprzedzać ich nazwą klasy, wystarczy, że wykonasz ':: Chef :: Recipe.send (: include, MysqlHelper)', a następnie możesz po prostu wywołać 'connect_root 'bezpośrednio. –

+0

Dziękuję @ John Morales. Przyjęta odpowiedź była doskonała, jednak linia, którą dodałeś (pokazana poniżej) sprawiła, że ​​działała do końca: :: Chef :: Recipe.send (: include, MysqlHelper) – KLaw

1

Dla przypomnienia właśnie stworzyłem bibliotekę z następującymi elementami. Ale wydaje się to przesadzone dla DRY w jednym pliku. Nie mogłem również wymyślić, jak uzyskać dostęp do innej przestrzeni nazw, aby moduł mógł działać.

class Chef 
    class Resource 
    def connect_root(root_password) 
     ... 
+8

Dokumentacja bibliotek w książkach kucharskich kucharza jest żałośnie niewystarczająca i mocno niejednoznaczna. – DragonFax

+2

Nie powinieneś monkeypatch klasy zasobów. Znacznie lepiej jest stworzyć moduł i zaadresować metody przez moduł. –

Powiązane problemy