# = functor.rb # # == Copyright (c) 2004 Thomas Sawyer # # Ruby License # # This module is free software. You may use, modify, and/or redistribute this # software under the same terms as Ruby. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. # # == Author(s) # # * Thomas Sawyer # Author:: Thomas Sawyer # Copyright:: Copyright (c) 2006 Thomas Sawyer # License:: Ruby License require 'facets/core/binding/self' require 'facets/more/basicobject' # = Functor # # By definition a Functor is simply a first class method, but these are common # in the form of Method and Proc. So here a Functor is a bit more specialized # as a 1st class _metafunction_. Essentally, a Functor can vary its behavior # accorrding to the operation applied to it. # # == Synopsis # # f = Functor.new { |op, x| x.send(op, x) } # f + 1 #=> 2 # f + 2 #=> 4 # f + 3 #=> 6 # f * 1 #=> 1 # f * 2 #=> 2 # f * 3 #=> 9 # class Functor < BasicObject def initialize(*targets, &function) @self = function.binding.self @targets = targets @function = function end def method_missing(op, *args, &blk) if block_given? @function.call(op, *(@targets + args), &blk) else @function.call(op, *(@targets + args)) end end # TODO use __xxx__ notation? def instance_self ; @self ; end def instance_targets ; @targets ; end def instance_objects ; @objects ; end # deprecate? def instance_function ; @function ; end end # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin testing require 'test/unit' class TC_Functor < Test::Unit::TestCase def test_function f = Functor.new { |op, x| x.send(op, x) } assert_equal( 2, f + 1 ) #=> 2 assert_equal( 4, f + 2 ) #=> 4 assert_equal( 6, f + 3 ) #=> 6 assert_equal( 1, f * 1 ) #=> 1 assert_equal( 4, f * 2 ) #=> 4 assert_equal( 9, f * 3 ) #=> 9 end def test_decoration f = Functor.new("A") { |op, a, x| x.send(op, a + x) } assert_equal( 'BAB', f + 'B' ) assert_equal( 'CAC', f + 'C' ) assert_equal( 'DAD', f + 'D' ) end end =end