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
Related
What is the idea behind creating a new instance of a method inside the class << self construct?
I understand methods are put under the class << self block to make them class methods but what does it mean to create a new instance of the method itself?
class foo
class << self
def bar(param)
new.bar(some_param)
end
end
end
I think what your trying to describe is a convenience method:
class FooService
def initialize
#bar= Bar.new
end
# this does the actual work
def call
results = #bar.do_some_work
results.each do
# ...
end
end
# this is just a convenient wrapper
def self.call
new.call
end
end
This lets you call the FooService.call class method for instead of manually instantiating the class with FooService.new.call. It does not really look like that much from this simple example but its really useful for abstracting away object initialization in things like service objects or to combine initializer arguments with method arguments.
class ApiClient
def initialize(api_key)
#api_key = api_key
end
def get(path)
# ...
end
def self.get(path, api_key: ENV['API_KEY'])
new(api_key).call(path)
end
end
ApiClient.get('foo')
Hi I am trying to create a helper for mass defining ruby methods as private class methods. In general one can define a method as a private class method by using private_class_method key work. But I would like to create a helper in the following style:
class Person
define_private_class_methods do
def method_one
end
def method_two
end
end
end
The way I planned to dynamically define this is in the following way, which is not at all working:
class Object
def self.define_private_class_methods &block
instance_eval do
private
&block
end
end
end
any ideas where I might be going wrong?
$ cat /tmp/a.rb
class Object
def self.define_private_class_methods &cb
existing = methods(false)
instance_eval &cb
(methods(false) - existing).each { |m| singleton_class.send :private, m }
end
end
class Person
define_private_class_methods do
def method_one
puts "¡Yay!"
end
end
end
Person.send(:method_one)
Person.public_send(:method_one)
$ ruby /tmp/a.rb
¡Yay!
/tmp/a.rb:18:in `public_send': private method `method_one'
called for Person:Class (NoMethodError)
Did you mean? method
from /tmp/a.rb:18:in `<main>'
Please note, that it’s hard to understand, what you are trying to achieve and possibly there is better, cleaner and more robust way to achieve this functionality.
Similar, yet different (and semantically more correct IMHO) to #mudasobwa's answer:
class Class
def define_private_class_methods(&definition)
class_methods_prior = methods
singleton_class.class_eval(&definition)
(methods - class_methods_prior).each do |method_name|
private_class_method method_name
end
end
end
class Person
define_private_class_methods do
def method_one
1
end
end
end
Person.method_one # !> NoMethodError: private method `method_one' called for Person:Class
Person.send :method_one # => 1
Note: It will not change the accessibility of a class method that you are currently overwriting.
You could define the methods in an anonymous module by passing the block to Module.new, make each instance method in the module private and extend your class with the module:
class Class
def define_private_class_methods(&block)
mod = Module.new(&block)
mod.instance_methods.each { |m| mod.send(:private, m) }
extend(mod)
end
end
This has the desired result:
class Person
define_private_class_methods do
def method_one
123
end
end
end
Person.send(:method_one)
#=> 123
Person.method_one
#=> private method `method_one' called for Person:Class (NoMethodError)
... and as a bonus, it also gives you a super method: (probably of little use)
class Person
def self.method_one
super * 2
end
end
Person.method_one
#=> 456
Of course, you don't have to use extend, you could just as well define the methods manually:
class Class
def define_private_class_methods(&block)
mod = Module.new(&block)
mod.instance_methods.each do |m|
define_singleton_method(m, mod.instance_method(m))
private_class_method(m)
end
end
end
The essential component is the anonymous module, so you have a (temporary) container to define the methods in.
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
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