首页 > 解决方案 > 在define_method中动态设置参数

问题描述

我有一个类方法::add_method(name, params = {}),它使用define_method.

我需要定义方法的参数是关键字参数,具体取决于params.

class Whatever
  def self.add_method(name, params = {})
    # do something with params
    define_method name do |?|
      # some business
    end
  end
end

目标是当::add_method调用时:

params = { 
  foo: { required: false, default: 0 },
  bar: { required: true }
}

Whatever.add_method(:hello, params)

然后它创建这个方法:

def hello(foo: 0, bar:)
  # some business
end

Nota bene:这不是真正的业务,我已经过度简化了,所以这个问题更容易理解。

标签: ruby

解决方案


所以按照建议我去了class_eval

class Whatever
  class << self
    def add_method(name, parameters = {})
      class_eval <<-RUBY, __FILE__, __LINE__ + 1
        def #{name}(#{method_parameters(parameters)})
          #{method_body(parameters)}
        end
      RUBY
    end

    # method_parameters({
    #   foo: { required: false, default: 0 },
    #   bar: { required: true }
    # })
    # => "foo: 0, bar:"
    def method_parameters(parameters)
      parameters.map do |key, options|
        value = options[:required] ? '' : " #{options[:default] || 'nil'}"
        "#{key}:#{value}"
      end.join(', ')
    end

    # method_parameters({
    #   foo: { required: false, default: 0 },
    #   bar: { required: true }
    # })
    # => "[foo, bar]"
    def method_body(parameters)
      "[#{parameters.keys.map(&:to_s).join(', ')}]"
    end
  end
end
params = {
  foo: { required: false, default: 0 },
  bar: { required: true }
}

Whatever.add_method(:hello, params)

Whatever.new.hello(bar: true) # => [0, true]
Whatever.new.hello(foo: 42, bar: true) # => [42, true]
Whatever.new.hello # missing keyword: bar (ArgumentError)

推荐阅读