How are symbols used to identify arguments in ruby methods

后端 未结 5 1124
星月不相逢
星月不相逢 2021-02-01 23:20

I am learning rails and going back to ruby to understand how methods in rails (and ruby really work). When I see method calls like:

validates :first_name, :presen         


        
相关标签:
5条回答
  • 2021-02-01 23:36

    I thought I'd add an update for Ruby 2+ since this is the first result I found for 'symbols as arguments'.

    Since Ruby 2.0.0 you can also use symbols when defining a method. When calling the method these symbols will then act almost the same as named optional parameters in other languages. See example below:

    def variable_symbol_method(arg, arg_two: "two", arg_three: "three")
      [arg, arg_two, arg_three]
    end
    
    result = variable_symbol_method :custom_symbol, arg_three: "Modified symbol arg"
    
    # result is now equal to:
    [:custom_symbol, "two", "Modified symbol arg"]
    

    As shown in the example, we omit arg_two: when calling the method and in the method body we can still access it as variable arg_two. Also note that the variable arg_three is indeed altered by the function call.

    0 讨论(0)
  • 2021-02-01 23:41

    Symbols are not limited to hashes. They are identifiers, without the extra storage space of a string. It's just a way to say "this is ...."

    A possible function definition for the validates call could be (just to simplify, I don't know off the top of my head what it really is):

    def validates(column, options)
       puts column.to_s
       if options[:presence]
         puts "Found a presence option"
       end
     end
    

    Notice how the first symbol is a parameter all of its own, and the rest is the hash.

    0 讨论(0)
  • 2021-02-01 23:43

    I think all replies have missed the point of question; and the fact it is asked by someone who is - I guess - not clear on what a symbol is ?

    As a newcomer to Ruby I had similar confusions and to me an answer like following would have made more sense

    Method Arguments are local variables populated by passed in values.

    You cant use symbols as Arguments by themselves, as you cant change value of a symbol.

    0 讨论(0)
  • 2021-02-01 23:45

    Symbols and hashes are values like any other, and can be passed like any other value type.

    Recall that ActiveRecord models accept a hash as an argument; it ends up being similar to this (it's not this simple, but it's the same idea in the end):

    class User
      attr_accessor :fname, :lname
    
      def initialize(args)
        @fname = args[:fname] if args[:fname]
        @lname = args[:lname] if args[:lname]
      end
    end
    
    u = User.new(:fname => 'Joe', :lname => 'Hacker')
    

    This takes advantage of not having to put the hash in curly-brackets {} unless you need to disambiguate parameters (and there's a block parsing issue as well when you skip the parens).

    Similarly:

    class TestItOut
      attr_accessor :field_name, :validations
    
      def initialize(field_name, validations)
        @field_name = field_name
        @validations = validations
      end
    
      def show_validations
        puts "Validating field '#{field_name}' with:"
        validations.each do |type, args|
          puts "  validator '#{type}' with args '#{args}'"
        end
      end
    end
    
    t = TestItOut.new(:name, presence: true, length: { min: 2, max: 10 })
    t.show_validations
    

    This outputs:

    Validating field 'name' with:
      validator 'presence' with args 'true'
      validator 'length' with args '{min: 2, max: 10}'
    

    From there you can start to see how things like this work.

    0 讨论(0)
  • 2021-02-01 23:47

    In Ruby, if you call a method with a bunch of name => value pairs at the end of the argument list, these get automatically wrapped in a Hash and passed to your method as the last argument:

    def foo(kwargs)
      p kwargs
    end
    
    >> foo(:abc=>"def", 123=>456)
    {:abc=>"def", 123=>456}
    
    >> foo("cabbage")
    "cabbage"
    
    >> foo(:fluff)
    :fluff
    

    There's nothing "special" about how you write the method, it's how you call it. It would be perfectly legal to just pass a regular Hash object as the kwargs parameter. This syntactic shortcut is used to implement named parameters in an API.

    A Ruby symbol is just a value as any other, so in your example, :first_name is just a regular positional argument. :presence is a symbol used as a Hash key – any type can be used as a Hash key, but symbols are a common choice because they're immutable values.

    0 讨论(0)
提交回复
热议问题