Ruby: How to set instance variables from a class method? - ruby

I'm not sure that's the right title for this question, but I don't know how else to ask it. I have classes that need to be registered globally so they can be called later. I have most of it working except for a very important part. When the child inherits from the parent class, it registers a new instance, but when the on_message class method is called, I can't figure out how to set the instance variables that I need.
class MyExtension < ExtensionBase
on_message '/join (.+)' do |username|
# this will be a callback function used later
end
end
class ExtensionBase
def self.inherited(child)
MainAppModule.registered_extensions << child.new
end
def self.on_message(string, &block)
# these need to be set on child instance
#regex = Regexp.new(string)
#on_message_callback = block
end
def exec(message)
args = #regex.match(message).captures
#on_message_callback.call(args)
end
end
# somewhere else in the code, I find the class that I need...
MainAppModule.registered_extensions.each do |child|
puts child.regex.inspect # this is nil and I dont want it to be
if message =~ child.regex
return child.exec(message)
end
end
How can I design this so that the #regex will be set so I can access it within the loop?

I finally found a solution that works, and I have added now the whole code that is executable. Just store the code e.g. in file callexample.rb and call it by ruby callexample.rb
The main difference of my solution to the question is that the call to on_message now creates the instance with the relevant arguments and registers the created instance. Therefore I have deleted the method inherited because I don't need it any more.
I have added some puts statements to demonstrate in which order the code works.
class MainAppModule ## Added class
##registered_extensions = []
def self.registered_extensions; ##registered_extensions; end
end
class ExtensionBase
attr_reader :regex
def self.on_message(string, &block)
MainAppModule.registered_extensions << self.new(string, block)
end
def initialize(string, block)
#regex = Regexp.new(string)
#on_message_callback = block
end
def exec(message)
args = #regex.match(message).captures
#on_message_callback.call(args)
end
end
class MyExtension < ExtensionBase
on_message '/join (.+)' do |username|
# this will be a callback function used later
puts "Callback of #{self} called."
"returnvalue"
end
end
# somewhere else in the code, I find the class that I need...
MainAppModule.registered_extensions.each do |child|
puts "Value of regex: #{child.regex}" # this is no more nil
message = '/join something'
if message =~ child.regex
puts "On match evalue 'child.exec(message)' to: #{child.exec(message)}"
end
end

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 pass self of caller of method into method being called automaticly

I'm trying to create a method that passes the caller as the default last argument. According to this, I only need:
class A
def initialize(object = self)
# work with object
end
end
so that in:
class B
def initialize
A.new # self is a B instance here
end
end
self will be B rather than A;
However, this doesn't seem to work. Here's some test code:
class A
def self.test test, t=self
puts t
end
end
class B
def test test,t=self
puts t
end
end
class T
def a
A.test 'hey'
end
def b
B.new.test 'hey'
end
def self.a
A.test 'hey'
end
def self.b
B.new.test'hey'
end
end
and I get:
T.new.a # => A
T.new.b # => #<B:0x000000015fef00>
T.a # => A
T.b # => #<B:0x000000015fed98>
whereas I expect it to be T or #<T:0x000000015fdf08>. Is there a way to set the default last argument to the caller?
EDIT:
class Registry
class << self
def add(component, base=self)
self.send(component).update( base.to_s.split('::').last => base)
end
end
end
The idea is pretty simple, you would use it like this
class Asset_Manager
Registry.add :utilities
end
and you access it like:
include Registry.utilities 'Debugger'
I'm trying to de-couple classes by having a middle-man management type class that takes care of inter-class communications, auto-loading of missing classes and erroring when it doesn't exist, it works but I just want to be able to use the above rather than:
class Asset_Manager
Registry.add :utilities, self
end
It just feels cleaner, that and I wanted to know if such a thing was possible.
You can't escape the explicit self. But you can hide it with some ruby magic.
class Registry
def self.add(group, klass)
puts "registering #{klass} in #{group}"
end
end
module Registrable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def register_in(group)
Registry.add(group, self)
end
end
end
class AssetManager
include Registrable
register_in :utilities
end
# >> registering AssetManager in utilities
In short, you can't.
Ruby resolves the default arguments in the context of the receiver. That is, the object before the . in a method call. What you called the receiver should be the caller, actually.
class A
def test1(value = a)
puts a
end
def test2(value = b)
puts b
end
def a
"a"
end
end
a = A.new
a.test1 #=> a
def a.b; "b" end
a.test2 #=> b
If I were you, I would use the extended (or included) hook, where both the extending class and the extended module can be accessed. You can program what ever logic you want based on the information.
module Registry
module Utilities
def self.extended(cls)
#puts cls
::Registry.send(component).update( cls.to_s.split('::').last => cls)
end
end
end
class Asset_Manager
extend Registry::Utilities
end

Using instance_exec and converting a method to a Proc

