Mixing keyword with regular arguments in Ruby?

后端 未结 3 1819
后悔当初
后悔当初 2020-11-27 03:45

Ruby 2.0 supports keyword arguments. I was wondering, what are the \'rules\' for mixing regular with keyword arguments? Something like this would not work:

d         


        
3条回答
  •  孤城傲影
    2020-11-27 03:47

    A pseudo-regex for parameter lists in Ruby (this applies equally to methods, blocks and lambda literals) is something like this:

    mand* opt* splat? mand* (mand_kw | opt_kw)* ksplat? block?
    

    Here's an example:

    def foo(m1, m2, o1=:o1, o2=:o2, *splat, m3, m4, 
              ok1: :ok1, mk1:, mk2:, ok2: :ok2, **ksplat, &blk)
      Hash[local_variables.map {|var| [var, eval(var.to_s)] }]
    end
    
    method(:foo).arity
    # => -5
    
    method(:foo).parameters
    # => [[:req, :m1], [:req, :m2], [:opt, :o1], [:opt, :o2], [:rest, :splat], 
    #     [:req, :m3], [:req, :m4], [:keyreq, :mk1], [:keyreq, :mk2], 
    #     [:key, :ok1], [:key, :ok2], [:keyrest, :ksplat], [:block, :blk]]
    
    foo(1, 2, 3, 4)
    # ArgumentError: missing keywords: mk1, mk2
    
    foo(1, 2, 3, mk1: 4, mk2: 5)
    # ArgumentError: wrong number of arguments (3 for 4+)
    
    foo(1, 2, 3, 4, mk1: 5, mk2: 6)
    # => { m1: 1, m2: 2, o1: :o1, o2: :o2, splat: [], m3: 3, m4: 4, 
    #      ok1: :ok1, mk1: 5, mk2: 6, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, mk1: 6, mk2: 7)
    # => { m1: 1, m2: 2, o1: 3, o2: :o2, splat: [], m3: 4, m4: 5, 
    #      ok1: :ok1, mk1: 6, mk2: 7, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, mk1: 7, mk2: 8)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [], m3: 5, m4: 6, 
    #      ok1: :ok1, mk1: 7, mk2: 8, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, mk1: 8, mk2: 9)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5], m3: 6, m4: 7, 
    #      ok1: :ok1, mk1: 8, mk2: 9, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, mk1: 9, mk2: 10)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: :ok1, mk1: 9, mk2: 10, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, 
          ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13, k4: 14)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13, k4: 14}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, 
          ok1: 9, ok2: 10, mk1: 11, mk2: 12, k3: 13, k4: 14) do 15 end
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13, k4: 14}, 
    #      blk: # }
    

    [Note: mandatory keyword arguments will be introduced in Ruby 2.1, all the rest already works.]

提交回复
热议问题