I have the following code:
class Derp
#state = Hash.new
def run
#state[:ran] = true
end
end
derp = Derp.new
derp.run
Which results in the following error:
NoMethodError: undefined method `[]=' for nil:NilClass
from (irb):4:in `run'
from (irb):8
from /usr/local/bin/irb:11:in `<main>'
I'm pretty new to Ruby, so I'm not sure exactly what's going on here. Anyone have any ideas?
class Derp
def initialize
#state = Hash.new
end
def run
#state[:ran] = true
end
end
derp = Derp.new
derp.run
The problem in your code is that in the way you did the hash is assigned to the instance variable #state of the class object Derp, not to Derp's objects. Instance variables of the class are different from instance variables of that class’s objects. You could use that variable in class methods. E.g.
class Derp
#state = 42
def self.state
#state
end
end
puts Derp.state # 42
Related
I am trying to access class methods within a define_singleton_method block, but it doesn't seem to be working.
Here is an example.
class Test
attr_accessor :tags
def initialize
#tags = []
#tags.define_singleton_method(:<<) do |val|
val = tosymbol(val)
push(val)
end
end
def tosymbol(value)
value = value.to_s
value = value.gsub!(/\s+/,'_') || value
value = value.downcase! || value
return value.to_sym
end
end
But when I use it I get an error.
test = Test.new
test.tags<<"Hello World"
NoMethodError: undefined method `tosymbol' for []:Array
from /home/joebloggs/GitHub/repo/file.rb:183:in `block in initialize'
from (irb):9
from /home/joebloggs/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'
I tried changing val = tosymbol(val) to val = Test::tosymbol(val) but that didn't work either, I get undefined method 'tosymbol' for Test:Class
I could re-write what tosymbol is doing, but it wouldn't be very DRY. Where am I going wrong? Thanks.
Where am I going wrong?
You're (re)defining a << method for instance of Array class, not Test class.
While doing so you are trying to access tosymbol method, that is not defined in Array class, but in Test class.
What you want, probably (read judging by your code sample), is to define << method for instances of Test class:
def initialize
#tags = []
end
def <<(val)
tags << tosymbol(val)
end
test = Test.new
test << "Hello World"
#=> [:hello_world]
EDIT
To make your example to work you just need to assign the instance to a variable and call the tosymbol method with correct receiver:
def initialize
#tags = []
test = self # <============
#tags.define_singleton_method(:<<) do |val|
val = test.tosymbol(val)
push(val)
end
end
Now:
test.tags << 'Hello World'
#=> [:hello_world]
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
My class is
class LineAnalyzer
attr_reader :highest_wf_words,:highest_wf_count,:content,:line_number
def initialize(content ="",line_number)
#content = content
#line_number = line_number
end
def calculate_word_frequency
end
end
When I make object of class like this
l = LineAnalyzer.new("", 2)
l.calculate_word_frequency
It gives me this error.HOw to avoid this?
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 }
I was trying if I can call Class instance methods by the instances of class or not. Accordingly tried the below:
class Foo
def show; p "hi" ; end
def self.display ; p "hello" ; end
end
#=> nil
Foo.display
#"hello"
#=> "hello"
Foo.new.show
#"hi"
#=> "hi"
Foo.show
#NoMethodError: undefined method `show' for Foo:Class
#from (irb):7
#from C:/Ruby200/bin/irb:12:in `<main>'
But in the below call I expect the same error as NoMethodError: undefined method `display'. But why is it not the case?
Foo.new.display
#<Foo:0x538020> #=> nil
foo = Foo.new
#=> #<Foo:0x22bc438>
foo.display
#<Foo:0x22bc438> #=> nil
There is an existing method display on all objects.
class Bar
end
Bar.new.methods.grep(/disp/) # => [:display]
Bar.methods.grep(/disp/) # => [:display]
Your code just overwrites it for instances of Foo. Choose another name (display1, for example) and you'll see expected error.