This question already has answers here:
How to call methods dynamically based on their name? [duplicate]
(5 answers)
Closed 8 years ago.
Is there a way to transform a symbol to a method call? I know it's possible for a String, but not for a symbol. I have this code in conveyance.rb:
def boats
boats = []
User.all.each{ |u| boats += u.boats}
boats
end
def boats_nb
self.boats.length
end
def cars
cars = []
User.all.each{ |u| cars += u.cars}
cars
end
def cars_nb
self.cars.length
end
I would like to know if there is a means to make a method like that:
def conveyances(:symb)
c = []
User.all.each{ |u| c += u.to_method(:symb) }
c
end
def conveyances_nb(:symb)
User.to_method(:symb).length
end
You could use Object#public_send method:
def conveyqnces_nb(symb)
User.public_send(symb).length
end
or, if you would like, Object#send might be suitable. The difference is that send allows to call private and protected methods, while public_send acts as typical method call - it raises an error if method is private or protected and the caller object isn't allowed to call it.
Use the #send instance method
u.send(:symb)
Related
I don't get this, when I try to run below code, I am getting
employee.rb:55:in `hourly_wage=': stack level too deep (SystemStackError)
class HourlyEmployee < Employee
attr_reader :hourly_wage, :hours_per_week
def hourly_wage=(hourly_wage)
self.hourly_wage = hourly_wage
end
def hours_per_week=(hours_per_week)
self.hours_per_week = hours_per_week
end
def print_pay_stub
print_name
pay_for_period = (hourly_wage) * (hours_per_week) * 2
formatted_pay = format("$%.2f", pay_for_period)
puts "Pay for this period: #{formatted_pay}"
end
end
Isn't this basically the same in Java where I use the this keyword in the setter method?
If I replaced the def with then everything works fine.
def hourly_wage=(hourly_wage)
#hourly_wage = hourly_wage
end
Sorry, just started picking up Ruby
you can imagine that hourly_wage= is a method name
your code:
def hourly_wage=(hourly_wage)
self.hourly_wage = hourly_wage
end
if you replace the name hourly_wage= with assign, it'll become:
def assign(hourly_wage)
self.assign(hourly_wage)
end
you recursively call yourself without a break-point, so it raise stack level too deep exception.
You are recursively calling hourly_wage= in hourly_wage=, with no termination condition, so you are recursing infinitely. Since Ruby does not have Proper Tail-Recursion, you will at some time run out of stack space.
Isn't this basically the same in Java where I use the this keyword in the setter method?
Yes, it is exactly the same as this equivalent Java code:
void setHourlyWage(BigDecimal hourlyWage) {
this.setHourlyWage(hourlyWage);
}
This will have the exact same result: a stack overflow.
If I replaced the def with then everything works fine.
def hourly_wage=(hourly_wage)
#hourly_wage = hourly_wage
end
This is something completely different. Here you are not recursively calling hourly_wage= but instead simply assigning to an instance variable ("field" in Java jargon).
This question already has answers here:
Ruby local variable is undefined
(3 answers)
Closed 7 years ago.
I'm getting a NameError, which supposedly indicates that my array "pentagonals" is undefined. But I'm a monkey's uncle if I didn't define it in line 1. What am I forgetting/misunderstanding? The goal is to write a method that tells me whether a given number is pentagonal.
pentagonals = []
def pent?(num)
pentagonals.include?(num)
end
(1..1000).each {|i|
pentagonals << (i * (3 * i - 1) / 2)
}
puts pent?(1)
Global variables in Ruby are distinguished from every other program name (like regular variables, class names, methods names, module names, etc.) by an initial $, so you should change your program in this way:
$pentagonals = []
def pent?(num)
$pentagonals.include?(num)
end
(1..1000).each {|i|
$pentagonals << (i * (3 * i - 1) / 2)
}
puts pent?(1)
Note that global variables should be used sparingly, in fact they are dangerous because they can be written to from anywhere in your program.
Variables in a method are local to the method scope, unless they are passed in as parameters.
The method can also access global, class variables and other methods in the same scope.
class MyClass
# calling methods in the same class
def method1
method2
end
def method2
puts 'method2 was called'
end
# getter / setter method pair for class variables
# #class_variable is only accessible within this class
def print_class_variable
puts #class_variable
end
def set_class_variable(param)
#class_variable = param
end
# global variables can be accessed from anywhere
def print_global_var
puts $global_variable
end
def self.some_class_method
# cannot be directly accessed by the instance methods above
end
end
Note that global variables are not recommended as they can easily result in conflicts and ambiguity.
class Dog
$name = "Dog"
end
class Cat
$name = "Cat"
end
puts $name
# which one does $name refer to?
def initialize_sign_in_guard_stack
default_guard = DefaultSignInGuard.new(self)
guards = Clearance.configuration.sign_in_guards
guards.inject(default_guard) do |stack, guard_class|
guard_class.new(self, stack)
end
end
class DefaultSignInGuard < SignInGuard
def call
if session.signed_in?
success
else
failure default_failure_message.html_safe
end
end
end
class SignInGuard
def initialize(session, stack = [])
#session = session
#stack = stack
end
private
attr_reader :stack, :session
def signed_in?
session.signed_in?
end
def current_user
session.current_user
end
end
Pry(main)> Clearance.configuration.sign_in_guards # => []
No. 1
Since guards is an empty array, so what the guard_class refers to?
And how could it run the new method? Can you explain what does this line of code do?
No. 2
signed_in? is a private method of SignInGuard. I know that only 'self' can
call it. Here, session.signed_in? Why does it make sense?
No1: To nothing. The block will never execute when you call it on an empty array, therefore a value will not be assigned. It is like asking what is item in [].each { |item| puts item }. The idea is when it is not empty to create objects of a list of guard classes. Then guard_class will refer to each individual guard class.
No2: You can't call private methods with explicit receiver, even if it is self. However, here signed_in? called on session is Session#signed_in?, not SignInGuard#signed_in?, which is public so it is fine.
This question already has answers here:
Is it possible to define a Ruby singleton method using a block?
(2 answers)
Closed 7 years ago.
I have a container class Foo with a method frob, and I want to add a similarly named method, which will delegate to the container, to each of the contained elements.
First I tried
self.children.each do |c|
def c.frob
self.frob
end
end
but this of course leads to SystemStackError: stack level too deep, as self is c at that point. I then tried
parent = self
self.children.each do |c|
def c.frob
parent.frob
end
end
but local variables aren't part of the closure of the newly defined method, so I get undefined local variable or method 'parent'.
I came up with the following hack, which works:
self.children.each do |c|
c.instance_variable_set('#parent', self)
def c.frob
#parent.frob
end
end
However, it pollutes the variable space of the child with something that's only needed by this one method. How can I get parent/self in there while keeping the newly defined method self-contained?
This should work:
children.each do |c|
parent = self
c.send(:define_method, :frob) do
parent.frob
end
end
This question already has answers here:
In Ruby is there a way to overload the initialize constructor?
(7 answers)
Closed 9 years ago.
is there a way to have multiple “initialize” methods in ruby?
For example: one method excepting one argument while another excepts three ?
Something like
class One
def initialize (a)
puts a
end
def initialize_1 (a,b)
puts a ,b
end
end
initialize is actually not a constructor. You can indeed have two constructors.
class One
singletonclass.class_eval{alias old_new :new}
def self.new a
puts a
old_new
end
def self.new_1 a, b
puts a, b
old_new
end
end