lib/tangle/currify.rb
# frozen_string_literal: true
module Tangle
# Raised for zero arity of a currified method, subclass of ArgumentError
class CurrifyError < ArgumentError
def initialize(msg = 'method accepts no arguments', *)
super
end
end
# Currification of instance methods, for adding callbacks to other objects
module Currify
def self.included(base)
base.extend(ClassMethods)
end
# Class method extensions for currification of instance methods
module ClassMethods
# Return a list of currified methods for a given tag.
#
# :call-seq:
# self.class.currified_methods(tag) => Array of Symbol
def currified_methods(tag)
mine = @currified_methods&.[](tag) || []
return mine unless superclass.respond_to?(:currified_methods)
superclass.currified_methods(tag) + mine
end
private
# Add a symbol to the list of currified methods for a tag.
#
# :call-seq:
# class X
# currify :tag, :method
def currify(tag, method)
raise CurrifyError if instance_method(method).arity.zero?
@currified_methods ||= {}
@currified_methods[tag] ||= []
@currified_methods[tag] << method
end
end
private
def define_currified_methods(obj, tag)
self.class.currified_methods(tag)&.each do |name|
obj.instance_exec(name, method(name).curry) do |method_name, method|
define_singleton_method(method_name) do |*args|
method.call(self, *args)
end
end
end
end
end
end