Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are symbols used to identify arguments in ruby methods

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, :presence => true

I get confused. How do you write methods in ruby that accept symbols or hashes. The source code for the validates method is confusing too. Could someone please simplify this topic of using symbols as arguments in ruby class and instance methods for me?

UPDATE:

Good one @Dave! But What I was trying out was something like:

def full_name (:first_name, :last_name)
  @first_name = :first_name
  @last_name = :last_name
  p "#{@first_name} #{last_name}"
end

full_name("Breta", "Von Sustern")

Which obviously raises errors. I am trying to understand: Why is passing symbols like this as arguments wrong if symbols are just like any other value?

like image 250
Amit Erandole Avatar asked Nov 05 '11 16:11

Amit Erandole


People also ask

How are symbols used in Ruby?

Ruby symbols are defined as “scalar value objects used as identifiers, mapping immutable strings to fixed internal values.” Essentially what this means is that symbols are immutable strings. In programming, an immutable object is something that cannot be changed.

What does * args mean in Ruby?

In the code you posted, *args simply indicates that the method accepts a variable number of arguments in an array called args . It could have been called anything you want (following the Ruby naming rules, of course).

What are symbols in Ruby on Rails?

The :symbol , is as you mentioned it's an efficient way of representing names and strings; they are literal values. It is initialized and exists only once during the ruby session. It's not a string, since you don't have access to String methods; it's a Symbol. On top of that, it's immutable.

What does :: mean in Ruby?

The :: is a unary operator that allows: constants, instance methods and class methods defined within a class or module, to be accessed from anywhere outside the class or module. Remember in Ruby, classes and methods may be considered constants too.


4 Answers

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.

like image 141
Dave Newton Avatar answered Oct 21 '22 07:10

Dave Newton


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.

like image 13
Hless Avatar answered Oct 21 '22 06:10

Hless


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.

like image 5
millimoose Avatar answered Oct 21 '22 05:10

millimoose


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.

like image 3
sevgun Avatar answered Oct 21 '22 05:10

sevgun