This question already has answers here:
What does the (unary) * operator do in this Ruby code?
(3 answers)
Closed 7 years ago.
I see this *MyModel::MY_CONSTANT
and it references this in MyModel:
MY_CONSTANT = [
:a_field,
:another_field,
[
When called as
permit(:name, *MyModel::MY_CONSTANT)
it expands to
permit(:name, :a_field, :b_field)
but what just happened?
I hope that it actually expanded to permit(:name, :a_field, :another_field) :) But yeah, basically that's what it does when used on an array, it takes the values of the array and expands them out as if they were provided as individual arguments. So then you can take those array elements and send them into a method that's expecting individual arguments.
You can also use it in the inverse, you can define a method like:
def foo *args
end
...and when it's called with individual arguments:
foo 'a', 'b', 'c'
...those end up inside the foo method in the array args - this is very handy for wrapping another method, eg.
def some_method *args
do_something args.first
super *args # call the superclass's `some_method` with whatever args it would have received
end
Update
Btw, here's the official docs about this operator.
Related
This question already has an answer here:
naked asterisk as parameter in method definition: def f(*)
(1 answer)
Closed 4 years ago.
I am new in ruby and found this code:
def initialize(*)
# ...
end
What does * mean in initialize arguments list?
It mean's it's indiscriminate about arguments passed to it, i.e. you can pass as many or as few as you like.
They're 'throwaway' arguments, in that you can't access them subsequently. If you want to access them subsequently, you can use the commonly seen pattern def initialize(*args) and access the data via args.
It's often called with super to accept the arguments from a parent class, perhaps if they're not required.
For example, with your usage:
class MyClass
def initialize(*)
end
end
The following will work just fine:
MyClass.new(1, 2, 3, 4, 5, 'etc')
MyClass.new
It's largely undocumented, though is covered in the Ruby specs:
it "accepts an unnamed '*' argument" do
def foo(*); end;
foo.should == nil
foo(1, 2).should == nil
foo(1, 2, 3, 4, :a, :b, 'c', 'd').should == nil
end
This question already has answers here:
What does map(&:name) mean in Ruby?
(17 answers)
Closed 8 years ago.
I'm reviewing someone's ruby code and in it they've written something similar to:
class Example
attr_reader :val
def initialize(val)
#val = val
end
end
def trigger
puts self.val
end
anArray = [Example.new(10), Example.new(21)]
anArray.each(&:trigger)
The :trigger means the symbol is taken and the & transforms it into a proc?
If that's correct, is there any way of passing variables into trigger apart from using self.?
This is related but never answered: http://www.ruby-forum.com/topic/198284#863450
is there any way of passing variables into trigger
No.
You're invoking Symbol#to_proc which does not allow you to specify any arguments. This is a convenient bit of sugar Ruby provides specifically for invoking a method with no arguments.
If you want arguments, you'll have to use the full block syntax:
anArray.each do |i|
i.trigger(arguments...)
end
Symbol#to_proc is a shortcut for calling methods without parameters. If you need to pass parameters, use full form.
[100, 200, 300].map(&:to_s) # => ["100", "200", "300"]
[100, 200, 300].map {|i| i.to_s(16) } # => ["64", "c8", "12c"]
This will do exactly what you need:
def trigger(ex)
puts ex.val
end
anArray = [Example.new(10), Example.new(21)]
anArray.each(&method(:trigger))
# 10
# 21
I am attempting to write my own solution to a Ruby exercise from Rubymonk where the purpose is to create three methods (add, subtract, and calculate) so when 'calculate' is called you can determine whether or not numbers are added or subtracted based on what is passed in. I am receiving the following error:
main:11: syntax error, unexpected '=', expecting ')' def calculate(*numbers, options={})
Can anyone tell me what the issue is with my code? Thanks for any and all help!
def add(*numbers)
numbers.inject(0) {|sum, number| sum + number}
end
def subtract(*numbers)
numbers.inject{|diff, number| diff - number}
end
def calculate(*numbers, options={})
result = add(numbers) if options.empty?
result = add(numbers) if options[:add]
result = subtract(numbers) if options[:subtract]
result
end
def calculate(*numbers, options={})
is not a valid method definition b/c *numbers takes the place a variable number of arguments. You have two options as I see it -
def calculate(options={}, *numbers)
or
def calculate(*args)
numbers, options = args[0..-2], args[-1] || {}
if you want to keep the same argument order
The splat argument *numbers needs to be the last argument. Otherwise, how would Ruby know when to treat the last argument as options or as the last number?
You can use (*numbers, options) (without a default value), but that would require that you always pass an options hash to the method (otherwise your last number will be set as the options variable instead).
Try this way:
def calculate(options={},*numbers)
Using optional arguments after the fully optional argument ( the * notation) do not work since it creates an ambiguity.
Read more at:
http://www.skorks.com/2009/08/method-arguments-in-ruby/
You can't use both a splat and a param with a default as last argument, this is too ambiguous for the parser (how to know that the last arg passed is meant to be the options?)
you can work around this in many ways ; one idiom from rails (active support) is :
def calculate(*args)
options = args.extract_options!
# ...
end
where extract_options! is a monkey-patch to Array from ActiveSupport defined as follow :
def extract_options!
last.is_a?(::Hash) ? pop : {}
end
as a side note :
an options hash is not really usefull here. you could pass in just a symbol as first argument, maybe.
if you use a hash, logic could be simpler :
def calculate(*args)
options = args.extract_options!
method = options.fetch(:method, :add)
send method, *args
end
on add, you don't need inject(0), injectuses the first element of your array as a first "memo" value if you don't provide one
you can pass a symbol to inject, which will be the method called on your "memo" value, with "next value" as argument :
(1..10).inject(:+)
# this is the same as
(1..10).inject{ |memo, next| memo + next }
# or, more exactly
(1..10).inject{ |memo, next| memo.send :+, next }
How do I get a list of the arguments passed to a method, preferably one that I can iterate through?
For example something like
def foo(a,b,c)
puts args.inspect
end
foo(1,2,3)
=> [1,2,3]
?
Thanks!
You can always define a method that takes an arbitrary number of arguments:
def foo(*args)
puts args.inspect
end
This does exactly what you want, but only works on methods defined in such a manner.
The *args notation means "zero or more arguments" in this context. The opposite of this is the splat operator which expands them back into a list, useful for calling other methods.
As a note, the *-optional arguments must come last in the list of arguments.
If you define your method as you specified, you'll always have 3 args, or the method call is invalid. So "all the args" is already defined for you. So you would just change your method to:
def foo(a,b,c)
[a, b, c]
end
To define a method that can be called with any args (and to then access those args) you can do something like this:
def foo(*args)
args
end
What the * does is put all args after that point into an array.
As others pointed out you can use the splat operator (*) for achieving what you want. If you don't like that, you can use the fact that Ruby methods can take a hash as last argument with nicer syntax.
def foo(args)
raise ArgumentError if args.keys.any? { |arg| arg.nil? || !arg.kind_of?(Integer) }
end
puts foo(:a => 1, :b => 2, :c => "a") # raise an ArgumentError
To access the arguments inside the method you have to use args[:a] etc.
I am using Ruby on Rails 3 and I would like to know what means the presence of a * operator near a function argument and to understand its usages in others scenarios.
Example scenario (this method was from the Ruby on Rails 3 framework):
def find(*args)
return to_a.find { |*block_args| yield(*block_args) } if block_given?
options = args.extract_options!
if options.present?
apply_finder_options(options).find(*args)
else
case args.first
when :first, :last, :all
send(args.first)
else
find_with_ids(*args)
end
end
end
This is the splat operator, which comes from ruby (and is thus not rails specific). It can be applied in two ways depending on where it is used:
to "pack" a number of arguments into an array
to split up an array into an argument list
In your function, you see the splat operator used in the function definition. The result is that the function accepts any number of arguments. The complete argument list will be put into args as an array.
def foo(*args)
args.each_with_index{ |arg, i| puts "#{i+1}. #{arg}" }
end
foo("a", "b", "c")
# 1. a <== this is the output
# 2. b
# 3. c
The second variant would be when you consider the following method:
def bar(a, b, c)
a + b + c
end
It requires exactly three arguments. You can now call this method like follows
my_array = [1, 2, 3]
bar(*my_array)
# returns 6
The splat applied in this case to the array will split it and pass each element of the array as an individual parameter to the method. You could do the same even by calling foo:
foo(*my_array)
# 1. 1 <== this is the output
# 2. 2
# 3. 3
As you can see in your example method, these rules do apply to block parameters in the same way.
This is a splat argument, which basically means that any 'extra' arguments passed to the method will all be assigned to *args.