Skip to content

Instantly share code, notes, and snippets.

@marcotc
Created November 29, 2019 14:26
Show Gist options
  • Save marcotc/e67feb1f4eeacaf052d12a63107fa2f4 to your computer and use it in GitHub Desktop.
Save marcotc/e67feb1f4eeacaf052d12a63107fa2f4 to your computer and use it in GitHub Desktop.
Configurable Ruby Modules: The Module Builder Pattern
module Wrapper
InstanceMethods = Module.new
def self.for(klass, accessor_name: nil)
InstanceMethods.module_eval do
define_method :initialize do |object|
raise TypeError, "not a #{klass}" unless object.is_a?(klass)
@object = object
end
method_name = accessor_name || begin
klass_name = klass.to_s.gsub(/(.)([A-Z])/, '\1_\2').downcase
"original_#{klass_name}"
end
define_method(method_name) { @object }
end
InstanceMethods
end
end
class IntWrapper
include Wrapper.for(Integer)
end
class StringWrapper
include Wrapper.for(String)
end
IntWrapper.new(1).original_integer
# TypeError: not a String
# from (pry):7:in `block (2 levels) in for'
@citizen428
Copy link

module Wrapper
  def self.for(klass, accessor_name: nil)
    mod = const_set("#{klass}InstanceMethods", Module.new)

    mod.module_eval do
      define_method :initialize do |object|
        raise TypeError, "not a #{klass}" unless object.is_a?(klass)
        @object = object
      end

      method_name = accessor_name || begin
        klass_name = klass.to_s.gsub(/(.)([A-Z])/, '\1_\2').downcase
        "original_#{klass_name}"
      end

      define_method(method_name) { @object }
    end

    mod
  end
end

class IntWrapper
  include Wrapper.for(Integer)
end

class StringWrapper
  include Wrapper.for(String)
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment