带有可选选项和&block参数的Ruby方法

Den*_*ler 2 ruby parameters methods unary-operator

  1. 是否可以将可选属性和块作为方法调用的参数?

    示例:我必须打电话

    method(foo, foo: bar, -> { do_something }
    
    Run Code Online (Sandbox Code Playgroud)

    并尝试了

    def method(foo, *bar, &block)
    end
    
    Run Code Online (Sandbox Code Playgroud)

    至于我的理解,块总是必须在最后位置?

    经过一番研究后,我发现一元(?)*似乎是用于数组.因为我尝试传递一个Hash我改变了代码

    def method(foo, bar={}, &block)
    end
    
    Run Code Online (Sandbox Code Playgroud)

    但这也不能解决问题.我猜它是因为他无法弄清楚栏的结束位置和块的开始.

    任何想法或建议?先感谢您

    追加:只是为了好奇我为什么需要这个.我们有一个大的json架构在运行,并且有一个小型DSL,可以从模型定义构建json.我们没有太多细节,我们想要实现exportable_scopes.

    class FooBar
      exportable_scope :some_scope, title: 'Some Scope', -> { rewhere archived: true }
    end
    
    Run Code Online (Sandbox Code Playgroud)

    在一些初始化器上,这应该发生:

    def exportable_scope scope, attributes, &block
      scope scope block
      if attributes.any?
        attributes.each do |attribute|
          exportable_schema.scopes[scope] = attribute
        end
      else
        exportable_schema.scopes[scope] = {title: scope}
      end
    end
    
    Run Code Online (Sandbox Code Playgroud)

    所以这工作正常,我只需要提示方法参数.

Bru*_*cca 5

对的,这是可能的.

混合不同类型的参数时,它们必须按特定顺序包含在方法定义中:

  1. 位置参数(必需和可选)和单个splat参数,以任何顺序;
  2. 关键字参数(必需和可选),任何顺序;
  3. 双splat参数;
  4. 块参数(以&为前缀);

上面的顺序有点灵活.我们可以定义一个方法并使用单个splat参数开始参数列表,然后使用几个可选的位置参数,依此类推.尽管Ruby允许这样做,但这通常是一种非常糟糕的做法,因为代码难以阅读,甚至更难调试.通常最好使用以下顺序:

  1. 所需的位置参数;
  2. 可选的位置参数(默认值);
  3. 单个splat参数;
  4. 关键字参数(必需和可选,它们的顺序无关紧要);
  5. 双splat参数;
  6. 显式块参数(以&为前缀).

例:

def meditate cushion, meditation="kinhin", *room_items, time: , posture: "kekkafuza", **periods, &b
    puts "We are practicing #{meditation}, for #{time} minutes, in the #{posture} posture (ouch, my knees!)."
    puts "Room items: #{room_items}"
    puts "Periods: #{periods}"
    b.call # Run the proc received through the &b parameter
end

meditate("zafu", "zazen", "zabuton", "incense", time: 40, period1: "morning", period2: "afternoon" ) { puts "Hello from inside the block" }

# Output:
We are practicing zazen, for 40 minutes, in the kekkafuza posture (ouch, my knees!).
Room items: ["zabuton", "incense"]
Periods: {:period1=>"morning", :period2=>"afternoon"}
Hello from inside the block
Run Code Online (Sandbox Code Playgroud)

请注意,在调用方法时,我们有:

  • 提供缓冲强制性位置论证;
  • 覆盖冥想可选位置参数的默认值;
  • 通过*room_items参数传递了几个额外的位置参数(zabuton和熏香);
  • 提供时间必需的关键字参数;
  • 省略了姿势可选关键字参数;
  • 通过**期间参数传递了几个额外的关键字参数(period1:"morning",period2:"afternoon");
  • 通过&b参数传递块{puts"块内的Hello"};

请注意上面的示例服务器仅用于说明混合不同类型参数的可能性.在实际代码中构建这样的方法将是一种不好的做法.如果一个方法需要那么多参数,最好将它拆分成更小的方法.如果绝对有必要将那么多数据传递给单个方法,我们应该创建一个类来以更有条理的方式存储数据,然后将该类的实例作为单个参数传递给该方法.