Skip to content

Instantly share code, notes, and snippets.

@jacobo
Last active December 17, 2015 22:19
Show Gist options
  • Select an option

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

Select an option

Save jacobo/5681361 to your computer and use it in GitHub Desktop.
In http://rubykaigi.org/2013/talk/S58 @Shogu describes how refinements work, but says he would rather they work with a block-like syntax. I asked why he couldn't just implement these extensions in pure ruby using the same techniques that stub and mock libraries use. The translated answer was "Because I want to refinement only to apply inside the…
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
class_refined.instance_eval do
define_method(method_refined, new_method)
end
end
end
end
def self.using_refinement(&context)
@applies.each(&:call)
yield
ensure
@reverts.each(&:call)
end
end
class MathRefinement < BlockRefinement
refines Float, String
refines_method(:*) do |arg|
"(#{self.to_s}) * (#{arg.to_s})"
end
refines_method(:+) do |arg|
"(#{self.to_s}) + (#{arg.to_s})"
end
end
class MyDSL
end
class Object
def refined_instance_eval(using, &block)
using.using_refinement do
instance_eval(&block)
end
end
end
puts 3.14159 * 5 + 10
MyDSL.refined_instance_eval(MathRefinement) do
puts 3.14159 * 5 + 10
end
puts 3.14159 * 5 + 10
# OUTPUT:
# 25.70795
# ((3.14159) * (5)) + (10)
# 25.70795
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment