Ruby, initialize method with * [duplicate] - ruby-on-rails

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

Related

How does rails activerecord where clause accepts dynamic parameter?

In ruby web define parameters for a method.
def para_check(para1, para2, para3 .... )
end
How does activerecord .where is defined so that it accepts dynamic parameters ?
I went though few blogs/websites but could not find useful resources.
In Ruby you can prefix the parameter with a splat (*) to define methods that accept any number of positional arguments:
def foo(*x)
x
end
foo(1,2,3) == [1,2,3] # true
This is also known as a variadic function. As you can see this creates a array from the list of arguments.
You can also combine numbered and positional arguments and a splat:
foo(bar, *args)
[bar, args]
end
foo(1, 'a', 'b') == [1, ['a','b']] # true
This makes the method require one argument but allows an infinate number of arguments.
The ActiveRecord::QueryMethods#where method accepts both positional and keyword arguments:
where('foo = :x OR bar = :y', x: 1, x: 2)
Starting with Ruby 2.0 you can do this with:
def foo(*args, **kwargs)
[args, kwargs]
end
foo(1, 2, 3, bar: 'baz') == [[1, 2, 3], { bar: 'baz' }] ## true
Previously you had to use various hacky solutions with array parameters and and optional hash parameter. You can still find these in the Rails source code and in a lot of other code written before Ruby 2.0.
There are a few ways to do this. For starters you could accept a hash or array as parameter.
So if you expect a Hash, that is what where does, you can just write
def para_check(params)
params.each do |param_name, param_value|
# do something with the params
end
end
and then you can write:
para_check(para1: "X", para2: "Y", para5: "Z")
An alternative, in this case maybe, if you need to specify a list/array of parameters, you can also define your method as follows:
def para_check(*params)
params.each do |param_name|
# do something with param_name
end
end
(the '*'-operator is called the splat-operator)
and then you call your method as follows
para_check(:para1, :para2, :para4)

Ruby: Pass super into another method to execute conditionally

I have some code that looks like this:
if args
eval("super(#{args.join(',')})")
else
super
end
twice in a method. I'd like to move it so that my code looks more like:
def special_method
if a
some_block do
call_super(args, super_method)
end
else
call_super(args, super_method)
end
end
def call_super(args, super_method)
if args
eval("super(#{args.join(',')})")
else
super
end
end
I need to have a reference to the super I want to call (super special_method), since if I just create a method call_super and call super, it calls call_super on the superclass instead.
Does any of this make sense? x_x
It makes sense except for why you would ever need it. super already passes any parameters that the current method receives. super() passes no params. super(*args) passes any params in args, or no params if args is [] or nil.
If you actually want to do what your code currently does (pass args if they are non-nil, but current method's params if not) and not what I think you wanted, you can write args ? super(*args) : super as a short alternative (you can't put this in another method since it wouldn't know what the current parameters are).
(Also, you will find that in 99% of cases you think eval is the answer, there is a better answer.)
EDIT in response to the comment:
if args is ['testing', 1], then super(args) will pass one parameter that is an array; super(*args) passes two parameters (a string and an integer):
# a module
module Foo
def special_method
# multiple arguments in `args`
args = ['testing', 1]
super(*args)
end
end
class Bar
# fixed number of arguments (without splats):
def special_method(first, second)
puts "First parameter: #{first}"
puts "Second parameter: #{second}"
end
end
# subclass that includes the module
class Baz < Bar
include Foo
end
Baz.new.special_method
# First parameter: testing
# Second parameter: 1
(Note that "multiple arguments in *args" does not make sense, as *args is not a variable, args is).
I think one of the reasons for the confusion is the fact that splat has two different but related roles. In method definitions, they collect arguments into an array. Everywhere else, they distribute an array to an argument list.
require 'pp'
def foo(*args)
pp args
end
foo([1, 2]) # all the parameters (namely, the one) collected into `args`
# [[1, 2]]
foo(1, 2) # all the parameters (the two) collected into `args`
# [1, 2]
foo(*[1, 2]) # distribute `[1, 2]` to two parameters; collect both into `args`
# [1, 2]
def foo(args)
pp args
end
foo([1, 2]) # all the parameters (the one that exists) passed as-is
# [1, 2]
foo(1, 2) # all the parameters (the two) passed as-is, but method expects one
# ArgumentError: wrong number of arguments (2 for 1)
foo(*[1, 2]) # distribute `[1, 2]` to two parameters, but method expects one
# ArgumentError: wrong number of arguments (2 for 1)

What does an asterisk in front of a constant mean? [duplicate]

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.

Rails special symbol [duplicate]

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

What does the * (asterisk) symbol do near a function argument and how to use that in others scenarios?

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.

Resources