This question already has an answer here:
Closures in Ruby with Module
(1 answer)
Closed 4 months ago.
I have a question about scopes in ruby, why the baz method cannot access the variable foo, it seems counter intuitive because the scope of baz is contained in that of create_B
class A
def self.create_B(foo)
Class.new do
def baz
p foo
end
end
end
end
A.create_B(4).new.baz
NameError: undefined local variable or method `foo' for #<#<Class:0x00007f3a31bddf18>:0x00007f3a31bdde28>
from (pry):23:in `baz'
The def keyword creates a new scope. In order to access variables that were defined outside, you can use the define_method method:
class A
def self.create_B(foo)
Class.new do
define_method(:baz) do
p foo
end
end
end
end
A.create_B(4).new.baz
#=> 4
Related
This question already has answers here:
In ruby how to use class level local variable? (a ruby newbie's question)
(4 answers)
Closed 7 years ago.
I have noticed the following code is syntactically correct:
class Foo
bar = 3
end
Now, I know that instance variables are accessed by #, and class variables by ##, but I couldn't figure out where bar is stored in this case or how to access it.
How can I find bar's scope?
The body of a class in Ruby is just executable Ruby code. These are indeed local variables (no quotation needed) and follow the "regular" rules being local variables. You can access them in the body of the class. If you literally want the scope where bar is defined, you can use Kernel.binding:
class Foo
bar = 42
##scope = binding
def self.scope
##scope
end
end
Foo.scope.local_variables # => [:bar]
Foo.scope.local_variable_get(:bar) # => 42
A thing to note - using def changes the scope, therefore, they won't be visible inside methods defined using def.
It is accessible from the same class body.
class Foo
bar = 3
bar # => 3
end
It is lexically scoped, so it is accessible from within a block:
class Foo
bar = 3
pr = ->{p bar}
pr.call # => 3
end
but it is not accessible even in the same class once the class body has been closed:
class Foo
bar = 3
end
class Foo
bar # => error
end
nor can it be accessed from within a method definition:
class Foo
bar = 3
def baz; bar end
new.baz # => error
end
The bar variable will be accessible until you close the definition of the class. It will not be accessible inside the methods you define.
You can try to run the code in irb:
$ irb
irb(main):001:0> class Test
irb(main):002:1> bar = 1
irb(main):003:1> puts bar
irb(main):004:1> end
1
=> nil
irb(main):005:0> puts bar
NameError: undefined local variable or method `bar' for main:Object
from (irb):5
from /usr/bin/irb:11:in `<main>'
irb(main):006:0> class Test
irb(main):007:1> puts bar
irb(main):008:1> end
NameError: undefined local variable or method `bar' for Test:Class
from (irb):7:in `<class:Test>'
from (irb):6
from /usr/bin/irb:11:in `<main>'
irb(main):009:0>
Check for the availability in the instance methods:
irb(main):018:0> class Test
irb(main):019:1> bar = 1
irb(main):020:1> def test
irb(main):021:2> puts bar
irb(main):022:2> end
irb(main):023:1> end
=> :test
irb(main):024:0> a = Test.new
=> #<Test:0x00000000f447a0>
irb(main):025:0> a.test
NameError: undefined local variable or method `bar' for #<Test:0x00000000f447a0>
from (irb):21:in `test'
from (irb):25
from /usr/bin/irb:11:in `<main>'
Check for availability in the class methods:
irb(main):026:0> class Test
irb(main):027:1> bar = 1
irb(main):028:1> def self.test
irb(main):029:2> puts bar
irb(main):030:2> end
irb(main):031:1> end
=> :test
irb(main):032:0> Test.test
NameError: undefined local variable or method `bar' for Test:Class
from (irb):29:in `test'
from (irb):32
from /usr/bin/irb:11:in `<main>'
You could make it a constant and use it instance and class methods:
class Foo
Bar = 3
def local_bar(param = Bar)
param
end
end
p Foo.new.local_bar
#=> 3
This question already has answers here:
Ruby self in layman terms?
(3 answers)
Closed 7 years ago.
What is the difference between:
module Math
def self.square(num)
num**2
end
end
puts Math.square(6)
and
module Math
def square(num)
num**2
end
end
puts Math.square(6)
What is "self" in the first example? I'm only used to using self inside of a class, where self refers to the instance of the class.
Well, let’s see:
module Foo
p self
end
# prints: Foo
So self is the module itself. This allows us to define methods directly on Foo, rather than instances of it:
module Foo
def self.bar
42
end
end
Foo.bar #=> 42
class A; include Foo; end
A.new.respond_to?(:bar) #=> false
Note that this is not unique to Modules, and is the same for Classes. And since self == Foo, nothing is stopping us from doing:
def Foo.baz
3.14
end
Foo.baz #=> 3.14
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What does ##variable mean in Ruby?
What is the difference when I declare an object with double '#'
##lexicon = Lexicon.new()
and declaring object with single '#' in Ruby?
#lexicon = Lexicon.new()
The difference is that the first one is a class variable and the second one is an instance variable.
An instance variable is only available to that instance of an object. i.e.
class Yasin
def foo=(value)
#foo = value
end
def foo
#foo
end
end
yasin = Yasin.new
yasin.foo=1
yasin.foo #=> 1
yasin_2 = Yasin.new
yasin_2.foo #> nil
A class variable is available to all instances of the class (and subclasses, iirc) where the class variable was defined.
class Yasin
def foo=(value)
##foo = value
end
def foo
##foo
end
end
yasin = Yasin.new
yasin.foo=1
yasin.foo #=> 1
yasin_2 = Yasin.new
yasin_2.foo #=> 1
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Ruby.Metaprogramming. class_eval
I have this little project, the goal is to create a 'attr_accessor_with_history' method, that will keep a record of every single value assigned to variables created by it. Here's the code :
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s # make sure it's a string
attr_reader attr_name # create the attribute's getter
attr_reader attr_name+"_history" # create bar_history getter
a = %Q{
def initialize
##{attr_name}_history = [nil]
end
def #{attr_name}
##{attr_name}
end
def #{attr_name}=(new_value)
##{attr_name}=new_value
##{attr_name}_history.push(new_value)
end }
puts a
class_eval(a)
end
end
Now, when I test the script for one variable. It works fine. But when I try to create two or more variables (like this) ....
class Foo
attr_accessor_with_history :bar
attr_accessor_with_history :lab
end
a = Foo.new
a.bar = 45
a.bar = 5
a.bar = 'taat'
puts a.bar_history
b = Foo.new
b.lab = 4
b.lab = 145
b.lab = 'tatu'
puts b.lab_history
....Ruby gives out a "no-existing 'push' method for (class_eval) bar_history.push(new_value)". I think that 'initialize' method gets overriden on the second call of attr_accessor_with_history, so the record for the first variable gets destroyed.
I have no idea how to get around this. I already tried calling 'super' . Any clue ?
In your setter method just check if the the history instance variable is already initialized:
def #{attr_name}=(new_value)
##{attr_name}=new_value
##{attr_name}_history ||= [nil]
##{attr_name}_history.push(new_value)
end
You'll need another getter for your history variable that sets your default value if it was not set before:
def #{attr_name}_history
##{attr_name}_history ||= [nil]
end
Then you could remove your initialize method, that was btw vulnerable to be overwritten.
This question already has answers here:
Ruby Definition of Self
(3 answers)
Closed 7 years ago.
What does ruby self represent? what is it? what does it mean? Could some please explain it to me? in simple terms please
And what is its function in a class?
class MyClass
def method.self
end
end
self refers to the object that is currently in context.
In your example, self is the class itself and def self.method is defining a class method. For example:
class MyClass
def self.method
puts "Hello!"
end
end
> MyClass.method
#=> "Hello"
You can also use self on instances of a class.
class MyClass
def method_a
puts "Hello!"
end
def method_b
self.method_a
end
end
> m = MyClass.new
> m.method_b
#=> "Hello!"
In this case, self refers to the instance of MyClass.
There is a good blog post on self in Ruby here, or, as it was pointed out in the comments, there is some more on this in the Ruby documentation.