2012-03-14 2 views
0

мне найти себя повторяющуюся вещи много, когда я создаю классы в рубин, часто я в конечном итоге с чем-то подобным следующему:Избегайте повторения при определении класса в Ruby?

class Foo 
    attr_reader :bar_0, 
       :bar_1, 
       . 
       . 
       . 
       :bar_n 
    def initialize(bar_0 = something, 
        bar_1 = something, 
         . 
         . 
         . 
        bar_n = something) 
    @bar_0 = bar_0 
    @bar_1 = bar_1 
      . 
      . 
      . 
    @bar_n = bar_n 
    end 
end 

используют ли рубин ярлык для более эффективного осуществления что-то вроде этого?

+0

Что именно вы пытаетесь сделать? Конструктор с 50 параметрами является уродливым на любом языке. –

+0

Не то, чтобы я хотел включить что-то, что уже было включено, я просто хочу иметь возможность определять переменную экземпляра при вызове new в классе ('@bar = bar'), установить значение по умолчанию для нового (bar = nil) и сделать его доступным ('attr_reader'), не повторяя мое собственное три раза – rudolph9

ответ

1

Судя по тому, как сформулирован вопрос, вы должны, вероятно, переосмыслить дизайн своих классов. Тем не менее, Ruby предоставляет интересный способ быстро создавать классы с attr_accessor s (а не читателями). Вот простой пример:

>> class Person < Struct.new(:name, :age) ; end 
=> nil 
>> p = Person.new 
=> #<struct Person name=nil, age=nil> 
>> p.age = 23 
=> 23 
>> p.class 
=> Person 
>> p.methods.grep(/age/) 
=> [:age, :age=] 

Конечно, это обычный класс, и вы можете добавить все методы, которые вы хотите (и использовать методы получения и установки вместо переменных экземпляра, например var для геттер и self.var = foo для сеттер) ,

Если вы действительно не хотите авторов, сделайте их частными или undef их.

>> attrs = [:name, :age] 
=> [:name, :age] 
>> class Person < Struct.new *attrs ; end 
=> nil 
>> Person.instance_eval { private *attrs.map{|attr| "#{attr}=" }} 
=> Person 
>> p = Person.new 
=> #<struct Person name=nil, age=nil> 
>> p.methods.grep(/age/) 
=> [:age] 

Все вышеперечисленное не помогает тоннам заданий в initialize конечно, но тогда возникает вопрос, если вы действительно хотите много аргументов конструктора или, если возможно, вы просто один хэш аргумента и объединить, что в хэш по умолчанию.

+0

Мне было интересно, чтобы погода просто помещала все в хэш на столько переменной конструктора, но я хотел бы иметь доступный способ инициализации.По сути, я пишу Gem, чтобы взаимодействовать с REST api, и я работаю над тем, чтобы он был максимально благоприятным для любого проекта, в который он встроен. СПЕЦИАЛЬНО Я хотел бы, чтобы каждая переменная, извлеченная из вызова REST, была доступна через 'p = Foo.new (аргумент_0, ..., аргумент_n)' и/или 'p = Foo.new (hash)' и имеет доступ к любому аргументу через 'p.bar_i'. Немного java mindset, но полезно, тем не менее. – rudolph9

0

Ruby динамичен и предлагает много возможностей для интроспекции, поэтому вы можете использовать метапрограммирование (или писать код, который по существу записывает код). В вашем примере есть несколько вещей, которые вы можете сделать, чтобы очистить до подробности:

class Foo 
    # Rather than writing bar_1, bar_2, bar_3, ... 
    attr_accessor ((0..9).to_a + ('a'..'n').to_a).map { |x| :"foo_#{x}" } 

    # Using mass assignment... 
    def initialize(attributes = {}) 
    attributes.each do |attribute, value| 
     respond_to?(:"#{attribute}=") && send(:"#{attribute}=", value) 
    end 
    end 
end 

Поскольку массовое присвоение является популярным и многоразовые поведением, оно имеет смысл, чтобы извлечь его в отдельный модуль и сделать его подмешать:

module MassAssignment 
    def initialize(attributes = {}) 
    mass_assign(attributes) 
    end 

    def mass_assign(attributes) 
    attributes.each do |attribute, value| 
     respond_to?(:"#{attribute}=") && send(:"#{attribute}=", value) 
    end 
    end 
end 

class Foo 
    include MassAssignment 
end 
+0

' attr_reader ((0..9) .to_a + ('a' .. 'n'). to_a) .map { | х | : "foo _ # {x}"} 'Я думаю, что это классный пример кода WTF. Ruby может это сделать, но я не думаю, что он должен использоваться в живом коде, который будет отображаться anybode else. – iafonov

+1

Не обязательно соглашение об именах констант для переменных экземпляра bar_i, и мне нужно иметь возможность устанавливать значения по умолчанию. Я хотел бы иметь возможность для трех отдельных определений, которые я сейчас делаю в одном определении. – rudolph9

+1

В 1.9 вы можете создать такой массив следующим образом: '[* 0..9, *? A ..? N]'. :-) –

Смежные вопросы