Skip to content

Instantly share code, notes, and snippets.

@MaxPleaner
Last active November 12, 2017 21:54
Show Gist options
  • Save MaxPleaner/f8332a44b290a6c787a213d5b450ba89 to your computer and use it in GitHub Desktop.
Save MaxPleaner/f8332a44b290a6c787a213d5b450ba89 to your computer and use it in GitHub Desktop.
refinement builder class
module CoreExt; end
module CoreExt::RefinementBuilder
def build_refinement(class_name, namespace: Object, refines: Object, &blk)
const = namespace.const_set class_name, Module.new(&blk)
const.instance_methods(false).each do |method_name|
orig_method = const.instance_method method_name
const.send :define_method, method_name do |*args, **keywords, &blk|
if eql?(const)
if keywords.empty?
orig_method.bind(const).call *args, &blk
else
orig_method.bind(const).call *args, **keywords, &blk
end
else
if keywords.empty?
const.send method_name, *args, &blk
else
const.send method_name, *args, **keywords, &blk
end
end
end
const.send :module_function, method_name
const.send(:refine, refines) { include const }
end
end
module_function :build_refinement
refine Object do
include CoreExt::RefinementBuilder
end
end
using CoreExt::RefinementBuilder
build_refinement "Util" do
def a
1
end
def b
a
end
end
# The above definitiomn enables all the following usages:
# 1. Use the methods as a refinement
# By default they are patched onto Object but this can be changed
# by supplying a refines: <class> option to build_refinement.
class Foo
using Util
puts b # => 1
puts a => 1
end
# 2. Use the methods statically
puts Util.a # => 1
puts Util.b # => 2
# 3. Use as a typical module via include
include Util
puts b # => 1
puts a # => 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment