Class: Curry

Inherits:
Object
  • Object
show all
Defined in:
lib/curry.rb

Overview

Ruby Murray is a Ruby port of Perl’s Sub::Curry library that allows curried blocks and methods to be handled in a pretty flexible way.

See search.cpan.org/~lodin/Sub-Curry-0.8/lib/Sub/Curry.pm and search.cpan.org/~lodin/Sub-Curry-0.8/lib/Sub/Curry/Cookbook.pod for details on the original, and some general background.

Simple usage:

curry = lambda { |*args| args }.curry(Curry::HOLE, "foo", Curry::HOLE)
curry.call(1,3)     # => [1, "foo", 3]

curry = "string".method(:slice).curry(Curry::HOLE, 2)
curry.call(0)       # => "st"
curry.call(2)       # => "ri"

The curry methods are provided by the Curriable module, which simply provides convenient wrapping for Curry.new. There are a few variations between the various forms, but mostly they are equivalent and can be used interchangeably.

See TestCurry (and click the method signatures) for more usage.

Curried procs are immutable once created. If you wish to apply further special spice to a curried method, you may do so either using the instance method new to create a new curried proc by applying new spice to the old spice, or by passing the special spices directly to a call.

You can download Ruby Murray (with documentation and explanatory comments) from roscopeco.co.uk/ruby-quiz-entries/64/curry.rb

Defined Under Namespace

Classes: AntiSpiceArg, BlackHoleArg, HoleArg, LazySpice, SpiceArg

Constant Summary collapse

VERSION =
'0.1.2'
WHITEHOLE =

A whitehole removes the blackhole, but the spice that has been put into the blackhole remains since blackholes themselves don’t store anything.

Object.new
ANTIHOLE =

An antihole put in a hole makes the hole disappear. If the spice is 1, <HOLE>, 3, <HOLE>, 4 and 2, <ANTIHOLE>, 5 is applied then the result will become 1, 2, 3, 4, 5.

Object.new
HOLE =

A hole is what it sounds like: a gap in the argument list. Later, when the subroutine is called the holes are filled in. So if the spice is 1, <HOLE>, 3 and then 2, 4 is applied to the curried proc, the resulting argument list is 1, 2, 3, 4.

Holes can be called “scalar inserters” that default to nil.

HoleArg.instance
BLACKHOLE =

A blackhole is like a hole for lists that never gets full. There’s an imaginary untouchable blackhole at the end of the spice. The blackhole thusly inserts the new spice before itself. The blackhole never gets full because nothing is ever stored in a blackhole as it isn’t a hole really…

Blackholes are used to move the point of insertion from the end to somewhere else, so you can curry the end of the argument list.

Blackholes can be called “list inserters” that defaults to the empty list.

BlackHoleArg.instance
ANTISPICE =

An antispice is like a hole except that when it’s filled it disappears. It’s like a combination of a hole and an antihole. If the spice is 1, <ANTISPICE>, 3 and 2, 4 is applied, then the result will become 1, 3, 4.

AntiSpiceArg.instance

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*spice, &block) ⇒ Curry

call-seq:

Curry.new(*spice) { |*args| ... }  -> #&lt;Curry...&gt;
Curry.new(callable, *spice)        -> #&lt;Curry...&gt;

Create a new curry with the specified spice and block or callable object. The second form requires only that the first argument respond_to?(:call)

Raises:

  • (ArgumentError)


172
173
174
175
176
# File 'lib/curry.rb', line 172

def initialize(*spice, &block)
  block = block || (spice.shift if spice.first.respond_to?(:call))
  raise ArgumentError, "No block supplied" unless block
  @spice, @uncurried = spice, block
end

Instance Attribute Details

#spiceObject (readonly)

The raw spice held by this curried proc. May contain special spices.



160
161
162
# File 'lib/curry.rb', line 160

def spice
  @spice
end

#uncurriedObject (readonly)

The block (Proc) for which arguments are curried.



163
164
165
# File 'lib/curry.rb', line 163

def uncurried
  @uncurried
end

Instance Method Details

#[](*args) ⇒ Object

Had some trouble with aliases and doc so it’s done this way



202
203
204
# File 'lib/curry.rb', line 202

def [](*args) # :nodoc:
  call(*args)
end

#call(*args, &blk) ⇒ Object

call-seq:

some_curry.call(*args) { |b| ... } -> result
some_curry[*args]      { |b| ... } -> result

Call the curried proc, passing the supplied arguments. This method resolves all special spices and passes the resolved arguments to the block. If a block is passed to call it will be passed on as a block argument to the curried method only if this curry was created from a Method. Curries created from a block passed to Curry.new (or from Proc#curry) cannot have block arguments passed to them.

Unlike Perl’s Sub::Curry implementation, special spices may be passed in the call arguments, and are applied as with new. This means that whiteholes and antiholes can be passed in to make single-call modifications to the argument spice. This probably isn’t as great on performance but it’s more fun.

see also new



197
198
199
# File 'lib/curry.rb', line 197

def call(*args, &blk)
  @uncurried.call(*call_spice(args), &blk)
end

#new(*spice) ⇒ Object

call-seq:

some_curry.new(*spice) -> #&lt;Curry...&gt;

Create a new curried proc by applying the supplied spice to the current spice in this curried proc. This does not simply append the spices - Arguments in the supplied spice are applied to the curried spice arguments, with black/white hole and antiholes operating as documented.

See also call.



216
217
218
# File 'lib/curry.rb', line 216

def new(*spice)
  Curry.new(*merge_spice(spice), &@uncurried)
end

#to_procObject

call-seq:

some_curry.to_proc -> #&lt;Proc...&gt;

Convert to a proc



224
225
226
227
# File 'lib/curry.rb', line 224

def to_proc
  # since we're immutable we can keep this
  @extern_proc ||= method(:call).to_proc
end