2009-09-09 9 views
2

내가 가진 지금 오브젝트 : 나는 그것을 배열로 개별 개체로 할당되는이루비 객체 배열 ... 또는 해시

class Items 
    attr_accessor :item_id, :name, :description, :rating 

    def initialize(options = {}) 
     options.each { 
     |k,v| 
     self.send("#{k.to_s}=".intern, v) 
     } 
    end 

end 

...

@result = [] 

some loop>> 
    @result << Items.new(options[:name] => 'name', options[:description] => 'blah') 
end loop>> 

을하지만 대신 내 할당 단일 객체를 배열로 ... 어떻게 객체 자체를 컬렉션으로 만들 수 있습니까?

는 기본적으로 가능성이 내가 내 인생을 무한히 더 쉽게 만들 것입니다 일부 웅대 한 계획을 내려다하고, 내가 방법을 정의 할 수 있도록 나는 그 말이 희망 등

def self.names 
    @items.each do |item| 
     item.name 
    end 
end 

하는 방식으로 객체를 갖고 싶어 2 라인.

답변

6

몇 가지 관찰을하기 전에이를 다시 작성하는 방법을 게시합니다. 사실 실제로 일을 할 때 여러 항목을 만드는 의미, 당신은 Items.new 전화 줄이 경우에서와 같이 새로운 객체를 선언 할 때 복수의 이름이 의미 론적 문제의 많은으로 이어질 수있는 클래스를주기

  • . 개별 개체에 대해 단수 형태를 사용하십시오.
  • 임의의 메서드를 호출 할 때주의해야합니다. 모든 누락시 예외가 발생하므로주의해야합니다. 먼저 전화를 걸거나 피할 수없는 재난으로부터 구할 수 있는지 확인하십시오.

문제를 해결하는 한 가지 방법은 Item 객체에 대한 사용자 지정 컬렉션 클래스를 만들어 이름 등에 필요한 정보를 제공하는 것입니다.

class Item 
    attr_accessor :item_id, :name, :description, :rating 

    def initialize(options = { }) 
    options.each do |k,v| 
     method = :"#{k}=" 

     # Check that the method call is valid before making it 
     if (respond_to?(method)) 
     self.send(method, v) 
     else 
     # If not, produce a meaningful error 
     raise "Unknown attribute #{k}" 
     end 
    end 
    end 
end 

class ItemsCollection < Array 
    # This collection does everything an Array does, plus 
    # you can add utility methods like names. 

    def names 
    collect do |i| 
     i.name 
    end 
    end 
end 

# Example 

# Create a custom collection 
items = ItemsCollection.new 

# Build a few basic examples 
[ 
    { 
    :item_id => 1, 
    :name => 'Fastball', 
    :description => 'Faster than a slowball', 
    :rating => 2 
    }, 
    { 
    :item_id => 2, 
    :name => 'Jack of Nines', 
    :description => 'Hypothetical playing card', 
    :rating => 3 
    }, 
    { 
    :item_id => 3, 
    :name => 'Ruby Book', 
    :description => 'A book made entirely of precious gems', 
    :rating => 1 
    } 
].each do |example| 
    items << Item.new(example) 
end 

puts items.names.join(', ') 
# => Fastball, Jack of Nines, Ruby Book 
+0

에는 Items의 모든 속성이 자동으로 'names'메소드를 사용하도록 동작하도록 만드는 방법이 있습니까? IE. .descriptions를 호출하면 .names ...와 같은 결과를 반환합니다. – holden

+0

모험을하고 싶다면이 메소드를 동적으로 만들거나 method_missing을 사용하여 호출을 잡을 수 있습니다. – tadman

+0

Ruby 믹스 인을 사용하여 ActiveRecord 객체가 포함 된 모든 배열에 이러한 기능을 추가 할 수 있습니까? 몇 가지 포인터가 유용 할 것입니다. – Sanjay

-1

키가 반환 값입니다. 'return'문이 주어지지 않으면 마지막 문에 대한 결과가 반환됩니다. 마지막 문장은 해시를 반환합니다.

초기화의 마지막 줄에 'return self'를 추가하면 황금색이됩니다.

Class Item 
    def initialize(options = {}) 
    ## Do all kinds of stuff. 

    return self 
    end 
end 
+0

