【问题标题】:How to reuse symbols from a hash in another method in Ruby如何在 Ruby 的另一种方法中重用哈希中的符号
【发布时间】:2014-08-21 08:56:00
【问题描述】:

我有以下方法,它定义了一个带有多个键的哈希(有很多,我只是为了这个例子把它删掉了)。

def data
  @data ||= {
    name: "Some Name",
    email: "my@email.com"
  }
end

现在,我想在同一个类中的另一个方法中使用每个键,如下所示:

[:name, :email].each { |key| define_method("get_#{key}") { data[key] } }

虽然这可以正常工作,但对密钥进行硬编码似乎不是一个好主意——我宁愿让它们动态化,并让它们从我在第一种方法中创建的哈希中重用。由于我从另一个类调用该类的实例,因此在使用明显方法时出现以下错误:

data.keys.each { |key| define_method("get_#{key}") { data[key] } }

# => undefined local variable or method `data' for #<Class:0x0000000dc55938>

有什么办法可以解决这个问题吗?

【问题讨论】:

  • 如果你想在同一个类中使用那有什么问题,只需调用该方法并使用键。你想在另一个类中使用这些键吗?
  • @pramod 我更新了问题以澄清问题。
  • 看来你没有从另一个类调用这个类的实例。因为如果你想调用数据方法,你必须从你定义的类实例中调用它。例如,如果 A 类中存在数据方法,那么如果您没有任何继承机制,则必须从 A 的实例调用它。

标签: ruby-on-rails ruby hash metaprogramming


【解决方案1】:

由于这两种方法属于同一类,为什么不使用data 而不是@data

2.1.2 :001 > def data
2.1.2 :002?>     @data ||= {
2.1.2 :003 >           name: "Some Name",
2.1.2 :004 >           email: "my@email.com"
2.1.2 :005?>       }
2.1.2 :006?>   end
 => :data 
2.1.2 :007 > data.keys.each { |key| define_method("get_#{key}") { data[key] } }
 => [:name, :email] 
2.1.2 :008 > get_name
 => "Some Name" 
2.1.2 :009 > 

【讨论】:

    【解决方案2】:

    您可以定义类似data_keys 的方法。在课堂之外使用此方法并获取密钥。

    class YourClass
      def self.data
        ...
      end
    
      def self.data_keys
        @data_keys ||= data.keys
      end
    end
    
    YourClass.data_keys.each { |key| define_method("get_#{key}") { YourClass.data[key] } }
    

    【讨论】:

    • 你能举个例子吗?
    • NoMethodError: undefined method 'data_keys' for YourClass:Class... 使用def self.data_keys???
    • 没关系,您在哪里定义definge_method,您可以在任何地方访问数据。 YourClass 仅存储您的数据。
    【解决方案3】:

    你可以试试这样的:--

      def  data(*args)
          options = args.extract_options!
          options ||= {
            name: "Some Name",
            email: "my@email.com"
          }
       ##save it to instance variable for further use
        @data=options
        ##either pass to another method
        other_method(options)
        ##or call any other method to call private methods as well using send
        new_obj =OtherObject.new
        new_obj.send(:method_name,options)
    
        end
    

    相同的解决方案,使用类变量

    def data
      @@data ||= {
        name: "Some Name",
        email: "my@email.com"
      }
    end
    
    in this way..you can even access data in model
    
    def get_data
      ##  @@data is available
      end
    

    【讨论】:

      【解决方案4】:

      如果我正确理解了您的要求,您希望在类的每个实例上都有方法来映射(带有 get/set 前缀)到数据哈希中的键?

      虽然我鄙视类中的神奇逻辑,但你能不能只定义#method_missing 并根据它从数据哈希中获取值?

      def method_missing method_symbol, *args, &block
          if method_symbol.to_s.match(/^get_(.+)$/) && data.keys.include?($1.to_sym)
              # Using the matching key in the data hash
              data[$1.to_sym]
          else
              # Cannot detect method for current class, bubble method_missing to super class
              super
          end
      end
      

      还应注意,当覆盖方法缺失时,您应该始终覆盖#respond_to?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-30
        • 1970-01-01
        • 2012-02-06
        • 2012-03-31
        • 2012-07-15
        • 2014-01-02
        相关资源
        最近更新 更多