This question already has answers here:
How to call methods dynamically based on their name? [duplicate]
(5 answers)
Closed 8 years ago.
How can I use a string as a method call?
"Some Word".class #=> String
a = "class"
"Some World".a #=> undefined method 'a'
"Some World"."#{a}" #=> syntax error, unexpected tSTRING_BEG
Object#send
>> a = "class"
>> "foo".send(a)
=> String
>> a = "reverse"
>> "foo".send(a)
=> "oof"
>> a = "something"
>> "foo".send(a)
NoMethodError: undefined method `something' for "foo":String
If you want to do a chain, can also use Object#eval
>> a = "foo"
=> "foo"
>> eval "a.reverse.upcase"
=> "OOF"
If you have a string that contains a snippet of ruby code, you can use eval. I was looking for question with that answer when I landed here. After going off and working it out (thanks ProgrammingRuby), I'm posting this in case others come here looking for what I was looking for.
Consider the scenario where I have a line of code. here it is:
NAMESPACE::method(args)
Now consider the scenario where that is in a string variable
myvar = "NAMESPACE::method(args)"
Using send(myvar) does not execute the command. Here is how you do it:
eval(myvar)
Related
This question already has answers here:
Passing block into a method - Ruby [duplicate]
(2 answers)
Closed 2 years ago.
I can't figure out why I get this error message when I run my file on the console: no block given (yield) (LocalJumpError)
Here my code:
def block_splitter(array)
array.partition { |item| yield(item) }
end
beatles = ["John", "Paul", "Ringo", "George"]
puts block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end
Thanks for your help!
It's a whitespace issue. Your problem is in this line:
puts block_splitter(beatles) do |beatle|
# ...
end
The above code is being interpreted like this:
puts(block_splitter(beatles)) do |beatle|
# ...
end
I.e. the ruby interpreter thinks that the block is being passed to the puts method, not the block_splitter method.
By assigning a variable and printing the result, you'll see that this works as expected:
result = block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end
puts result
Or, you can define this as a 1-liner, and the ruby interpreter handles it like you expected:
puts block_splitter(beatles) { |beatle| beatle.start_with?("P") }
Or, you could wrap it in extra brackets:
puts(block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end)
So there is a problem with missing parentheses. Ruby interpreter allow not to use those, but when You use nested method calls It's better (and sometimes necessary) to use them. To fix it You can do something like this
puts(block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end)
Or even better
puts(block_splitter(beatles) {|beatle| beatle.start_with?("P")})
This question already has answers here:
How to dynamically create a local variable?
(4 answers)
Closed 3 years ago.
Not sure what am I doing wrong here or missing.
avar = 'test'
test_bvar = 'passed'
finalanswer = send "#{avar}_bvar"
puts " #{finalanswer}"
thanks,
The send method is used to call a method by name programmatically. Since your test_bvar is not a method but a local variable, you need to refactor it like this:
def test_bvar
"passed"
end
avar = "test"
finalanswer = send "#{avar}_bvar"
puts " #{finalanswer}"
Then you will reach your aim.
You are defining test_bvar as a local variable:
test_bvar = 'passed'
and you're trying to call it like a method:
send "test_bvar"
If you want to make this a method, do as #Mack94's answer suggests.
This question already has answers here:
Setter method (assignment) with multiple arguments
(2 answers)
Closed 8 years ago.
My method is:
def title=(text, sub_text = 'another piece of text')
self.title = text + sub_text
end
Somewhere else in my code, I do something like:
subtext = "enhusiasts"
title = "hello ruby "
How can I pass subtext to the title setter function so that my title becomes:
hello ruby enthusiasts
Do I have to write a separate function to use this setter?
While there is nothing particularly special about writer methods ending in =, the syntax of the language will not allow them to be called with multiple arguments. You can use send:
object.send :title=, title, subtext
That is not a clean solution, though. Also, your title= method is recursive; you should be setting an instance variable directly.
I recommend something like this:
attr_writer :text, :sub_text
def title
text + sub_text
end
# ...
object.text = 'hello ruby '
object.sub_text = 'enthusiasts'
object.title
# => "hello ruby enthusiasts"
You can call it using self.send('title=', 'string1') or self.send('title=', 'string1', 'string2').
But you cannot just call it the usual way title = 'string1', 'string2'. That is because the parser wont allow it. When = is present, the statement is expected to be in identifier = expression format.
Better you don"t you name your function with the = in such case.
Also it is recommended and is the convention that you concat your string by interpolation i.e.:
self.title = "#{text} #{sub_text}" instead of self.title = text + sub_text.
This prevents error being generated when text is nil.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
What does ||= mean in Ruby?
I tested like this:
>> a||=3
=> 3
>> a
=> 3
>> a||=b
=> 3
>> b
NameError: undefined local variable or method `b' for main:Object
from (irb):11
It is the shorthand for a logical OR operation. It is equivalent to:
a || a = b
Note: The above code sample has been corrected to reflect the true (if unintuitive) behavior if expanding a ||= b. Thanks to the people who pointed that out for me. Here is the source
if a evaluates to true it will remain as is, otherwise b will be assigned to a. In ruby nil evaluates to false, so you can see how this is useful for lazy loading and default value assignment.
This question already has answers here:
How to call methods dynamically based on their name? [duplicate]
(5 answers)
Closed 8 years ago.
Regardless of whether it's good practice or not, how can I dynamically call accessor methods in Ruby?
Here's an example class:
class Test_Class
attr_accessor :a, :b
end
I can use the Object.send method to read the variable...
instance.a = "value"
puts( instance.send( "a" ) )
# => value
But I'm having a hard time trying to write to it. These throw "wrong number of arguments (1 for 0) (ArgumentError)"
instance.send("a", "value")
and
instance.method("a").call("value")
Please help me StackOverflow!
I am not a ruby expert, but I think that you could do:
instance.send("a=", "value")
You can also directly access instance variables of an object using instance_variable_* functions:
instance = Test_Class.new # => #<Test_Class:0x12b3b84>
# instance variables are lazily created after first use of setter,
# so for now instance variables list is empty:
instance.instance_variables # => []
instance.instance_variable_set(:#a, 123) # => 123
instance.a # => 123
instance.instance_variables # => ["#a"]
instance.instance_variable_get("#a") # => 123