글쎄, 그 부분은 실제로 작동합니다. 함수를 수행 할 수있는 메가 객체 (컬렉션)를 갖고 싶을 때 배열에 객체를 넣고 있습니다. – holden

+0

Item.new는 항상 새로 생성 된 객체를 반환합니다. initialize()의 반환 값에 관계없이 객체. 반환 자체를 추가하는 것은 아무런 효과가 없습니다. – molf

+1

다른 언어와 달리 Ruby 초기화 프로그램의 반환 값은 무시되며 생성 된 객체는 항상 반환됩니다. 클래스 새 메서드를 다시 작성하면이 변경 될 수 있지만 그것은 나쁜 생각 일 수 있습니다. – tadman

2

당신은 루비 키워드가를 얻을 알고 계십니까?

정확히 무엇을하고 싶은지 잘 모르겠습니다. 나는 당신의 의도를 두 가지 해석을, 그래서 희망이 당신의 질문에 대답 완전히 다른 두 가지, 그 중 하나 만드는 예를 제공합니다 :

class Items 
    @items = [] 
    class << self 
    attr_accessor :items 
    end 
    attr_accessor :name, :description 
    def self.each(&args) 
    @items.each(&args) 
    end 
    def initialize(name, description) 
    @name, @description = name, description 
    Items.items << self 
    end 
    def each(&block) 
    yield name 
    yield description 
    end 
end 

a = Items.new('mug', 'a big cup') 
b = Items.new('cup', 'a small mug') 
Items.each {|x| puts x.name} 
puts 
a.each {|x| puts x} 

mug 
cup 

mug 
a big cup 

당신이 뭔가를 요구 했는가 출력을 Items.each 또는 a.each 또는 완전히 다른 무엇인가?

+0

두 개의 인수가있는 것이 더 유용 할 때 두 수확량을 사용하는 것이 이상하게 보입니다. – tadman

+0

무엇을하고 싶은가에 달려 있습니다. "each"메서드는 일반적으로 현재 요소를 삽입하는 각 요소에 대해 한 번 주어진 블록을 호출합니다. 당연히 당신은 나의보기의 경우에 맞다 (너무 많이 이해하지 않는, 나는 다만 사용법을 보여주고 싶었다). 두 인수를 모두 사용하면 두 요소를 한 번만 삽입하여 블록을 호출합니다. – Whoever

1

당신이 tadman의 솔루션에 귀하의 코멘트에 요청 바로 추가 질문에 대답 : 예를 들어, 당신은

def method_missing(symbol_s, *arguments) 
    symbol, s = symbol_s.to_s[0..-2], symbol_s.to_s[-1..-1] 
    if s == 's' and arguments.empty? 
    select do |i| 
     i.respond_to?(symbol) && i.instance_variables.include?("@#{symbol}") 
    end.map {|i| i.send(symbol)} 
    else 
    super 
    end 
end 

에 의해 tadman의 코드에서 클래스 ItemsCollection에서 이름을하는 방법의 정의를 교체하는 경우 그의 예제 데이터는 다음과 같은 결과를 얻을 수 있습니다 :

puts items.names.join(', ') 
# => Fastball, Jack of Nines, Ruby Book 
puts items.descriptions.join(', ') 
# => Faster than a slowball, Hypothetical playing card, A book made entirely of precious gems 

나는 방법을 확인하는 방법에 대해 모르겠다. 이름은 속성 또는 다른 메소드에서 온다. (모듈 클래스에서 attr_accessor, attr 등을 재정의하는 것을 제외하고) 나는 몇 가지 온 전성 체크를 추가했다 : 나는 해당 메소드와이 이름의 인스턴스 변수가 존재하는지 테스트했다. ItemCollection 클래스는 Item 클래스의 객체 만 추가하도록 강요하지 않으므로 두 검사를 모두 충족하는 요소 만 선택합니다. 또한 select를 제거하고 테스트를 맵에 넣고 검사가 실패하면 nil을 리턴 할 수 있습니다.

+0

위의 내 의견을 추가 한 후 여기를 보았습니다. 레일즈를 사용하고 있다면 singularize 메소드를 사용하여 's'스트립핑 대신에 당신을 위해 디 플루 라이 제이션을 수행 할 수 있습니다. – tadman