我有几个带有关键字参数的方法,它们使用相同的参数调用other methods.目前,我必须手动传递每个参数.有没有一种方法可以将所有关键字参数作为Hash访问并直接传递下go ?

示例代码-

def method1(arg1:, arg2:)
  # do something specific to method1
  result = executor1(arg1: arg1, arg2: arg2)
  # do something with result
end

def method2(arg3:, arg4:, arg5:, arg6:)
  # do something specific to method2
  result = executor2(arg3: arg3, arg4: arg4, arg5: arg5, arg6: arg6)
  # do something with result
end

def method3(arg7:)
  # do something specific to method3
  result = executor3(arg7: arg7)
  # do something with result
end

我能做点什么把代码改成-

def method1(arg1:, arg2:)
  # do something specific to method1
  args = method1_args_as_a_hash
  result = executor1(args)
  # do something with result
end

def method2(arg3:, arg4:, arg5:, arg6:)
  # do something specific to method2
  args = method2_args_as_a_hash
  result = executor2(args)
  # do something with result
end

def method3(arg7:)
  # do something specific to method3
  args = method3_args_as_a_hash
  result = executor3(args)
  # do something with result
end

上下文-在我的代码库中,这些关键字参数的数量已经变得相当多,将它们按原样(或有时稍加修改)传递给executorX个方法会使代码文件太大,难以阅读.不幸的是,我不能更改methodX方法的签名,因为我不能访问使用它们的每个代码库,也不能冒险 destruct 它们的任何使用者.我确实完全控制了他们的逻辑和executorX多种方法.我的目标是重构这段代码,以减少行数并提高可读性.

谢谢!

推荐答案

这是可以做到的,但相当笨拙.

您可以使用method方法来查看某个方法并获取其签名,然后使用binding来获取同名的局部变量:

def foo(bar:, baz:)
  params = method(__method__).parameters # [[:keyreq, :bar], [:keyreq, :baz]]
  params.each_with_object({}) do |(_, name), hash|
    hash[name] = binding.local_variable_get(name) 
  end
end
irb(main):025:0> foo(bar: 1, baz: 2)
=> {:bar=>1, :baz=>2}

__method__是一个特殊的魔术方法,它包含当前方法的名称.

只需注意提取,如果您希望避免在代码库中重复此操作,则需要将绑定对象传递给其他方法以及该方法的名称.

module Collector
  # @param [Binding] context
  # @param [String|Symbol] method_name
  # @return [Hash] 
  def collect_arguments(context, method_name)
    params = context.reciever.method(method_name).parameters
    puts method_name, params.inspect
    params.each_with_object({}) do |(_, name), hash|
      hash[name] = context.local_variable_get(name) 
    end
  end
end
class Thing
  include Collector

  def method1(arg1:, arg2:)
    # do something specific to method1
    args = collect_arguments(binding, __method__)
    result = executor1(**args)
    # do something with result
  end
end

Ruby相关问答推荐

Ruby Case语句和固定,不适用于attr_reader

Ruby错误-应为数组或字符串,已获取哈希

为什么我的二维 Ruby 数组的多个值会发生变化,尽管只更改了其中一个?

如何使用 Ruby 的 optparse 解析没有名称的参数

RSpec 模拟对象示例

Ruby 的 Object#taint 和 Object#trust 方法是什么?

在 gem 中放置/访问配置文件的位置?

如何在没有继承方法的情况下获取类的公共方法?

Rails 在最后一个之前加入逗号和and的字符串列表

Ruby:继承与类变量一起工作的代码

在 ruby​​ 的超类中调用另一个方法

如何合并 Ruby 哈希

如何理解 strptime 与 strftime

有条件的数组的第一个元素

工厂女孩 - 目的是什么?

如何理解 class_eval() 和 instance_eval() 的区别?

相当于 Ruby 的 cURL?

如何在文件夹及其所有子文件夹中搜索特定类型的文件

Ruby:从 Ruby 中的变量创建哈希键和值

你可以在Ruby中使用分号吗?