Skip to content

Instantly share code, notes, and snippets.

@bil-bas
Created November 1, 2010 10:58
Show Gist options
  • Save bil-bas/657983 to your computer and use it in GitHub Desktop.
Save bil-bas/657983 to your computer and use it in GitHub Desktop.
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