I can't seem to see what's up with this piece of code:
class Cherry
class << self
def call env
self::Application.call
end
end
end
class Cherry
class Application
def call env
#Framework logic
end
end
end
run Cherry
That's the part of my application that is not working. I have no idea why:
NoMethodError at / undefined method 'call' for Cherry::Application:Class
You need to adjust a couple of things.
When you are defining the call method inside of Application, you are defining it as an instance method, then you are attempting to call it as a class method, so lets fix the definition to be a class method definition:
class Cherry
class Application
def self.call env
#Framework logic
end
end
end
Next there will be a new error, about not passing the right number of arguments to the call method, so we add the env param to where you are calling the call method.
class Cherry
class << self
def call env
self::Application.call env
end
end
end
Hope that helps!
Related
In the Ruby programming language, I am creating a class with a class-level macro, as follows:
class Timer
def self.add_time
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
The class method add_time, when executed, will generate a time method.
Now, I can execute that class-level macro in another class Example as follows:
class Example < Timer
add_time
end
When I now call time on an instance of class Example, the time method is present there, as I intended:
ex = Example.new
ex.time
and prints the current time: 23:18:38.
But now I would like to put the add_time macro in a module and still have the same overall effect. I tried with an include like this:
module Timer
def self.add_time
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
class Example
include Timer
add_time
end
ex = Example.new
ex.time
but then I receive an error that the method add_time is not defined on the class Example: NameError: undefined local variable or method ‘add_time’ for Example:Class. So then I tried with an extend instead like this:
class Example
extend Timer
add_time
end
but it gives me a similar error.
So the question is: How can I get the same effect as in my original example where the Timer was defined as a class, but using a module instead?
As #CarySwoveland pointed out, the method def self.add_time in the module Timer gets disregarded upon inclusion or extension in a class. Only the module's instance methods are added to the class as instance method of the class (in case of inclusion) or as class methods of the class (in case of extends).
module Timer
def add_time # INSTANCE METHOD !
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
So the first step of the solution is to declare the method def add_time as an instance method of the module. Next, we extend the class Example with that module, so that the module's instance method gets added as a class method in the class Example, and we call the add_timemethod:
class Example
extend Timer # EXTEND INSTEAD OF INCLUDE
add_time
end
However, this doesn't quite work as desired yet as the time method has now been generated as a class method: Example.time prints the current time 01:30:37, but an instance ex of class Example does not understand the method time.
The solution is thus to generate the method def time as an instance method rather than as a class method. This can be done using class_eval, which leads us to the following working solution:
module Timer
def add_time # INSTANCE METHOD !
self.class_eval do # USE class_eval TO DEFINE AN INSTANCE METHOD !
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
end
class Example
extend Timer # USE EXTEND TO ADD add_time AS A CLASS METHOD
add_time
end
ex = Example.new
ex.time
I have searched around for the answer to this and I can see a lot of similar problems but I still do not understand what I am doing wrong here. I have declared a Ruby class and attempted to new it and then call some instance methods on the instance, so why do I get the NoMethodError on my start method?
class MyClass
def initialize
self.class.reset
end
def self.reset
...
end
def self.start(port)
...
end
end
test = MyClass.new
test.start '8082' <- here <- undefined method `start' for #<MyClass:0x2f494b0> (NoMethodError)
As you can see I am a Ruby noob. Any help would be appreciated. I can change my class structure but I would really like to understand what I am doing wrong here.
here start is a class method.
By your current approach, you can use it in the following way
MyClass.start '8080'
But if you want to use it on instance of class then use the following code
class MyClass
def initialize
self.class.reset
end
def self.reset
...
end
def start(port)
...
end
end
test = MyClass.new
test.start '8080'
You are using start as a Class variable, the method names preceded with self-keyword make those methods as Class methods. So if you really want to not change your class then you should call it like this:
MyClass.start '8080'
Else you can remove the self from your reset and start methods and make them as Instance methods and use them as:
test = MyClass.new
test.start '8082'
I was wondering how I could call a method in an instance of a class in another class.
This is what I came up with
class ClassA
def method
return "This is a method_from_class_A"
end
end
class ClassB
def initialize
#method_from_class_A=instance.method
end
def method_calls_method
#method_from_class_A
end
end
instance=ClassA.new
instance2=ClassB.new
puts instance2.method_calls_method
But I get this error:
Testing.rb:9:in initialize': undefined local variable or method
instance' for # (NameError) from
Testing.rb:19:in new' from Testing.rb:19:in'
How could I fix it?
Thank you for your response.
From your description this seems to be what you're going for:
class ClassB
def initialize
#instance_of_class_a = ClassA.new
end
def method_calls_method
#instance_of_class_a.method
end
end
Or to pass in the ClassA instance (this is called dependency injection):
class ClassB
def initialize(class_a_instance)
#instance_of_class_a = class_a_instance
end
def method_calls_method
#instance_of_class_a.method
end
end
instance_a = ClassA.new
instance_b = ClassB.new(instance_a)
puts instance_b.method_calls_method
Another Option would be to take a look at class methods: https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/113-class-variables
So in your code it would look similar to this:
class ClassA
def self.method
return "This is a method_from_class_A"
end
end
class ClassB
def method_calls_method
ClassA.method
end
end
instance=ClassB.new
puts instance.method_calls_method
*Notice the self. in ClassA to signify a class method. This is similar to a static method in other languages.
According to wikipedia: https://en.wikipedia.org/wiki/Method_(computer_programming)#Static_methods
Class(static) methods are meant to be relevant to all the instances of a class rather than to any specific instance.
You see class methods used a lot in the ruby Math class:
http://ruby-doc.org/core-2.2.2/Math.html
For example taking a square root of a number in is done by using the class method Math.sqrt. This is different from an instance method which would look like object.method instead Class.method. There are a lot of resources and tutorials out that explains this concept in more detail and probably clearer.
I'm trying to create a singleton class that requires some sophisticated initialization. I've boiled my problem down to this test case:
class Dumb
attr_accessor :mything
#my_thing = 1 # this works
self.init_some_stuff # this gives undefined method
class << self
def init_some_stuff
#my_thing = 2
end
def spill_it
puts "My Thing: #{#my_thing}"
end
end
end
I can initialize simple variables, but want to call class methods to do it, and I get "undefined method". Since I intend it to be used as a singleton, a constructor would not get called. What am I missing?
A method is executed whenever it is met.
self.init_some_stuff
is placed before the definition of it. That is the problem. Place it after the definition.
I have a class:
class One
def initialize; end
end
I need to create a new class with my own constructor like this:
class Two < One
def initialize(some)
puts some
super
end
end
Two.new("thing")
but when I launch the code, I got an error:
thing
test.rb:10:in `initialize': wrong number of arguments (1 for 0) (ArgumentError)
super in this case (without parentheses) is a special form. It calls the superclass method with the original params.
Instead try calling
super()