Skip to content

Instantly share code, notes, and snippets.

@americodls
Created June 7, 2018 05:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save americodls/68ae9944e0cefed671d5ce9405faf66d to your computer and use it in GitHub Desktop.
Save americodls/68ae9944e0cefed671d5ce9405faf66d to your computer and use it in GitHub Desktop.
Create an object that is an improvement over Proc (curried by default and better inspection for debug)
class Function
attr_reader :arity, :source_location
def initialize(&block)
unless block_given?
message = "tried to create #{self.class.name} object without a block"
raise(ArgumentError, message)
end
@arity = block.arity
@source_location = block.source_location
define_singleton_method(:__call__, &block)
@block = method(:__call__).curry
end
def call(*args)
result = @block.call(*args)
if @arity != -1 && @arity > args.size
new_source = caller[0][/[^:]+:[^:]+/].split(":")
new_arity = @arity - args.size
new(new_source, new_arity, &result)
else
result
end
end
alias_method :[], :call
alias_method :===, :call
alias_method :yield, :call
def to_proc
@block
end
def inspect
id = "0x%014x" % (object_id << 1)
source = @source_location.join(":")
%(#<#{self.class.name}:#{id} #{source}>)
end
protected
attr_writer :arity, :source_location
private
def new(source, arity, &block)
self.class.new(&block).tap do |other|
other.arity = arity
other.source_location = source
end
end
end
def function(&block)
Function.new(&block)
end
add = function { |a,b| a + b }
add.(1, 2)
add.(1)
add.(1).(2)
sum = function { |*n| n.reduce(:+) }
sum.(1)
sum.(1, 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment