Passing hashes instead of method parameters
Both approaches have their own advantages and disadvantages, when you use an options hash replacing standard arguments you lose clarity in the code defining the method but gain clarity whenever you use the method because of the pseudo-named paramaters created by using an options hash.
My general rule is if you either have a lot of arguments for a method (more than 3 or 4) or lots of optional arguments then use an options hash otherwise use standard arguments. However when using an options hash it is important to always include a comment with the method definition describing the possible arguments.
Accepting either a hash or an array of hashes as arguments to a Ruby method
For me, the best solution is to change the method to:
def self.store(*hashes)
params = hashes.flatten
puts params.inspect
end
- If you pass a single hash, it will be an array
- If you pass an array of hashes, it remains the same
- If you pases N hashes, it compacts all parameters into a one dimensional array.
You can pass whatever you want.
self.store({:key => 'value'}) # => [{:key => 'value'}]
self.store({:key => 'value'}, {:foo => 'bar'}) # => [{:key => 'value'}, {:foo => 'bar'}]
self.store([{:key => 'value'}, {:foo => 'bar'}]) # => [{:key => 'value'}, {:foo => 'bar'}]
How do methods use hash arguments in Ruby?
Example:
def foo(regular, hash={})
puts "regular: #{regular}"
puts "hash: #{hash}"
puts "a: #{hash[:a]}"
puts "b: #{hash[:b]}"
end
foo("regular argument", a: 12, :b => 13)
I use hash={}
to specify that the last argument is a hash, with default value of empty hash. Now, when I write:
foo("regular argument", a: 12, :b => 13)
It's actually a syntactic sugar for:
foo("regular argument", {a: 12, :b => 13})
Also, {a: 12}
is syntactic sugar for {:a => 12}
.
When all of this is combined together, you get a syntax that looks similar to named arguments in other languages.
Passing Hash values as parameters to methods in Ruby
Thats easy
met1("abc" => "xyz")
def met1(options)
puts options
# with key
puts options["abc"]
end
I assume you know what the options might contain in terms of keys right? if not,
def met1(options)
puts options.keys # options is the hash you passed it, use it like one
end
In Ruby, how can you pass more than one hash to a method, without parentheses?
Mu points out that you can pass multiple hashes without parentheses, if you pass them in as non-literals i.e. as variables.
But other than that, so, for literal hashes,
You do(need parentheses to pass multiple literal hashes), unless you are passing keyword arguments.. You can pass multiple keyword arguments without parentheses.
a keyword argument would be when the parameters of the method include a colon like e.g. def blah x:, y:
then you can call with blah y:2,x:3
. Sometimes you have to look at the parameter(s) to see if an argument is a keyword argument, e.g. if you have a method called with abc x:3
then that might be def abc x:
in which case you called it with a keyword argument. Or it might be def abc x
in which case you called it with a hash, omitting the {}.
When I say keyword argument, I don't mean a hash.. and vice versa, when I say hash I mean not a keyword argument.
When a call is without parentheses, you can only pass one hash and that hash has to be the last argument. And you can skip the {} around it.
note- I'm no expert, but as to a related question of whether a keyword argument is a type of hash, from what I understand, as of writing, pre ruby 3, they are, but there is a proposal for ruby 3 to have 'real' keyword arguments that are distinct from hashes https://bugs.ruby-lang.org/issues/14183
a keyword argument can't be multi-valued.
also, a hash can be automatically converted to a keyword argument. (e.g. if a method is defined with a parameter that is a keyword argument, you can pass a hash in e.g. {x:"a"}
, that x being a symbol, and that hash will be converted to a keyword argument x:"a"
(that x being a parameter name).
I'll add a point regarding blocks and parentheses, because a block done with {} does look a little bit like a hash though is not a hash. And a block can have some influence on whether parentheses are needed.
If you see abc {}
, that {} is a block not a hash, and blocks don't count as an argument. Hence that call works for def abc
but not for def abc x
where one would get an error related to number of arguments passed.
even when passing a block after some other arguments, there should be no comma before the block, and if a block done with {} follows some arguments, you need parentheses, but if a block done with do .. end
follows some arguments, you don't need parentheses
it is suggested that one use parentheses when one has multiple arguments, unless it's a DSL(domain specific language). Do you leave parentheses in or out in Ruby?
Create a ruby method that accepts a hash of parameters
If you pass paramaters to a Ruby function in hash syntax, Ruby will assume that is your goal. Thus:
def login_success(hsh = {})
puts hsh[:msg]
end
Passing a hash as arguments in Ruby
Use the double splat operator (**) to convert the hash into keyword arguments.
user = User.from_google(**from_google_params)
The separation of keywords and positional arguments was a big change in Ruby 3. Previous versions of Ruby would coerce the last positional argument into keywords if its a hash - this behavior was depreciated in Ruby 2.7 and removed completely in 3.0.
Related Topics
Routing Error During "Ruby on Rails-Tutorial"
Replicating Xml Request with Savon/Ruby
Rails: How to Pass Custom Params to a Controller Method
Cannot Install Ruby 1.9.3 on a Clean Lion Install
Understanding Usage of Symbols in Routes.Rb Files
Issue with Precision of Ruby Math Operations
Error Occurs When Trying to Install Homebrew on a MAC for Ruby on Rails
Rails "Template Is Missing" Error
Rails Form_For Never Invokes the Create Controller Action to Use Redirect_To
Tilt (Kramdown) Preventing Erb Processing When Rendering Markdown
Ruby, Value Bucketing, Beautify Code
Rails Console Is Not Outputting SQL Statements to My Development Log
Download All Gems Dependencies
Ruby on Rails: Adding Columns to Existing Database
Shoulda/Rspec Matchers - Conditional Validation
Rspec Error 'Report_Activate_Error': Could Not Find Rubygem Rspec-Core (>=0) (Gem:Loaderror)