Given a set of class definitions:
class Application
def self.open_current
return Current.new()
end
end
class Current
def get_row(row)
Row.new(row)
end
end
class Row
def get_col(row)
#...
end
end
Design a Proxy class which will:
Create Proxy<<Class>> versions of each class which are extendable via
class ProxyApplication
def myMethod()
#...
end
end
#...
Wrap all return values of all methods in each class such that a proxied class is always used instead of a standard class. I.E.
app = Proxy.new(Application) #app == ProxyApplication
current = app.open_current #current == #<ProxyCurrent>
Ultimately, the definition of Proxy must be dynamic rather than static definitions.
I've been working on this problem for about 6 hours now. I've got the following code. This includes 3 sections:
Initial class setup
Proxy class definition
Testing proxy class
Currently I've got to the point where pApplication=Proxy.new(Application) returns #<Proxy> and pApplication.open_current returns #<ProxyCurrent> which seems kind of on the correct line. However currently it errors when delegate.rb tries to call test() with 2,3 arguments instead of 0...
But my question is, realistically am I going about this correctly? Is using SimpleDelegator the easiest way to do this? One current problem is I'm basically having to add new functionality to the existing SimpleDelegator. I've also looked at using Forwardable, but having to delegate methods manually is not where I want to go with this project, if possible.
Any ideas?
Due to numerous limitations with the initial idea of packing all the calls into a single class, I redesigned it a bit, but it works in exactly the same way.
def proxy__enwrap(obj)
isClass = obj.is_a?(Class)
oldClass = isClass ? obj : obj.class
sNewClass = "Proxy#{oldClass.to_s}"
code = <<-EOF
class #{sNewClass}
include InstanceProxy
def self.__cinit__(obj)
##__cobj__ = obj
end
def self.__cget__
##__cobj__
end
def self.method_missing(m,*args,&block)
if ##__cobj__.respond_to? m
retVal = ##__cobj__.public_send(m,*args,*block)
return proxy__enwrap(retVal)
else
puts "ERROR " + m.to_s + "(" + args.to_s + ") + block?"
#Throw error
end
end
end
#{sNewClass}.__cinit__(#{oldClass.to_s})
if isClass
return #{sNewClass}
else
return #{sNewClass}.new(obj)
end
EOF
::Kernel.eval(code)
end
module InstanceProxy
def method_missing(m,*args,&block)
retVal = #__obj__.__send__(m,*args,&block)
return proxy__enwrap(retVal)
end
def initialize(obj)
#__obj__ = obj
end
end
XXApplication = Application
::Object.const_set "Application", proxy__enwrap(Application)
Currently the only issue is that the object doesn't wrap correctly around yielded objects... I'm not sure if that's even possible though.
Edit:
I've improved the system to also wrap objects passed in as blocks:
def proxy__enwrap(obj)
isClass = obj.is_a?(Class)
oldClass = isClass ? obj : obj.class
sNewClass = "Proxy#{oldClass.to_s}"
code = <<-EOF
class #{sNewClass}
include InstanceProxy
def self.__cinit__(obj)
##__cobj__ = obj
end
def self.__cget__
##__cobj__
end
def self.to_ary
#fix for puts (puts calls to_ary. see: https://stackoverflow.com/questions/8960685/ruby-why-does-puts-call-to-ary)
[self.to_s]
end
def self.method_missing(m,*args,&block)
#Wrap block arguments:
newBlock = Proc.new {}
if block_given?
newBlock = Proc.new do |*args|
args = args.map {|arg| proxy__enwrap(arg)}
block.call(*args)
end
end
#Call delegated functions. Raise error if object doesn't respond to method.
#Return wrapped value
if ##__cobj__.respond_to? m
retVal = ##__cobj__.public_send(m,*args,*block)
return proxy__enwrap(retVal)
else
raise ArgumentError.new("Method '\#\{m.to_s}' doesn't exist.")
end
end
end
#{sNewClass}.__cinit__(#{oldClass.to_s})
if isClass
return #{sNewClass}
else
return #{sNewClass}.new(obj)
end
EOF
::Kernel.eval(code)
end
module InstanceProxy
def method_missing(m,*args,&block)
#Wrap block arguments:
newBlock = Proc.new {}
if block_given?
newBlock = Proc.new do |*args|
args = args.map {|arg| proxy__enwrap(arg)}
block.call(*args)
end
end
#Call delegated functions. Raise error if object doesn't respond to method.
#Return wrapped value
if #__obj__.respond_to? m
retVal = #__obj__.__send__(m,*args,&newBlock)
return proxy__enwrap(retVal)
else
raise ArgumentError.new("Method '#{m.to_s}' doesn't exist.")
end
end
def initialize(obj)
#__obj__ = obj
end
def to_ary
#fix for puts (puts calls to_ary. see: https://stackoverflow.com/questions/8960685/ruby-why-does-puts-call-to-ary)
[self.to_s]
end
end
#
XXApplication = Application
#Silence warnings of overwriting constant
original_verbosity = $VERBOSE
$VERBOSE = nil
::Object.const_set "Application", proxy__enwrap(Application)
$VERBOSE = original_verbosity
Related
I have a class that does calculations. Most of the times it is used in the code to output a single value:
Use: value = Calculator.new(1234).output
This is an example of the class definition:
class Calculator
def initialize(parameter_1)
#parameter_1 = parameter_1
end
def output
op_1_result = operation_1(#parameter_1)
op_2_result = operation_2(op_1_result)
operation_3(op_2_result)
end
def operation_1(param)
...
end
But sometimes the user has to print a report of the calculation, showing many of the variables from inside the calculations.
The first solution I implemented was to pass a parameter at initialization telling the class that it should save some internal variables for the report, like this:
class Calculator
attr_reader :report
def initialize(parameter_1, reporting=false)
#parameter_1 = parameter_1
#reporting = reporting
#report = {}
end
def output
op_1_result = operation_1(#parameter_1)
#report[:op_1_result] = op_1_result if #reporting
op_2_result = operation_2(op_1_result)
#report[:op_2_result] = op_2_result if #reporting
operation_3(op_2_result)
end
def operation_1(param)
...
end
Then, when I want to get those intermediate variables, I would:
calculator = Calculator.new(1234, true) # reporting activated
report = calculator.report
report[:op_1_result] # one of the intermediate variables of the calculation
Does this break the single responsibility principle, as the class is now calculating the value and reporting at the same time?
Is there a better way to do this, a design pattern where I could have a fast calculation of the output result where it is needed and show the report where needed without all those ifs?
Any light on this and comments will be really appreciated!
Obs (another discussion): I've read that a more functional approach to just outputting a value would be a great thing. But that kept me wondering about how to show those internal intermediate values when needed. How do more functional programmers would do it...?
I guess "builder pattern" is suitable and "report pad" should be injected from outside.
class Calculator
def initialize(*parameters)
#parameters = parameters
end
def report_to(report_pad)
#report_pad = report_pad
self
end
def output()
ret = #parameters[0].to_i + #parameters[1].to_i
report('Did p0 + p1')
ret
end
private
def report(message)
#report_pad << "\n".prepend(message) if #report_pad.respond_to? '<<'
end
end
####
reports = ""
result = Calculator
.new(1, 2)
.report_to(reports)
.output()
puts result, reports
Why don't you just make all intermediate results public methods and chain the results in the final output?
Perhaps something like this:
class Calculator
def initialize(parameter)
#parameter = parameter
end
def output
op_3_result
end
def op_1_result
#op_1_result ||= operation_1(parameter)
end
def op_2_result
#op_2_result ||= operation2(op_1_result)
end
def op_3_result
#op_3_result ||= operation3(op_2_result)
end
private
def operation1(arg)
# ...
end
def operation2(arg)
# ...
end
def operation3(arg)
# ...
end
attr_reader :parameter
end
That would allow you to call whatever you need on the same instance:
calculator = Calculator.new(1234)
calculator.output #=> the final result
calculator.op_2_result #=> the intermediate result of step 2
You could use a different pattern with Report being its own class and allow it to just pass through when reporting is turned off. Here is a simple example:
class Calculator
attr_reader :report
def initialize(parameter_1, reporting=false)
#parameter_1 = parameter_1
#report = Report.new(reporting)
end
def output
op1 = operation_1(report.capture(:param1,#parameter_1))
report.capture(:op1,op1)
op2 = report.capture(:op2) { operation_2(op1) }
operation_3(op2)
end
def operation_1(param);
param + 7
end
def operation_2(param);
param - 3
end
def operation_3(param);
param * 2
end
end
class Report
attr_reader :reporting, :reportables
def initialize(reporting)
#reporting = reporting
#reportables = {}
end
def capture(key, val=nil,&block)
warn "Block supercedes value" if val && block_given?
result = block_given? ? block.call : val
#reportables[key] = result if reporting
result
end
def [](key)
return 'No Reporting' unless reporting
#reportables[key]
end
end
Then you can use like so
c = Calculator.new(12)
c.output
#=> 32
c.report[:op1]
#=> "No Reporting"
c = Calculator.new(12, true)
c.output
#=> 32
c.report[:op1]
#=> 19
c.report[:param1]
#=> 12
This way each step can use a block for more complicated items where the result should be captured or just pass a value if you choose and intermediate steps like operation_3 (in this case) that do not need to be "captured" can just flow through.
If reporting is off then everything just flows through and the captures are ignored.
Your #output method could also look like this (no intermediate locals at all although it does hurt the readability a bit)
def output
operation_3 (
report.capture(:op2,
operation_2(
report.capture(:op1) do
operation_1(report.capture(:param1,#parameter_1))
end
)
)
)
end
You can use dependency injection like this:
class Calculator
def initialize(parameter_1, reporter = nil)
#parameter_1 = parameter_1
#reporter = reporter
end
def output
op_1_result = call_with_reporting :operation_1, #parameter_1
op_2_result = call_with_reporting :operation_2, op_1_result
operation_3(op_2_result)
end
def operation_1(param)
...
end
def call_with_reporting(operation, *args)
result = self.send(operation, *args)
#reporter.report(operation, result) if #reporter
result
end
end
class ConsoleReporter
def initialize
#results = {}
end
def report(operation, result)
#results[operation] = result
end
def run_report
puts #operations
end
end
Now you can use Calculator like this:
reporter = ConsoleReporter.new
Calculator.new(12, reporter).output
reporter.run_report
Later you can use Calculator with other format reporter (like ToFileReporter)
I'm trying to figure out a way to have a method trigger another method by creating a new Listener class. I'd really like the code to be simplified and not involve adding anything specific to the callback method or the trigger method. Basically, what I'm trying to do is this:
def level_up
level += 1
end
def print_level
puts "Level Up! (#{level})"
end
notify_level = Listener.new(:level_up, :print_level);
What my Listener class is (right now) is this:
# Listener.new(attached_to, callbacks)
class Listener
def initialize(attached_to, function)
#owner, #callback = attached_to, function
end
def owner
#owner
end
def callback
#callback
end
def trigger
# execute callback manually
self.method(#owner).call
self.method(#callback).call
end
end
In order to call both, I need to execute notify_level.trigger itself, but what I want is to execute level_up and call print_level. I know someone will mention something about observers, but I need more than just that. I want to hold fast to DRY. Manually adding observers and listeners to every single method is just terrible, especially since I can't add or remove them with ease.
Personally I'm not a big fan of this pattern but this is kind of a fun question so here is my solution. Should work in Ruby 1.9 and greater.
module MethodListener
##observed_methods = {}
def method_added(method)
alias_name = "__#{method}_orig"
return if method_defined?(alias_name) || method.match(/__.*_orig/)
alias_method alias_name, method
define_method(method) do |*args|
ret = send(alias_name, *args)
(##observed_methods[method] || []).each {|callback| send(callback)}
ret
end
end
def listen(owner, callback)
(##observed_methods[owner] ||= []) << callback
end
end
Usage example:
class A
extend MethodListener
def b(a,b)
puts "b #{a} #{b}"
true
end
def c
puts 'c'
end
listen :b, :c
end
A.new.b(1,2) # => true
# Prints:
# b 1 2
# c
I changed my original code to be more semantic and so it would make more sense.
class Event
def initialize(event, callback_array = [])
if callback_array.kind_of? Array
#callbacks = callback_array
else
#callbacks = [callback_array]
end
#event = event
end
def trigger(*args)
self.method(#event).call *args
#callbacks.each{ |callback|
if callback.instance_of? Event
callback.trigger *args
else
method(callback).call *args
end
}
end
def add(callback)
#callbacks.push callback
end
def remove(callback)
#callbacks.delete_at(#callbacks.index(callback) || #callbacks.length)
end
def event_name
#event
end
end
Usage:
$infinite_break = 10
def infinite_loop_a(type)
puts "#{$infinite_break} points of #{type} damage taken"
$infinite_break -= 1
if $infinite_break > 0
$infinite.trigger(type)
else
$infinite.remove(:infinite_loop_a)
end
end
def infinite_loop_b(type)
puts "player is dealing #{$infinite_break} damage"
end
$infinite = Event.new(:infinite_loop_b, :infinite_loop_a)
$infinite.trigger('fire')
Also, I know I'm calling the infinite_loop_b inside infinite_loop_a, but that's for a specific reason. The Event instances can have another Event as a callback.
I'm trying to make a small game where you go from room to room but when I try to return the value for the next room instead of being the string I intended I get something that looks like this:
#<Roseroom:0x007fe40984c778>
instead of
"skullroom"
This happens whether I use a $global variable or try to return "a string"
Perhaps I'm going about this completely wrong, so if you have any suggestions that would be appreciated as well.
Here is my code, the problem is with class Roseroom not being about to send "skullroom" back to the map class (which is the runner).
$next_room = ''
class Engine
def initialize(stage)
#stage = stage
puts "succesfully initialized game"
#map = Map.new(#stage)
end
end
class Map
def initialize(start)
#start = start
#rooms = {"roseroom" => method(:enterRose),
"skullroom" => method(:enterSkull)
}
runner(#rooms, #start)
end
def runner(map, start)
$next_room = start
while true
room = map[$next_room]
puts $next_room
$next_room = room.call()
#method(:enterSkull).call() #This work if I call it directly
end
end
def enterRose()
#roseroom = Roseroom.new
end
def enterSkull()
#skullroom = Skullroom.new
end
end
class Roseroom
def initialize
puts "succesfully initialized roseroom"
#$next_room = "skullroom"
return "skullroom"
end
def exit
end
end
class Skullroom
def initialize
puts "succesfully initialized skullroom"
Process.exit(1)
end
end
game = Engine.new("roseroom")
I have it here on codepad if that helps:
http://codepad.org/AlpkRIGb
Thanks!
There is nothing in Roseroom class that would return "skullroom"... you may be under the impression that because the last line in initialize is return "skullroom" you would then see "skullroom" returned on a a Roseroom.new but that's not what happens... doing Roseroom.new will always return a new Roseroom object.
you'd be better off defining a next_room method within Roseroom that returns "skullroom"
class Roseroom
def next_room
return "skullroom"
end
Then when you do...
def enterRose
i_am_here = Roseroom.new
i_am_here.next_room
end
Hope this helps.
Heres what I have/want:
module Observable
def observers; #observers; end
def trigger(event, *args)
good = true
return good unless (#observers ||= {})[event]
#obersvers[event].each { |e| good = false and break unless e.call(self, args) }
good
end
def on(event, &block)
#obersvers ||= {}
#obersvers[event] ||= []
#observers[event] << block
end
end
class Item < Thing
include Observable
def pickup(pickuper)
return unless trigger(:before_pick_up, pickuper)
pickuper.add_to_pocket self
trigger(:after_pick_up, pickuper)
end
def drop(droper)
return unless trigger(:before_drop, droper)
droper.remove_from_pocket self
trigger(:after_drop, droper)
end
# Lots of other methods
end
# How it all should work
Item.new.on(:before_pickup) do |item, pickuper|
puts "Hey #{pickuper} thats my #{item}"
return false # The pickuper never picks up the object
end
While starting on trying to create a game in Ruby, I thought it would be great if it could be based all around Observers and Events. The problem is have to write all of these triggers seems to be a waste, as it seems like a lot of duplicated code. I feel there must be some meta programming method out there to wrap methods with functionality.
Ideal Sceanrio:
class CustomBaseObject
class << self
### Replace with correct meta magic
def public_method_called(name, *args, &block)
return unless trigger(:before_+name.to_sym, args)
yield block
trigger(:after_+name.to_sym, args)
end
###
end
end
And then I have all of my object inherit from this Class.
I'm still new to Ruby's more advanced meta programming subjects, so any knowledge about this type of thing would be awesome.
There are a several ways to do it with the help of metaprogramming magic. For example, you can define a method like this:
def override_public_methods(c)
c.instance_methods(false).each do |m|
m = m.to_sym
c.class_eval %Q{
alias #{m}_original #{m}
def #{m}(*args, &block)
puts "Foo"
result = #{m}_original(*args, &block)
puts "Bar"
result
end
}
end
end
class CustomBaseObject
def test(a, &block)
puts "Test: #{a}"
yield
end
end
override_public_methods(CustomBaseObject)
foo = CustomBaseObject.new
foo.test(2) { puts 'Block!' }
# => Foo
Test: 2
Block!
Bar
In this case, you figure out all the required methods defined in the class by using instance_methods and then override them.
Another way is to use so-called 'hook' methods:
module Overrideable
def self.included(c)
c.instance_methods(false).each do |m|
m = m.to_sym
c.class_eval %Q{
alias #{m}_original #{m}
def #{m}(*args, &block)
puts "Foo"
result = #{m}_original(*args, &block)
puts "Bar"
result
end
}
end
end
end
class CustomBaseObject
def test(a, &block)
puts "Test: #{a}"
yield
end
include Overrideable
end
The included hook, defined in this module, is called when you include that module. This requires that you include the module at the end of the class definition, because included should know about all the already defined methods. I think it's rather ugly :)
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