rubymurray 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|