In pure Ruby irb, one cannot type {if: 1}
. The statement will not terminate, because irb thinks if
is not a symbol but instead the beginning of an
The code in your example is part of the Rails DSL. What you are actually setting there is a hash which just happens to look a bit like code.
Internally, Rails will evaluate this hash specifying conditions to the before_save
call.
In a very simplified version, Rails basically does this when saving:
class ActiveRecord::Base
@before_save_rules = []
def self.before_save(method, options={})
@before_save_rules << [method, options]
end
def self.before_save_rules
@before_save_rules
end
def save
# Evaluate the defined rules and decide if we should perform the
# before_save action or not
self.class.before_safe_rules.each do |method, options|
do_perform = true
if options.key?(:if)
do_perform = false unless send(options[:if])
end
if options.key?(:unless)
do_perform = false if send(options[:unless])
end
send(method) if do_perform
end
# now perform the actual save to the database
# ...
end
end
Again, this is very simplified and just in the spirit of actual code, but this is basically how it works.
That's an irb issue, not Ruby.
bash=> ruby -e "puts({if: 1})"
bash=# {:if=>1}
You can use pry
instead. It will read input correctly.
https://github.com/pry/pry
IRb's parser is well-known to be broken. (In fact, the very bug you encountered was already reported months ago: Bug #12177: Using if: as symbol in hash with new hash syntax in irb console is not working.) Just ignore it. There are also other differences in behavior between IRb and Ruby, semantic ones, not just syntactic. E.g. methods defined at the top-level are implicitly public
instead of implicitly private
as they should be.
IRb tries to parse the code with its own parser to figure out, e.g. whether to submit it to the engine when you hit ENTER or wait for you on the next line to continue the code. However, because Ruby's syntax is extremely complex, it is very hard to parse it correctly, and IRb's parser is known to deviate from Ruby's.
Other REPLs take different approaches, e.g. Pry actually uses Ruby's parser instead of its own.