ludy 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. data/CHANGES +88 -57
  2. data/Manifest.txt +96 -0
  3. data/NOTICE +10 -23
  4. data/README +173 -10
  5. data/Rakefile +33 -0
  6. data/TODO +5 -0
  7. data/bin/ludy +11 -0
  8. data/lib/ludy/all.rb +3 -0
  9. data/lib/ludy/array/body.rb +9 -0
  10. data/lib/ludy/array/combine.rb +16 -0
  11. data/lib/ludy/array/combos.rb +23 -0
  12. data/lib/ludy/array/filter.rb +4 -0
  13. data/lib/ludy/array/foldl.rb +5 -0
  14. data/lib/ludy/array/foldr.rb +8 -0
  15. data/lib/ludy/array/reverse_map.rb +7 -0
  16. data/lib/ludy/array/rotate.rb +22 -0
  17. data/lib/ludy/array.rb +3 -0
  18. data/lib/ludy/blackhole.rb +17 -0
  19. data/lib/ludy/class/undef_all_methods.rb +9 -0
  20. data/lib/ludy/class.rb +3 -0
  21. data/lib/ludy/deprecated/aspect.rb +26 -0
  22. data/lib/ludy/deprecated/callstack.rb +24 -0
  23. data/lib/ludy/deprecated/curry.rb +29 -0
  24. data/lib/ludy/deprecated/rambda.rb +23 -0
  25. data/lib/ludy/deprecated/this.rb +14 -0
  26. data/lib/ludy/deprecated/untranspose.rb +12 -0
  27. data/lib/ludy/deprecated/unzip.rb +7 -0
  28. data/lib/ludy/{dice.rb → dices.rb} +18 -22
  29. data/lib/ludy/kernel/defun.rb +10 -0
  30. data/lib/ludy/kernel/ergo.rb +16 -0
  31. data/lib/ludy/kernel/id.rb +6 -0
  32. data/lib/ludy/kernel/if_else.rb +14 -0
  33. data/lib/ludy/kernel/m.rb +5 -0
  34. data/lib/ludy/kernel/public_send.rb +13 -0
  35. data/lib/ludy/kernel/singleton_method.rb +13 -0
  36. data/lib/ludy/kernel/tap.rb +10 -0
  37. data/lib/ludy/kernel.rb +3 -0
  38. data/lib/ludy/lazy.rb +9 -16
  39. data/lib/ludy/message_dispatcher.rb +58 -0
  40. data/lib/ludy/pattern_matcher.rb +41 -0
  41. data/lib/ludy/proc/bind.rb +21 -0
  42. data/lib/ludy/proc/chain.rb +17 -0
  43. data/lib/ludy/proc/compose.rb +9 -0
  44. data/lib/ludy/proc/curry.rb +39 -0
  45. data/lib/ludy/proc.rb +3 -0
  46. data/lib/ludy/symbol/curry.rb +10 -0
  47. data/lib/ludy/symbol/to_msg.rb +10 -0
  48. data/lib/ludy/symbol/to_proc.rb +7 -0
  49. data/lib/ludy/symbol.rb +3 -0
  50. data/lib/ludy/tasks/erb_cpp/attr_builder.rb +49 -0
  51. data/lib/ludy/tasks/erb_cpp/header_guard.rb +12 -0
  52. data/lib/ludy/tasks/erb_cpp/template_forward_parameters.rb +43 -0
  53. data/lib/ludy/tasks/erb_cpp.rb +35 -0
  54. data/lib/ludy/tasks.rb +3 -0
  55. data/lib/ludy/test/helper.rb +3 -0
  56. data/lib/ludy/variable.rb +9 -17
  57. data/lib/ludy/y_combinator.rb +3 -22
  58. data/lib/ludy/z_combinator.rb +2 -16
  59. data/lib/ludy.rb +74 -23
  60. data/lib/puzzle_generator/chain.rb +2 -2
  61. data/lib/puzzle_generator/chained_map.rb +7 -10
  62. data/lib/puzzle_generator/colored_map.rb +2 -2
  63. data/lib/puzzle_generator/map.rb +8 -12
  64. data/lib/puzzle_generator/misc.rb +5 -4
  65. data/lib/puzzle_generator/puzzle.rb +4 -4
  66. data/lib/puzzle_generator.rb +2 -2
  67. data/spec/ludy_spec.rb +22 -0
  68. data/tasks/annotations.rake +30 -0
  69. data/tasks/doc.rake +50 -0
  70. data/tasks/gem.rake +89 -0
  71. data/tasks/manifest.rake +41 -0
  72. data/tasks/rubyforge.rake +57 -0
  73. data/tasks/setup.rb +151 -0
  74. data/tasks/spec.rake +40 -0
  75. data/tasks/svn.rake +44 -0
  76. data/tasks/test.rake +40 -0
  77. data/test/deprecated/callstack.rb +18 -0
  78. data/test/deprecated/curry.rb +34 -0
  79. data/test/deprecated/rambda.rb +15 -0
  80. data/test/{tc_this.rb → deprecated/this.rb} +2 -18
  81. data/test/{ts_ludy.rb → deprecated/ts_ludy.rb} +2 -17
  82. data/test/deprecated/unzip_and_untranspose.rb +13 -0
  83. data/test/{test_puzzle.rb → example_puzzle.rb} +3 -2
  84. data/test/test_all.rb +21 -0
  85. data/test/test_array.rb +47 -0
  86. data/test/test_class.rb +13 -0
  87. data/test/test_defun.rb +37 -0
  88. data/test/test_dices.rb +32 -0
  89. data/test/test_kernel.rb +36 -0
  90. data/test/test_lazy.rb +18 -0
  91. data/test/test_proc.rb +57 -0
  92. data/test/test_symbol.rb +15 -0
  93. data/test/test_variable.rb +29 -0
  94. data/test/test_y_combinator.rb +21 -0
  95. data/test/test_z_combinator.rb +20 -0
  96. metadata +134 -51
  97. data/lib/lib/amulti.rb +0 -40
  98. data/lib/lib/multi.rb +0 -139
  99. data/lib/lib/smulti.rb +0 -56
  100. data/lib/ludy/aspect.rb +0 -41
  101. data/lib/ludy/bind.rb +0 -31
  102. data/lib/ludy/callstack.rb +0 -39
  103. data/lib/ludy/curry.rb +0 -49
  104. data/lib/ludy/ludy_ext.rb +0 -145
  105. data/lib/ludy/rambda.rb +0 -42
  106. data/lib/ludy/this.rb +0 -34
  107. data/ludy.gemspec +0 -44
  108. data/test/tc_bind.rb +0 -29
  109. data/test/tc_callstack.rb +0 -34
  110. data/test/tc_curry.rb +0 -51
  111. data/test/tc_dice.rb +0 -48
  112. data/test/tc_lazy.rb +0 -34
  113. data/test/tc_ludy_ext.rb +0 -154
  114. data/test/tc_rambda.rb +0 -31
  115. data/test/tc_variable.rb +0 -45
  116. data/test/tc_y_combinator.rb +0 -37
  117. data/test/tc_z_combinator.rb +0 -36
