How can I define Thread#initialize? I tried the following:
(1)
class Thread
def initialize
super
#foo = []
end
end
Thread.new{}.join
(2)
class Thread
def initialize &pr
super(&pr)
#foo = []
end
end
Thread.new{}.join
(3)
class Thread
def initialize
end
end
Thread.new{}.join
but they return an error:
Uninitialized thread - check `Thread#initialize'.
You're destroying the original Thread.initialize when open up the class this way, the call to super is Object.initialize, not to what was previously in Thread.initialize.
It's similar to what is happening here:
class Dog
def initialize
puts 'Arf'
end
end
class Dog
def initialize
super
puts 'I did not arf'
end
end
#dog.new "I did not arf"
You could subclass Thread and then use super, or you could use alias_method
class Thread
alias_method :old_initialize, :initialize
def initialize(*args,&blk)
puts 'Before initialize'
old_initialize(*args,&blk)
end
end
Related
I have a class that was built for subclassing.
class A
def initialize(name)
end
def some
# to define in subclass
end
end
# usage
p A.new('foo').some
#=> nil
In my use case, I don't want to create a subclass since I need just one instance. Therefore, I'll change the initialize method to support the following usage.
p A.new('foo') { 'YEAH' }.some
#=> YEAH
How could I support the usage above?
BTW: I found the following solutions for a Ruby 1.8.7 project, but they look awkward to me.
class A
def singleton_class
class << self; self; end
end
def initialize(name, &block)
#name = name
self.singleton_class.send(:define_method, :some) { block.call } if block_given?
end
def some
# to define in subclass
end
end
You can store the block argument in an instance variable and call it later on:
class A
def initialize(name, &block)
#name = name
#block = block
end
def some
#block.call
end
end
A.new('foo') { 'YEAH' }.some
#=> "YEAH"
You can also pass arguments into the block:
class A
# ...
def some
#block.call(#name)
end
end
A.new('foo') { |s| s.upcase }.some
#=> "FOO"
Or instance_exec the block in the context of the receiver:
class A
# ...
def some
instance_exec(&#block)
end
end
Which allows you to bypass encapsulation:
A.new('foo') { #name.upcase }.some
#=> "FOO"
For example, how could I implement the following:
class A
def initialize
b = B.new
end
end
class B
def initialize
puts #how can I find out who instantiated me
end
end
class A
def initialize
B.new(self)
end
end
class B
def initialize initializer
puts initializer
end
end
A.new # => #<A:0x007fee78368dc8>
I'm writing aspect-ish code more or less lifted from the chosen solution for this question that looks like the following:
class Module
def add_logging klass, *method_names
method_names.each do |method_name|
original_method = instance_method method_name
define_method method_name do |*args, &blk|
log.debug("#{klass}.#{method_name} called")
original_method.bind(klass).call(*args, &blk)
end
end
end
end
The solution in the other post doesn't require the klass parameter, but it only works for instance methods, whereas I hope to call my code like this:
module MyModule
def MyModule.module_method
p "hello"
end
class << self
add_logging self, :module_method1
end
end
Unfortunately when I run this code I get in 'bind': singleton method called for a different object (TypeError). Seeing as I pass self in the context of the class << self block, I don't understand why the bind call in the above code thinks it isn't binding to the exact same metaclass.
This should work for you:
class Module
def add_logging(*method_names)
method_names.each do |method_name|
original_method = method(method_name).unbind
define_singleton_method(method_name) do |*args, &blk|
puts "#{self}.#{method_name} called"
original_method.bind(self).call(*args, &blk)
end
end
end
end
# class method example
module MyModule
def self.module_method1
puts "hello"
end
add_logging :module_method1
end
MyModule.module_method1
# output:
#
# MyModule.module_method1 called
# hello
I currently have a superclass which has a function that I want all the subclass to call within each of its function. The function is supposed to behave like a before_filter function in rails but I am not sure on how to go about implementing before_filter. Here is an example
class Superclass
def before_each_method
puts "Before Method" #this is supposed to be invoked by each extending class' method
end
end
class Subclass < Superclass
def my_method
#when this method is called, before_each_method method is supposed to get invoked
end
end
This is one way to do it:
class Superclass
def before_each_method name
p [:before_method, name]
end
def self.method_added name
return if #__last_methods_added && #__last_methods_added.include?(name)
with = :"#{name}_with_before_each_method"
without = :"#{name}_without_before_each_method"
#__last_methods_added = [name, with, without]
define_method with do |*args, &block|
before_each_method name
send without, *args, &block
end
alias_method without, name
alias_method name, with
#__last_methods_added = nil
end
end
class SubclassA < Superclass
def my_new_method
p :my_new_method
end
def my_new_other_method
p :my_new_other_method
end
end
SubclassA.new.my_new_method
SubclassA.new.my_new_other_method
This will create a wrapper method using the alias_method_chaining method as soon as the method you'd like to wrap is defined in the subclass.
This is my solution:
require 'active_support/all'
module BeforeEach
extend ActiveSupport::Concern
module InstanceMethods
def before_each
raise NotImplementedError('Please define before_each method')
end
end
module ClassMethods
def method_added(method)
method = method.to_s.gsub(/_with(out)?_before$/, '')
with_method, without_method = "#{method}_with_before", "#{method}_without_before"
return if method == 'before_each' or method_defined?(with_method)
define_method(with_method) do |*args, &block|
before_each
send(without_method, *args, &block)
end
alias_method_chain(method, :before)
end
end
end
To use it, just include BeforeEach into your class like so:
class Superclass
include BeforeEach
def before_each
puts "Before Method" #this is supposed to be invoked by each extending class' method
end
end
class Subclass < Superclass
def my_method
#when this method is called, before_each_method method is supposed to get invoked
end
end
Subclass.new.my_method
# => Before Method
Hopefully this will work for you!
class BalanceChart < BalanceFind
include ExecutionHooks
attr_reader :options
def initialize(options = {})
#options = options
#begin_at = #options[:begin_at]
end
def months_used
range.map{|date| I18n.l date, format: :month_year}.uniq!
end
before_hook :months_data, :months_used, :debits_amount
end
module ExecutionHooks
def self.included(base)
base.send :extend, ClassMethods
end
module ClassMethods
def before
#hooks.each do |name|
m = instance_method(name)
define_method(name) do |*args, &block|
return if #begin_at.blank? ## the code you can execute before methods
m.bind(self).(*args, &block) ## your old code in the method of the class
end
end
end
def before_hook(*method_name)
#hooks = method_name
before
end
def hooks
#hooks ||= []
end
end
end
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