Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing keyword with regular arguments in Ruby?

Tags:

ruby

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:

def some_method(a: 'first', b: 'second', c)   [a, b, c] end 

but this will:

def some_method(c, a: 'first', b: 'second')   [a, b, c] end 

So why does putting a regular argument before the keyword arguments (and not after) works?

Is there some reference on the web on this (mixing keyword and regular arguments)? I can't seem to find any.

like image 940
daremkd Avatar asked Dec 17 '13 11:12

daremkd


People also ask

How do you pass keyword arguments in Ruby?

So when you want to pass keyword arguments, you should always use foo(k: expr) or foo(**expr) . If you want to accept keyword arguments, in principle you should always use def foo(k: default) or def foo(k:) or def foo(**kwargs) .

What are keyword arguments in Ruby?

What are keyword arguments? Keyword arguments are a feature in Ruby 2.0 and higher. They're an alternative to positional arguments, and are really similar (conceptually) to passing a hash to a function, but with better and more explicit errors.

What is argument and parameter in Ruby?

In Ruby, all arguments are required when you invoke the method. You can't define a method to accept a parameter and call the method without an argument. Additionally, a method defined to accept one parameter will raise an error if called with more than one argument. def greeting(name) puts "Hello, #{name}!"


2 Answers

The order is as follows:

  • required arguments
  • arguments with default values (arg=default_value notation)
  • optional arguments (*args notation, sometimes called "splat parameter")
  • required arguments, again
  • keyword arguments
    • optional (arg:default_value notation, since 2.0.0)
    • intermixed with required (arg: notation, since 2.1.0)
  • arbitrary keyword arguments (**args notation, since 2.0.0)
  • block argument (&blk notation)

For example:

def test(a, b=0, *c, d, e:1, f:, **g, &blk)   puts "a = #{a}"   puts "b = #{b}"   puts "c = #{c}"   puts "d = #{d}"   puts "e = #{e}"   puts "f = #{f}"   puts "g = #{g}"   puts "blk = #{blk}" end  test(1, 2, 3, 4, 5, e:6, f:7, foo:'bar') { puts 'foo' } # a = 1 # b = 2 # c = [3, 4] # d = 5 # e = 6 # f = 7 # g = {:foo=>"bar"} # blk = #<Proc:0x007fb818ba3808@(irb):24> 

More detailed information is available from the official Ruby Syntax Documentation.

like image 118
Patrick Oscity Avatar answered Sep 19 '22 22:09

Patrick Oscity


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: #<Proc:0xdeadbeefc00l42@(irb):15> } 

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

like image 24
Jörg W Mittag Avatar answered Sep 22 '22 22:09

Jörg W Mittag