Why isn't Class.new called? - ruby

I am trying to override Class.new so that I can see what classes are being created e.g.
class Class
class << self
alias new_orig new
def new(*args)
obj = new_orig *args
print "created",obj,"\n"
obj
end
end
end
class X
end
It doesn't print anything, but if I create class using Class.new it works
puts Class.new
created#<Class:0x8b75888>
#<Class:0x8b75888>
So why there is a difference between class X and Class.new ?

To get the wanted effect, you could use Class#inherited:
class Class
def inherited(subclass)
puts "Created #{subclass}"
end
end
class XX #writes "Created XX"
end

Related

In ruby from class with function without self how to get current class name?

how is is possible in the below example to print ValidatorStatus class name?
class ValidatorStatus
def initialize(host, msg)
#host = host
#msg = msg
end
attr_accessor :host
attr_accessor :msg
def to_s
puts %|How to have this print *ValidatorStatus*
by dynamically discovering class name?
also if im a subclass of this should print
the subclass name|
end
end
self.class.name
Does just what you want. But as you added the restriction not to use self:
public_send(:class).name
def to_s
self.class.name
end
As others have said, the correct answer is self.class.name
If you want to get creative, you could use :
class A
def to_s
Module.nesting.first.to_s
end
end
puts A.new
# A
There's no self here, not even an implicit, hidden one.
It doesn't return the subclass though:
class B < A
end
puts B.new
# A
Another possibility would be to parse the current file :
class C < A
def to_s
File.readlines(__FILE__).take(__LINE__).reverse.join[/(?<=^class )\w+/]
end
end
puts C.new
# C

Insert code into the beginning of each method of a class

How can I dynamically and easily insert code into the beginning of each method of a class and subclasses without actually inserting it manually? I want something like a macros.
class C1
def m1
#i_am = __method__
end
def m2
#i_am = __method__
end
end
This is one of the examples where I want to avoid repetition.
I initially misinterpreted the question (but have left my original answer after the horizontal line below). I believe the following may be what you are looking for.
class C1
[:m1, :m2].each do |m|
define_method(m) do |name|
#i_am = __method__
puts "I'm #{name} from method #{#i_am}"
end
end
end
C1.instance_methods(false)
#=> [:m1, :m2]
c1 = C1.new
#=> #<C1:0x007f94a10c0b60>
c1.m1 "Bob"
# I'm Bob from method m1
c1.m2 "Lucy"
# I'm Lucy from method m2
My original solution follows.
class C1
def add_code_to_beginning(meth)
meth = meth.to_sym
self.class.send(:alias_method, "old_#{meth}".to_sym, meth)
self.class.send(:define_method, meth) do
yield
send("old_#{meth}".to_sym)
end
end
end
Module#alias_method
and Module#define_method are private; hence the need to use send.
c = C1.new
#=> #<C1:0x007ff5e3023650>
C1.instance_methods(false)
#=> [:m1, :m2, :add_code_to_beginning]
c.add_code_to_beginning(:m1) do
puts "hiya"
end
C1.instance_methods(false)
#=> [:m1, :m2, :add_code_to_beginning, :old_m1]
c.m1
# hiya
#=> :m1
You can use a rails like class decorators to that. The piece of code below is rendering a method called before_action defined in the Base class of the ActiveRecord module. The Test class is inherited from the ActiveRecord. The define_method is used if we want to call something explicitly from the Base class.
module ActiveRecord
class Base
def self.before_action(name)
puts "#{name}"
puts "inside before_action of class Base"
define_method(name) do
puts "Base: rendering code from Base class"
end
end
end
end
class Test < ActiveRecord::Base
before_action :hola
def render()
puts "inside render of class Test"
end
end
test = Test.new
test.render
test.hola
It has the output
hola
inside before_action of class Base
inside render of class Test
Base: rendering code from Base class
So, before running the render method it runs the before_action method in the Base class. It can be applied to all other methods in the Test class. This is a way of representing macros in ruby.
Assuming that the function is the same, you could create a module and include it in your classes.
Example:
module MyModule
def test_method
puts "abc"
end
end
class MyClass
include MyModule
def my_method
puts "my method"
end
end
inst = MyClass.new
inst.test_method # => should print "abc"
inst.my_method # => should print "my method"

ruby: how to initialize class method with parameters?

