简体   繁体   中英

Passing arguments to Ruby methods

It seems that arguments can be passed to certain Ruby methods by appending the arguments after the method, and separating the two by a space. I'm trying to understand the mechanism that makes this happen. This is how arguments are passed to scripts in the command line. Why does the following statement work in Ruby?

item = 'orange'
fruits = ['orange', 'grapefruit', 'apple']
x = fruits.include? item
puts x

And why does the following statement not work?

item = 'orange'
fruits = ['orange', 'grapefruit', 'apple']

x = fruits.include? item ? 'You picked a fruit' : 'You did not pick a fruit'

puts x

Examine the AST with Ripper

In Ruby, parentheses are largely optional except when needed to avoid ambiguity, such as when passing arguments to methods that take a block. Under the hood, mainline Ruby has a lot of moving parts that tokenize and parse the code you write. One of the most useful is the Ripper module (documented here ) which enables you to see the abstract syntax tree that Ruby produces from your code.

Here are two versions of your code as Ruby sees them. You can see from the S-expressions that the failing version is different from the non-failing version. In irb:

Ripper.sexp %q{x = fruits.include?(item) ? 'You picked a fruit' : 'You did not pick a fru
it'}
#=> 
[:program,
 [[:assign,
   [:var_field, [:@ident, "x", [1, 0]]],
   [:ifop,
    [:method_add_arg,
     [:call,
      [:vcall, [:@ident, "fruits", [1, 4]]],
      [:@period, ".", [1, 10]],
      [:@ident, "include?", [1, 11]]],
     [:arg_paren, [:args_add_block, [[:vcall, [:@ident, "item", [1, 20]]]], false]]],
    [:string_literal, [:string_content, [:@tstring_content, "You picked a fruit", [1, 29]]]],
    [:string_literal, [:string_content, [:@tstring_content, "You did not pick a fruit", [1, 52]]]]]]]]
Ripper.sexp %q{x = fruits.include? item ? 'You picked a fruit' : 'You did not pick a frui
t'}
#=> 
[:program,
 [[:assign,
   [:var_field, [:@ident, "x", [1, 0]]],
   [:command_call,
    [:vcall, [:@ident, "fruits", [1, 4]]],
    [:@period, ".", [1, 10]],
    [:@ident, "include?", [1, 11]],
    [:args_add_block,
     [[:ifop,
       [:vcall, [:@ident, "item", [1, 20]]],
       [:string_literal, [:string_content, [:@tstring_content, "You picked a fruit", [1, 28]]]],
       [:string_literal, [:string_content, [:@tstring_content, "You did not pick a fruit", [1, 51]]]]]],
     false]]]]]

Since Ruby treats almost everything as an expression that returns a value, the order of operations can affect how the parser forms expressions. The ternary operator must ultimately evaluate as three expressions, and if you use what the parser considers ambiguous syntax it will cause problems.

See Also

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM