Skip to content

Instantly share code, notes, and snippets.

@jacobo
Created May 31, 2013 01:37
Show Gist options
  • Select an option

  • Save jacobo/5682477 to your computer and use it in GitHub Desktop.

Select an option

Save jacobo/5682477 to your computer and use it in GitHub Desktop.
Yet another example of implementing something LIKE refinements directly in pure ruby. I run into the contraint of being unable to properly set 'self' in my blocks. (could be solved if I had https://bugs.ruby-lang.org/issues/8465) AND, it's very hacky because it uses caller. but I *think* this is what @Shogu generally intends the semantics of blo…
class BlockRefinement
def self.refines(*classes_refined)
@classes_refined = classes_refined
end
def self.refines_method(method_refined, &new_method)
@classes_refined.each do |class_refined|
old_method = class_refined.instance_method(method_refined)
@reverts ||= []
@reverts << Proc.new do
class_refined.instance_eval do
define_method(method_refined, old_method)
end
end
@applies ||= []
@applies << Proc.new do |limit_context_to|
class_refined.instance_eval do
define_method(method_refined) do |*args|
if caller[0].include?(limit_context_to.to_s)
new_method.call(self, *args)
else
bound = old_method.bind(self)
bound.call(*args)
end
end
end
end
end
end
def self.using_refinement(&context)
@limit_context_to = context.binding.eval("self")
@applies.each{|a| a.call(@limit_context_to) }
yield
ensure
@reverts.each(&:call)
end
end
class MathRefinement < BlockRefinement
refines Float, Fixnum, String
refines_method(:*) do |realself, arg|
"(#{realself.to_s}) * (#{arg.to_s})"
end
refines_method(:+) do |realself, arg|
"(#{realself.to_s}) + (#{arg.to_s})"
end
end
class Elsewhere
def self.calculate_a_thing
5 + 5
end
end
class MyDSL
class << self
attr_accessor :things
end
self.things = []
MathRefinement.using_refinement do
self.things << 3.14159 * 5 + 10 * Elsewhere.calculate_a_thing
end
end
puts 3.14159 * 5 + 10 * Elsewhere.calculate_a_thing
puts MyDSL.things.inspect
puts 3.14159 * 5 + 10 * Elsewhere.calculate_a_thing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment