Remember that Ruby has a parser feature that you can omit braces if
the last argument of a method call is a Hash. Rails and Hobo use
that feature for "named options".
EOS
def enum_string(*args)
"type enum_string #{args.inspect}"
end
def decl(type, *args)
puts "@@@ decl(): type = #{type}"
options = args.extract_options!
args.each_with_index { |val, i| puts " args[#{i}] = #{val.inspect}" }
options.each { |key, val| puts " options[#{key.inspect}] = #{val.inspect}" }
end
# decl :decimal, :scale => 1, :precision => 3, :required # 1. syntax error, unexpected '\n', expecting tASSOC
decl :decimal, { :scale => 1, :precision => 3 }, :required # 2. no syntax error, but won't work as expected
decl :decimal, :required, { :scale => 1, :precision => 3 } # 3. works
decl :decimal, :required, :scale => 1, :precision => 3 # 4. works, same as 3.
decl enum_string(:first, :second, :third), :required, {} # 5. works
decl enum_string(:first, :second, :third), :required # 6. works, same as 5.
I would agree that it is really confusing for programmers who has no
Rails background, though I don't know if I can call it a documentation
bug. If you know it, it's obvious, but if not, it's not. Here are
some hints:
- .rb files are Ruby files. DSL fragments such as field
declarations of Hobo Fields, assocations (has_many, etc.) and
validations (validates_presence_of, etc) are all syntactically
valid Ruby expressions.
- Rails uses "hash as a named option" feature throughout the API.
A `:key => something` argument is probably a named option and you
should place it as the last argument of the method call. Simple
`:key` argument (without associated value) is not a hash and it
won't be a named option. There are some exceptions such as
`button_to(name, options = {}, html_options = {})` helper where
two hashes are expected and you must sometimes explicitly place
surrounding braces to solve ambiguities.
> Even stuff like
> http://api.rubyonrails.org/classes/ActiveRecord.ConnectionAdapaters/TableDefinition.htl
> doesn't mention that the :scale and :precision have to come
> last because they are in a named option hash.
The method signature `column(name, type, options = {})` and the
descriptions in
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html
tell you that `name` should be provided first, `type` should be
second, and options hash may be followed and the options may contain
`:scale => something`.
-----
Tomoaki Hayasaka <haya...@pfsl.mech.tohoku.ac.jp>