filigree 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -19
- data/lib/filigree.rb +0 -1
- data/lib/filigree/commands.rb +2 -3
- data/lib/filigree/configuration.rb +3 -3
- data/lib/filigree/match.rb +202 -44
- data/lib/filigree/version.rb +1 -1
- data/lib/filigree/visitor.rb +32 -4
- data/test/tc_visitor.rb +23 -0
- data/test/ts_filigree.rb +0 -1
- metadata +27 -30
- data/lib/filigree/array.rb +0 -35
- data/test/tc_array.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7264462695b42d279eabfc6cf85ff3569dc256ce
|
4
|
+
data.tar.gz: 29f78a7573518bcffe8b4ac1a7e4c17ada4e1679
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e38b5a5cc832448271b531dafe9c31fa9cc897274bd9e75dad2bb8bc11bbc1c10dc00a2a441aaeeb7e137d98d88aa3bdf4534d94abcb23a021b289aaf19c906
|
7
|
+
data.tar.gz: 4b56356808f786d479cc5cadcbfb769188f4c1bbdbd3bcb3255aa9f77a0ce8f2e5dc5e447c6dc1e2ec3046df1611c1e4c1977517a43182e25ad0f7073ab21798
|
data/README.md
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
Filigree: For more beautiful Ruby
|
2
2
|
=================================
|
3
3
|
|
4
|
-
|
4
|
+
<div style="float: left; padding-right: 25px">
|
5
|
+
<img src="https://raw.github.com/chriswailes/filigree/master/resources/filigree_logo_large.jpg" alt="Filigree: For more beautiful Ruby" height=256 width=256>
|
6
|
+
</div>
|
5
7
|
|
6
|
-
|
7
|
-
* An implementation of pattern matching
|
8
|
-
* An implementation of the visitor pattern
|
9
|
-
* Module for defining class methods in a mixin
|
10
|
-
* Modules for configuration and command handling
|
11
|
-
* Easy dynamic type checking
|
12
|
-
* Small extensions to standard library classes
|
8
|
+
Filigree is a collection of classes, modules, and functions that I found myself re-writing in each of my projects. In addition, I have thrown in a couple of other features that I've always wanted. Most of these features can be used independently. Bellow is a list of many of the files and the features that each file provides:
|
13
9
|
|
14
|
-
|
10
|
+
* **filigree/abstract_class.rb** - Abstract class and method implementations
|
11
|
+
* **filigree/application.rb** - A basic application framework
|
12
|
+
* **filigree/class_methods_module.rb** - Easy way to include class methods in a mixin
|
13
|
+
* **filigree/commands.rb** - Framework for defining and processing command lines
|
14
|
+
* **filigree/configuration.rb** - Framework for parsing configuration strings
|
15
|
+
* **filigree/match.rb** - An implementation of pattern matching for Ruby
|
16
|
+
* **filigree/request_file.rb** - Conditionally do something if a file can be included; great for Rakefiles
|
17
|
+
* **filigree/types.rb** - Helper functions/classes for type checking ruby code; great for FFI integration
|
18
|
+
* **filigree/visitor.rb** - Implementation of the Visitor pattern based on pattern matching library
|
19
|
+
|
20
|
+
The above is not a complete list of files provided by this gem, and the documentation bellow only covers the most important features of the library. Explore the rest of the documentation to discover additional features.
|
15
21
|
|
16
22
|
Abstract Classes and Methods
|
17
23
|
----------------------------
|
@@ -130,7 +136,7 @@ match Foo.new(4, 2) do
|
|
130
136
|
end
|
131
137
|
```
|
132
138
|
|
133
|
-
Of particular note is the destructuring of arrays. When an array is destructured like so, `Array.(xs)`, the array is bound to `xs`. If an additional pattern is added, `Array.(x, xs)`, then `x` will hold the first element of the array and `xs` will hold the
|
139
|
+
Of particular note is the destructuring of arrays. When an array is destructured like so, `Array.(xs)`, the array is bound to `xs`. If an additional pattern is added, `Array.(x, xs)`, then `x` will hold the first element of the array and `xs` will hold the remaining characters. As more patterns are added more elements will be pulled off of the front of the array. You can match an array with a specific number of elements by using an empty array literal: `Array.(x, [])`
|
134
140
|
|
135
141
|
Both `match` and `with` can take multiple arguments. When this happens, each object is paired up with the corresponding pattern. If they all match, then the `with` clause matches. In this way you can match against tuples.
|
136
142
|
|
@@ -184,6 +190,16 @@ mv.visit(Add.new(6, 8)) # => 14
|
|
184
190
|
mv.visit(Mul.new(7, 6)) # => 42
|
185
191
|
```
|
186
192
|
|
193
|
+
The only complicated aspect of the Visitor mixin is the method used to select the order in which the patterns are tested. If patterns were tested in order of definition then a subclass of a visitor would be unable to define a more specific pattern than one defined int he parent visitor. To address this issue the most _specific_ patterns are tested first. This gets a bit complicated when it gets to destructuring patterns, but most cases are fairly simple. Pattern specificity is as follows:
|
194
|
+
|
195
|
+
1. Literals
|
196
|
+
2. Destructurings
|
197
|
+
3. Regular expressions
|
198
|
+
4. Instances
|
199
|
+
5. Wildcard
|
200
|
+
|
201
|
+
There are special rules for destructuring and instance patterns. In both cases, a pattern for a subclass is preferred to a pattern for a superclass. Destructuring patterns have the additional rule that longer, more specific destructurings are preferred to shorter, less specific destructurings. Lastly, any pattern that has a guard expression is more specific than an otherwise equivalent expression that doesn't have a guard expression.
|
202
|
+
|
187
203
|
Class Methods
|
188
204
|
-------------
|
189
205
|
|
@@ -317,15 +333,6 @@ var = Foo.new(42, '42')
|
|
317
333
|
var.bar = '42' # Raises a TypeError
|
318
334
|
```
|
319
335
|
|
320
|
-
Array#map
|
321
|
-
---------
|
322
|
-
|
323
|
-
The Array class has been monkey patched so that it takes an optional symbol argument. If it is provided, the symbol is sent to each of the objects in the array and the result is used for the new array.
|
324
|
-
|
325
|
-
```Ruby
|
326
|
-
[1, 2, 3, 4].map :to_sym # => [:1, :2, :3, :4]
|
327
|
-
```
|
328
|
-
|
329
336
|
Contributing
|
330
337
|
------------
|
331
338
|
|
data/lib/filigree.rb
CHANGED
data/lib/filigree/commands.rb
CHANGED
@@ -10,7 +10,6 @@
|
|
10
10
|
# Standard Library
|
11
11
|
|
12
12
|
# Filigree
|
13
|
-
require 'filigree/array'
|
14
13
|
require 'filigree/class_methods_module'
|
15
14
|
require 'filigree/configuration'
|
16
15
|
|
@@ -85,7 +84,7 @@ module Filigree
|
|
85
84
|
# @return [void]
|
86
85
|
def add_command(command_obj)
|
87
86
|
@command_list << command_obj
|
88
|
-
namespace = reify_namespace(command_obj.name.split.map(
|
87
|
+
namespace = reify_namespace(command_obj.name.split.map(&:to_sym))
|
89
88
|
namespace[:nil] = command_obj
|
90
89
|
end
|
91
90
|
|
@@ -225,7 +224,7 @@ module Filigree
|
|
225
224
|
comm_list = self.class.command_list
|
226
225
|
|
227
226
|
sorted_comm_list = comm_list.sort { |a, b| a.name <=> b.name }
|
228
|
-
max_length = comm_list.map
|
227
|
+
max_length = comm_list.lazy.map { |opt| opt.name.length }.max
|
229
228
|
|
230
229
|
|
231
230
|
sorted_comm_list.each do |comm|
|
@@ -378,9 +378,9 @@ module Filigree
|
|
378
378
|
# @return [String]
|
379
379
|
def self.to_s(options, indent = 0)
|
380
380
|
lines = []
|
381
|
-
|
382
|
-
max_long = options.
|
383
|
-
max_short = options.
|
381
|
+
|
382
|
+
max_long = options.lazy.map { |opt| opt.long.length }.max
|
383
|
+
max_short = options.lazy.map(&:short).reject { |opt| opt.nil? }.map(&:length).max
|
384
384
|
|
385
385
|
options.each do |opt|
|
386
386
|
lines << opt.to_s(max_long, max_short, indent)
|
data/lib/filigree/match.rb
CHANGED
@@ -13,6 +13,7 @@ require 'singleton'
|
|
13
13
|
|
14
14
|
# Filigree
|
15
15
|
require 'filigree/abstract_class'
|
16
|
+
require 'filigree/class'
|
16
17
|
|
17
18
|
##########
|
18
19
|
# Errors #
|
@@ -166,7 +167,32 @@ end
|
|
166
167
|
#######################
|
167
168
|
|
168
169
|
module Filigree
|
169
|
-
|
170
|
+
|
171
|
+
###########
|
172
|
+
# Methods #
|
173
|
+
###########
|
174
|
+
|
175
|
+
# Wrap non-pattern objects in pattern objects so they can all be treated
|
176
|
+
# in the same way during pattern sorting and matching.
|
177
|
+
#
|
178
|
+
# @param [Array<Object>] pattern Naked pattern object
|
179
|
+
#
|
180
|
+
# @return [Array<BasicPattern>] Wrapped pattern object
|
181
|
+
def Filigree::wrap_pattern_elements(pattern)
|
182
|
+
pattern.map do |el|
|
183
|
+
case el
|
184
|
+
when BasicPattern then el
|
185
|
+
when Class then InstancePattern.new(el)
|
186
|
+
when Regexp then RegexpPattern.new(el)
|
187
|
+
else LiteralPattern.new(el)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
#######################
|
193
|
+
# Modules and Classes #
|
194
|
+
#######################
|
195
|
+
|
170
196
|
# A module indicating that an object may be destructured. The including
|
171
197
|
# class must define the `destructure` instance method, which takes one
|
172
198
|
# argument specifying the number of pattern elements it is being matched
|
@@ -178,7 +204,7 @@ module Filigree
|
|
178
204
|
#
|
179
205
|
# @return [DestructuringPattern]
|
180
206
|
def call(*pattern)
|
181
|
-
DestructuringPattern.new(self,
|
207
|
+
DestructuringPattern.new(self, Filigree::wrap_pattern_elements(pattern))
|
182
208
|
end
|
183
209
|
end
|
184
210
|
|
@@ -235,7 +261,9 @@ module Filigree
|
|
235
261
|
# @return [void]
|
236
262
|
def with(*pattern, &block)
|
237
263
|
guard = if pattern.last.is_a?(Proc) then pattern.pop end
|
238
|
-
|
264
|
+
|
265
|
+
pattern = Filigree::wrap_pattern_elements(pattern)
|
266
|
+
|
239
267
|
@patterns << (mp = OuterPattern.new(pattern, guard, block))
|
240
268
|
|
241
269
|
if block
|
@@ -264,7 +292,18 @@ module Filigree
|
|
264
292
|
|
265
293
|
# This class provides the basis for all match patterns.
|
266
294
|
class BasicPattern
|
267
|
-
extend
|
295
|
+
extend AbstractClass
|
296
|
+
include Comparable
|
297
|
+
|
298
|
+
# Base implementation of bi-directional comparison for patterns.
|
299
|
+
#
|
300
|
+
# @param [BasicPattern] other Right-hand side of the comparison
|
301
|
+
#
|
302
|
+
# @return [Integer] Value corresponding to less than, equal to, or
|
303
|
+
# greater than the right-hand side pattern.
|
304
|
+
def <=>(other)
|
305
|
+
self.weight - other.weight
|
306
|
+
end
|
268
307
|
|
269
308
|
# Wraps this pattern in a {BindingPattern}, causing the object that
|
270
309
|
# this pattern matches to be bound to this name in the with block.
|
@@ -273,32 +312,6 @@ module Filigree
|
|
273
312
|
def as(binding_pattern)
|
274
313
|
binding_pattern.tap { |bp| bp.pattern_elem = self }
|
275
314
|
end
|
276
|
-
|
277
|
-
# Test to see if a single object matches a single pattern, using the
|
278
|
-
# given environment to store bindings.
|
279
|
-
#
|
280
|
-
# @param [Object] pattern_elem Object representing the pattern
|
281
|
-
# @param [Object] object Object to be matched
|
282
|
-
# @param [Object] env Environment in which to store bindings
|
283
|
-
#
|
284
|
-
# @return [Boolean] If the pattern element matched
|
285
|
-
def match_pattern_element(pattern_elem, object, env)
|
286
|
-
case pattern_elem
|
287
|
-
when Class
|
288
|
-
object.is_a?(pattern_elem)
|
289
|
-
|
290
|
-
when Regexp
|
291
|
-
(object.is_a?(String) and (md = pattern_elem.match(object))).tap do |match|
|
292
|
-
env.send("match_data=", md) if match
|
293
|
-
end
|
294
|
-
|
295
|
-
when BasicPattern
|
296
|
-
pattern_elem.match?(object, env)
|
297
|
-
|
298
|
-
else
|
299
|
-
object == pattern_elem
|
300
|
-
end
|
301
|
-
end
|
302
315
|
end
|
303
316
|
|
304
317
|
# A pattern that matches any object
|
@@ -311,28 +324,59 @@ module Filigree
|
|
311
324
|
def match?(_, _)
|
312
325
|
true
|
313
326
|
end
|
327
|
+
|
328
|
+
def weight
|
329
|
+
4
|
330
|
+
end
|
314
331
|
end
|
315
332
|
|
316
333
|
# An abstract class that matches only a single object to a single pattern.
|
317
334
|
class SingleObjectPattern < BasicPattern
|
318
335
|
extend AbstractClass
|
319
336
|
|
337
|
+
# @return [BasicPattern]
|
338
|
+
attr_reader :pattern_elem
|
339
|
+
|
320
340
|
# Create a new pattern with a single element.
|
321
341
|
#
|
322
342
|
# @param [Object] pattern_elem Object representing the pattern
|
323
343
|
def initialize(pattern_elem)
|
324
344
|
@pattern_elem = pattern_elem
|
325
345
|
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# A pattern for checking to see if an object is an instance of a given
|
349
|
+
# class.
|
350
|
+
class InstancePattern < SingleObjectPattern
|
351
|
+
# Specialized version of the bi-directional comparison operator.
|
352
|
+
#
|
353
|
+
# @param [BasicPattern] other Right-hand side of the comparison
|
354
|
+
#
|
355
|
+
# @return [-1, 0, 1] Value corresponding to less than, equal to, or
|
356
|
+
# greater than the right-hand side pattern.
|
357
|
+
def <=>(other)
|
358
|
+
if other.is_a?(InstancePattern)
|
359
|
+
if self.pattern_elem == other.pattern_elem then 0
|
360
|
+
elsif self.pattern_elem.subclass_of?(other.pattern_elem) then 1
|
361
|
+
else -1
|
362
|
+
end
|
363
|
+
else
|
364
|
+
super
|
365
|
+
end
|
366
|
+
end
|
326
367
|
|
327
|
-
#
|
328
|
-
#
|
368
|
+
# Test the object to see if the object is an instance of the given
|
369
|
+
# class.
|
329
370
|
#
|
330
371
|
# @param [Object] object Object to test pattern against
|
331
|
-
# @param [Object] env Binding environment
|
332
372
|
#
|
333
373
|
# @return [Boolean]
|
334
|
-
def match?(object,
|
335
|
-
|
374
|
+
def match?(object, _)
|
375
|
+
object.is_a?(@pattern_elem)
|
376
|
+
end
|
377
|
+
|
378
|
+
def weight
|
379
|
+
3
|
336
380
|
end
|
337
381
|
end
|
338
382
|
|
@@ -346,22 +390,52 @@ module Filigree
|
|
346
390
|
def match?(object, _)
|
347
391
|
object == @pattern_elem
|
348
392
|
end
|
393
|
+
|
394
|
+
def weight
|
395
|
+
0
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# A pattern that tests a string against a regular expression.
|
400
|
+
class RegexpPattern < SingleObjectPattern
|
401
|
+
# Test the object to see if it matches the wrapped regular
|
402
|
+
# expression.
|
403
|
+
#
|
404
|
+
# @param [Object] object Object to test pattern against
|
405
|
+
# @param [Object] env Binding environment
|
406
|
+
#
|
407
|
+
# @return [Boolean]
|
408
|
+
def match?(object, env)
|
409
|
+
(object.is_a?(String) and (md = @pattern_elem.match(object))).tap do |match|
|
410
|
+
env.send("match_data=", md) if match
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
def weight
|
415
|
+
2
|
416
|
+
end
|
349
417
|
end
|
350
418
|
|
351
419
|
# A pattern that binds a sub-pattern's matching object to a name in the
|
352
420
|
# binding environment.
|
353
421
|
class BindingPattern < SingleObjectPattern
|
354
|
-
|
422
|
+
|
423
|
+
attr_writer :pattern_elem
|
355
424
|
|
356
425
|
# Create a new binding pattern.
|
357
426
|
#
|
358
427
|
# @param [Symbol] name Name to bind to
|
359
428
|
# @param [Object] pattern_elem Sub-pattern
|
360
|
-
def initialize(name, pattern_elem =
|
429
|
+
def initialize(name, pattern_elem = WildcardPattern.instance)
|
361
430
|
@name = name
|
362
431
|
super(pattern_elem)
|
363
432
|
end
|
364
433
|
|
434
|
+
# Overridden method to prevent binding BindingPattern objects.
|
435
|
+
def as(_, _)
|
436
|
+
raise 'Binding a BindingPattern is not allowed.'
|
437
|
+
end
|
438
|
+
|
365
439
|
# Test the object for equality to the pattern element. Binds the
|
366
440
|
# object to the binding pattern's name if it does match.
|
367
441
|
#
|
@@ -370,9 +444,11 @@ module Filigree
|
|
370
444
|
#
|
371
445
|
# @return [Boolean]
|
372
446
|
def match?(object, env)
|
373
|
-
|
374
|
-
|
375
|
-
|
447
|
+
@pattern_elem.match?(object, env).tap { |match| env.send("#{@name}=", object) if match }
|
448
|
+
end
|
449
|
+
|
450
|
+
def weight
|
451
|
+
@pattern_elem.weight
|
376
452
|
end
|
377
453
|
end
|
378
454
|
|
@@ -380,6 +456,9 @@ module Filigree
|
|
380
456
|
class MultipleObjectPattern < BasicPattern
|
381
457
|
extend AbstractClass
|
382
458
|
|
459
|
+
# @return [Array<BasicPattern>]
|
460
|
+
attr_reader :pattern
|
461
|
+
|
383
462
|
# Create a new pattern with multiple elements.
|
384
463
|
#
|
385
464
|
# @param [Array<Object>] pattern Array of pattern elements
|
@@ -387,6 +466,21 @@ module Filigree
|
|
387
466
|
@pattern = pattern
|
388
467
|
end
|
389
468
|
|
469
|
+
# A wrapper method to sort MultipleObjectPattern objects by their
|
470
|
+
# arity.
|
471
|
+
#
|
472
|
+
# @param [BasicPattern] other Right-hand side of the comparison
|
473
|
+
#
|
474
|
+
# @return [Integer] Value corresponding to less than, equal to, or
|
475
|
+
# greater than the right-hand side pattern.
|
476
|
+
def base_compare(other)
|
477
|
+
if self.pattern.length == other.pattern.length
|
478
|
+
yield
|
479
|
+
else
|
480
|
+
self.pattern.length - other.pattern.length
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
390
484
|
# Test multiple objects against multiple pattern elements.
|
391
485
|
#
|
392
486
|
# @param [Object] objects Object to test pattern against
|
@@ -395,7 +489,7 @@ module Filigree
|
|
395
489
|
def match?(objects, env)
|
396
490
|
if objects.length == @pattern.length
|
397
491
|
@pattern.zip(objects).each do |pattern_elem, object|
|
398
|
-
return false unless
|
492
|
+
return false unless pattern_elem.match?(object, env)
|
399
493
|
end
|
400
494
|
|
401
495
|
true
|
@@ -406,9 +500,31 @@ module Filigree
|
|
406
500
|
end
|
407
501
|
end
|
408
502
|
|
409
|
-
# The that contains all of the pattern elements passed to a with clause.
|
503
|
+
# The class that contains all of the pattern elements passed to a with clause.
|
410
504
|
class OuterPattern < MultipleObjectPattern
|
411
505
|
attr_writer :block
|
506
|
+
attr_reader :guard
|
507
|
+
|
508
|
+
# Specialized version of the bi-directional comparison operator.
|
509
|
+
#
|
510
|
+
# @param [BasicPattern] other Right-hand side of the comparison
|
511
|
+
#
|
512
|
+
# @return [-1, 0, 1] Value corresponding to less than, equal to, or
|
513
|
+
# greater than the right-hand side pattern.
|
514
|
+
def <=>(other)
|
515
|
+
base_compare(other) do
|
516
|
+
comp_res =
|
517
|
+
self.pattern.zip(other.pattern).inject(0) do |total, pair|
|
518
|
+
total + (pair.first <=> pair.last)
|
519
|
+
end <=> 0
|
520
|
+
|
521
|
+
if comp_res == 0
|
522
|
+
self.guard ? (other.guard ? 0 : 1) : (other.guard ? -1 : comp_res)
|
523
|
+
else
|
524
|
+
comp_res
|
525
|
+
end
|
526
|
+
end
|
527
|
+
end
|
412
528
|
|
413
529
|
# Create a new outer pattern with the given pattern elements, guard,
|
414
530
|
# and block.
|
@@ -444,11 +560,39 @@ module Filigree
|
|
444
560
|
# A pattern that matches an instance of a class and destructures it so
|
445
561
|
# that the values contained by the object may be matched upon.
|
446
562
|
class DestructuringPattern < MultipleObjectPattern
|
563
|
+
|
564
|
+
# @return [Class]
|
565
|
+
attr_reader :klass
|
566
|
+
|
567
|
+
# Specialized version of the bi-directional comparison operator.
|
568
|
+
#
|
569
|
+
# @param [BasicPattern] other Right-hand side of the comparison
|
570
|
+
#
|
571
|
+
# @return [Integer] Value corresponding to less than, equal to, or
|
572
|
+
# greater than the right-hand side pattern.
|
573
|
+
def <=>(other)
|
574
|
+
if other.is_a?(DestructuringPattern)
|
575
|
+
if self.klass == other.klass
|
576
|
+
base_compare(other) do
|
577
|
+
self.pattern.zip(other.pattern).inject(0) do |total, pair|
|
578
|
+
total + (pair.first <=> pair.last)
|
579
|
+
end / self.pattern.length
|
580
|
+
end
|
581
|
+
|
582
|
+
elsif self.klass.subclass_of?(other.klass) then 1
|
583
|
+
else -1
|
584
|
+
end
|
585
|
+
|
586
|
+
else
|
587
|
+
super
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
447
591
|
# Create a new destructuring pattern.
|
448
592
|
#
|
449
593
|
# @param [Class] klass Class to match instances of. It must be destructurable.
|
450
594
|
# @param [Object] pattern Pattern elements to use in matching the object's values
|
451
|
-
def initialize(klass,
|
595
|
+
def initialize(klass, pattern)
|
452
596
|
@klass = klass
|
453
597
|
super(pattern)
|
454
598
|
end
|
@@ -464,6 +608,10 @@ module Filigree
|
|
464
608
|
def match?(object, env)
|
465
609
|
object.is_a?(@klass) and super(object.destructure(@pattern.length), env)
|
466
610
|
end
|
611
|
+
|
612
|
+
def weight
|
613
|
+
1
|
614
|
+
end
|
467
615
|
end
|
468
616
|
end
|
469
617
|
|
@@ -494,6 +642,16 @@ class Class
|
|
494
642
|
#
|
495
643
|
# @param [BindingPattern] binding_pattern Name to bind the instance to
|
496
644
|
def as(binding_pattern)
|
497
|
-
binding_pattern.tap { |bp| bp.pattern_elem = self }
|
645
|
+
binding_pattern.tap { |bp| bp.pattern_elem = Filigree::InstancePattern.new(self) }
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
class Regexp
|
650
|
+
# Causes a string matching the regular expression to be bound the the
|
651
|
+
# given name.
|
652
|
+
#
|
653
|
+
# @param [BindingPattern] binding_pattern Name to bind the instance to
|
654
|
+
def as(binding_pattern)
|
655
|
+
binding_pattern.tap { |bp| bp.pattern_elem = Filigree::RegexpPattern.new(self) }
|
498
656
|
end
|
499
657
|
end
|
data/lib/filigree/version.rb
CHANGED
data/lib/filigree/visitor.rb
CHANGED
@@ -88,11 +88,38 @@ module Filigree
|
|
88
88
|
LiteralPattern.new(obj)
|
89
89
|
end
|
90
90
|
|
91
|
+
# Inserts a new pattern in the appropriate place in the patterns
|
92
|
+
# list.
|
93
|
+
#
|
94
|
+
# @param [OuterPattern] new_pat New pattern to add
|
95
|
+
#
|
96
|
+
# @return [void]
|
97
|
+
def add_pattern(new_pat)
|
98
|
+
@patterns.each_with_index do |old_pat, index|
|
99
|
+
if new_pat > old_pat
|
100
|
+
@patterns.insert(index, new_pat)
|
101
|
+
return
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@patterns << new_pat
|
106
|
+
end
|
107
|
+
|
108
|
+
# A callback used to pass patterns declared in a parent class to
|
109
|
+
# a subclass.
|
110
|
+
#
|
111
|
+
# @param [Class] klass Subclass
|
112
|
+
#
|
113
|
+
# @return [void]
|
114
|
+
def inherited(klass)
|
115
|
+
klass.install_icvars(@patterns.clone)
|
116
|
+
end
|
117
|
+
|
91
118
|
# Install the instance class variables in the including class.
|
92
119
|
#
|
93
120
|
# @return [void]
|
94
|
-
def install_icvars
|
95
|
-
@patterns =
|
121
|
+
def install_icvars(inherited_patterns = Array.new)
|
122
|
+
@patterns = inherited_patterns
|
96
123
|
@deferred = Array.new
|
97
124
|
end
|
98
125
|
|
@@ -106,8 +133,9 @@ module Filigree
|
|
106
133
|
# @return [void]
|
107
134
|
def on(*pattern, &block)
|
108
135
|
guard = if pattern.last.is_a?(Proc) then pattern.pop end
|
109
|
-
|
110
|
-
|
136
|
+
|
137
|
+
pattern = Filigree::wrap_pattern_elements(pattern)
|
138
|
+
add_pattern (mp = OuterPattern.new(pattern, guard, block))
|
111
139
|
|
112
140
|
if block
|
113
141
|
@deferred.each { |pattern| pattern.block = block }
|
data/test/tc_visitor.rb
CHANGED
@@ -157,9 +157,32 @@ class VisitorTester < Minitest::Test
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
+
class NumericVisitor
|
161
|
+
include Filigree::Visitor
|
162
|
+
|
163
|
+
on Numeric do |n|
|
164
|
+
"Numeric: #{n}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class SubclassVisitor < NumericVisitor
|
169
|
+
on Integer do |i|
|
170
|
+
"Integer: #{i}"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
160
174
|
def setup
|
161
175
|
end
|
162
176
|
|
177
|
+
def test_inheritance
|
178
|
+
sv = SubclassVisitor.new
|
179
|
+
|
180
|
+
assert_equal "Numeric: 3.1415296", sv.visit(3.1415296)
|
181
|
+
assert_equal "Integer: 42", sv.visit(42)
|
182
|
+
|
183
|
+
assert_raises(MatchError) { sv.visit(:hoopy) }
|
184
|
+
end
|
185
|
+
|
163
186
|
def test_simple_visitor
|
164
187
|
sv = SimpleVisitor.new
|
165
188
|
|
data/test/ts_filigree.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filigree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wailes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -175,35 +175,33 @@ files:
|
|
175
175
|
- AUTHORS
|
176
176
|
- README.md
|
177
177
|
- Rakefile
|
178
|
-
- lib/filigree/request_file.rb
|
179
|
-
- lib/filigree/class_methods_module.rb
|
180
|
-
- lib/filigree/visitor.rb
|
181
178
|
- lib/filigree/types.rb
|
182
|
-
- lib/filigree/object.rb
|
183
|
-
- lib/filigree/string.rb
|
184
|
-
- lib/filigree/commands.rb
|
185
|
-
- lib/filigree/abstract_class.rb
|
186
179
|
- lib/filigree/boolean.rb
|
180
|
+
- lib/filigree/match.rb
|
187
181
|
- lib/filigree/application.rb
|
182
|
+
- lib/filigree/abstract_class.rb
|
183
|
+
- lib/filigree/class.rb
|
184
|
+
- lib/filigree/string.rb
|
188
185
|
- lib/filigree/version.rb
|
189
186
|
- lib/filigree/configuration.rb
|
190
|
-
- lib/filigree/
|
191
|
-
- lib/filigree/
|
192
|
-
- lib/filigree/
|
187
|
+
- lib/filigree/visitor.rb
|
188
|
+
- lib/filigree/object.rb
|
189
|
+
- lib/filigree/commands.rb
|
190
|
+
- lib/filigree/request_file.rb
|
191
|
+
- lib/filigree/class_methods_module.rb
|
193
192
|
- lib/filigree.rb
|
194
|
-
- test/
|
195
|
-
- test/
|
193
|
+
- test/tc_boolean.rb
|
194
|
+
- test/tc_object.rb
|
196
195
|
- test/tc_types.rb
|
197
|
-
- test/
|
196
|
+
- test/tc_configuration.rb
|
197
|
+
- test/tc_commands.rb
|
198
198
|
- test/tc_string.rb
|
199
|
-
- test/tc_application.rb
|
200
|
-
- test/tc_match.rb
|
201
199
|
- test/tc_abstract_class.rb
|
202
|
-
- test/tc_object.rb
|
203
|
-
- test/tc_class_methods_module.rb
|
204
|
-
- test/tc_configuration.rb
|
205
|
-
- test/tc_boolean.rb
|
206
200
|
- test/tc_visitor.rb
|
201
|
+
- test/tc_class_methods_module.rb
|
202
|
+
- test/tc_match.rb
|
203
|
+
- test/tc_class.rb
|
204
|
+
- test/tc_application.rb
|
207
205
|
- test/ts_filigree.rb
|
208
206
|
homepage: https://github.com/chriswailes/filigree
|
209
207
|
licenses:
|
@@ -230,18 +228,17 @@ signing_key:
|
|
230
228
|
specification_version: 4
|
231
229
|
summary: Extra functionality for Ruby.
|
232
230
|
test_files:
|
233
|
-
- test/
|
234
|
-
- test/
|
231
|
+
- test/tc_boolean.rb
|
232
|
+
- test/tc_object.rb
|
235
233
|
- test/tc_types.rb
|
236
|
-
- test/
|
234
|
+
- test/tc_configuration.rb
|
235
|
+
- test/tc_commands.rb
|
237
236
|
- test/tc_string.rb
|
238
|
-
- test/tc_application.rb
|
239
|
-
- test/tc_match.rb
|
240
237
|
- test/tc_abstract_class.rb
|
241
|
-
- test/tc_object.rb
|
242
|
-
- test/tc_class_methods_module.rb
|
243
|
-
- test/tc_configuration.rb
|
244
|
-
- test/tc_boolean.rb
|
245
238
|
- test/tc_visitor.rb
|
239
|
+
- test/tc_class_methods_module.rb
|
240
|
+
- test/tc_match.rb
|
241
|
+
- test/tc_class.rb
|
242
|
+
- test/tc_application.rb
|
246
243
|
- test/ts_filigree.rb
|
247
244
|
has_rdoc:
|
data/lib/filigree/array.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
-
# Project: Filigree
|
3
|
-
# Date: 2013/05/04
|
4
|
-
# Description: Additional features for Arrays.
|
5
|
-
|
6
|
-
############
|
7
|
-
# Requires #
|
8
|
-
############
|
9
|
-
|
10
|
-
# Standard Library
|
11
|
-
|
12
|
-
# Filigree
|
13
|
-
|
14
|
-
#######################
|
15
|
-
# Classes and Modules #
|
16
|
-
#######################
|
17
|
-
|
18
|
-
class Array
|
19
|
-
alias :aliased_map :map
|
20
|
-
|
21
|
-
# Map now takes an optional symbol argument. If a symbol is provided the
|
22
|
-
# specified method is invoked on each of the objects in the array.
|
23
|
-
#
|
24
|
-
# @param [Symbol] method Method to be invoked on the array elements.
|
25
|
-
# @param [Proc] block Normal Array#each block.
|
26
|
-
#
|
27
|
-
# @return [Array<Object>]
|
28
|
-
def map(method = nil, &block)
|
29
|
-
if method
|
30
|
-
self.aliased_map { |obj| obj.send(method) }
|
31
|
-
else
|
32
|
-
self.aliased_map(&block)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/test/tc_array.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
-
# Project: Filigree
|
3
|
-
# Date: 2014/02/05
|
4
|
-
# Description: Test cases for the Array extensions.
|
5
|
-
|
6
|
-
############
|
7
|
-
# Requires #
|
8
|
-
############
|
9
|
-
|
10
|
-
# Gems
|
11
|
-
require 'minitest/autorun'
|
12
|
-
|
13
|
-
# Filigree
|
14
|
-
require 'filigree/array'
|
15
|
-
|
16
|
-
#######################
|
17
|
-
# Classes and Modules #
|
18
|
-
#######################
|
19
|
-
|
20
|
-
class ArrayTester < Minitest::Test
|
21
|
-
|
22
|
-
def setup
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_map_with_method
|
26
|
-
assert_equal [:cat, :dog, :cow], ['cat', 'dog', 'cow'].map(:to_sym)
|
27
|
-
end
|
28
|
-
end
|