instance_eval doesn't work as expected - ruby

I'm trying to build a tinny DSL using the approach that Russ Olsen exposes in his book, Eloquent Ruby. However it is not working for me. Let's consider the following code:
class SayHello
def initialize
#message = "Hello."
instance_eval(yield) if yield
end
def say_it
puts #message
end
end
SayHello.new { say_it }
The error I get is:
say_hello.rb:12:in `block in <main>': undefined local variable or method `say_it' for main:Object (NameError)
from say_hello.rb:4:in `initialize'
from say_hello.rb:12:in `new'
from say_hello.rb:12:in `<main>'
But... when you use instance_eval method, the value of self shouldn't be assigned to the object that calls the method?
Thanks in advance!

When the block runs, you want self to be equal to your SayHello instance instead of the main object.
I Googled for "ruby change self for a block" and found a good answer which makes me think you should change your code to:
class SayHello
def initialize(&p)
#message = "Hello."
instance_eval(&p) if block_given?
end
def say_it
puts #message
end
end
SayHello.new { say_it }

Related

Ruby error: undefined method `each' for nil:NilClass (NoMethodError)

I am ruby beginner. I am use proc class but I am getting error.
class Timeline
attr_accessor :tweets
def each(&block) # Block into the proc
tweets.each(&block) # proc back into the block
end
end
timeline = Timeline.new(tweets)
timeline.each do |tweet|
puts tweet
end
Getting error :-
`each': undefined method `each' for nil:NilClass (NoMethodError)
How to solve this error? Please tell us!
When you define attr_accessor :tweets, you just define 2 instance methods:
def tweets
#tweets
end
def tweets=(tweets)
#tweets = tweets
end
When you call tweets inside the each method, you just call method with this name, not a local variable, so you should set #tweets in the initialize method because right now your #tweets variable is not set:
class Timeline
attr_accessor :tweets # this is just a nice syntax for instance variable setter
# and getter
def initialize(tweets)
#tweets = tweets
end
def each(&block) # Block into the proc
tweets.each(&block) # proc back into the block
end
end

Ruby proc vs lambda in initialize()

I found out this morning that proc.new works in a class initialize method, but not lambda. Concretely, I mean:
class TestClass
attr_reader :proc, :lambda
def initialize
#proc = Proc.new {puts "Hello from Proc"}
#lambda = lambda {puts "Hello from lambda"}
end
end
c = TestClass.new
c.proc.call
c.lambda.call
In the above case, the result will be:
Hello from Proc
test.rb:14:in `<main>': undefined method `call' for nil:NilClass (NoMethodError)
Why is that?
Thanks!
The fact that you have defined an attr_accessor called lambda is hiding the original lambda method that creates a block (so your code is effectively hiding Ruby's lambda). You need to name the attribute something else for it to work:
class TestClass
attr_reader :proc, :_lambda
def initialize
#proc = Proc.new {puts "Hello from Proc"}
#_lambda = lambda {puts "Hello from lambda"}
end
end
c = TestClass.new
c.proc.call
c._lambda.call

Why isn't my class working in ruby?

I was testing my code in IRB and I typed in this:
class be
def new_text
text = gets()
end
def show_text
puts "#{text}"
end
end
When I typed in new_text it worked but when I typed in show_text it came up with an error:
NameError: undefined local variable or method `text' for #<BE:0xd3cc08>
from (irb):14:in `show'
from (irb):14:in `show'
from C:/Program Files/Ruby1.9.2/bin/irb:12:in `<main>'
Any ideas of how to fix that?
Change text to be an instance variable:
class Be
def new_text
#text = gets()
end
def show_text
puts "#{#text}"
end
end
You're getting the error because the show_text method is trying to access a variable called #text which hadn't been defined in your original example.

ScopeGates in Ruby

I am reading Metaprogramming in Ruby book. In that book, when I was reading about scopegates, the following code was shown
my_var = "Success"
MyClass = Class.new do
puts "#{my_var} in the class definition"
define_method :my_method do
puts "#{my_var} in the method"
end
end
MyClass.new.my_method
=>Success in the class definition
Success in the method
Now when I do the execute in the following, I get an error saying undefined method my_method
MyClass.new
MyClass:0x00000100936a30
MyClass.my_method
NoMethodError: undefined method `my_method' for MyClass:Class
from (irb):11
from /usr/local/bin/irb:12:in `<main>'
Why my_method gets created, when it gets called as MyClass.new.my_method and not MyClass.my_method?
The define_method method adds an instance method to a class. When you call define_method in your anonymous class, your method is being added as an instance method. To add it as a class method, you have to add it to the metaclass.
The easiest way to do that is with the class << self syntax.
MyClass = Class.new do
class << self
define_method(:my_method) do
puts "class method"
end
end
end
MyClass.my_method # => "class method"

Ruby Proc object as public member variable doesn't work?

I am a bit of a Ruby noob when it comes to the more advanced features. Currently I am experiencing with Proc objects. Can someone tell me what is wrong with this code sample?
class Tester
#printer = Proc.new do |text|
puts text
end
attr_accessor :printer
end
t = Tester.new
t.printer.call("Hello!")
It gives me the following error:
Test.rb:10: undefined method `call' for nil:NilClass (NoMethodError)
I don't immediately see why it shouldn't work. Can someone enlighten me?
You're not setting #printer in the class's initialize method. This'll work:
class Tester
def initialize
#printer = Proc.new { |t| puts t }
end
attr_accessor :printer
end

Resources