Why is it not possible to print a hash directly.
p {:First=>1, :Second=>2}
syntax error, unexpected =>, expecting '}'
But its possible to save it to a variable and then print that variable?
my_hash = {:First=>1, :Second=>2}
p my_hash
{:First=>1, :Second=>2}
It appears that it's because Ruby is confused and thinks you're passing a block to the p method.
p {:First=>1, :Second=>2}
SyntaxError: unexpected =>, expecting '}'
As you can see from the error, it was expecting a } where your hash rocket for the first key is. As you've already found out, you can set this as a variable and it works. But you can also pass the hash to the p method without setting it as a variable if you use parenthesis, because p, puts and print are just methods too. This works, because passing a block to a method in Ruby requires it to be outside of the parenthesis which then cuts down on the ambiguity of what you're trying to do.
p({:First=>1, :Second=>2})
{:First=>1, :Second=>2}
#=> {:First=>1, :Second=>2}
As noted by tadman in the comments, you can also omit the parenthesis and curly braces as Ruby knows that key/value pairs passed as arguments to a method are the equivalent to passing a hash and wouldn't be misinterpreted as a block.
p :First => 1, :Second => 2
{:First=>1, :Second=>2}
#=> {:First=>1, :Second=>2}
Related
I've got an array of strings. A few of the strings in this array contain a certain substring I'm looking for. I want to get an array of those strings containing the substring.
I would hope to do it like this:
a = ["abc", "def", "ghi"]
o.select(&:include?("c"))
But that gives me this error:
(repl):2: syntax error, unexpected ')', expecting end-of-input
o.select(&:include?("c"))
^
If your array was a file lines.txt
abc
def
ghi
Then you would select the lines containing c with the grep command-line utility:
$ grep c lines.txt
abc
Ruby has adopted this as Enumerable#grep. You can pass a regular expression as the pattern and it returns the strings matching this pattern:
['abc', 'def', 'ghi'].grep(/c/)
#=> ["abc"]
More specifically, the result array contains all elements for which pattern === element is true:
/c/ === 'abc' #=> true
/c/ === 'def' #=> false
/c/ === 'ghi' #=> false
You can use the &-shorthand here. It's rather irrational (don't do this), but possible.
If you do manage to find an object and a method so you can make checks in your select like so:
o.select { |e| some_object.some_method(e) }
(the important part is that some_object and some_method need to be the same in all iterations)
...then you can use Object#method to get a block like that. It returns something that implements to_proc (a requirement for &-shorthand) and that proc, when called, calls some_method on some_object, forwarding its arguments to it. Kinda like:
o.m(a, b, c) # <=> o.method(:m).to_proc.call(a, b, c)
Here's how you use this with the &-shorthand:
collection.select(&some_object.method(:some_method))
In this particular case, /c/ and its method =~ do the job:
["abc", "def", "ghi"].select(&/c/.method(:=~))
Kinda verbose, readability is relatively bad.
Once again, don't do this here. But the trick can be helpful in other situations, particularly where the proc is passed in from the outside.
Note: you may have heard of this shorthand syntax in a pre-release of Ruby 2.7, which was, unfortunately, reverted and didn't make it to 2.7:
["abc", "def", "ghi"].select(&/c/.:=~)
You are almost there, you cannot pass parameter in &:. You can do something like:
o.select{ |e| e.include? 'c' }
def foo
1,2
end
causes syntax error "unexpected ',', expecting keyword_end"
I'd think this is valid Ruby. What's wrong?
You're not returning an array.
You should have this:
def foo
[1, 2]
end
Ruby isn't expecting a comma (,) because it isn't valid syntax. Integers in a simple array should be surrounded by brackets as well as delineated by a comma.
If you used explicit return it will work.
def foo
return 1,2
end
But that wouldn't work with implicit return. To make it work with implicit return you need to give it [1, 2].
Why do I get this?
p {a:3}
# => syntax error, unexpected tINTEGER, expecting tSTRING_CONTENT or tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
# => p {a:3}
^
Ruby has a few oddities in its parsing engine. One is that certain things require parentheses around them.
For instance, this should work.
p({a:3})
Or this
hash = { a: 3 }
p hash
As the other answer pointed out. The reason for this is that the interpreter processes as below.
# Input
p { a: 3 }
# What the interpreter sees
p do
a: 3
end
The Kernel#p doesn't support blocks, so you must use the parentheses.
When I used respond_with and passed a literal hash, it gave me the error:
syntax error, unexpected tASSOC, expecting '}'
`respond_with {:status => "Not found"}`
However, when I enclosed the literal hash in parentheses like so:
respond_with({:status => "Not found"})
the function runs without a hitch. Why do the parentheses make a difference? Isn't a hash an enclosed call?
When calling a method, the opening curly bracket directly after the method name is interpreted as the start of a block. This has precedence over the interpretation as a hash. One way to circumvent the issue is to use parenthesis to enforce the interpretation as a method argument. As an example, please note the difference in meaning of these two method calls:
# interpreted as a block
[:a, :b, :c].each { |x| puts x }
# interpreted as a hash
{:a => :b}.merge({:c => :d})
Another way is to just get rid of the curly brackets as you can always skip the brackets on the last argument of a method. Ruby is "clever" enough to interpret everything which looks like an association list at the end of an argument list as a single hash. Please have a look at this example:
def foo(a, b)
puts a.inspect
puts b.inspect
end
foo "hello", :this => "is", :a => "hash"
# prints this:
# "hello"
# {:this=>"is", :a=>"hash"}
So the loose tolerance of Ruby to use braces sometimes and not REQUIRE them has led to alot of confusion for me as I'm trying to learn Rails and when/where to use each and why?
Sometimes parameters or values are passed as (#user, #comment) and other times they seem to be [ :user => comment ] and still others it's just: :action => 'edit'
I'm talking about the us of [ ] vs ( ) vs { }
What ARE the rules? And are there any tricks you have to help you remember?
Parentheses () are for grouping logical or mathematical expressions and grouping arguments to a function call, e.g.:
a = 2 * (3 + 4)
b = (x==y) || (m==n)
Hash.new.send('[]=', :a, :b)
Curly Braces {} are used for hash literals and blocks, e.g.:
h = {1=>2, 2=>3}
h.each {|k,v| puts k+v}
Square Brackets [] are used for array literals, array indexing and slicing, and fetching from a hash, e.g.:
arr = [1, 2, 3]
two = arr[1]
three = h[2]
To confuse the matter, hash literals can also be used in-place as an argument to a method call without needing the curly braces or parentheses as long as it is the last argument (thanks samuil). Additionally, hash literals can be used in-place in square brackets to create a single-item array containing the hash:
puts 1=>2, 3=>4 #=> 1234
[5=>6, 7=>8] #=> [{5=>6, 7=>8}]
When in doubt, always use parentheses to group items and wrap your hashes in curly braces.