I'm struggling with a simple question how to instantiate a class with arguments.
For example i have a class with an initializer that takes two arguments and a class method:
class MyClass
attr_accessor :string_1, :string_2
def initialize(string_1, string_2)
#string_1 = string_1
#string_2 = string_2
end
def self.some_method
# do something
end
end
If some_method were an instance method i could instantiate a new object of MyClass and call the instance method like:
MyClass.new("foo", "bar").some_method
But how can i achieve that for the MyClass itself and the class method instead of an instance?
Something like MyClass.self("foo", "bar").some_method does not work.
You could do this.
class MyClass
singleton_class.send(:attr_accessor, :string_3)
end
MyClass.string_3 = "It's a fine day."
MyClass.string_3 #=> "It's a fine day."
#string_3 is a class instance variable.
I believe the conventional way to initiate a class and then run a method on those values would be like:
class MyClass
def initialize(string_1, string_2)
#string_1 = string_1
#string_2 = string_2
end
def some_method
"#{#string_1} #{#string_2}"
end
end
a = MyClass.new("foo", "bar")
puts a.some_method #=> "foo bar"
If you want to use attr_accessor then you can bypass the some_method to return those values:
class MyClass
attr_accessor :string_1, :string_2
def initialize(string_1, string_2)
#string_1 = string_1
#string_2 = string_2
end
end
a = MyClass.new("foo", "bar")
puts a.string_1 + a.string_2 #=> "foobar"

Unable to override base class method in derived class

Here are the Ruby classes I have:
class MyBase
class << self
def static_method1
##method1_var ||= "I'm a base static method1"
end
def static_method1=(value)
##method1_var = value
end
def static_method2
##method2_var ||= "I'm a base static method2"
end
def static_method2=(value)
##method2_var = value
end
end
def method3
MyBase::static_method1
end
end
class MyChild1 < MyBase
end
class MyChild2 < MyBase
class << self
def static_method1
##method1_var ||= "I'm a child static method1"
end
end
end
c1 = MyChild1.new
puts c1.method3 #"I'm a base static method1" - correct
c2 = MyChild2.new
puts c2.method3 # "I'm a base static method1" - incorrect. I want to get "I'm a child static method1"
I'm aware of attr_accessor and modules, but I can't use use them here because I want them to give default values in MyBase class. I want to override MyBase.static_method1 in MyChild2.
The problem is that method3 is always explicitly calling the method on the base class. Change it to this:
def method3
self.class.static_method1
end
After that, consider not using ##.
## in ruby is extremely counterintuitive and rarely means what you think it means.
The problem with ## is that it is shared across the all of the inherited classes and the base class. See this blog post for an explanation.

Ruby methods similar to attr_reader

I'm trying to make a method similar to attr_reader but I can't seem to get the instance of the class that the method gets called in.
class Module
def modifiable_reader(*symbols)
# Right here is where it returns Klass instead of #<Klass:0x1df25e0 #readable="this">
mod = self
variables = symbols.collect { |sym| ("#" << sym.to_s).to_sym }
attr_reader *symbols
(class << ModifyMethods; self; end).instance_eval do
define_method(*symbols) do
mod.instance_variable_get(*variables)
end
end
end
end
class Object
module ModifyMethods; end
def modify(&block)
ModifyMethods.instance_eval(&block)
end
end
class Klass
modifiable_reader :readable
def initialize
#readable = "this"
end
end
my_klass = Klass.new
my_klass.modify do
puts "Readable: " << readable.to_s
end
I'm not sure what it is you're trying to do.
If it helps, the spell for attr_reader is something like this:
#!/usr/bin/ruby1.8
module Kernel
def my_attr_reader(symbol)
eval <<-EOS
def #{symbol}
##{symbol}
end
EOS
end
end
class Foo
my_attr_reader :foo
def initialize
#foo = 'foo'
end
end
p Foo.new.foo # => "foo"
What I can understand from your code is that you want to have the modify block to respond to the instance methods of Klass, that's as simple as:
class Klass
attr_reader :modifiable
alias_method :modify, :instance_eval
def initialize(m)
#modifiable = m
end
end
Klass.new('john').modify do
puts 'Readable %s' % modifiable
end
About this tidbit of code:
def modifiable_reader(*symbols)
# Right here is where it returns Klass instead of #<Klass:0x1df25e0 #readable="this">
mod = self
...
Probably this can give you a hint of what is going on:
Class.superclass # => Module
Klass.instance_of?(Class) # => true
Klass = Class.new do
def hello
'hello'
end
end
Klass.new.hello # => 'hello'
When you are adding methods to the Module class, you are also adding methods to the Class class, which will add an instance method to instances of Class (in this case your class Klass), at the end this means you are adding class methods on your Klass class

Resources