@@ -0,0 +1,17 @@
1
+
2
+ require 'ludy/class/undef_all_methods'
3
+ require 'singleton'
4
+
5
+ module Ludy
6
+ # a blackhole would eat any message it received.
7
+ class Blackhole
8
+ undef_all_methods
9
+ include Singleton
10
+ def method_missing msg, *args, &block
11
+ self
12
+ end
13
+ def nil?
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+
2
+ class Class
3
+ # undefine all instance methods, used for delegation class
4
+ def undef_all_methods
5
+ instance_methods.each{ |m|
6
+ undef_method m unless (m =~ /^__/ || m.to_sym == :object_id || m.to_sym == :public_send )
7
+ }
8
+ end
9
+ end
data/lib/ludy/class.rb ADDED
@@ -0,0 +1,3 @@
1
+
2
+ require 'ludy'
3
+ Ludy.require_all_in 'class'
@@ -0,0 +1,26 @@
1
+
2
+ module Ludy
3
+
4
+
5
+ end
6
+
7
+ module Kernel
8
+ def cut target, &block
9
+ (class << target; self; end)
10
+ end
11
+ end
12
+
13
+ class Name
14
+ def name
15
+ 'name'
16
+ end
17
+ end
18
+
19
+ cut Name do
20
+ def name
21
+ "<#{super}>"
22
+ end
23
+ def g
24
+ '??'
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+
2
+ module Ludy
3
+ # TRACE_EVENT = 0
4
+ # TRACE_FILE = 1
5
+ # TRACE_LINE = 2
6
+ # TRACE_MSG = 3
7
+ # TRACE_BINDING = 4
8
+ # TRACE_CLASS = 5
9
+
10
+ def callstack levels = -1
11
+ st = Thread.current[:callstack]
12
+ if levels then st && st[levels - 2] else st end
13
+ end
14
+ module_function :callstack
15
+ end # of Ludy
16
+
17
+ set_trace_func lambda{ |*args|
18
+ case args[0]
19
+ when /call$/
20
+ (Thread.current[:callstack] ||= []).push args
21
+ when /return$/
22
+ (Thread.current[:callstack] ||= []).pop
23
+ end
24
+ }
@@ -0,0 +1,29 @@
1
+
2
+ require 'ludy/proc/curry'
3
+
4
+ module Ludy
5
+
6
+ module Curry
7
+ def self.included target
8
+ target.module_eval{
9
+ instance_methods.each{ |m|
10
+ next unless m =~ /^\w/
11
+ module_eval <<-END
12
+ def c#{m} *args, &block
13
+ if args.size == method(:#{m}).arity
14
+ self.__send__ :#{m}, *args, &block
15
+ else
16
+ method(:c#{m}).to_proc.send :__curry__, *args
17
+ end
18
+ end
19
+ END
20
+ }
21
+ }
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ =begin
28
+ method(:#{m}).to_proc.curry.call *args, &block
29
+ =end
@@ -0,0 +1,23 @@
1
+
2
+ require 'rubygems'
3
+ raise LoadError.new('you need ruby2ruby gem to use this tool') unless require 'ruby2ruby'
4
+
5
+ require 'ludy/symbol/to_proc'
6
+
7
+ module Ludy
8
+
9
+ class Rambda
10
+ def initialize &block
11
+ @this = eval block.to_ruby
12
+ define_instance_method :call, &@this
13
+ alias_instance_method :[], :call
14
+ end
15
+ attr_reader :this
16
+ alias_method :to_proc, :this
17
+ end
18
+
19
+ def rambda &block
20
+ Rambda.new &block
21
+ end
22
+
23
+ end # of Ludy
@@ -0,0 +1,14 @@
1
+
2
+ require 'ludy/callstack'
3
+
4
+ module Ludy
5
+ def this
6
+ info = callstack(-2)
7
+ # lambda{ |*args|
8
+ # Thread.current[:temp_args] = args
9
+ # eval("send :#{info[3]}, *Thread.current[:temp_args]", info[4])
10
+ # }
11
+ eval('self', info[TRACE_BINDING]).method(info[TRACE_MSG])
12
+ end
13
+ module_function :this
14
+ end # of Ludy
@@ -0,0 +1,12 @@
1
+
2
+ class Array
3
+ def untranspose
4
+ result = ([nil]*self.first.size).map{[]}
5
+ self.each{ |zipped|
6
+ zipped = zipped.clone
7
+ result.each{ |r| r << zipped.shift }
8
+ }
9
+ result
10
+ end
11
+ def untranspose!; replace untranspose; end
12
+ end
@@ -0,0 +1,7 @@
1
+
2
+ require 'ludy/array/untranspose'
3
+
4
+ class Array
5
+ def unzip; untranspose.first; end
6
+ def unzip!; replace unzip; end
7
+ end
@@ -1,34 +1,25 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Copyright (c) 2007, Lin Jen-Shin(a.k.a. godfat 真常)
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
1
 
17
2
  module Ludy
18
3
 
19
- class Dice
4
+ # dices, e.g., 4d6, 2d20, etc.
5
+ class Dices
20
6
  attr_reader :amounts, :faces
7
+ # the default dice is 1d20
21
8
  def initialize amounts = 1, faces = 20
22
9
  @amounts = amounts
23
10
  @faces = faces
24
11
  end
12
+ # roll the dices
25
13
  def roll
26
14
  @amounts.roll @faces
27
15
  end
16
+ # the possible min value these dices would roll out.
28
17
  def min; @amounts; end
18
+ # the possible max value these dices would roll out.
29
19
  def max; @amounts*@faces; end
30
20
  end
31
21
 
22
+ # a dice set could contain 4d6 + 2d20 and more dices.
32
23
  class DiceSet
33
24
  attr_reader :min, :max
34
25
  def initialize *args
@@ -39,15 +30,17 @@ module Ludy
39
30
  @max += i.max
40
31
  }
41
32
  end
33
+ # roll the dice set
42
34
  def roll
43
35
  result = 0
44
36
  @diceset.each { |i| result += i.roll }
45
37
  result
46
38
  end
47
- def << dice
48
- @diceset << dice
49
- @min += dice.min
50
- @max += dice.max
39
+ # put dices into this dice set
40
+ def << dices
41
+ @diceset << dices
42
+ @min += dices.min
43
+ @max += dices.max
51
44
  self
52
45
  end
53
46
  end
@@ -55,6 +48,7 @@ module Ludy
55
48
  end
56
49
 
57
50
  class Numeric
51
+ # roll dices (with amounts equal to self.to_i) with faces = ?
58
52
  def roll faces = 20
59
53
  return nil unless self > 0 && self.integer? &&
60
54
  faces > 0 && faces.integer?
@@ -62,7 +56,9 @@ class Numeric
62
56
  1.step(self){ |i| result += rand(faces) + 1 }
63
57
  result
64
58
  end
65
- def dice faces = 20
66
- Ludy::Dice.new self, faces
59
+
60
+ # create dices with faces = ?
61
+ def dices faces = 20
62
+ Ludy::Dices.new self, faces
67
63
  end
68
64
  end
@@ -0,0 +1,10 @@
1
+
2
+ require 'ludy/message_dispatcher'
3
+
4
+ module Kernel
5
+ # you can use defun for overloading(ad-hoc polymorphism),
6
+ # multi-method, pattern matching, and perhaps others?
7
+ def defun name, *args, &fun
8
+ Ludy::MessageDispatcher.create self, name, args, &fun
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+
2
+ require 'ludy/blackhole'
3
+
4
+ module Kernel
5
+ # it simply return self, see NilClass#ergo
6
+ def ergo
7
+ self
8
+ end
9
+ end
10
+
11
+ class NilClass
12
+ # return blackhole to eat any message, see Kernel#ergo
13
+ def ergo
14
+ Ludy::Blackhole.instance
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+
2
+ module Kernel
3
+ undef_method :id if RUBY_VERSION < '1.9.0'
4
+ # id returns self
5
+ def id a = nil; a.nil? ? self : a; end
6
+ end
@@ -0,0 +1,14 @@
1
+
2
+ require 'ludy/blackhole'
3
+
4
+ module Kernel
5
+ # another if variant...
6
+ def if
7
+ (yield if self).ergo
8
+ end
9
+ # another else variant...
10
+ def else
11
+ if self && !self.kind_of?(Blackhole) then self
12
+ else yield end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+
2
+ module Kernel
3
+ # for lazy people like me...
4
+ alias_method :m, :method
5
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Kernel
3
+ if RUBY_VERSION < '1.9.0'
4
+ # it would be defined if RUBY_VERSION < '1.9.0', see rdoc in ruby 1.9
5
+ def public_send msg, *args, &block
6
+ if self.respond_to? msg
7
+ self.__send__ msg, *args, &block
8
+ else
9
+ self.method_missing msg, *args, &block
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Kernel
3
+ if RUBY_VERSION < '1.9.0'
4
+ # it would be defined if RUBY_VERSION < '1.9.0', see rdoc in ruby 1.9
5
+ def define_singleton_method msg, &block
6
+ self.class.__send__ :define_method, msg, &block
7
+ end
8
+ end
9
+ # it simply alias singleton(instance) method
10
+ def alias_singleton_method new_msg, old_msg
11
+ self.class.__send__ :alias_method, new_msg, old_msg
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+
2
+ module Kernel
3
+ if RUBY_VERSION < '1.9.0'
4
+ # it would be defined if RUBY_VERSION < '1.9.0', see rdoc in ruby 1.9
5
+ def tap
6
+ yield self
7
+ self
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+
2
+ require 'ludy'
3
+ Ludy.require_all_in 'kernel'
data/lib/ludy/lazy.rb CHANGED
@@ -1,24 +1,15 @@
1
- #!/usr/bin/env ruby
2
1
 
3
- # Copyright (c) 2007, Lin Jen-Shin(a.k.a. godfat 真常)
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
2
+ require 'ludy/kernel/public_send'
3
+ require 'ludy/class/undef_all_methods'
16
4
 
17
5
  module Ludy
18
6
 
7
+ # a lazy object would be evaluated until the time it called,
8
+ # and save the result for futher use.
19
9
  class Lazy
20
- instance_methods.each{|m| undef_method m unless m =~ /^__/}
10
+ undef_all_methods
21
11
 
12
+ # supply the evaluation function through first argument or block
22
13
  def initialize func = nil, &block
23
14
  if block_given? then @func = block
24
15
  else
@@ -27,11 +18,13 @@ module Ludy
27
18
  end
28
19
  end
29
20
 
21
+ # :nodoc:
30
22
  def method_missing msg, *arg, &block
31
- (@obj ||= @func.call).__send__ msg, *arg, &block
23
+ (@obj ||= @func.call).public_send msg, *arg, &block
32
24
  end
33
25
  end
34
26
 
27
+ # provided for creating lazy object more convient
35
28
  def lazy arg = nil, &block
36
29
  Lazy.new arg, &block
37
30
  end
@@ -0,0 +1,58 @@
1
+
2
+ require 'ludy/pattern_matcher'
3
+ if RUBY_VERSION < '1.9.0'
4
+ require 'ludy/kernel/singleton_method'
5
+ end
6
+
7
+ module Ludy
8
+
9
+ class MessageDispatcher
10
+ # create a dispatcher or append arg_list to the existed dispatcher,
11
+ # see Kernel#defun
12
+ def self.create actor, msg, args, &fun
13
+ if (@patchers ||= {})[[actor, msg]].nil?
14
+ @patchers[[actor, msg]] = MessageDispatcher.new actor, msg, args, &fun
15
+ else
16
+ @patchers[[actor, msg]].listen args, &fun
17
+ end
18
+ end
19
+ # actor is the listener who listen to the message
20
+ def initialize actor, msg, args, &fun
21
+ @actor = actor
22
+ @msg = msg
23
+ @matcher = PatternMatcher.new args, &fun
24
+ define_method_in_actor
25
+ end
26
+ # open your ear and listen, and call me when you hear
27
+ def listen arg_list, &fun
28
+ @matcher << [arg_list, fun]
29
+ end
30
+
31
+ private
32
+ def define_method_in_actor
33
+ # if @actor.respond_to? @msg
34
+ # raise RuntimeError.new("#{@actor.inspect}'s method \"#{@msg}\" already defined.")
35
+ # else
36
+ matcher = @matcher
37
+ msg = @msg # make them close in the closure
38
+ define_method = @actor.kind_of?(Class) ? :define_method : :define_singleton_method
39
+
40
+ # comment off &block in lambda for ruby 1.8 compatibility
41
+ @actor.public_send define_method, msg do |*args|#, &block|
42
+ fun = matcher.first_match args
43
+ if fun.nil?
44
+ if self.respond_to? :method_missing
45
+ self.method_missing msg, *args#, &block
46
+ else
47
+ raise NoMethodError.new("#{self.inspect} doesn't respond to \"#{msg}\"")
48
+ end
49
+ else
50
+ fun.call(*args)#, &block)
51
+ end
52
+ end
53
+ # end
54
+ end
55
+ end
56
+
57
+ end # of Ludy
58
+
@@ -0,0 +1,41 @@
1
+
2
+ require 'ludy/kernel/public_send'
3
+
4
+ module Ludy
5
+ # someone who does the pattern matching thing
6
+ # see Kernel#defun
7
+ class PatternMatcher
8
+ # init for the first parameter
9
+ def initialize args, &fun; @params = [[args, fun]]; end
10
+ # find the first match of this arguments. notice,
11
+ # this is not the best match. maybe someday i could
12
+ # implement the match policy accordingly or selectable policy.
13
+ def first_match args
14
+ @params.find{ |parameters, fun|
15
+ match? parameters, args
16
+ }.ergo.last
17
+ end
18
+ # delegate all the rest message to @params array
19
+ def method_missing msg, *args, &block
20
+ if @params.respond_to? msg
21
+ @params.public_send msg, *args, &block
22
+ else
23
+ raise NoMethodError.new("PatternMatcher doesn't respond to #{msg}")
24
+ end
25
+ end
26
+
27
+ private
28
+ def match? parameters, arguments
29
+ return false unless parameters.size == arguments.size
30
+ parameters.zip(arguments).each{ |param, arg|
31
+ if param.kind_of? Class
32
+ return false unless arg.kind_of?(param)
33
+ else
34
+ return false unless arg == param
35
+ end
36
+ }
37
+ return true
38
+ end
39
+ end
40
+
41
+ end # of Ludy
@@ -0,0 +1,21 @@
1
+
2
+ class Proc
3
+ # C++ TR1 style bind
4
+ # use _#{n} for placeholders
5
+ # _1 => 1st arg
6
+ # _2 => 2nd arg
7
+ # ...and so on
8
+ def bind *args
9
+ lambda{ |*new_args|
10
+ self[*(args.map{ |arg|
11
+ if (arg.kind_of? Symbol) && arg.to_s =~ /^_(\d+)$/
12
+ # is placeholder
13
+ new_args[$1.to_i-1]
14
+ else
15
+ # is not placeholder
16
+ arg
17
+ end
18
+ } + new_args).first(self.arity)]
19
+ }
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+
2
+ class Proc
3
+ # TODO: missing traversal of chain
4
+ # create a chain of proc. whenever you call the chain,
5
+ # each proc would be called. the return value would be
6
+ # all the results saved orderly in a array.
7
+ def chain *procs, &block
8
+ procs << block if block
9
+ lambda{ |*args|
10
+ result = []
11
+ ([self] + procs).each{ |i|
12
+ result += [i[*args]].flatten
13
+ }
14
+ result
15
+ }
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+
2
+ class Proc
3
+ # function coposition
4
+ # i.e., f compose g => f of g => f (g args)
5
+ def compose *procs, &block
6
+ procs << block if block
7
+ lambda{ |*args| ([self] + procs).reverse.inject(args){ |val, fun| fun[*val] } }
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+
2
+ require 'ludy/kernel/public_send'
3
+
4
+ class Proc
5
+ def __curry__ *pre # :nodoc:
6
+ lambda{ |*post| self[*(pre + post)] }
7
+ end
8
+
9
+ # make the caller be a curried function
10
+ # lambda{|a,b,c| [a,b,c]}.curry[1][2][3]
11
+ # => [1,2,3]
12
+ def curry
13
+ class << self
14
+ alias_method :__call__, :call
15
+ def call *args, &block
16
+ if self.arity == -1
17
+ begin # let's try if arguments are ready
18
+ # is there any better way to determine this?
19
+ # it's hard to detect correct arity value when
20
+ # Symbol#to_proc happened
21
+ # e.g., :message_that_you_never_know.to_proc.arity => ?
22
+ # i'd tried put hacks in Symbol#to_proc, but it's
23
+ # difficult to implement in correct way
24
+ # i would try it again in other day
25
+ self.public_send :__call__, *args, &block
26
+ rescue ArgumentError # oops, let's curry it
27
+ method(:call).to_proc.public_send :__curry__, *args
28
+ end
29
+ elsif args.size == self.arity
30
+ self.public_send :__call__, *args, &block
31
+ else
32
+ method(:call).to_proc.public_send :__curry__, *args
33
+ end
34
+ end
35
+ alias_method :[], :call
36
+ end
37
+ self
38
+ end
39
+ end
data/lib/ludy/proc.rb ADDED
@@ -0,0 +1,3 @@
1
+
2
+ require 'ludy'
3
+ Ludy.require_all_in 'proc'
@@ -0,0 +1,10 @@
1
+
2
+ require 'ludy/symbol/to_proc'
3
+ require 'ludy/proc/curry'
4
+
5
+ class Symbol
6
+ # synonymy for to_proc.curry
7
+ def curry
8
+ to_proc.curry
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+
2
+ class Symbol
3
+ # it is like to_proc, but much more powerful
4
+ # :'*2'.to_msg[5]
5
+ # => 10
6
+ #
7
+ # :'to_s(16)'.to_msg[15]
8
+ # => "f"
9
+ def to_msg; lambda{ |*args| eval "args[0].#{self.to_s} #{args[1..-1].join ', '}" }; end
10
+ end
@@ -0,0 +1,7 @@
1
+
2
+ class Symbol
3
+ if RUBY_VERSION < '1.9.0'
4
+ # it would be defined if RUBY_VERSION < '1.9.0', see rdoc in ruby 1.9
5
+ def to_proc; lambda{ |*args| args.shift.__send__ self, *args }; end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+
2
+ require 'ludy'
3
+ Ludy.require_all_in 'symbol'