I can take a block of code, instance_exec it, and get the proper result. I would like to take a method off a different object and call one of it's methods in my scope. When I take a method from a different object, turn it into a proc, and then instance_exec it, I don't get the expected result. Code follows.
class Test1
def ohai(arg)
"magic is #{#magic} and arg is #{arg}"
end
end
class Test2
def initialize
#magic = "MAGICAL!"
end
def scope_checking
#magic
end
def do_it
ohai = Test1.new.method(:ohai)
self.instance_exec("foobar", &ohai)
end
end
describe "Test2 and scopes" do
before do
#t2 = Test2.new
end
it "has MAGICAL! in #magic" do
#t2.scope_checking.should == "MAGICAL!"
end
# This one fails :(
it "works like I expect converting a method to a proc" do
val = #t2.do_it
val.should == "magic is MAGICAL! and arg is foobar"
end
it "should work like I expect" do
val = #t2.instance_exec do
"#{#magic}"
end
val.should == "MAGICAL!"
end
end
It seems that, in Ruby, methods defined using def some_method are bound permanently to the class they're defined in.
So, when you call .to_proc on them they keep the binding of their original implementation, and you cannot rebind them. Well, you can, but only to an object of the same type as the first one. It's possible I could do some fancyness with inheritance, but I don't think so.
The solution becomes instead of using methods, I just put actual Procs into variables and use them then, as they're not bound until execution time.
not sure how good of an idea this is, but this passes your tests:
class Test1
def ohai(arg, binding)
eval('"magic is #{#magic} "', binding).to_s + "and arg is #{arg}"
end
end
class Test2
def initialize
#magic = "MAGICAL!"
end
def scope_checking
#magic
end
def get_binding
return binding()
end
def do_it
self.instance_exec(get_binding) {|binding| Test1.new.ohai("foobar", binding) }
end
end

Having a method re-defining another class's method

I have a simple class with a simple method definition
class Printer
def print
p '1'
end
end
And now I introduce a separate script that re-defines the print method by adding some extra stuff to print
class Printer
alias :old_print :print
def print
old_print
p '2'
end
end
Can I do this programmatically?
module Test
def self.redefine_print(arg)
# redefine Printer's print method so that it will print all of the stuff it should
# print, followed by the arg I specified
end
end
So a sample interaction might look like
>>>a = Printer.new
>>>a.print
1
>>>Test.redefine_print("new stuff")
>>>a.print
1
new stuff
>>>Test.redefine_print("more")
>>>a.print
1
new stuff
more
It is ok if existing instances are affected by the changes (because any instance of Printer will be created, do its printing, and then disposed immediately)
You could use define_method or a module for that, but it is overkill (and probably very slow). It is possible (and simpler) to use a class variables and a class method instead:
class Printer
##tokens = []
def print
##tokens.each do |token|
p token
end
end
def self.add_token(token)
##tokens << token
end
end
Printer.add_token("foo")
printer = Printer.new
printer.print
# foo
Printer.add_token("bar")
printer.print
#foo
#bar
To answer to your question though, it's possible to redefine methods of other classes by using class_eval and define_method:
class Printer
def print
p '1'
end
end
module Test
def self.redefine_print(arg)
old_print = Printer.instance_method(:print)
Printer.class_eval do
define_method(:print) do
old_print.bind(self).call
p arg
end
end
end
end
printer = Printer.new
printer.print
# 1
Test.redefine_print("new stuff")
printer.print
# 1
# new stuff
Test.redefine_print("more")
printer.print
# 1
# new stuff
# more

Dynamic class creation, problem with function definition inside block: function body does not see local scope

I'm writing a function to dynamically create classes. I run into a problem with the *vars variable (below), where inside the block passed to Class::new, the "def initialize" method cannot see the value of *vars (and thus Ruby reports a unbound variable error on *vars).
What to do?
Thanks!
class MyParentClass
def do_something_with(*args)
end
def do_something_else_with(*vars)
end
end
def create_class(class_name,*vars)
new_class = Class::new(MyParentClass) do
def initialize(*args)
super
do_something_with(args)
do_something_else_with(vars)
end
end
Object::const_set(class_name.intern,new_class)
end
# Ruby: Error: *vars is unbound variable
# My notes: *vars is in scope inside the do..end block passed to Class::new, but cannot be seen inside def initialize (why?) . And, how to fix this?
I am not sure what are you trying to achieve with this contraption, but after some changes it works (well, depending on your definition of "to work"):
class MyParentClass
def do_something_with(*args)
puts "something #{args.inspect}"
end
def do_something_else_with(*vars)
puts "else #{vars.inspect}"
end
end
def create_class(class_name,*vars)
new_class = Class::new(MyParentClass) do
define_method :initialize do |*args|
super()
do_something_with(*args)
do_something_else_with(*vars)
end
end
Object::const_set(class_name.intern,new_class)
end
create_class :MyClass, 1, :foo, :bar
MyClass.new(2, :baz)
The trick to make vars visible is to define the constructor using a closure.

Resources