Skip to content

Instantly share code, notes, and snippets.

@taqtiqa-mark
Forked from sparkertime/temporary_dsl.rb
Created December 2, 2012 07:48
Show Gist options
  • Save taqtiqa-mark/4187639 to your computer and use it in GitHub Desktop.
Save taqtiqa-mark/4187639 to your computer and use it in GitHub Desktop.
A Ruby 1.9 DSL strategy
# An unintrusive, temporary DSL strategy.
#
# Why discusses Ruby DSLs and instance_eval vs. block arguments:
# http://hackety.org/2008/10/06/mixingOurWayOutOfInstanceEval.html
#
# This takes advantage of some Ruby 1.9 features to implement a DSL mixin that
# is temporary and doesn't override locally defined methods.
class DslInstance
attr_accessor :script
def intialize &script
self.script = script
end
def script_receiver
script.binding.eval('self')
end
def script_metaclass
(class << script_receiver; self; end)
end
def mixin!
@script_old_method_missing = script_receiver.method :method_missing
dsl = Dsl.new
script_metaclass.send :define_method, :method_missing do |m, *a, &b|
if dsl.respond_to?(m)
dsl.send m, *a, &b
else
@script_old_method_missing.call m, *a, &b
end
end
end
def mixout!
script_metaclass.send :define_method, :method_missing,
&@script_old_method_missing
end
def with_mixin &block
mixin!
yield
ensure
mixout!
end
def go!
with_mixin &script
end
class Dsl
def foo; puts 'in Dsl foo'; end
def bar; puts 'in Dsl bar'; end
end
end
def foo; puts 'in root foo'; end
d = DslInstance.new{foo; bar}
d.go!
bar
# Outputs:
# in root foo
# in Dsl bar
# NameError: undefined local variable or method `bar' for main:Object
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment