I want to self-initialize a class when it is inherited, but it seems inherited gets called before the inherited class is loaded. is this perhaps bad form?
class Foo
def self.inherited klass
klass.new
end
end
class Bar < Foo
def initialize
puts 'initialize'
end
end
Related
Can somebody help me distinguish When we create methods inside class << self block and when we define normal methods.
I saw somewhere code like this, but I don't know concisely the use cases of them
class Foo
def initialize
end
def bar
end
class << self
def foobar
end
end
end
The methods defined right inside a class block are instance methods:
class Foo
def bar
end
end
Methods defined within class << self inside a class block are class methods:
class Foo
class << self
def baz
end
end
end
Instance methods become available to any instance of a given class:
foo = Foo.new
foo.bar
Whereas class methods can be called directly on the class:
Foo.baz
Attempting to call instance methods on the class or vice versa results in an error:
Foo.bar #=> NoMethodError: undefined method `bar' for Foo:Class
foo.baz #=> NoMethodError: undefined method `baz' for #<Foo:0x00007ffe20055a20>
Another way to define class methods is by prefixing the method name with self.:
class Foo
def self.baz
end
end
You could also define them outside the class block, although this is rarely seen:
def Foo.baz
end
Or likewise:
class << Foo
def baz
end
end
Note that defining methods this way is not limited to classes. You can add methods to arbitrary objects, e.g.:
o = Object.new
def o.hello
"hello from o"
end
o.hello
#=> "hello from o"
Or via:
class << o
def hello
"hello from o"
end
end
Internally, these methods are added to the object's singleton class. It's a special purpose class to hold methods for just that instance:
o.singleton_class.instance_methods(false)
#=> [:hello]
For the Foo class above:
Foo.instance_methods(false) #=> [:bar]
Foo.singleton_class.instance_methods(false) #=> [:baz]
So technically, a class method is just an instance method defined on the class' singleton class.
You may need to read up on Ruby's instance and class methods.
But personally, I'd do
class Foo
class << self
def foobar
end
end
end
instead of
class Foo
def self.foobar
end
end
whenever I want to add some class level attributes, or make a method private etc as
class Foo
private
def self.foobar
end
end
wouldn't work the same as
class Foo
class << self
private
def foobar
end
end
end
An example might be:
module SharedStuff
def has_foo
!#foo.nil?
end
class StuffGenerator
def initialize
# super can't work here
end
# Will return nil.
def try_foo
#foo
end
end
end
class NeedsSharedStuff < BaseSource
include SharedStuff
def initialize
super
end
end
class AlsoSharedStuff < OtherSource
include SharedStuff
def initialize
super
end
end
class BaseSource
attr_reader :foo, :bar
def initalize
#foo, #bar = get_foo, get_bar
end
end
class OtherSource < BaseSource
def initialize
super
end
def extra_stuff
# whatever...
end
end
I've lost my #foo and #bar attributes in the nested classes within SharedStuff. Is there a way to get it without resorting to this?:
module SharedStuff
def has_foo
#foo.empty?
end
def stuff_generator
StuffGenerator.new #foo, #bar
end
class StuffGenerator
attr_reader :foo, :bar
def initialize(foo, bar)
#foo, #bar = foo, bar
end
def try_foo
#foo
end
end
end
I know this isn't right because I still can't reach has_foo in the parent module.
I'm sort of new to using mixins and modules in Ruby, is there a way to arrange this to get the methods in SharedStuff and the instance methods of the classes that extend it inside of the StuffGenerator?
You can still inherit inside of modules. All I needed was the #foo and #bar attributes, so I just went to the BaseSource and got them. :D.
module SharedStuff
def has_foo
!#foo.nil?
end
class StuffGenerator < BaseSource
def initialize
super
end
# Will return foo.
def try_foo
#foo
end
end
end
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 the following Ruby script, in which class Foo includes module Baz, module Baz has a included hook to make Bar extended by the including class (Foo). I am just wondering why:
class << klass
extend Bar #this doesn't work. Why?
end
does not work while:
klass.extend(Bar) works.
Here is my code:
#! /usr/bin/env ruby
module Baz
def inst_method
puts "dude"
end
module Bar
def cls_method
puts "Yo"
end
end
class << self
def included klass
# klass.extend(Bar) this works, but why the other approach below doesn't?
class << klass
extend Bar #this doesn't work. Why?
def hello
puts "hello"
end
end
end
end
end
class Foo
include Baz
end
foo = Foo.new
foo.inst_method
Foo.hello
Foo.cls_method
Within the body of class << klass, self refers to the singleton class of klass, not klass itself, whereas in klass.extend(Bar), the receiver is klass itself. The difference comes from there.
class A
end
class << A
p self # => #<Class:A> # This is the singleton class of A, not A itself.
end
p A # => A # This is A itself.
And since you want to apply extend to klass, doing it within the body of class << klass does not work.
What you want is invoke the extend method on the class object (klass) not the singleton class (class << klass).
Therefore the following code doesn't work because you are invoking the extend method on the singleton class:
class << klass
extend Bar # doesn't work because self refers to the the singleton class of klass
def hello
puts "hello"
end
end
In class Foo I'd like to include method Bar under certain conditions:
module Bar
def some_method
"orly"
end
end
class Foo
def initialize(some_condition)
if !some_condition
"bar"
else
class << self; include Bar; end
end
end
end
Is there any cleaner (and clearer) way to achieve the include in the method without having to do it inside the singleton class?
extend is the equivalent of include in a singleton class:
module Bar
def some_method
puts "orly"
end
end
class Foo
def initialize(some_condition)
extend(Bar) if some_condition
end
end
Foo.new(true).some_method # => "orly"
Foo.new(false).some_method # raises NoMethodError