2012-03-14 6 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'). new (bar = nil), 자기 자신을 세 번 반복하지 않고도 접근 할 수있게 만든다. (attr_reader) – rudolph9

답변

1

질문의 표현 방식을 판단 할 때 수업 디자인을 다시 생각해 봐야합니다. 그러나 Ruby는 attr_accessor (독자가 아님)으로 클래스를 빠르게 만드는 흥미로운 방법을 제공합니다. 이것은 보통의 클래스 물론

>> 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=] 

당신은 모든 당신이 원하는 방법 (및 사용 getter 및 setter 대신 인스턴스 변수, 세터에 대한 예 게터에 대한 varself.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

나는 많은 생성자 변수에 해시로 모든 것을 넣기 위해 날씨를 궁금해했지만 초기화 메소드를 사용하고 싶습니다.본질적으로 나는 REST API와의 인터페이스를 위해 보석을 쓰고 있으며, 그것이 통합 된 어떤 프로젝트에도 최대한 도움이되는 방향으로 작업 중이다. 특히 나는 REST 호출에서 추출 된 각 변수를'p = Foo.new (argument_0, ..., argument_n)'및/또는'p = Foo.new (hash)'를 통해 사용 가능하게하고 어떤 인수도 사용할 수있게하고 싶습니다 'p.bar_i'를 통해. 약간의 자바 마인드이지만 유용하지는 않습니다. – rudolph9

0

루비는 동적이며 인트로 스펙 측면에서 많은 것을 제공하므로 메타 프로그래밍 (또는 코드를 기본적으로 작성하는 코드 작성)을 활용할 수 있습니다. 당신의 예에서 상세 정리하는 당신이 할 수있는 몇 가지가있다 : 대량 할당이 인기 재사용 가능한 동작이다

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 { | x | : "foo _ # {x}"}'이것은 WTF 종류의 코드의 멋진 예제라고 생각합니다. 루비는 이것을 할 수는 있지만, 라이브 코드에서 anybode가 볼 수있는 코드를 사용해야한다고 생각하지는 않습니다. – iafonov

+1

bar_i 인스턴스 변수에 대한 일관된 명명 규칙 일 필요는 없으며 기본값을 설정할 수 있어야합니다. 나는 지금 내가 정의하고있는 세 가지 분리 된 정의를 모두 할 수 있기를 바란다. – rudolph9

+1

1.9에서는 다음과 같이 배열을 만들 수 있습니다 :'[* 0. 0., *? a ..? n]'. :-) –

관련 문제