Ruby - method parameters - ruby

My method:
def my_method=(attributes, some_option = true, another_option = true)
puts hello
end
When i try to call this, i get such error:
my_method=({:one => 'one', :two => 'two'}, 1, 1)
#you_code.rb:4: syntax error, unexpected ',', expecting ')'
#my_method=({:one => 'one', :two => 'two'}, 1, 1)
^
What's the problem?

Method with suffix punctuation = can have only one argument.
Otherwise, you must use send to invoke with multiple parameters.
send :'my_method=', {:a => 1}, 1, 1

Don't use parenthesis when invoking a method using the = syntactic sugar.
Invoke it like this:
mymethod= {:one => 'one', :two => 'two'}, 1, 1

Related

`Hash()` when creating a hash

I see many seemingly interchangeable ways to create a hash. The following all create the same hash:
w = {:one => 1, :two => 2}
x = Hash[:one => 1, :two => 2]
y = Hash.[](:one => 1, :two => 2)
z = Hash.send(:[], :one => 1, :two => 2)
huh = Hash(:one => 1, :two => 2)
As for Hash(:one => 1, :two => 2), I expect to find a :() method for Hash in the documentation. Along with the documented method ::[], shouldn't the documentation also list a ::() method?
If they are both just syntactic sugar, where is the latter method documented?
It's a method in Kernel (which contains other methods that you can call directly like Kernel.puts) - Kernel.Hash. Don't use it (it's not idiomatic).

What is the proper way to pass a hash as a parameter to function call?

I have a function:
def a p
p
end
and a hash of symbols :a => :b. How should I pass it as a's parameter? What are possible ways?
I can use parentheses or the shorter form:
a(:a => :b) # => {:a=>:b}
a(a: :b) # => {:a=>:b}
Is there any way to pass this hash as a parameter without setting a variable and using parens? Just omitting them doesn't work.
a :a => :b # => SyntaxError: (irb):103: syntax error, unexpected ':', expecting end-of-input
a a: :b # => SyntaxError: (irb):105: syntax error, unexpected ':', expecting end-of-input

Does declaring a hash with curly braces require assignment?

I thought I could declare a hash using either {} or Hash[], but curly braces doesn't seem to work unless I assign it to a variable (see below). I'm guessing irb gets confused about whether it's a hash or a block. Is that correct, or am I declaring the hash with curly braces incorrectly?
>> puts h = { :a=>1, :b=>2 }
{:a=>1, :b=>2}
>> puts { :a=>1, :b=>2 }
SyntaxError: (irb):58: syntax error, unexpected =>, expecting '}'
puts { :a=>1, :b=>2 }
^
from /usr/bin/irb:12:in `<main>'
>> puts Hash[ :a=>1, :b=>2 ]
{:a=>1, :b=>2}
>>
You can fix this by adding parentheses:
puts({ :a => 1, :b => 2 })
# {:a=>1, :b=>2}
If you leave off the parentheses, Ruby will interpret the curly braces as a block:
puts { :a => 1, :b => 2 }
# SyntaxError: unexpected ':', expecting '}'
# semantically the same as
puts do
:a => 1, :b => 2
end
# SyntaxError: unexpected =>, expecting keyword_end
But you can also omit both parentheses and Ruby will treat it as a Hash:
puts :a => 1, :b => 2
# {:a=>1, :b=>2}
# same as
puts(:a => 1, :b => 2)
# {:a=>1, :b=>2}
# same as
puts({:a => 1, :b => 2})
# {:a=>1, :b=>2}
And you can even use short notation for symbol keys ;-)
puts a: 1, b: 2
# {:a=>1, :b=>2}
It just requires unambiguous syntax, e.g.,
irb> puts({ :a => 1, :b => 2 })
{:a=>1, :b=>2}
Your puts { ... } looks to ruby as though you are passing a block of code. Since puts is a method that can take arguments and/or a block you need to specify that the stuff inside the curly brackets is intended to be an argument and not a block. Try:
puts( { a: 1, b: 2 })

How to pass the second parameter to Mongo::Collection#find?

This is a newbie question. I find the method definition in the YARD Rdoc:
(Object) find(selector = {}, opts = {})
Options Hash (opts):
:fields (Array, Hash)
then I try this coll.find('English' => 'fulcrum',{English:1,Chinese:1}), want the result 'English' field is fulcrum ,and only return English and Chinese field, but Ruby punished me with the this
irb(main):018:0> coll.find('English' => 'fulcrum',{English:1,Chinese:1})
SyntaxError: (irb):18: syntax error, unexpected ')', expecting tASSOC
from /usr/local/bin/irb:12:in `<main>'
irb(main):019:0>
I want to know why, thanks
after correct the syntax problem by the suggestion by #mu, I got Unknown options error:
irb(main):013:0> coll.find({English:'fulcrum'},{English:1, :Chinese => 1})RuntimeError: Unknown options [{:English=>1, :Chinese=>1}]
from /usr/local/lib/ruby/gems/1.9.1/gems/mongo-1.5.2/lib/mongo/collection.rb:234:in `find'
from (irb):13
from /usr/local/bin/irb:12:in `<main>'
irb(main):014:0>
When Ruby sees an unwrapped Hash in argument list:
o.m(k => v, ...)
it assumes that you really mean this:
o.m({ k => v, ... })
So, when you say this:
coll.find('English' => 'fulcrum', {English: 1, Chinese: 1})
Ruby sees this:
coll.find({ 'English' => 'fulcrum', {English: 1, Chinese: 1} })
A Hash is a perfectly valid key so Ruby expects it to be followed by a => value:
coll.find('English' => 'fulcrum', {English: 1, Chinese: 1} => some_value)
and that's where the error message comes from:
syntax error, unexpected ')', expecting tASSOC
If you want to pass two hashes, you need to wrap the first one in braces:
coll.find({'English' => 'fulcrum'}, {English: 1, Chinese: 1})
The second argument to [find](
http://api.mongodb.org/ruby/current/Mongo/Collection.html#find-instance_method) should be an options Hash and it looks like you want the :fields option and you can give that an array of names instead of a noisy Hash:
coll.find({'English' => 'fulcrum'}, :fields => %w[English Chinese])

Ruby on Rails 3, syntax error while creating a new object

I am still learning Ruby, and still copy pasting from my manual. But I run on a problem, that I dont know how to explain and what am I doing wrong. So here it is:
I want to create a new object with this:
second_page = Page.new ( :name=>"Second page", :position=>1, :permalink => "second" )
and I got a error:
Loading development environment (Rails 3.0.10)
ruby-1.9.2-p290 :001 > second_page = Page.new ( :name=>"Second page", :position=>1, :permalink => "second" )
SyntaxError: (irb):1: syntax error, unexpected tASSOC, expecting ')'
...econd_page = Page.new ( :name=>"Second page", :position=>1, ...
... ^
(irb):1: syntax error, unexpected ',', expecting $end
...age.new ( :name=>"Second page", :position=>1, :permalink => ...
... ^
from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/console.rb:44:in `start'
from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/console.rb:8:in `start'
from /usr/local/rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
but, if I do this:
ruby-1.9.2-p290 :002 > second_page = Page.new :name=>"Second page", :position=>1, :permalink => "second"
=> #<Page id: nil, subject_id: nil, name: "Second page", permalink: "second", position: 1, visible: false, created_at: nil, updated_at: nil>
that seems to work.
I got example from manual, and I am wondering what is going on?
And without () I dont know how can I do stuff with that object?
Thank you
Ruby doesn't allow you to put spaces before round brackets if you choose to place them. This should work:
second_page = Page.new( :name=>"Second page", :position=>1, :permalink => "second" )
What you have here is the parser trying to resolve syntax ambiguities. Page.new accepts a single argument: a hash containing attributes which should be set on the newly created active record object.
If you now call the method without any parentheses, it is not initially clear what the arguments are. Thus the parser is smart enough to figure out it should be a hash in this case.
If you actually write the parentheses, you have to be a bit more specific and have to actually write down the hash braces too. Thus the following statements are equivalent:
first_page = Page.new :foo => "Bar"
second_page = Page.new({:foo => "Bar"})
third_page = Page.new ({:foo => "Bar"})
In most cases, parentheses are optional in method calls in Ruby. But only if there aren't any ambiguities. If in doubt, always specify the parentheses. Note that Ruby 1.9 changed the syntax here and is thus a bit more strict.
In ruby parenthesis to the method arguments are not necessary. So,
object.method()
# is same as
object.method
object.method(param1, param2)
# is same as
object.method param1, param2
There is another popular syntax for passing arbitrary number of parameters:
def print_a(*params)
puts params.inspect
end
print_a "a"
#prints: ["a"]
print_a "a", "b"
#prints: ["a", "b"]
print_a "a", "b", 2, :four => 4
#prints: ["a", "b", 2, {:four=>4}]
print_a "a", "b", 3, :four => 4, :five => 5
#prints: ["a", "b", 3, {:four=>4, :five=>5}]
As you may have noticed in the last example ruby is smart enough to detect hashes and aggregate the key value pairs in a single hash argument. But it only works if the hash is last argument.
print_a("a", "b", :four => 4, :five => 5, 3)
# gives error: syntax error, unexpected '\n', expecting tASSOC
# converting the hash to an explicit hash works again
print_a "a", "b", {:four => 4, :five => 5}, 3
# ["a", "b", {:four=>4, :five=>5}, 3]

Resources