Created
November 1, 2010 10:58
-
-
Save bil-bas/657983 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'mixico' | |
module Redirector | |
# @param [Object] target Target of the redirection. | |
# @param [Array<Symbol>] methods ([]) If empty, redirect all methods, otherwise only redirect named ones. | |
def self.create(target, *methods) | |
my_module = Module.new | |
if methods.empty? | |
# Equivalent to gen_eval, but won't crash and probably lower performance. | |
my_module.send :define_method, :method_missing do |method, *args, &block| | |
target.send method, *args, &block | |
end | |
else | |
# Just redirect named methods. | |
methods.each do |method| | |
my_module.send :define_method, method do |*args, &block| | |
target.send method, *args, &block | |
end | |
end | |
end | |
my_module | |
end | |
end | |
class State | |
def initialize | |
@state_packer = Packer.new | |
self.extend @state_packer.redirector | |
setup | |
end | |
# Set everything up at the start. | |
def setup | |
@header = "State:" | |
label "chunky" | |
@packer = pack do | |
label "bacon" | |
pack do | |
@my_label = label "CHUNKY" # ivar on State, not a packer. | |
label "BACON" | |
@footer = "ended" # Check that outer var is set. | |
end | |
end | |
end | |
# Dynamic additions later. | |
def change | |
@packer.label "Cazoo!" | |
@packer.pack do | |
@header = "Changed State:" # Check that outer var is set. | |
label "Cazoo too!" | |
end | |
@my_label.text = "VERY CHUNKY" | |
end | |
def draw | |
puts @header | |
@state_packer.draw | |
puts @footer | |
end | |
end | |
class Packer | |
attr_reader :redirector | |
def initialize | |
@children = [] | |
@redirector = Redirector.create(self, :pack, :label, :inside) | |
end | |
def label(text) | |
label = Label.new(text) | |
add label | |
label | |
end | |
def inside(&block) | |
mix_eval(redirector, &block) | |
end | |
def pack(&block) | |
packer = Packer.new | |
@children << packer | |
context = eval('self', block.binding) | |
context.mix_eval(packer.redirector, &block) | |
packer | |
end | |
def draw(indent = "") | |
puts "#{indent}--->" | |
@children.each { |c| c.draw(indent + " ") } | |
puts "#{indent}<---" | |
end | |
protected | |
def add(child) | |
@children << child | |
end | |
end | |
class Label | |
attr_accessor :text | |
def initialize(text) | |
@text = text | |
end | |
def draw(indent) | |
print indent | |
puts @text | |
end | |
end | |
state = State.new | |
state.draw | |
state.change | |
class Other | |
def initialize(state) | |
@state = state | |
end | |
def change | |
@state.pack do | |
pack do | |
label "Added from another object" | |
end | |
end | |
end | |
end | |
Other.new(state).change | |
state.pack do | |
pack do | |
label "Added from main" | |
end | |
end | |
state.inside do | |
label "Added from main using #inside" | |
end | |
puts | |
puts '--------' | |
puts | |
state.draw | |
=begin | |
State: | |
---> | |
chunky | |
---> | |
bacon | |
---> | |
CHUNKY | |
BACON | |
<--- | |
<--- | |
<--- | |
ended | |
-------- | |
Changed State: | |
---> | |
chunky | |
---> | |
bacon | |
---> | |
VERY CHUNKY | |
BACON | |
<--- | |
Cazoo! | |
---> | |
Cazoo too! | |
<--- | |
<--- | |
---> | |
---> | |
Added from another object | |
<--- | |
<--- | |
---> | |
---> | |
Added from main | |
<--- | |
<--- | |
Added from main using #inside | |
<--- | |
ended | |
=end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment