rubymurray 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README +35 -0
- data/Rakefile +379 -0
- data/doc/currybook.rdoc +146 -0
- data/doc/jamis.rb +591 -0
- data/lib/curry.rb +291 -0
- data/setup.rb +35 -0
- data/test/tc_curry.rb +170 -0
- metadata +61 -0
data/lib/curry.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
#
|
2
|
+
# Ruby Murray - Ruby version of Perl's Sub::Curry.
|
3
|
+
# (c)2006 Ross Bamford
|
4
|
+
#
|
5
|
+
# For Ruby Quiz 64. License: Same as Ruby.
|
6
|
+
# See +Curry+ for documentation and +TestCurry+ for examples.
|
7
|
+
require 'singleton'
|
8
|
+
|
9
|
+
# *Ruby* *Murray* is a Ruby port of Perl's Sub::Curry library that allows
|
10
|
+
# curried blocks and methods to be handled in a pretty flexible way.
|
11
|
+
#
|
12
|
+
# See http://search.cpan.org/~lodin/Sub-Curry-0.8/lib/Sub/Curry.pm and
|
13
|
+
# http://search.cpan.org/~lodin/Sub-Curry-0.8/lib/Sub/Curry/Cookbook.pod
|
14
|
+
# for details on the original, and some general background.
|
15
|
+
#
|
16
|
+
# Simple usage:
|
17
|
+
#
|
18
|
+
# curry = lambda { |*args| args }.curry(Curry::HOLE, "foo", Curry::HOLE)
|
19
|
+
# curry.call(1,3) # => [1, "foo", 3]
|
20
|
+
#
|
21
|
+
# curry = "string".method(:slice).curry(Curry::HOLE, 2)
|
22
|
+
# curry.call(0) # => "st"
|
23
|
+
# curry.call(2) # => "ri"
|
24
|
+
#
|
25
|
+
# The +curry+ methods are provided by the +Curriable+ module, which simply
|
26
|
+
# provides convenient wrapping for Curry.new. There are a few variations
|
27
|
+
# between the various forms, but mostly they are equivalent and can be
|
28
|
+
# used interchangeably.
|
29
|
+
#
|
30
|
+
# See TestCurry (and click the method signatures) for more usage.
|
31
|
+
#
|
32
|
+
# Curried procs are immutable once created. If you wish to apply further
|
33
|
+
# special spice to a curried method, you may do so either using the
|
34
|
+
# instance method +new+ to create a new curried proc by applying new
|
35
|
+
# spice to the old spice, or by passing the special spices directly to
|
36
|
+
# a +call+.
|
37
|
+
#
|
38
|
+
# You can download Ruby Murray (with documentation and explanatory
|
39
|
+
# comments) from http://roscopeco.co.uk/ruby-quiz-entries/64/curry.rb
|
40
|
+
class Curry
|
41
|
+
VERSION = '0.1.2'
|
42
|
+
|
43
|
+
# A whitehole removes the blackhole, but the spice that has been put
|
44
|
+
# into the blackhole remains since blackholes themselves don't store
|
45
|
+
# anything.
|
46
|
+
WHITEHOLE = Object.new
|
47
|
+
|
48
|
+
# An antihole put in a hole makes the hole disappear. If the spice is
|
49
|
+
# 1, <HOLE>, 3, <HOLE>, 4 and 2, <ANTIHOLE>, 5 is applied then the
|
50
|
+
# result will become 1, 2, 3, 4, 5.
|
51
|
+
ANTIHOLE = Object.new
|
52
|
+
|
53
|
+
def WHITEHOLE.inspect #:nodoc:
|
54
|
+
"<WHITEHOLE>"
|
55
|
+
end
|
56
|
+
def ANTIHOLE.inspect #:nodoc:
|
57
|
+
"<ANTIHOLE>"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Just a base class for 'active' special spices (holes, really).
|
61
|
+
# SpiceArgs have a spice_arg method that must return an array.
|
62
|
+
# Maybe you can subclass up your own special spices...
|
63
|
+
#
|
64
|
+
# All the standard subclasses are singletons, the instance of
|
65
|
+
# which is assigned to the appropriate constant (HOLE, BLACKHOLE,
|
66
|
+
# etc).
|
67
|
+
class SpiceArg
|
68
|
+
def initialize(name)
|
69
|
+
@name = name
|
70
|
+
end
|
71
|
+
|
72
|
+
def spice_arg(args_remain)
|
73
|
+
raise NoMethodError, "Abstract method"
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect
|
77
|
+
"<#{@name}>"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class HoleArg < SpiceArg #:nodoc: all
|
82
|
+
include Singleton
|
83
|
+
def initialize; super("HOLE"); end
|
84
|
+
def spice_arg(args_remain)
|
85
|
+
a = args_remain.shift
|
86
|
+
if a == ANTIHOLE
|
87
|
+
[]
|
88
|
+
else
|
89
|
+
[a]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class BlackHoleArg < SpiceArg #:nodoc: all
|
95
|
+
include Singleton
|
96
|
+
def initialize; super("BLACKHOLE"); end
|
97
|
+
def spice_arg(args_remain)
|
98
|
+
if idx = args_remain.index(WHITEHOLE)
|
99
|
+
args_remain.slice!(0..idx)[0..-2]
|
100
|
+
else
|
101
|
+
args_remain.slice!(0..args_remain.length)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class AntiSpiceArg < SpiceArg #:nodoc: all
|
107
|
+
include Singleton
|
108
|
+
def initialize; super("ANTISPICE"); end
|
109
|
+
def spice_arg(args_remain)
|
110
|
+
args_remain.shift
|
111
|
+
[]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
# Special spice that calls out to a block to get it's argument.
|
117
|
+
# The block is called each time an argument is required.
|
118
|
+
# Unlike the other spices, this must be instantiated with the
|
119
|
+
# block you want lazily evaluated.
|
120
|
+
class LazySpice < Curry::SpiceArg
|
121
|
+
def initialize( &promise )
|
122
|
+
super("LAZYSPICE")
|
123
|
+
@promise = promise
|
124
|
+
end
|
125
|
+
|
126
|
+
def spice_arg( args ) # called to provide the missing argument
|
127
|
+
[@promise.call(args)]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# A hole is what it sounds like: a gap in the argument list. Later,
|
132
|
+
# when the subroutine is called the holes are filled in. So if the
|
133
|
+
# spice is 1, <HOLE>, 3 and then 2, 4 is applied to the curried proc,
|
134
|
+
# the resulting argument list is 1, 2, 3, 4.
|
135
|
+
#
|
136
|
+
# Holes can be called "scalar inserters" that default to +nil+.
|
137
|
+
HOLE = HoleArg.instance
|
138
|
+
|
139
|
+
# A blackhole is like a hole for lists that never gets full. There's
|
140
|
+
# an imaginary untouchable blackhole at the end of the spice. The
|
141
|
+
# blackhole thusly inserts the new spice before itself. The blackhole
|
142
|
+
# never gets full because nothing is ever stored in a blackhole as it
|
143
|
+
# isn't a hole really...
|
144
|
+
#
|
145
|
+
# Blackholes are used to move the point of insertion from the end to
|
146
|
+
# somewhere else, so you can curry the end of the argument list.
|
147
|
+
#
|
148
|
+
# Blackholes can be called "list inserters" that defaults to the
|
149
|
+
# empty list.
|
150
|
+
BLACKHOLE = BlackHoleArg.instance
|
151
|
+
|
152
|
+
# An antispice is like a hole except that when it's filled it disappears.
|
153
|
+
# It's like a combination of a hole and an antihole. If the spice is
|
154
|
+
# 1, <ANTISPICE>, 3 and 2, 4 is applied, then the result will become
|
155
|
+
# 1, 3, 4.
|
156
|
+
ANTISPICE = AntiSpiceArg.instance
|
157
|
+
|
158
|
+
# The raw spice held by this curried proc. May contain special
|
159
|
+
# spices.
|
160
|
+
attr_reader :spice
|
161
|
+
|
162
|
+
# The block (+Proc+) for which arguments are curried.
|
163
|
+
attr_reader :uncurried
|
164
|
+
|
165
|
+
# call-seq:
|
166
|
+
# Curry.new(*spice) { |*args| ... } -> #<Curry...>
|
167
|
+
# Curry.new(callable, *spice) -> #<Curry...>
|
168
|
+
#
|
169
|
+
# Create a new curry with the specified spice and
|
170
|
+
# block or callable object. The second form requires only
|
171
|
+
# that the first argument respond_to?(:call)
|
172
|
+
def initialize(*spice, &block)
|
173
|
+
block = block || (spice.shift if spice.first.respond_to?(:call))
|
174
|
+
raise ArgumentError, "No block supplied" unless block
|
175
|
+
@spice, @uncurried = spice, block
|
176
|
+
end
|
177
|
+
|
178
|
+
# call-seq:
|
179
|
+
# some_curry.call(*args) { |b| ... } -> result
|
180
|
+
# some_curry[*args] { |b| ... } -> result
|
181
|
+
#
|
182
|
+
# Call the curried proc, passing the supplied arguments.
|
183
|
+
# This method resolves all special spices and passes the
|
184
|
+
# resolved arguments to the block. If a block is passed to
|
185
|
+
# +call+ it will be passed on as a block argument to the curried
|
186
|
+
# method *only* if this curry was created from a +Method+. Curries
|
187
|
+
# created from a block passed to Curry.new (or from Proc#curry)
|
188
|
+
# cannot have block arguments passed to them.
|
189
|
+
#
|
190
|
+
# Unlike Perl's Sub::Curry implementation, special spices *may*
|
191
|
+
# be passed in the call arguments, and are applied as with new.
|
192
|
+
# This means that whiteholes and antiholes can be passed in to
|
193
|
+
# make single-call modifications to the argument spice.
|
194
|
+
# This probably isn't as great on performance but it's more fun.
|
195
|
+
#
|
196
|
+
# see also +new+
|
197
|
+
def call(*args, &blk)
|
198
|
+
@uncurried.call(*call_spice(args), &blk)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Had some trouble with aliases and doc so it's done this way
|
202
|
+
def [](*args) # :nodoc:
|
203
|
+
call(*args)
|
204
|
+
end
|
205
|
+
|
206
|
+
# call-seq:
|
207
|
+
# some_curry.new(*spice) -> #<Curry...>
|
208
|
+
#
|
209
|
+
# Create a new curried proc by applying the supplied spice to the
|
210
|
+
# current spice in this curried proc. This does not simply append
|
211
|
+
# the spices - Arguments in the supplied spice are applied to the
|
212
|
+
# curried spice arguments, with black/white hole and antiholes
|
213
|
+
# operating as documented.
|
214
|
+
#
|
215
|
+
# See also +call+.
|
216
|
+
def new(*spice)
|
217
|
+
Curry.new(*merge_spice(spice), &@uncurried)
|
218
|
+
end
|
219
|
+
|
220
|
+
# call-seq:
|
221
|
+
# some_curry.to_proc -> #<Proc...>
|
222
|
+
#
|
223
|
+
# Convert to a proc
|
224
|
+
def to_proc
|
225
|
+
# since we're immutable we can keep this
|
226
|
+
@extern_proc ||= method(:call).to_proc
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
# Handles new curry merges
|
232
|
+
def merge_spice(spice)
|
233
|
+
largs = spice.dup
|
234
|
+
|
235
|
+
res = @spice.inject([]) do |res, sparg|
|
236
|
+
# If we've used all the new spice, don't
|
237
|
+
# touch any more of the old spice.
|
238
|
+
if sparg.is_a?(SpiceArg) && !largs.empty?
|
239
|
+
res + sparg.spice_arg(largs)
|
240
|
+
else
|
241
|
+
res << sparg
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
res + largs
|
246
|
+
end
|
247
|
+
|
248
|
+
# Merges, then resolves all special spices
|
249
|
+
def call_spice(args)
|
250
|
+
sp = merge_spice(args)
|
251
|
+
sp.inject([]) do |ary, a|
|
252
|
+
if a.is_a? SpiceArg
|
253
|
+
ary + a.spice_arg([])
|
254
|
+
else
|
255
|
+
ary << a
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Provided for Perl compatibility
|
262
|
+
module Sub #:nodoc: all
|
263
|
+
Curry = ::Curry
|
264
|
+
end
|
265
|
+
|
266
|
+
# Provides a +curry+ method that can be mixed in to classes that make
|
267
|
+
# sense with currying. Depends on +self+ implementing a +call+ method.
|
268
|
+
module Curriable
|
269
|
+
# call-seq:
|
270
|
+
# curriable.curry(*spice) -> #<Curry...>
|
271
|
+
#
|
272
|
+
# Create a new curried proc from this curriable, using the supplied
|
273
|
+
# spice.
|
274
|
+
def curry(*spice)
|
275
|
+
Curry.new(self, *spice)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
unless defined? NO_CORE_CURRY
|
280
|
+
NO_CORE_CURRY = (ENV['NO_CORE_CURRY'] || $SAFE > 3)
|
281
|
+
end
|
282
|
+
|
283
|
+
unless NO_CORE_CURRY
|
284
|
+
class Proc
|
285
|
+
include Curriable
|
286
|
+
end
|
287
|
+
|
288
|
+
class Method
|
289
|
+
include Curriable
|
290
|
+
end
|
291
|
+
end
|
data/setup.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'find'
|
3
|
+
require 'ftools'
|
4
|
+
|
5
|
+
include Config
|
6
|
+
|
7
|
+
$ruby = CONFIG['ruby_install_name']
|
8
|
+
$sitedir = CONFIG["sitelibdir"]
|
9
|
+
unless $sitedir
|
10
|
+
version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
11
|
+
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
12
|
+
$sitedir = $:.find {|x| x =~ /site_ruby/}
|
13
|
+
if !$sitedir
|
14
|
+
$sitedir = File.join($libdir, "site_ruby")
|
15
|
+
elsif $sitedir !~ Regexp.quote(version)
|
16
|
+
$sitedir = File.join($sitedir, version)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
if (destdir = ENV['DESTDIR'])
|
21
|
+
$sitedir = destdir + $sitedir
|
22
|
+
File::makedirs($sitedir)
|
23
|
+
end
|
24
|
+
|
25
|
+
# The library files
|
26
|
+
|
27
|
+
files = Dir.chdir('lib') { Dir['**/*.rb'] }
|
28
|
+
for fn in files
|
29
|
+
fn_dir = File.dirname(fn)
|
30
|
+
target_dir = File.join($sitedir, fn_dir)
|
31
|
+
if ! File.exist?(target_dir)
|
32
|
+
File.makedirs(target_dir)
|
33
|
+
end
|
34
|
+
File::install(File.join('lib', fn), File.join($sitedir, fn), 0644, true)
|
35
|
+
end
|
data/test/tc_curry.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../lib/curry"
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# Included for example purposes. Click method signatures to open code.
|
5
|
+
class TestCurry < Test::Unit::TestCase
|
6
|
+
def test_fixed_args
|
7
|
+
curry = Curry.new(1,2,3) { |a,b,c| [a,b,c] }
|
8
|
+
assert_equal [1,2,3], curry.call
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_fixed_array_args
|
12
|
+
curry = Curry.new([1],[2,3]) { |*args| args }
|
13
|
+
assert_equal [[1],[2,3]], curry.call
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_hole
|
17
|
+
curry = Curry.new(1,Curry::HOLE,3) { |a,b,c| [a,b,c] }
|
18
|
+
assert_equal [1,nil,3], curry.call
|
19
|
+
assert_equal [1,2,3], curry.call(2)
|
20
|
+
|
21
|
+
curry = Curry.new(1,Curry::HOLE,3,Curry::HOLE) { |*args| args }
|
22
|
+
assert_equal [1,2,3,4], curry.call(2,4)
|
23
|
+
|
24
|
+
# Make sure extra args go to the end
|
25
|
+
assert_equal [1,2,3,4,5,6], curry.call(2,4,5,6)
|
26
|
+
|
27
|
+
# Make sure array args are handled right.
|
28
|
+
# This tests both explicitly holed arrays
|
29
|
+
# and extra arrays at the end
|
30
|
+
assert_equal [1,[2,'two'],3,[4,0],[[14]]],
|
31
|
+
curry.call([2,'two'],[4,0],[[14]])
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_antihole
|
36
|
+
curry = Curry.new(1,Curry::HOLE,3) { |*args| args }
|
37
|
+
assert_equal [1,3], curry.call(Curry::ANTIHOLE)
|
38
|
+
|
39
|
+
curry = Curry.new(1,Curry::HOLE,3,Curry::HOLE,4) { |*args| args }
|
40
|
+
assert_equal [1,2,3,4,5], curry.call(2,Curry::ANTIHOLE,5)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_antispice
|
44
|
+
curry = Curry.new(1,Curry::ANTISPICE,3,Curry::HOLE,4) { |*args| args }
|
45
|
+
assert_equal [1,3,4,5], curry.call(2,Curry::ANTIHOLE,5)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_black_hole
|
49
|
+
# There's an implicit black-hole at the end
|
50
|
+
# so this should just act as normal.
|
51
|
+
curry = Curry.new(1,Curry::BLACKHOLE) { |*args| args }
|
52
|
+
assert_equal [1,2,3], curry.call(2,3)
|
53
|
+
|
54
|
+
curry = Curry.new(1,Curry::BLACKHOLE,3,4) { |*args| args }
|
55
|
+
assert_equal [1,2,10,3,4], curry.call(2,10)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_white_hole
|
59
|
+
# spice gives 1
|
60
|
+
# blackhole gives 2
|
61
|
+
# blackhole finished by whitehole
|
62
|
+
# spice gives 3
|
63
|
+
# hole matches the 7
|
64
|
+
# spice gives 5
|
65
|
+
# remaining args give 8 and 9
|
66
|
+
curry = Curry.new(1,Curry::BLACKHOLE,3,Curry::HOLE,5) { |*args| args }
|
67
|
+
assert_equal [1,2,3,7,5,8,9], curry.call(2,Curry::WHITEHOLE,7,8,9)
|
68
|
+
# spice gives 1
|
69
|
+
# blackhole gives 10 and 20
|
70
|
+
# whitehole ends blackhole
|
71
|
+
# spice gives 3
|
72
|
+
# hole matches nothing, gives nil
|
73
|
+
# spice gives 5
|
74
|
+
assert_equal [1,10,20,3,nil,5], curry.call(10,20,Curry::WHITEHOLE)
|
75
|
+
|
76
|
+
# spice gives 1
|
77
|
+
# blackhole gives 10, 20, 25
|
78
|
+
# whitehole kills black
|
79
|
+
# spice gives 3
|
80
|
+
# hole matches 4
|
81
|
+
# spice gives 5
|
82
|
+
assert_equal [1,10,20,25,3,4,5], curry.call(10,20,25,Curry::WHITEHOLE,4)
|
83
|
+
|
84
|
+
# Multiple blackholes.
|
85
|
+
#
|
86
|
+
# spice gives 1
|
87
|
+
# blackhole 1 gives 10, 20, 25
|
88
|
+
# whitehole, blackhole 1 negated
|
89
|
+
# spice gives 6
|
90
|
+
# hole matches 40
|
91
|
+
# spice gives 3, 4
|
92
|
+
# blackhole 2 gives 50, 60
|
93
|
+
# spice gives 5
|
94
|
+
curry = Curry.new(1,Curry::BLACKHOLE,6,Curry::HOLE,3,4,Curry::BLACKHOLE,5) { |*args| args }
|
95
|
+
assert_equal [1,10,20,25,6,40,3,4,50,60,5], curry.call(10,20,25,Curry::WHITEHOLE,40,50,60)
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_curry_from_curry
|
99
|
+
curry = Curry.new(1,Curry::BLACKHOLE,6,Curry::HOLE,3,4,Curry::BLACKHOLE,5) { |*args| args }
|
100
|
+
curry = curry.new(Curry::HOLE,Curry::WHITEHOLE,8,9,10)
|
101
|
+
assert_equal [1,Curry::HOLE,6,8,3,4,9,10,5], curry.spice
|
102
|
+
|
103
|
+
# How to add after that hole?
|
104
|
+
curry = curry.new(Curry::HOLE, 4, Curry::BLACKHOLE)
|
105
|
+
assert_equal [1,Curry::HOLE,6,8,3,4,9,10,5,4,Curry::BLACKHOLE], curry.spice
|
106
|
+
|
107
|
+
curry = curry.new(Curry::ANTIHOLE)
|
108
|
+
assert_equal [1,6,8,3,4,9,10,5,4,Curry::BLACKHOLE], curry.spice
|
109
|
+
|
110
|
+
# how to add after that blackhole?
|
111
|
+
curry = curry.new(3,Curry::BLACKHOLE,Curry::WHITEHOLE,0)
|
112
|
+
assert_equal [1,6,8,3,4,9,10,5,4,3,Curry::BLACKHOLE,0], curry.spice
|
113
|
+
|
114
|
+
assert_equal [1,6,8,3,4,9,10,5,4,3,2,1,0], curry.call(2,1)
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_cant_block_to_curried_block
|
118
|
+
a = Curry.new(1,2) { |*args| args }
|
119
|
+
|
120
|
+
# block is lost
|
121
|
+
assert_equal [1,2,3], a.call(3) { |b| }
|
122
|
+
end
|
123
|
+
|
124
|
+
if (NO_CORE_CURRY if defined? NO_CORE_CURRY)
|
125
|
+
warn "Skipping core extension tests"
|
126
|
+
else
|
127
|
+
def test_curry_proc
|
128
|
+
a = [1,2,3,4,5]
|
129
|
+
c = Curry.new(*a) { |*args| args * 2 }
|
130
|
+
assert_equal [1,2,3,4,5,1,2,3,4,5], c.call
|
131
|
+
|
132
|
+
c = lambda { |*args| args * 2 }.curry(*a)
|
133
|
+
assert_equal [1,2,3,4,5,1,2,3,4,5], c.call
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_curry_method
|
137
|
+
a = [1,2,3,4,5]
|
138
|
+
injsum = Curry.new(a.method(:inject),0)
|
139
|
+
assert_equal 15, injsum.call { |s,i| s + i }
|
140
|
+
|
141
|
+
injsum = a.method(:inject).curry(0)
|
142
|
+
assert_equal 15, injsum.call { |s,i| s + i }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_curry_to_proc
|
147
|
+
curry = Curry.new(Curry::HOLE, Curry::HOLE, 'thou') { |ary,i,msg| ary << "#{i} #{msg}" }
|
148
|
+
assert_equal ["1 thou", "2 thou", "3 thou"], [1,2,3].inject([],&curry)
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_alt_bits
|
152
|
+
curry = Curry.new(Curry::BLACKHOLE, 'too', 'true') { |one, two, *rest| [one, two, rest] }
|
153
|
+
assert_equal [1,2,['too','true']], curry[1,2]
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_perlish
|
157
|
+
s = "str"
|
158
|
+
s = Sub::Curry.new(s.method(:+), "ing")
|
159
|
+
assert_equal "string", s.call
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_lazyspice_at_end_regression
|
163
|
+
a = [1,3,5]
|
164
|
+
b = [2,4,6]
|
165
|
+
l = lambda { |ary,aa,ba| ary + [aa,ba] }.curry(Curry::HOLE,Curry::HOLE,Curry::LazySpice.new { b.shift })
|
166
|
+
# bug behaviour: assert_equal [1,nil,3,nil,5,nil]
|
167
|
+
assert_equal [1,2,3,4,5,6], a.inject([], &l)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|