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/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c)2006 Ross Bamford. All rights reserved.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
20
|
+
|
data/README
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
= Ruby Murray - Ruby version of Perl's Sub::Curry.
|
2
|
+
== (c)2006 Ross Bamford
|
3
|
+
|
4
|
+
Originally for Ruby Quiz 64. License: see +LICENSE+.
|
5
|
+
See +Curry+ for documentation and the currybook for examples.
|
6
|
+
|
7
|
+
You can download Ruby Murray from the Project Homepage on Rubyforge.
|
8
|
+
|
9
|
+
== Install
|
10
|
+
|
11
|
+
=== As a Gem:
|
12
|
+
|
13
|
+
gem install rubymurray
|
14
|
+
|
15
|
+
=== Manual (site-ruby)
|
16
|
+
|
17
|
+
ruby setup.rb
|
18
|
+
|
19
|
+
or
|
20
|
+
|
21
|
+
rake install
|
22
|
+
|
23
|
+
== Usage
|
24
|
+
|
25
|
+
See currybook.rdoc for examples and ideas. See also the unit-tests
|
26
|
+
included with the distribution.
|
27
|
+
|
28
|
+
== Changelog
|
29
|
+
|
30
|
+
0.1.0 - 2005/01/27 - First version (Ruby Quiz #64)
|
31
|
+
0.1.2 - 2005/02/02 - Changed call_spice behaviour when processing
|
32
|
+
leftover SpiceArgs, arg is now called with
|
33
|
+
no remaining args.
|
34
|
+
|
35
|
+
Released on RubyForge.
|
data/Rakefile
ADDED
@@ -0,0 +1,379 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
SRC_RB = FileList['lib/**/*.rb']
|
6
|
+
|
7
|
+
# Determine the current version of the software
|
8
|
+
if File.read('lib/curry.rb') =~ /\s*VERSION\s*=\s*['"](\d.+)['"]/
|
9
|
+
CURRENT_VERSION = $1
|
10
|
+
else
|
11
|
+
CURRENT_VERSION = "0.0.0"
|
12
|
+
end
|
13
|
+
|
14
|
+
if ENV['REL']
|
15
|
+
PKG_VERSION = ENV['REL']
|
16
|
+
else
|
17
|
+
PKG_VERSION = CURRENT_VERSION
|
18
|
+
end
|
19
|
+
|
20
|
+
# The default task is run if rake is given no explicit arguments.
|
21
|
+
|
22
|
+
desc "Default Task (All tests)"
|
23
|
+
task :default => :alltests
|
24
|
+
|
25
|
+
# Test Tasks ---------------------------------------------------------
|
26
|
+
|
27
|
+
task :ta => :alltests
|
28
|
+
task :tu => :unittests
|
29
|
+
task :test => :unittests
|
30
|
+
|
31
|
+
Rake::TestTask.new(:alltests) do |t|
|
32
|
+
t.test_files = FileList[
|
33
|
+
'test/tc*.rb',
|
34
|
+
'test/contrib/tc*.rb',
|
35
|
+
'test/fun*.rb'
|
36
|
+
]
|
37
|
+
t.warning = true
|
38
|
+
t.verbose = true
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::TestTask.new(:unittests) do |t|
|
42
|
+
t.test_files = FileList['test/tc_*.rb']
|
43
|
+
t.warning = true
|
44
|
+
t.verbose = false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Install using the standard setup.rb script.
|
48
|
+
desc "Install to systemwide site-ruby directory"
|
49
|
+
task :install do
|
50
|
+
ruby "setup.rb"
|
51
|
+
end
|
52
|
+
|
53
|
+
task :upload => :doc do
|
54
|
+
Dir.chdir('doc') do
|
55
|
+
Rake::FtpUploader.connect('/htdocs/roscopeco/code/ruby-quiz-entries/64','roscopeco.co.uk','synergix','daytona') do |ftp|
|
56
|
+
ftp.instance_eval { @ftp.passive = true }
|
57
|
+
ftp.verbose = true
|
58
|
+
ftp.upload_files('**/*')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Website / Doc tasks ------------------------------------------------
|
64
|
+
|
65
|
+
desc "Build the Rdoc documentation"
|
66
|
+
rd = Rake::RDocTask.new("doc") { |rdoc|
|
67
|
+
rdoc.rdoc_dir = 'html'
|
68
|
+
rdoc.template = 'doc/jamis.rb'
|
69
|
+
rdoc.title = "Ruby Murray"
|
70
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README'
|
71
|
+
rdoc.rdoc_files.include('README', 'LICENSE')
|
72
|
+
rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
|
73
|
+
rdoc.rdoc_files.exclude(/\bcontrib\b/)
|
74
|
+
}
|
75
|
+
|
76
|
+
desc "Publish the documentation and web site"
|
77
|
+
task :doc_upload => [ :doc ] do
|
78
|
+
if acct = ENV['RUBYFORGE_ACCT']
|
79
|
+
require 'rake/contrib/sshpublisher'
|
80
|
+
Rake::SshDirPublisher.new(
|
81
|
+
"#{acct}@rubyforge.org",
|
82
|
+
"/var/www/gforge-projects/rote",
|
83
|
+
"html"
|
84
|
+
).upload
|
85
|
+
else
|
86
|
+
$stderr << "Skipping documentation upload - Need to set RUBYFORGE_ACCT to your rubyforge.org user name"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# ====================================================================
|
91
|
+
# Create a task that will package the software into distributable
|
92
|
+
# tar, zip and gem files.
|
93
|
+
|
94
|
+
PKG_FILES = FileList[
|
95
|
+
'setup.rb',
|
96
|
+
'[A-Z]*',
|
97
|
+
'lib/**/*.rb',
|
98
|
+
'test/**/*',
|
99
|
+
'doc/**/*'
|
100
|
+
]
|
101
|
+
|
102
|
+
if ! defined?(Gem)
|
103
|
+
puts "Package Target requires RubyGEMs"
|
104
|
+
else
|
105
|
+
spec = Gem::Specification.new do |s|
|
106
|
+
|
107
|
+
#### Basic information.
|
108
|
+
|
109
|
+
s.name = 'rubymurray'
|
110
|
+
s.version = PKG_VERSION
|
111
|
+
s.summary = "A Ruby port of Perl's Sub::Curry"
|
112
|
+
s.description = <<-EOF
|
113
|
+
Ruby Murray is a Ruby port of Perl's Sub::Curry,
|
114
|
+
originally written for Ruby Quiz #64 (Port a library).
|
115
|
+
EOF
|
116
|
+
|
117
|
+
#### Which files are to be included in this gem?
|
118
|
+
|
119
|
+
s.files = PKG_FILES.to_a
|
120
|
+
|
121
|
+
#### Load-time details
|
122
|
+
s.require_path = 'lib' # Use these for libraries.
|
123
|
+
|
124
|
+
#### Documentation and testing.
|
125
|
+
s.has_rdoc = true
|
126
|
+
s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
|
127
|
+
s.rdoc_options <<
|
128
|
+
'--title' << 'Ruby Murray' <<
|
129
|
+
'--main' << 'README' <<
|
130
|
+
'--line-numbers' <<
|
131
|
+
'--inline-source' <<
|
132
|
+
'--template' << 'doc/jamis.rb'
|
133
|
+
'-o' << 'html'
|
134
|
+
|
135
|
+
s.test_files = Dir.glob('test/gem_*.rb')
|
136
|
+
|
137
|
+
#### Author and project details.
|
138
|
+
|
139
|
+
s.author = "Ross Bamford"
|
140
|
+
s.email = "ross@roscopeco.co.uk"
|
141
|
+
s.homepage = "http://rubymurray.rubyforge.org"
|
142
|
+
s.rubyforge_project = "rubymurray"
|
143
|
+
end
|
144
|
+
|
145
|
+
# Quick fix for Ruby 1.8.3 / YAML bug
|
146
|
+
if (RUBY_VERSION == '1.8.3')
|
147
|
+
def spec.to_yaml
|
148
|
+
out = super
|
149
|
+
out = '--- ' + out unless out =~ /^---/
|
150
|
+
out
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
package_task = Rake::GemPackageTask.new(spec) do |pkg|
|
155
|
+
pkg.need_zip = true
|
156
|
+
pkg.need_tar_gz = true
|
157
|
+
pkg.package_dir = 'pkg'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Misc tasks =========================================================
|
162
|
+
|
163
|
+
def count_lines(filename)
|
164
|
+
lines = 0
|
165
|
+
codelines = 0
|
166
|
+
open(filename) { |f|
|
167
|
+
f.each do |line|
|
168
|
+
lines += 1
|
169
|
+
next if line =~ /^\s*$/
|
170
|
+
next if line =~ /^\s*#/
|
171
|
+
codelines += 1
|
172
|
+
end
|
173
|
+
}
|
174
|
+
[lines, codelines]
|
175
|
+
end
|
176
|
+
|
177
|
+
def show_line(msg, lines, loc)
|
178
|
+
printf "%6s %6s %s\n", lines.to_s, loc.to_s, msg
|
179
|
+
end
|
180
|
+
|
181
|
+
desc "Count total lines in source"
|
182
|
+
task :lines do
|
183
|
+
total_lines = 0
|
184
|
+
total_code = 0
|
185
|
+
show_line("File Name", "LINES", "LOC")
|
186
|
+
SRC_RB.each do |fn|
|
187
|
+
lines, codelines = count_lines(fn)
|
188
|
+
show_line(fn, lines, codelines)
|
189
|
+
total_lines += lines
|
190
|
+
total_code += codelines
|
191
|
+
end
|
192
|
+
show_line("TOTAL", total_lines, total_code)
|
193
|
+
end
|
194
|
+
|
195
|
+
ARCHIVEDIR = '/mnt/usb'
|
196
|
+
|
197
|
+
task :archive => [:package] do
|
198
|
+
cp FileList["pkg/*.tar.gz", "pkg/*.zip", "pkg/*.gem"], ARCHIVEDIR
|
199
|
+
end
|
200
|
+
|
201
|
+
# Support Tasks ------------------------------------------------------
|
202
|
+
|
203
|
+
desc "Look for TODO and FIXME tags in the code"
|
204
|
+
task :todo do
|
205
|
+
FileList['**/*.rb'].egrep /#.*(FIXME|TODO|TBD)/
|
206
|
+
end
|
207
|
+
|
208
|
+
desc "Look for Debugging print lines"
|
209
|
+
task :dbg do
|
210
|
+
FileList['**/*.rb'].egrep /\bDBG|\bbreakpoint\b/
|
211
|
+
end
|
212
|
+
|
213
|
+
desc "List all ruby files"
|
214
|
+
task :rubyfiles do
|
215
|
+
puts Dir['**/*.rb'].reject { |fn| fn =~ /^pkg/ }
|
216
|
+
puts Dir['bin/*'].reject { |fn| fn =~ /CVS|(~$)|(\.rb$)/ }
|
217
|
+
end
|
218
|
+
|
219
|
+
desc "Show deprecation notes"
|
220
|
+
task :deprecated do
|
221
|
+
Dir['lib/**/*.r?'].each do |fn|
|
222
|
+
File.open(fn) do |f|
|
223
|
+
[*f].each_with_index do |line,i|
|
224
|
+
if line =~ /#(.*)vv([0-9\.]+)(?:[\s\t]*)v-([0-9\.]+)/
|
225
|
+
cmnt = $~[1].strip
|
226
|
+
cmnt = '<No comment>' if (cmnt.nil? or cmnt.empty?)
|
227
|
+
printf "%s:%d\n%-60s %5s %5s\n\n", fn, i+1, cmnt, $~[2].strip, $~[3].strip
|
228
|
+
end #if splits okay
|
229
|
+
end #each_w_idx
|
230
|
+
end #fopen
|
231
|
+
end #dir
|
232
|
+
end
|
233
|
+
|
234
|
+
desc "Find features deprecated at VER"
|
235
|
+
task :deprecated_by do
|
236
|
+
fail "\nYou must specify the version to check (VER=x.y.z)\n\n" unless ver = ENV['VER']
|
237
|
+
Dir['lib/**/*.r?'].each do |fn|
|
238
|
+
File.open(fn) do |f|
|
239
|
+
[*f].each_with_index do |line,i|
|
240
|
+
if line =~ /vv#{ver}/
|
241
|
+
if line =~ /#(.*)vv([0-9\.]+)(?:[\s\t]*)v-([0-9\.]+)/
|
242
|
+
cmnt = $~[1].strip
|
243
|
+
cmnt = '<No comment>' if (cmnt.nil? or cmnt.empty?)
|
244
|
+
printf "%s:%d\n%-60s %5s %5s\n\n", fn, i+1, cmnt, $~[2].strip, $~[3].strip
|
245
|
+
end #if splits okay
|
246
|
+
end #if line is dep remove
|
247
|
+
end #each_w_idx
|
248
|
+
end #fopen
|
249
|
+
end #dir
|
250
|
+
end
|
251
|
+
|
252
|
+
desc "Find deprecated features to be removed by VER"
|
253
|
+
task :deprecated_due do
|
254
|
+
fail "\nYou must specify the version to check (VER=x.y.z)\n\n" unless ver = ENV['VER']
|
255
|
+
Dir['lib/**/*.r?'].each do |fn|
|
256
|
+
File.open(fn) do |f|
|
257
|
+
[*f].each_with_index do |line,i|
|
258
|
+
if line =~ /v-#{ver}/
|
259
|
+
if line =~ /#(.*)vv([0-9\.]+)(?:[\s\t]*)v-([0-9\.]+)/
|
260
|
+
cmnt = $~[1].strip
|
261
|
+
cmnt = '<No comment>' if (cmnt.nil? or cmnt.empty?)
|
262
|
+
printf "%s:%d\n%-60s %5s %5s\n\n", fn, i+1, cmnt, $~[2].strip, $~[3].strip
|
263
|
+
end #if splits okay
|
264
|
+
end #if line is dep remove
|
265
|
+
end #each_w_idx
|
266
|
+
end #fopen
|
267
|
+
end #dir
|
268
|
+
end
|
269
|
+
|
270
|
+
# --------------------------------------------------------------------
|
271
|
+
# Creating a release
|
272
|
+
|
273
|
+
def announce(msg='')
|
274
|
+
STDERR.puts msg
|
275
|
+
end
|
276
|
+
|
277
|
+
desc "Make a new release"
|
278
|
+
task :release => [
|
279
|
+
:prerelease,
|
280
|
+
:clobber,
|
281
|
+
:alltests,
|
282
|
+
:update_version,
|
283
|
+
:package,
|
284
|
+
:tag,
|
285
|
+
:doc_upload] do
|
286
|
+
|
287
|
+
announce
|
288
|
+
announce "**************************************************************"
|
289
|
+
announce "* Release #{PKG_VERSION} Complete."
|
290
|
+
announce "* Packages ready to upload."
|
291
|
+
announce "**************************************************************"
|
292
|
+
announce
|
293
|
+
end
|
294
|
+
|
295
|
+
# Validate that everything is ready to go for a release.
|
296
|
+
task :prerelease do
|
297
|
+
announce
|
298
|
+
announce "**************************************************************"
|
299
|
+
announce "* Making RubyGem Release #{PKG_VERSION}"
|
300
|
+
announce "* (current version #{CURRENT_VERSION})"
|
301
|
+
announce "**************************************************************"
|
302
|
+
announce
|
303
|
+
|
304
|
+
# Is a release number supplied?
|
305
|
+
unless ENV['REL']
|
306
|
+
fail "Usage: rake release REL=x.y.z [REUSE=tag_suffix]"
|
307
|
+
end
|
308
|
+
|
309
|
+
# Is the release different than the current release.
|
310
|
+
# (or is REUSE set?)
|
311
|
+
if PKG_VERSION == CURRENT_VERSION && ! ENV['REUSE']
|
312
|
+
fail "Current version is #{PKG_VERSION}, must specify REUSE=tag_suffix to reuse version"
|
313
|
+
end
|
314
|
+
|
315
|
+
# Are all source files checked in?
|
316
|
+
if ENV['RELTEST']
|
317
|
+
announce "Release Task Testing, skipping checked-in file test"
|
318
|
+
else
|
319
|
+
announce "Checking for unchecked-in files..."
|
320
|
+
data = `svn status`
|
321
|
+
unless data =~ /^$/
|
322
|
+
fail "SVN status is not clean ... do you have unchecked-in files?"
|
323
|
+
end
|
324
|
+
announce "No outstanding checkins found ... OK"
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
task :update_version => [:prerelease] do
|
329
|
+
if PKG_VERSION == CURRENT_VERSION
|
330
|
+
announce "No version change ... skipping version update"
|
331
|
+
else
|
332
|
+
announce "Updating Curry version to #{PKG_VERSION}"
|
333
|
+
open("lib/curry.rb") do |rakein|
|
334
|
+
open("lib/curry.rb.new", "w") do |rakeout|
|
335
|
+
rakein.each do |line|
|
336
|
+
if line =~ /^\s*VERSION\s*=\s*/
|
337
|
+
rakeout.puts " VERSION = '#{PKG_VERSION}'"
|
338
|
+
else
|
339
|
+
rakeout.puts line
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
mv "lib/curry.rb.new", "lib/curry.rb"
|
345
|
+
if ENV['RELTEST']
|
346
|
+
announce "Release Task Testing, skipping commiting of new version"
|
347
|
+
else
|
348
|
+
sh %{svn commit -m "Updated to version #{PKG_VERSION}" lib/curry.rb}
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
desc "Create a new SVN tag with the latest release number (REL=x.y.z)"
|
354
|
+
task :tag => [:prerelease] do
|
355
|
+
reltag = "REL_#{PKG_VERSION.gsub(/\./, '_')}"
|
356
|
+
reltag << ENV['REUSE'].gsub(/\./, '_') if ENV['REUSE']
|
357
|
+
announce "Tagging CVS with [#{reltag}]"
|
358
|
+
if ENV['RELTEST']
|
359
|
+
announce "Release Task Testing, skipping SVN tagging"
|
360
|
+
else
|
361
|
+
# need to get current base URL
|
362
|
+
s = `svn info`
|
363
|
+
if s =~ /URL:\s*([^\n]*)\n/
|
364
|
+
svnroot = $1
|
365
|
+
if svnroot =~ /^(.*)\/trunk/
|
366
|
+
svnbase = $1
|
367
|
+
sh %{svn cp #{svnroot} #{svnbase}/tags/#{reltag} -m "Release #{PKG_VERSION}"}
|
368
|
+
else
|
369
|
+
fail "Please merge to trunk before making a release"
|
370
|
+
end
|
371
|
+
else
|
372
|
+
fail "Unable to determine repository URL from 'svn info' - is this a working copy?"
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Require experimental XForge/Metaproject support.
|
378
|
+
# load 'xforge.rf' if File.exist?('xforge.rf')
|
379
|
+
|
data/doc/currybook.rdoc
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
== The Ruby Murray Cookbook - Recipes for Ruby's Sub::Curry port.
|
2
|
+
|
3
|
+
This is a translation of the Sub::Curry cookbook to Ruby Murray.
|
4
|
+
See the original at:
|
5
|
+
|
6
|
+
* http://search.cpan.org/~lodin/Sub-Curry-0.8/lib/Sub/Curry/Cookbook.pod
|
7
|
+
|
8
|
+
(c)2006 Ross Bamford. Same license as Ruby.
|
9
|
+
|
10
|
+
In case you're wondering, see http://en.wikipedia.org/wiki/Ruby_Murray.
|
11
|
+
|
12
|
+
=== Right currying
|
13
|
+
|
14
|
+
Special spices make rcurry unnecessary. You can add trailing
|
15
|
+
spice using blackholes.
|
16
|
+
|
17
|
+
c = lambda { |a,b,c| (a + b) / c }.curry(Curry::BLACKHOLE, 2)
|
18
|
+
c.call(5,3)
|
19
|
+
# => 4
|
20
|
+
|
21
|
+
=== Convert func -> method / method -> func / Curry a method
|
22
|
+
|
23
|
+
These are not really applicable to Ruby - the original was working around
|
24
|
+
Perl's broken implementation. But I guess something like:
|
25
|
+
|
26
|
+
def send_func(obj, msg, *args)
|
27
|
+
obj.send(msg,*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
c = method(:send_func).curry("object")
|
31
|
+
|
32
|
+
c.call(:length)
|
33
|
+
# => 6
|
34
|
+
|
35
|
+
c.call(:+, "ive C")
|
36
|
+
# => "objective C"
|
37
|
+
|
38
|
+
And (more useful?):
|
39
|
+
|
40
|
+
c = "string".method(:slice).curry(Curry::HOLE,2)
|
41
|
+
c.call(0)
|
42
|
+
# => "st"
|
43
|
+
c.call(2)
|
44
|
+
# => "ri"
|
45
|
+
|
46
|
+
=== Add trailing spice after a hole in a curried proc
|
47
|
+
|
48
|
+
You have a hole in your curried subroutine but want to add more spices
|
49
|
+
after or fill out holes after your first hole
|
50
|
+
|
51
|
+
Assuming no special spice before the hole, just put a hole in the hole.
|
52
|
+
|
53
|
+
plus = method(:send_func).curry(Curry::HOLE,:+)
|
54
|
+
"#{plus.spice.inspect} -> #{plus.call("object","ive")}"
|
55
|
+
# => "[<HOLE>, :+] -> objective"
|
56
|
+
|
57
|
+
plusion = plus.new(Curry::HOLE, "ion")
|
58
|
+
"#{plusion.spice.inspect} -> #{plusion.call("object")}"
|
59
|
+
# => "[<HOLE>, :+, "ion"] -> objection"
|
60
|
+
|
61
|
+
=== Add trailing spice after a blackhole
|
62
|
+
|
63
|
+
You want to add more spice, but have a blackhole that swallows anything
|
64
|
+
you try to put in there. You want to keep the blackhole, though.
|
65
|
+
|
66
|
+
withtwo = method(:send_func).curry(Curry::BLACKHOLE,2)
|
67
|
+
"#{withtwo.spice.inspect} -> #{withtwo.call([1,2,3,4],:index).inspect}"
|
68
|
+
# => "[<BLACKHOLE>, 2] -> 1"
|
69
|
+
|
70
|
+
Using a blackhole follwed by a whitehole, we can add extra spice at the
|
71
|
+
end:
|
72
|
+
|
73
|
+
twooh = withtwo.new(Curry::BLACKHOLE, Curry::WHITEHOLE, 0)
|
74
|
+
"#{twooh.spice.inspect} -> #{twooh.call([1,2,3,4],:[]=).inspect}"
|
75
|
+
# => "[<BLACKHOLE>, 2, 0] -> 0"
|
76
|
+
|
77
|
+
Or by placing spice between the black and white holes we can place it
|
78
|
+
immediately after the original blackhole.
|
79
|
+
|
80
|
+
ohtwo = withtwo.new(Curry::BLACKHOLE, 0, Curry::WHITEHOLE)
|
81
|
+
"#{ohtwo.spice.inspect} -> #{ohtwo.call([1,2,3,4],:slice).inspect}"
|
82
|
+
# => "[<BLACKHOLE>, 0, 2] -> [1, 2]"
|
83
|
+
|
84
|
+
By giving the blackhole another blackhole, you have two successive
|
85
|
+
blackholes, the first newly added and the second the one that added the
|
86
|
+
new. The whitehole is then removes the second blackhole -- the blackhole
|
87
|
+
doing the inserting. The spice is then added like usual, yet a blackhole
|
88
|
+
exists at the right place.
|
89
|
+
|
90
|
+
=== Append raw spice without processing
|
91
|
+
|
92
|
+
You have a curry that may have special spices in it. You want to add more
|
93
|
+
spices. You do not want the new spice to be processed as an application on
|
94
|
+
the old spice. You just want to append more spice.
|
95
|
+
|
96
|
+
To do this, you'll have to manually get the parts you need and make
|
97
|
+
a new curry, since applying the new spice the usual way results in it
|
98
|
+
being processed.
|
99
|
+
|
100
|
+
sary = lambda { |*args| args }.curry(Curry::HOLE,'Array')
|
101
|
+
"#{sary.spice.inspect} -> #{sary.call('The',2,3).inspect}"
|
102
|
+
# => "[<HOLE>, "Array"] -> ["The", "Array", 2, 3]"
|
103
|
+
|
104
|
+
sary2 = Curry.new(*sary.spice + [Curry::BLACKHOLE, 'The end'], &sary.uncurried)
|
105
|
+
"#{sary2.spice.inspect} -> #{sary2.call('The',2,3).inspect}"
|
106
|
+
# => "[<HOLE>, "Array", <BLACKHOLE>, "The end"] -> ["The", "Array", 2, 3, "The end"]"
|
107
|
+
|
108
|
+
=== Pass curries as blocks to methods
|
109
|
+
|
110
|
+
Curry implements the to_proc protocol so you're away.
|
111
|
+
|
112
|
+
adjsum = lambda { |sum, val, adj| sum + (val * adj) }.curry(Curry::BLACKHOLE, 2)
|
113
|
+
[1,2,3,4,5].inject(0,&adjsum)
|
114
|
+
# => 30
|
115
|
+
|
116
|
+
=== Apply block arguments via spice
|
117
|
+
|
118
|
+
Right now, Curry doesn't treat block arguments in the spice specially, and in
|
119
|
+
particular won't unwrap (with &) a block at the end of your spice. Also, since
|
120
|
+
it's not possible to pass a block to another block, you cannot pass blocks
|
121
|
+
to your curried procs or chain them together.
|
122
|
+
|
123
|
+
You *can* pass blocks to curried methods in a call, but *only* when they're
|
124
|
+
created from bound methods (passed before the spice, or from Method#curry).
|
125
|
+
|
126
|
+
curry = [10,20,30].method(:inject).curry(Curry::HOLE)
|
127
|
+
curry.call(0) { |s,i| s + i }
|
128
|
+
# => 60
|
129
|
+
|
130
|
+
Taking this a step further, you can do some pretty mad stuff:
|
131
|
+
|
132
|
+
mult_sum = lambda { |sum, i, mult| sum + (i * mult) }.curry(Curry::BLACKHOLE, Curry::HOLE)
|
133
|
+
|
134
|
+
double_sum = mult_sum.new(Curry::BLACKHOLE, Curry::WHITEHOLE, 2)
|
135
|
+
triple_sum = mult_sum.new(Curry::BLACKHOLE, Curry::WHITEHOLE, 3)
|
136
|
+
|
137
|
+
curry.call(0, &double_sum)
|
138
|
+
# => 120
|
139
|
+
|
140
|
+
curry.call(0, &triple_sum)
|
141
|
+
# => 180
|
142
|
+
|
143
|
+
(Wow, that's pretty useless ;)) Ruby doesn't allow block arguments to blocks,
|
144
|
+
so a block attached to a curried proc invocation is ignored.
|
145
|
+
|
146
|
+
|