I'm learning the object model of Ruby. I've written this script:
#/usr/bin/ruby
module MyModule
class MyBase
def class_b_method
puts "class_b_method called"
end
end
class MyClass < MyBase
attr_accessor :name
class_b_method
def set_name(name)
#name = "My name is #{name}"
end
def display_name
return #name
end
end
end
obj = MyModule::MyClass.new
obj.set_name "Martin"
puts obj.display_name
Running the code above I get this error:
module.rb:13: undefined local variable or method `class_b_method' for MyModule::MyClass:Class (NameError)
I'm trying to call the parent method within the class MyClass. What I'm doing wrong?
Inside class MyClass,self is MyClass.But you define class_b_method as an instance method inside class MyBase,i.e. method which can be called by the instances of the class MyBase,can't be invoked by the class itself. so self.class_b_method throws an legitimate error.To make your code workable write the method as below:
class MyBase
def self.class_b_method
puts "class_b_method called"
end
end
Related
I have the following classes:
Module
module AlertService
module MessageTemplate
def generate_message
"test"
end
end
end
Parent class:
module Client
def post uri, params={}
Net::HTTP.post_form uri, params
end
end
module AlertService
class BaseAlert
extend MessageTemplate
include Singleton
include Client
def initialize; end
end
end
Child Class:
module AlertService
class TestAlert < BaseAlert
include Singleton
def initialize
options = {
username: "Screen Alert Bot",
http_client: Client
}
#notifier = Slack::Notifier.new(rails.config.url, options)
end
def self.create_message
message = generate_message
end
def self.send_message
create_message
#notifier.post blocks: message
end
end
end
I can create the test alert like this: s= AlertService::TestAlert
But I get the error when I do this:
s.send_message
NoMethodError: undefined method `generate_message' for AlertService::TestAlert::Class
generate_message is a method from the MessageTemplate module included in the BaseAlert class. Why is it saying my inherited class doesn't have access to the method?
You're not using Singleton correctly. You're including it, but then not using it, instead bypassing that altogether and calling class methods that have nothing to do with Singleton. They're in turn calling class methods on the parent class that don't exist.
The solution is to use Singleton as intended:
module AlertService
class BaseAlert
include MessageTemplate
include Singleton
def initialize
end
end
end
module AlertService
class TestAlert < BaseAlert
def initialize
#notifier = Slack::Notifier.new(Rails.configuration.url, Rails.configuration.options)
end
def create_message
message = generate_message
end
def send_message
create_message
#notifier.post blocks: message
end
end
end
Where now you call with instance as documented:
AlertService::TestAlert.instance.send_message
I´m trying to develop a service class that provides payment services in my Rails app, but it´s not working.
Service class (lib/paypal_service.rb) (not sure if it should be placed here, I read it in some posts):
class PaypalService
attr_reader :api #, :express_checkout_response
def initialize()
#api = PayPal::SDK::Merchant::API.new
end
def test()
puts "Congratulations, you have called test"
end
end
Controller (uses service):
class BookingsController < ApplicationController
include BoatsHelper
require 'paypal_service'
def create
PaypalService.test
end
...
In output I get:
NoMethodError (private method `test' called for PaypalService:Class):
It's because you are calling a class method, but you have defined an instance method.
Change you controller to this
def create
PaypalService.new.test
end
Or define a class method and leave your controller as is
class PaypalService
attr_reader :api #, :express_checkout_response
def initialize()
#api = PayPal::SDK::Merchant::API.new
end
def self.test
new.test
end
def test()
puts "Congratulations, you have called test"
end
end
Use PaypalService.new.test instead of PaypalService.test as test is an instance method of class PaypalService and not a class method. Update it as below:
class BookingsController < ApplicationController
include BoatsHelper
require 'paypal_service'
def create
PaypalService.new.test
end
...
NOTE:
If you want to call it as PaypalService.test then you can convert test to a class method as follows:
class PaypalService
attr_reader :api #, :express_checkout_response
def initialize
#api = PayPal::SDK::Merchant::API.new
end
def self.test
puts "Congratulations, you have called test"
end
end
I am a NOOB trying to understand some code.
What does this self.class.current_section do?
class MyClass
class << self
def current_section(*section)
if section.empty?
#current_section
else
#current_section = section[0]
end
end
end
def current_section()
self.class.current_section
end
def current_section=(section)
self.class.current_section(section)
end
end
self returns the the current object.
self.class returns the class of current object.
self.class.current_section invokes the method of the class of current object (that method called current_section).
def current_section()
p self
p self.class
end
current_section()
It forwards the message (method call request) received by the object to the corresponding class.
Say you have a class
class MyClass
def MyClass.current_section
puts "I'm the class method."
end
def current_section
self.class.current_section
end
end
h = MyClass.new
h.current_section # outputs "I'm the class method."
Calling h's method, it looks up h's class (MyClass) and invokes the method current_section of that class.
So, by the definitions above, every object of the class MyClass has a method current_section which is routed to the central current_section of the class.
The definition of the class methods in your question is just using a different syntax for doing the same: adding a method to the class object.
class << self
def current_section(*section)
if section.empty?
#current_section
else
#current_section = section[0]
end
end
end
This code part is being evaluated in the Class Object scope because of the class << self statement. Thus current_section is being defined as a class method, invokable as Myclass.current_section.
def current_section()
self.class.current_section
end
This part is just the definition of an instance method, and thus self is an instance of the Myclass object.
self.class gets the class of such instance, thus, Myclass, and the current_section method of the class is invoked.
I realize this perhaps a naive question but still I cant figure out how to call one method from another in a Ruby class.
i.e. In Ruby is it possible to do the following:
class A
def met1
end
def met2
met1 #call to previously defined method1
end
end
Thanks,
RM
Those aren't class methods, they are instance methods. You can call met1 from met2 in your example without a problem using an instance of the class:
class A
def met1
puts "In met1"
end
def met2
met1
end
end
var1 = A.new
var1.met2
Here is the equivalent using class methods which you create by prefixing the name of the method with its class name:
class A
def A.met1
puts "In met1"
end
def A.met2
met1
end
end
A.met2
I am trying to get the name of the class from within a static method within the class:
class A
def self.get_class_name
self.class.name.underscore.capitalize.constantize
end
end
Though this returns Class instead of A. Any thoughts on how do I get A instead?
Eventually I also want to have a class B that inherits from A that will use the same method and will return B when called.
The reason I am doing this is because I have another object under this domain eventually: A::SomeOtherClass which I want to use using the result I receive.
Remove .class:
class A
def self.get_class_name
self.name.underscore.capitalize.constantize
end
end
self in a context of a class (rather than the context of an instance method) refers to the class itself.
This is why you write def self.get_class_name to define a class method. This means add method get_class_name to self (aka A). It is equivalent to def A.get_class_method.
It is also why when you tried self.class.name you got Class - the Object#class of A is Class.
To make this clearer, consider the output of:
class A
puts "Outside: #{self}"
def self.some_class_method
puts "Inside class method: #{self}"
end
def some_instance_method
puts "Inside instance method: #{self}"
end
end
A.some_class_method
A.new.some_instance_method
Which is:
Outside: A
Inside class method: A
Inside instance method: #<A:0x218c8b0>
The output for this:
class NiceClass
def self.my_class_method
puts "This is my #{name}"
end
end
NiceClass.my_class_method
Will be:
This is my NiceClass