Metaprogramming: How to access parameters of methods inside meta classes - ruby

I am learning ruby meta-programming's meta classes concept. i am trying to define method dynamically inside meta-class but the problem which i am facing is i am not able to access "name" inside meta-class.
Below is my code.
class Abc
def add_method(name)
class << self
define_method "#{name}" do
end
end
end
end
a = Module.const_get("Abc").new
a.add_method("my_method")
a.my_method

Ok. got solution after some online debugging. Below is the solution
class Abc
def add_method(name)
meta_class = class << self
self
end
meta_class.class_eval do
define_method "#{name}" do
end
end
end
end
a = Module.const_get("Abc").new
a.add_method("my_method")
a.my_method

Related

How could I implement something like Rails' before_initialize/before_new in plain Ruby?

In Rails we can define a class like:
class Test < ActiveRecord::Base
before_initialize :method
end
and when calling Test.new, method() will be called on the instance. I'm trying to learn more about Ruby and class methods like this, but I'm having trouble trying to implement this in plain Ruby.
Here's what I have so far:
class LameAR
def self.before_initialize(*args, &block)
# somehow store the symbols or block to be called on init
end
def new(*args)
## Call methods/blocks here
super(*args)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end
I'm trying to figure out where to store the blocks in self.before_initialize. I originally tried an instance variable like #before_init_methods, but that instance variable wouldn't exist in memory at that point, so I couldn't store or retrieve from it. I'm not sure how/where could I store these blocks/procs/symbols during the class definition, to later be called inside of new.
How could I implement this? (Either having before_initialize take a block/proc/list of symbols, I don't mind at this point, just trying to understand the concept)
For a comprehensive description, you can always check the Rails source; it is itself implemented in 'plain Ruby', after all. (But it handles lots of edge cases, so it's not great for getting a quick overview.)
The quick version is:
module MyCallbacks
def self.included(klass)
klass.extend(ClassMethods) # we don't have ActiveSupport::Concern either
end
module ClassMethods
def initialize_callbacks
#callbacks ||= []
end
def before_initialize(&block)
initialize_callbacks << block
end
end
def initialize(*)
self.class.initialize_callbacks.each do |callback|
instance_eval(&callback)
end
super
end
end
class Tester
include MyCallbacks
before_initialize { puts "hello world" }
end
Tester.new
Left to the reader:
arguments
calling methods by name
inheritance
callbacks aborting a call and supplying the return value
"around" callbacks that wrap the original invocation
conditional callbacks (:if / :unless)
subclasses selectively overriding/skipping callbacks
inserting new callbacks elsewhere in the sequence
... but eliding all of those is what [hopefully] makes this implementation more approachable.
One way would be by overriding Class#new:
class LameAR
def self.before_initialize(*symbols_or_callables, &block)
#before_init_methods ||= []
#before_init_methods.concat(symbols_or_callables)
#before_init_methods << block if block
nil
end
def self.new(*args, &block)
obj = allocate
#before_init_methods.each do |symbol_or_callable|
if symbol_or_callable.is_a?(Symbol)
obj.public_send(symbol_or_callable)
else
symbol_or_callable.(obj)
end
end
obj.__send__(:initialize, *args, &block)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end

Ruby global variable alternative

I know global variables should never be used but right now it's the only thing that I can get to work. So I'm looking for alternatives. What I want to do is pass #array which is is in method two in class New, to method one. The only way I was able to accomplish this is with $array.
module Test::Abc
class << self
def one
....
end
class New
def two
#array=[]
end
end
end
end
Here's what I did to get the result I needed...
module Test::Abc
class << self
def one(array)
....
end
end
class New
def two
#array=[]
array=#array
Test::Abc::one(array)
end
end
end
Here's what I came up with as a solution...
module Test::Abc
class << self
def one(array)
....
end
end
class New
def two
#array=[]
array=#array
Test::Abc::one(array)
end
end
end
Along with your answer, this should also work (slight modification):
module Test::Abc
class << self
def one(array)
....
end
end
class New
def two
#array=[]
Test::Abc::one(#array)
end
end
end

class << notation in modules

I'm trying to mix a module into a class, and I want some of the methods to behave as class methods and others to be instance methods.
However, I don't want to both include and extend the module. I'd rather just include it.
When I wrap the methods I want to be class methods in this notation, it works:
class <<
# ...
end
However, when I use this notation it doesn't work:
class << self
# ...
end
I suspect the self keyword is establishing an explicit binding to the module, rather than the class it gets mixed into. But I've not seen any documentation that recommends leaving the self keyword off when using the class << notation.
Does anyone know what's going on with this?
UPDATE: Here's some sample code for more clarity:
module M
class <<
def class_method
puts "From inside the class_method"
end
end
def instance_method
puts "From inside the instance_method"
end
end
class Object
include M
end
class C
end
C.class_method
obj = C.new
obj.instance_method
class << must always be followed by an object. Just class <<; end is a syntax error. In your case it looks like it works because of the following:
class <<
def class_method
puts "From inside the class_method"
end
end
is the same as
class << def class_method
puts "From inside the class_method"
end
end
which is the same as
temp = def class_method
puts "From inside the class_method"
end
class << temp
end
which is the same as
def class_method
puts "From inside the class_method"
end
class << nil
end
which is the same as
def class_method
puts "From inside the class_method"
end
Of course that doesn't actually define a class method. It defines an instance method.
Yeah, if you want to get a real self in your module you should use included callback. Something like this point you in the right direction:
module Bar
def self.included(base)
class << base
def class_method
"class_method"
end
end
end
end
class Foo
include Bar
end
p Foo.class_method # => "class_method"

Returning dynamically generated module from a method

I have a bunch of classes with similiar logic like this
class ApiWrapper
class << self
attr_accessor :app_id, :app_key
def configure
yield self
end
end
end
I want to extract this logic to a module similar to Ruby Struct class to be able to do something like this
class ApiWrapper
include Configurable.instance :app_id, :app_key
end
How can I do this?
From documentation
fred = Module.new do
def meth1
"hello"
end
def meth2
"bye"
end
end

Overriding instance variable array’s operators in Ruby and scoping

I have a test class and a box class, in the test class i have a var called boxHolder, which is an array, i want to override the << method for this array. Inside the singleton how can i access moski_call ?
class Test
attr_accessor :boxHolder
def initialize()
super
self.boxHolder = Array.new
class << #boxHolder
def <<(box)
box.setPositionWithinColumn(moski_call)
super(box)
end
end
end
def moski_call
"YAAAAAAAAAAAAAAAAAAAA"
end
end
class Box
def initialize
end
def setPositionWithinColumn(str)
puts "got a string #{str}"
end
end
# test
box = Box.new
test = Test.new
test.boxHolder
like this:
# need this or else `moski_call` method is looked up in context of #boxholder
moski_call_output = moski_call
class << #boxholder; self; end.send(:define_method, :<<) { |box|
box.setPositionWithinColumn(moski_call_output)
super(box)
}
What about:
def self.boxHolder.<< (box)
box.setPositionWithinColumn(moski_call)
super(box)
end
This would declare a method for your instance boxHolder. But boxHolder does not have access to the method moski_call
You need to maintain access to the "parent" Test object. This can be done using the fact that blocks are closures:
parent = self # to be accessible in the closure
#boxHolder.define_singleton_method(:<<) do |box|
box.setPositionWithinColumn(parent.moski_call)
super(box)
end
Note: define_singleton_method is new in Ruby 1.9, so either upgrade, require 'backports/1.9.1/kernel/define_singleton_method' or do class << #boxHolder; define_method(:<<){ "..." } end if using an older Ruby.

Resources