Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass hash to a function that accepts keyword arguments

I have a hash like this hash = {"band" => "for King & Country", "song_name" => "Matter"} and a class:

class Song
  def initialize(*args, **kwargs)
    #accept either just args or just kwargs
    #initialize @band, @song_name
  end
end

I would want to pass the hash as keyword arguments like Song.new band: "for King & Country", song_name: "Matter" Is it possible?

like image 676
mariya Avatar asked Feb 26 '15 15:02

mariya


People also ask

How do you pass keyword arguments?

Kwargs allow you to pass keyword arguments to a function. They are used when you are not sure of the number of keyword arguments that will be passed in the function. Kwargs can be used for unpacking dictionary key, value pairs. This is done using the double asterisk notation ( ** ).

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) .

Can we pass keyword arguments in any order?

A keyword argument is a name-value pair that is passed to the function. Here are some of the advantages: If the values passed with positional arguments are wrong, you will get an error or unexpected behavior. Keyword arguments can be passed in any order.

What is * args in Ruby?

In the code you posted, *args simply indicates that the method accepts a variable number of arguments in an array called args . It could have been called anything you want (following the Ruby naming rules, of course).


2 Answers

You have to convert the keys in your hash to symbols:

class Song
  def initialize(*args, **kwargs)
    puts "args = #{args.inspect}"
    puts "kwargs = #{kwargs.inspect}"
  end
end

hash = {"band" => "for King & Country", "song_name" => "Matter"}

Song.new(hash)
# Output:
# args = [{"band"=>"for King & Country", "song_name"=>"Matter"}]
# kwargs = {}

symbolic_hash = hash.map { |k, v| [k.to_sym, v] }.to_h
#=> {:band=>"for King & Country", :song_name=>"Matter"}

Song.new(symbolic_hash)
# Output:
# args = []
# kwargs = {:band=>"for King & Country", :song_name=>"Matter"}

In Rails / Active Support there is Hash#symbolize_keys

like image 142
Stefan Avatar answered Oct 04 '22 11:10

Stefan


As Stefan mentions, in Rails we have access to symbolize_keys that works like this:

{"band" => "for King & Country", "song_name" => "Matter"}.symbolize_keys
#=> {:band=>"for King & Country", :song_name=>"Matter"}

It's also aliased as: to_options, hence:

{"band" => "for King & Country", "song_name" => "Matter"}.to_options
#=> {:band=>"for King & Country", :song_name=>"Matter"}
like image 44
Fellow Stranger Avatar answered Oct 04 '22 11:10

Fellow Stranger