你如何用“。”定义一个方法。扩展了预先存在的属性的功能?

时间:2012-10-12 12:50:59

标签: ruby-on-rails ruby metaprogramming

所以,这就是我到目前为止所做的:

  # @return [Array<Hash>] of variables ([Placeholders, actual variables])
  def variables
      # @return [Hash] of all variables. 
      #     If actual variables are named teh same as the placeholders, the placeholders will be over written.
      #     This implementation of merging hashes of an array will work even if we add more elements to the 
      #     variables array.
      self.class.send(:define_method, "variables.flatten") do
        return self.variables.inject{|placeholders, vars| placeholders.merge(vars || {})}
      end

    return [placeholder_variables, self.variable_data]
  end

我希望能够做到:

my_object.variables # => return the Array<Hash>

但也能够做到

my_object.variables.flatten # => return a single merged hash

我刚做的时候的问题

def variables.flatten

是当我运行控制台时,我收到一条错误消息,指出variables未定义(或者我在.flatten之前放置的任何内容)

我是否可以仅在.flatten属性上定义自定义variables方法? (正常<Array>.flatten在这里不起作用,因为我需要合并哈希。)

4 个答案:

答案 0 :(得分:1)

直接回答:在自己的模块中定义方法,然后将其包含在您返回的数组中:

module SpecialFlatten
  def flatten
    first.update last
  end
end

......以后......

def variables
  vals = [placeholder_variables, self.variable_data]
  return vals.extend(SpecialFlatten)
end

但在这种情况下,更好的选择可能是这样做:

def variables(*flags)
  if flags.include? :flatten
    placeholder_variables.update self.variable_data
  else
    [placeholder_variables, self.variable_data]
  end
end

答案 1 :(得分:0)

我认为不可能定义“variables.flatten”方法。为了证明我们通过这个例子来检查:

require 'ruby_parser'

RubyParser.new.parse(<<-EOF)
  my_object.variables.flatten
EOF
#=> s(:call,
 s(:call, s(:call, nil, :my_object, s(:arglist)), :variables, s(:arglist)),
 :flatten,
 s(:arglist))

正如您所看到的,variablesflatten是不同的令牌,并且它们无法合并为一个令牌,这是一个解析问题。

但有一点可能是你错过了 - 这就是可连接性。方法variables返回变量数组,如果它们响应flatten方法,结果将是平坦的。如果他们没有响应该方法,您应该为这些对象实现flatten方法。

答案 2 :(得分:0)

您可以在返回值上定义单例方法。

def variables
  result = [placeholder_variables, self.variable_data]
  # redefine method flatten on the result array
  def result.flatten
    # did not understand what you are trying to do here
    # self is the array here
    inject{|placeholders, vars| placeholders.merge(vars || {})}
  end
  return result # return the array with added method
end

然而,这几乎总是一个坏主意。

答案 3 :(得分:0)

Array#flatten方法是Ruby核心的一部分,因此我建议不要更改它,特别是如果您正在与其他开发人员合作。您似乎正在尝试使用现有界面。我会寻找替代方法,但您可以在variables方法的返回值上覆盖flatten方法。

def variables
  [placeholder_variables, self.class.variable_data].tap do |vars|
    vars.instance_eval do
      def flatten
        inject{|result, vars_hash| result.merge!(vars_hash)}
      end
    end
  end
end