5 ms·
def test_changing_hashes hash = { :one => "uno", :two => "dos" } hash[:one] = "eins" expected = { :one => "eins", :two => "dos" } assert_equal
by ximeng 16y ago
def test_changing_hashes
hash = { :one => "uno", :two => "dos" }
hash[:one] = "eins"
expected = { :one => "eins", :two => "dos" }
assert_equal expected, hash
# Bonus Question: Why was "expected" broken out into a variable
# rather than used as a literal?
end
Can anyone help with the bonus question? From searching Google, I read that the reason:
assert_equal { :one => "eins", :two => "dos" }, hash
gives an error is that Ruby believes this to be a block. But then why doesn't it consider the hash to be a block below:
expected = { :one => "eins", :two => "dos" }
?
Edit: thanks jashkenas for the explanation!
Edit2: for anybody else trying these, I think the version in github is more up-to-date, with some corrections:
http://github.com/edgecase/ruby_koans http://github.com/edgecase/ruby_koans
- jashkenas 16y agoThis is one of those gotchas with Ruby's syntax for blocks clashing with Ruby's syntax for hash literals. I'm not familiar with the details of precisely why Ruby's parser handles some cases, and not others, but I bet there's a special case for assignment -- you can't ever assign a block literal, so it has to be a hash... Here are some of the variants: method({ ... }) # hash method { ... } # block, even though a hash would be possible. method = { ... } # hash method a, b, :c => d # implicit hash method a, b { ... } # SyntaxError method(a, b) { ... } # block Only #2 in that list is really a problem, because there are situations where you'd legitimately like to use both.
- andrewvc 16y agoThis is one reason why I always use parens on my method calls. Some rubyists find it cluttering, yeah, but I think it makes reading code easier. The other one to watch out for is precedence of {} vs do; end. Example: > x = [1,2].map do |i| i*2; end => [2, 4] > puts [1,2].map do |i| i*2; end 1 2 => nil > puts [1,2].map { |i| i*2} 2 4 => nil
- jashkenas 16y agoAgreed. It's why we've tried to be careful with lambda/hash/call syntax in CoffeeScript, especially where some of it is optional, and can be left out. For example: x = [1, 2].map (i) -> i * 2 ... is without optional parens. x = [1, 2].map((i) -> i * 2) ... is with them. configure start: 10, end: 25 ... is the syntax for calling a method and passing an implicit hash -- and with the optional braces and parens added, it's closer to JavaScript... configure({start: 10, end: 25})
- jimweirich 16y ago#5 is also not a syntax error. Rather b is interpreted as a method and the block is associated with it.