lib/phlex/unbuffered.rb
# frozen_string_literal: true module Phlex class Unbuffered < BasicObject CACHE = {} def self.call(object) decorator = CACHE[object.class.name] ||= ::Class.new(self) decorator.new(object) end def initialize(object) @object = object end def inspect "Unbuffered(#{@object.class.name})[object: #{@object.inspect}]" end # Borrow some important methods from Object define_method :__class__, ::Object.instance_method(:class) define_method :__public_send__, ::Object.instance_method(:public_send) define_method :__callee__, ::Object.instance_method(:__callee__) def respond_to_missing?(...) @object.respond_to?(...) end def method_missing(name, *args, &block) if @object.respond_to?(name) # If the object responds to this method, we want to define it by aliasing the __output_method__. __class__.alias_method(name, :__output_method__) # Now we've defined this missing method, we can call it. __public_send__(name, *args, &block) else super end end # This method is designed to be aliased and references the callee which is whatever alias you called. def __output_method__(*args, &block) @object.capture { @object.public_send(__callee__, *args, &block) } end def __forward_method__(*args, &block) @object.public_send(__callee__, *args, &block) end # Forward some methods to the original underlying method alias_method :call, :__forward_method__ alias_method :send, :__forward_method__ alias_method :public_send, :__forward_method__ end end