I noticed if I make a subclass which inherits from Datetime, it's .now will return the subclass instance, not Datetime instance.
class MyDateTime < DateTime
end
MyDateTime.now
>#<MyDateTime: 2012-06-05T16:42:57+08:00 ((2456084j,31377s,900801494n),+28800s,2299161j)>
It seems magical. I can't reproduce this behavior in my own class:
class A
def self.a
return A.new
end
end
class B < A
end
B.a
#<A:0x00000001e22358>
I tried to read the source code of DateTime but it's written in C. Is it possible to write a class method which returns an instance of the class it belongs to?
Try it with self:
class A
def self.a
return self.new
end
end
class B < A
end
B.a
Related
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.
How can I call super class method within class like:
class A
def foo
puts "lol"
end
end
class B < A
foo
end
You're trying to call an instance method from within the context of a class. This is not valid.
What would work:
class A
def self.foo
puts "lol"
end
end
class B < A
foo
end
I have a list of names and values I'm trying to read in and turn into classes so I'm using Class.new.
The end result I want is a number of classes that work as if defined like:
module MyMod
class AA < Base
def self.value
value1
end
end
class AB < Base
def self.value
value2
end
end
...
end
My current code looks like:
name = 'AA'
value = 'test'
MyMod.const_set name, Class.new(Base) do
???
end
Setting the name works great, but haven't figured out what I need in the block for get value in. Calling def doesn't work because the closure for value gets lost.
I have managed to get things working with:
temp = const_set name, Class.new(Base)
temp.define_singleton_method(:value) { value }
However, it seems like there should be a way to do it with the block of Class.new. Also, I'm really not sure define_singleton_method is actually putting the method in the right place. It works in my tests, but I'm not sure if the method is actually where I think it is or somewhere else up the call chain. I've tried various combinations of class_variable_set, attr_reader, class_eval, instance_eval, and others, but it got to a point where it was just guess and check. I think I still haven't quite wrapped my head around metaprogramming :-/
if i correctly understood your question, this should work for you:
class Base
end
class AA < Base
name = :Blah
klass = self.const_set name, Class.new(Base)
class << klass
def value
__method__
end
end
end
p AA::Blah.value
#=> :value
UPDATE: seems you want it defined in the block:
class Base
end
class AA < Base
name = :Blah
klass = Class.new(Base) do
class << self
def value
__method__
end
end
end
self.const_set name, klass
end
p AA::Blah.value
you trying this:
const_set name, Class.new(Base) do
...
end
it does not work cause the block is referring to const_set rather than to Class.new
If you prefer define_singleton_method over class << self:
class Base
end
class AA < Base
name = :Blah
klass = Class.new(Base) do
self.define_singleton_method :value do
__method__
end
end
self.const_set name, klass
end
And finally if you really want to define them at once, use brackets instead of do...end:
class Base
end
class AA < Base
name = :Blah
self.const_set name, Class.new(Base) {
self.define_singleton_method :value do
__method__
end
}
end
Here is a working demo
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.
Why there is an error in the following example?
class ClassA
class ClassB
end
class ClassC
def test
ClassB.new
end
end
end
p ClassA::ClassC.new.test # => #<ClassA::ClassB:0x0000010103f860>
class ClassA
class ClassD
def test
ClassB.new
end
end
end
p ClassA::ClassD.new.test # => #<ClassA::ClassB:0x0000010103f010>
class ClassA::ClassE
def test
ClassB.new
end
end
p ClassA::ClassE.new.test # => NameError: uninitialized constant ClassA::ClassE::ClassB
Is there another way to create ClassE, not by typing class ClassA; class ClassE?
Well, yes, if you define your test method to return ClassA::ClassB.new :-)
You could also play around with const_missing so that it calls ClassA.const_get.
Otherwise ClassB is not in the current scope, which at that point is only ClassA::ClassE and Object. When you first open ClassA, then ClassE, the lookup for ClassB is done first in ClassA::ClassE, then in ClassA (where it is found) and would also look in Object.
The custom Object#const_missing method, suggested by Marc-André Lafortune, would be then
def Object.const_missing(name)
#looked_for ||= {}
key = self.to_s + '~' + name.to_s
raise "Class not found: #{name}" if #looked_for[key] == key
return #looked_for[key] if #looked_for[key]
#looked_for[key] = key
if self.to_s.include? '::'
klass = Object
self.to_s.split('::')[0..-2].each do |klass_string|
klass = klass.const_get klass_string
end
return #looked_for[key] = klass.const_get(name) if klass # klass.is_a?(Class)
end
raise "Class not found: #{name}"
end
Some related questions:
Does Ruby provide the namespace path, e.g. something like [:A,:B] for class A::B::C?
If I define a class-method in Ruby Object class, how do I get the name of a child class calling this method?
How do I get class-object from string “A::B::C” in Ruby?