代码之家  ›  专栏  ›  技术社区  ›  holden

Ruby对象数组…或哈希

  •  2
  • holden  · 技术社区  · 15 年前

    我现在有一个物体:

    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
    

    我希望这是有道理的,可能我忽略了一些宏伟的计划,这将使我的生活在两行无限轻松。

    4 回复  |  直到 15 年前
        1
  •  6
  •   tadman    15 年前

    在我发布一个如何修改的示例之前,有一些观察。

    • 在声明新对象时,为类指定复数名称可能会导致许多语义问题,例如在本例中,您将调用items.new,这意味着您实际上正在创建多个项。对单个实体使用单数形式。
    • 调用任意方法时要小心,因为任何未命中都会引发异常。你可以先打电话给他们,或者在适用的情况下从不可避免的灾难中解救出来。

    解决问题的一种方法是专门为项对象创建一个自定义集合类,在该类中,它可以向您提供有关名称等所需的信息。例如:

    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
    
        2
  •  2
  •   Whoever    15 年前

    你知道红宝石关键词吗 产量 ?

    我不太确定你到底想做什么。我对你的意图有两种解释,所以我举了一个例子,让两件事情完全不同,其中一件很有希望回答你的问题:

    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
    

    你要什么东西吗? 每个项目 A.每个 或者完全不同的东西?

        3
  •  1
  •   Whoever    15 年前

    只回答你在对Tadman解决方案的评论中提出的附加问题:如果你在Tadman的代码中替换方法的定义 姓名 在类中itemscollection by

    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
    

    对于他的示例数据,您将获得以下输出:

    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_访问器、attr等),我添加了一些健全性检查:我测试相应的方法和此名称的实例变量是否存在。由于类itemscollection不强制只添加类item的对象,所以我只选择满足这两个检查的元素。您还可以删除select并将测试放入映射中,如果检查失败,则返回nil。

        4
  •  -1
  •   Ariejan    15 年前

    关键是返回值。如果没有给出'return'语句,则返回最后一条语句的结果。最后一条语句返回哈希值。

    添加“返回自我”作为初始化的最后一行,您就是黄金。

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