motion_virtus 1.0.0.beta0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +445 -0
  3. data/lib/motion_virtus.rb +13 -0
  4. data/lib/project/attribute/accessor/builder.rb +69 -0
  5. data/lib/project/attribute/accessor/lazy_accessor.rb +39 -0
  6. data/lib/project/attribute/accessor.rb +100 -0
  7. data/lib/project/attribute/accessor_method.rb +73 -0
  8. data/lib/project/attribute/array.rb +24 -0
  9. data/lib/project/attribute/boolean.rb +52 -0
  10. data/lib/project/attribute/class.rb +23 -0
  11. data/lib/project/attribute/coercer.rb +43 -0
  12. data/lib/project/attribute/collection/coercible_writer.rb +83 -0
  13. data/lib/project/attribute/collection.rb +56 -0
  14. data/lib/project/attribute/date.rb +36 -0
  15. data/lib/project/attribute/date_time.rb +38 -0
  16. data/lib/project/attribute/decimal.rb +23 -0
  17. data/lib/project/attribute/default_value/from_callable.rb +37 -0
  18. data/lib/project/attribute/default_value/from_clonable.rb +37 -0
  19. data/lib/project/attribute/default_value/from_symbol.rb +37 -0
  20. data/lib/project/attribute/default_value.rb +49 -0
  21. data/lib/project/attribute/embedded_value/open_struct_coercer.rb +43 -0
  22. data/lib/project/attribute/embedded_value/struct_coercer.rb +42 -0
  23. data/lib/project/attribute/embedded_value.rb +69 -0
  24. data/lib/project/attribute/float.rb +30 -0
  25. data/lib/project/attribute/hash/coercible_writer.rb +78 -0
  26. data/lib/project/attribute/hash.rb +66 -0
  27. data/lib/project/attribute/integer.rb +27 -0
  28. data/lib/project/attribute/numeric.rb +25 -0
  29. data/lib/project/attribute/object.rb +13 -0
  30. data/lib/project/attribute/reader.rb +39 -0
  31. data/lib/project/attribute/set.rb +22 -0
  32. data/lib/project/attribute/string.rb +24 -0
  33. data/lib/project/attribute/symbol.rb +23 -0
  34. data/lib/project/attribute/time.rb +36 -0
  35. data/lib/project/attribute/writer/coercible.rb +45 -0
  36. data/lib/project/attribute/writer.rb +73 -0
  37. data/lib/project/attribute.rb +292 -0
  38. data/lib/project/attribute_set.rb +260 -0
  39. data/lib/project/class_inclusions.rb +41 -0
  40. data/lib/project/class_methods.rb +102 -0
  41. data/lib/project/configuration.rb +65 -0
  42. data/lib/project/const_missing_extensions.rb +16 -0
  43. data/lib/project/extensions.rb +101 -0
  44. data/lib/project/instance_methods.rb +165 -0
  45. data/lib/project/module_builder.rb +92 -0
  46. data/lib/project/module_extensions.rb +72 -0
  47. data/lib/project/stubs/date.rb +2 -0
  48. data/lib/project/stubs/date_time.rb +2 -0
  49. data/lib/project/stubs/decimal.rb +2 -0
  50. data/lib/project/stubs/ostruct.rb +149 -0
  51. data/lib/project/stubs/set.rb +767 -0
  52. data/lib/project/stubs.rb +5 -0
  53. data/lib/project/support/equalizer.rb +147 -0
  54. data/lib/project/support/options.rb +114 -0
  55. data/lib/project/support/type_lookup.rb +109 -0
  56. data/lib/project/value_object.rb +139 -0
  57. data/lib/project/version.rb +3 -0
  58. data/lib/project/virtus.rb +128 -0
  59. metadata +158 -0
@@ -0,0 +1,767 @@
1
+ #--
2
+ # set.rb - defines the Set class
3
+ #++
4
+ # Copyright (c) 2002-2013 Akinori MUSHA <knu@iDaemons.org>
5
+ #
6
+ # Documentation by Akinori MUSHA and Gavin Sinclair.
7
+ #
8
+ # All rights reserved. You can redistribute and/or modify it under the same
9
+ # terms as Ruby.
10
+ #
11
+ # $Id$
12
+ #
13
+ # == Overview
14
+ #
15
+ # This library provides the Set class, which deals with a collection
16
+ # of unordered values with no duplicates. It is a hybrid of Array's
17
+ # intuitive inter-operation facilities and Hash's fast lookup. If you
18
+ # need to keep values sorted in some order, use the SortedSet class.
19
+ #
20
+ # The method +to_set+ is added to Enumerable for convenience.
21
+ #
22
+ # See the Set and SortedSet documentation for examples of usage.
23
+
24
+
25
+ #
26
+ # Set implements a collection of unordered values with no duplicates.
27
+ # This is a hybrid of Array's intuitive inter-operation facilities and
28
+ # Hash's fast lookup.
29
+ #
30
+ # Set is easy to use with Enumerable objects (implementing +each+).
31
+ # Most of the initializer methods and binary operators accept generic
32
+ # Enumerable objects besides sets and arrays. An Enumerable object
33
+ # can be converted to Set using the +to_set+ method.
34
+ #
35
+ # Set uses Hash as storage, so you must note the following points:
36
+ #
37
+ # * Equality of elements is determined according to Object#eql? and
38
+ # Object#hash.
39
+ # * Set assumes that the identity of each element does not change
40
+ # while it is stored. Modifying an element of a set will render the
41
+ # set to an unreliable state.
42
+ # * When a string is to be stored, a frozen copy of the string is
43
+ # stored instead unless the original string is already frozen.
44
+ #
45
+ # == Comparison
46
+ #
47
+ # The comparison operators <, >, <= and >= are implemented as
48
+ # shorthand for the {proper_,}{subset?,superset?} methods. However,
49
+ # the <=> operator is intentionally left out because not every pair of
50
+ # sets is comparable. ({x,y} vs. {x,z} for example)
51
+ #
52
+ # == Example
53
+ #
54
+ # require 'set'
55
+ # s1 = Set.new [1, 2] # -> #<Set: {1, 2}>
56
+ # s2 = [1, 2].to_set # -> #<Set: {1, 2}>
57
+ # s1 == s2 # -> true
58
+ # s1.add("foo") # -> #<Set: {1, 2, "foo"}>
59
+ # s1.merge([2, 6]) # -> #<Set: {1, 2, "foo", 6}>
60
+ # s1.subset? s2 # -> false
61
+ # s2.subset? s1 # -> true
62
+ #
63
+ # == Contact
64
+ #
65
+ # - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
66
+ #
67
+ class Set
68
+ include Enumerable
69
+
70
+ # Creates a new set containing the given objects.
71
+ def self.[](*ary)
72
+ new(ary)
73
+ end
74
+
75
+ # Creates a new set containing the elements of the given enumerable
76
+ # object.
77
+ #
78
+ # If a block is given, the elements of enum are preprocessed by the
79
+ # given block.
80
+ def initialize(enum = nil, &block) # :yields: o
81
+ @hash ||= Hash.new
82
+
83
+ enum.nil? and return
84
+
85
+ if block
86
+ do_with_enum(enum) { |o| add(block[o]) }
87
+ else
88
+ merge(enum)
89
+ end
90
+ end
91
+
92
+ def do_with_enum(enum, &block) # :nodoc:
93
+ if enum.respond_to?(:each_entry)
94
+ enum.each_entry(&block)
95
+ elsif enum.respond_to?(:each)
96
+ enum.each(&block)
97
+ else
98
+ raise ArgumentError, "value must be enumerable"
99
+ end
100
+ end
101
+ private :do_with_enum
102
+
103
+ # Copy internal hash.
104
+ def initialize_copy(orig)
105
+ @hash = orig.instance_variable_get(:@hash).dup
106
+ end
107
+
108
+ def freeze # :nodoc:
109
+ @hash.freeze
110
+ super
111
+ end
112
+
113
+ def taint # :nodoc:
114
+ @hash.taint
115
+ super
116
+ end
117
+
118
+ def untaint # :nodoc:
119
+ @hash.untaint
120
+ super
121
+ end
122
+
123
+ # Returns the number of elements.
124
+ def size
125
+ @hash.size
126
+ end
127
+ alias length size
128
+
129
+ # Returns true if the set contains no elements.
130
+ def empty?
131
+ @hash.empty?
132
+ end
133
+
134
+ # Removes all elements and returns self.
135
+ def clear
136
+ @hash.clear
137
+ self
138
+ end
139
+
140
+ # Replaces the contents of the set with the contents of the given
141
+ # enumerable object and returns self.
142
+ def replace(enum)
143
+ if enum.instance_of?(self.class)
144
+ @hash.replace(enum.instance_variable_get(:@hash))
145
+ else
146
+ clear
147
+ merge(enum)
148
+ end
149
+
150
+ self
151
+ end
152
+
153
+ # Converts the set to an array. The order of elements is uncertain.
154
+ def to_a
155
+ @hash.keys
156
+ end
157
+
158
+ # Returns self if no arguments are given. Otherwise, converts the
159
+ # set to another with klass.new(self, *args, &block).
160
+ #
161
+ # In subclasses, returns klass.new(self, *args, &block) unless
162
+ # overridden.
163
+ def to_set(klass = Set, *args, &block)
164
+ return self if instance_of?(Set) && klass == Set && block.nil? && args.empty?
165
+ klass.new(self, *args, &block)
166
+ end
167
+
168
+ def flatten_merge(set, seen = Set.new) # :nodoc:
169
+ set.each { |e|
170
+ if e.is_a?(Set)
171
+ if seen.include?(e_id = e.object_id)
172
+ raise ArgumentError, "tried to flatten recursive Set"
173
+ end
174
+
175
+ seen.add(e_id)
176
+ flatten_merge(e, seen)
177
+ seen.delete(e_id)
178
+ else
179
+ add(e)
180
+ end
181
+ }
182
+
183
+ self
184
+ end
185
+ protected :flatten_merge
186
+
187
+ # Returns a new set that is a copy of the set, flattening each
188
+ # containing set recursively.
189
+ def flatten
190
+ self.class.new.flatten_merge(self)
191
+ end
192
+
193
+ # Equivalent to Set#flatten, but replaces the receiver with the
194
+ # result in place. Returns nil if no modifications were made.
195
+ def flatten!
196
+ if detect { |e| e.is_a?(Set) }
197
+ replace(flatten())
198
+ else
199
+ nil
200
+ end
201
+ end
202
+
203
+ # Returns true if the set contains the given object.
204
+ def include?(o)
205
+ @hash.include?(o)
206
+ end
207
+ alias member? include?
208
+
209
+ # Returns true if the set is a superset of the given set.
210
+ def superset?(set)
211
+ set.is_a?(Set) or raise ArgumentError, "value must be a set"
212
+ return false if size < set.size
213
+ set.all? { |o| include?(o) }
214
+ end
215
+ alias >= superset?
216
+
217
+ # Returns true if the set is a proper superset of the given set.
218
+ def proper_superset?(set)
219
+ set.is_a?(Set) or raise ArgumentError, "value must be a set"
220
+ return false if size <= set.size
221
+ set.all? { |o| include?(o) }
222
+ end
223
+ alias > proper_superset?
224
+
225
+ # Returns true if the set is a subset of the given set.
226
+ def subset?(set)
227
+ set.is_a?(Set) or raise ArgumentError, "value must be a set"
228
+ return false if set.size < size
229
+ all? { |o| set.include?(o) }
230
+ end
231
+ alias <= subset?
232
+
233
+ # Returns true if the set is a proper subset of the given set.
234
+ def proper_subset?(set)
235
+ set.is_a?(Set) or raise ArgumentError, "value must be a set"
236
+ return false if set.size <= size
237
+ all? { |o| set.include?(o) }
238
+ end
239
+ alias < proper_subset?
240
+
241
+ # Returns true if the set and the given set have at least one
242
+ # element in common.
243
+ def intersect?(set)
244
+ set.is_a?(Set) or raise ArgumentError, "value must be a set"
245
+ if size < set.size
246
+ any? { |o| set.include?(o) }
247
+ else
248
+ set.any? { |o| include?(o) }
249
+ end
250
+ end
251
+
252
+ # Returns true if the set and the given set have no element in
253
+ # common. This method is the opposite of +intersect?+.
254
+ def disjoint?(set)
255
+ !intersect?(set)
256
+ end
257
+
258
+ # Calls the given block once for each element in the set, passing
259
+ # the element as parameter. Returns an enumerator if no block is
260
+ # given.
261
+ def each(&block)
262
+ block or return enum_for(__method__)
263
+ @hash.each_key(&block)
264
+ self
265
+ end
266
+
267
+ # Adds the given object to the set and returns self. Use +merge+ to
268
+ # add many elements at once.
269
+ def add(o)
270
+ @hash[o] = true
271
+ self
272
+ end
273
+ alias << add
274
+
275
+ # Adds the given object to the set and returns self. If the
276
+ # object is already in the set, returns nil.
277
+ def add?(o)
278
+ if include?(o)
279
+ nil
280
+ else
281
+ add(o)
282
+ end
283
+ end
284
+
285
+ # Deletes the given object from the set and returns self. Use +subtract+ to
286
+ # delete many items at once.
287
+ def delete(o)
288
+ @hash.delete(o)
289
+ self
290
+ end
291
+
292
+ # Deletes the given object from the set and returns self. If the
293
+ # object is not in the set, returns nil.
294
+ def delete?(o)
295
+ if include?(o)
296
+ delete(o)
297
+ else
298
+ nil
299
+ end
300
+ end
301
+
302
+ # Deletes every element of the set for which block evaluates to
303
+ # true, and returns self.
304
+ def delete_if
305
+ block_given? or return enum_for(__method__)
306
+ # @hash.delete_if should be faster, but using it breaks the order
307
+ # of enumeration in subclasses.
308
+ select { |o| yield o }.each { |o| @hash.delete(o) }
309
+ self
310
+ end
311
+
312
+ # Deletes every element of the set for which block evaluates to
313
+ # false, and returns self.
314
+ def keep_if
315
+ block_given? or return enum_for(__method__)
316
+ # @hash.keep_if should be faster, but using it breaks the order of
317
+ # enumeration in subclasses.
318
+ reject { |o| yield o }.each { |o| @hash.delete(o) }
319
+ self
320
+ end
321
+
322
+ # Replaces the elements with ones returned by collect().
323
+ def collect!
324
+ block_given? or return enum_for(__method__)
325
+ set = self.class.new
326
+ each { |o| set << yield(o) }
327
+ replace(set)
328
+ end
329
+ alias map! collect!
330
+
331
+ # Equivalent to Set#delete_if, but returns nil if no changes were
332
+ # made.
333
+ def reject!(&block)
334
+ block or return enum_for(__method__)
335
+ n = size
336
+ delete_if(&block)
337
+ size == n ? nil : self
338
+ end
339
+
340
+ # Equivalent to Set#keep_if, but returns nil if no changes were
341
+ # made.
342
+ def select!(&block)
343
+ block or return enum_for(__method__)
344
+ n = size
345
+ keep_if(&block)
346
+ size == n ? nil : self
347
+ end
348
+
349
+ # Merges the elements of the given enumerable object to the set and
350
+ # returns self.
351
+ def merge(enum)
352
+ if enum.instance_of?(self.class)
353
+ @hash.update(enum.instance_variable_get(:@hash))
354
+ else
355
+ do_with_enum(enum) { |o| add(o) }
356
+ end
357
+
358
+ self
359
+ end
360
+
361
+ # Deletes every element that appears in the given enumerable object
362
+ # and returns self.
363
+ def subtract(enum)
364
+ do_with_enum(enum) { |o| delete(o) }
365
+ self
366
+ end
367
+
368
+ # Returns a new set built by merging the set and the elements of the
369
+ # given enumerable object.
370
+ def |(enum)
371
+ dup.merge(enum)
372
+ end
373
+ alias + | ##
374
+ alias union | ##
375
+
376
+ # Returns a new set built by duplicating the set, removing every
377
+ # element that appears in the given enumerable object.
378
+ def -(enum)
379
+ dup.subtract(enum)
380
+ end
381
+ alias difference - ##
382
+
383
+ # Returns a new set containing elements common to the set and the
384
+ # given enumerable object.
385
+ def &(enum)
386
+ n = self.class.new
387
+ do_with_enum(enum) { |o| n.add(o) if include?(o) }
388
+ n
389
+ end
390
+ alias intersection & ##
391
+
392
+ # Returns a new set containing elements exclusive between the set
393
+ # and the given enumerable object. (set ^ enum) is equivalent to
394
+ # ((set | enum) - (set & enum)).
395
+ def ^(enum)
396
+ n = Set.new(enum)
397
+ each { |o| if n.include?(o) then n.delete(o) else n.add(o) end }
398
+ n
399
+ end
400
+
401
+ # Returns true if two sets are equal. The equality of each couple
402
+ # of elements is defined according to Object#eql?.
403
+ def ==(other)
404
+ if self.equal?(other)
405
+ true
406
+ elsif other.instance_of?(self.class)
407
+ @hash == other.instance_variable_get(:@hash)
408
+ elsif other.is_a?(Set) && self.size == other.size
409
+ other.all? { |o| @hash.include?(o) }
410
+ else
411
+ false
412
+ end
413
+ end
414
+
415
+ def hash # :nodoc:
416
+ @hash.hash
417
+ end
418
+
419
+ def eql?(o) # :nodoc:
420
+ return false unless o.is_a?(Set)
421
+ @hash.eql?(o.instance_variable_get(:@hash))
422
+ end
423
+
424
+ # Classifies the set by the return value of the given block and
425
+ # returns a hash of {value => set of elements} pairs. The block is
426
+ # called once for each element of the set, passing the element as
427
+ # parameter.
428
+ #
429
+ # e.g.:
430
+ #
431
+ # require 'set'
432
+ # files = Set.new(Dir.glob("*.rb"))
433
+ # hash = files.classify { |f| File.mtime(f).year }
434
+ # p hash # => {2000=>#<Set: {"a.rb", "b.rb"}>,
435
+ # # 2001=>#<Set: {"c.rb", "d.rb", "e.rb"}>,
436
+ # # 2002=>#<Set: {"f.rb"}>}
437
+ def classify # :yields: o
438
+ block_given? or return enum_for(__method__)
439
+
440
+ h = {}
441
+
442
+ each { |i|
443
+ x = yield(i)
444
+ (h[x] ||= self.class.new).add(i)
445
+ }
446
+
447
+ h
448
+ end
449
+
450
+ # Divides the set into a set of subsets according to the commonality
451
+ # defined by the given block.
452
+ #
453
+ # If the arity of the block is 2, elements o1 and o2 are in common
454
+ # if block.call(o1, o2) is true. Otherwise, elements o1 and o2 are
455
+ # in common if block.call(o1) == block.call(o2).
456
+ #
457
+ # e.g.:
458
+ #
459
+ # require 'set'
460
+ # numbers = Set[1, 3, 4, 6, 9, 10, 11]
461
+ # set = numbers.divide { |i,j| (i - j).abs == 1 }
462
+ # p set # => #<Set: {#<Set: {1}>,
463
+ # # #<Set: {11, 9, 10}>,
464
+ # # #<Set: {3, 4}>,
465
+ # # #<Set: {6}>}>
466
+ def divide(&func)
467
+ func or return enum_for(__method__)
468
+
469
+ if func.arity == 2
470
+ require 'tsort'
471
+
472
+ class << dig = {} # :nodoc:
473
+ include TSort
474
+
475
+ alias tsort_each_node each_key
476
+ def tsort_each_child(node, &block)
477
+ fetch(node).each(&block)
478
+ end
479
+ end
480
+
481
+ each { |u|
482
+ dig[u] = a = []
483
+ each{ |v| func.call(u, v) and a << v }
484
+ }
485
+
486
+ set = Set.new()
487
+ dig.each_strongly_connected_component { |css|
488
+ set.add(self.class.new(css))
489
+ }
490
+ set
491
+ else
492
+ Set.new(classify(&func).values)
493
+ end
494
+ end
495
+
496
+ InspectKey = :__inspect_key__ # :nodoc:
497
+
498
+ # Returns a string containing a human-readable representation of the
499
+ # set. ("#<Set: {element1, element2, ...}>")
500
+ def inspect
501
+ ids = (Thread.current[InspectKey] ||= [])
502
+
503
+ if ids.include?(object_id)
504
+ return sprintf('#<%s: {...}>', self.class.name)
505
+ end
506
+
507
+ begin
508
+ ids << object_id
509
+ return sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
510
+ ensure
511
+ ids.pop
512
+ end
513
+ end
514
+
515
+ def pretty_print(pp) # :nodoc:
516
+ pp.text sprintf('#<%s: {', self.class.name)
517
+ pp.nest(1) {
518
+ pp.seplist(self) { |o|
519
+ pp.pp o
520
+ }
521
+ }
522
+ pp.text "}>"
523
+ end
524
+
525
+ def pretty_print_cycle(pp) # :nodoc:
526
+ pp.text sprintf('#<%s: {%s}>', self.class.name, empty? ? '' : '...')
527
+ end
528
+ end
529
+
530
+ #
531
+ # SortedSet implements a Set that guarantees that it's element are
532
+ # yielded in sorted order (according to the return values of their
533
+ # #<=> methods) when iterating over them.
534
+ #
535
+ # All elements that are added to a SortedSet must respond to the <=>
536
+ # method for comparison.
537
+ #
538
+ # Also, all elements must be <em>mutually comparable</em>: <tt>el1 <=>
539
+ # el2</tt> must not return <tt>nil</tt> for any elements <tt>el1</tt>
540
+ # and <tt>el2</tt>, else an ArgumentError will be raised when
541
+ # iterating over the SortedSet.
542
+ #
543
+ # == Example
544
+ #
545
+ # require "set"
546
+ #
547
+ # set = SortedSet.new([2, 1, 5, 6, 4, 5, 3, 3, 3])
548
+ # ary = []
549
+ #
550
+ # set.each do |obj|
551
+ # ary << obj
552
+ # end
553
+ #
554
+ # p ary # => [1, 2, 3, 4, 5, 6]
555
+ #
556
+ # set2 = SortedSet.new([1, 2, "3"])
557
+ # set2.each { |obj| } # => raises ArgumentError: comparison of Fixnum with String failed
558
+ #
559
+ class SortedSet < Set
560
+ @@setup = false
561
+
562
+ class << self
563
+ def [](*ary) # :nodoc:
564
+ new(ary)
565
+ end
566
+
567
+ def setup # :nodoc:
568
+ @@setup and return
569
+
570
+ module_eval {
571
+ # a hack to shut up warning
572
+ alias old_init initialize
573
+ }
574
+ begin
575
+ require 'rbtree'
576
+
577
+ module_eval %{
578
+ def initialize(*args)
579
+ @hash = RBTree.new
580
+ super
581
+ end
582
+
583
+ def add(o)
584
+ o.respond_to?(:<=>) or raise ArgumentError, "value must respond to <=>"
585
+ super
586
+ end
587
+ alias << add
588
+ }
589
+ rescue LoadError
590
+ module_eval %{
591
+ def initialize(*args)
592
+ @keys = nil
593
+ super
594
+ end
595
+
596
+ def clear
597
+ @keys = nil
598
+ super
599
+ end
600
+
601
+ def replace(enum)
602
+ @keys = nil
603
+ super
604
+ end
605
+
606
+ def add(o)
607
+ o.respond_to?(:<=>) or raise ArgumentError, "value must respond to <=>"
608
+ @keys = nil
609
+ super
610
+ end
611
+ alias << add
612
+
613
+ def delete(o)
614
+ @keys = nil
615
+ @hash.delete(o)
616
+ self
617
+ end
618
+
619
+ def delete_if
620
+ block_given? or return enum_for(__method__)
621
+ n = @hash.size
622
+ super
623
+ @keys = nil if @hash.size != n
624
+ self
625
+ end
626
+
627
+ def keep_if
628
+ block_given? or return enum_for(__method__)
629
+ n = @hash.size
630
+ super
631
+ @keys = nil if @hash.size != n
632
+ self
633
+ end
634
+
635
+ def merge(enum)
636
+ @keys = nil
637
+ super
638
+ end
639
+
640
+ def each(&block)
641
+ block or return enum_for(__method__)
642
+ to_a.each(&block)
643
+ self
644
+ end
645
+
646
+ def to_a
647
+ (@keys = @hash.keys).sort! unless @keys
648
+ @keys
649
+ end
650
+ }
651
+ end
652
+ module_eval {
653
+ # a hack to shut up warning
654
+ remove_method :old_init
655
+ }
656
+
657
+ @@setup = true
658
+ end
659
+ end
660
+
661
+ def initialize(*args, &block) # :nodoc:
662
+ SortedSet.setup
663
+ initialize(*args, &block)
664
+ end
665
+ end
666
+
667
+ module Enumerable
668
+ # Makes a set from the enumerable object with given arguments.
669
+ # Needs to +require "set"+ to use this method.
670
+ def to_set(klass = Set, *args, &block)
671
+ klass.new(self, *args, &block)
672
+ end
673
+ end
674
+
675
+ # =begin
676
+ # == RestricedSet class
677
+ # RestricedSet implements a set with restrictions defined by a given
678
+ # block.
679
+ #
680
+ # === Super class
681
+ # Set
682
+ #
683
+ # === Class Methods
684
+ # --- RestricedSet::new(enum = nil) { |o| ... }
685
+ # --- RestricedSet::new(enum = nil) { |rset, o| ... }
686
+ # Creates a new restricted set containing the elements of the given
687
+ # enumerable object. Restrictions are defined by the given block.
688
+ #
689
+ # If the block's arity is 2, it is called with the RestrictedSet
690
+ # itself and an object to see if the object is allowed to be put in
691
+ # the set.
692
+ #
693
+ # Otherwise, the block is called with an object to see if the object
694
+ # is allowed to be put in the set.
695
+ #
696
+ # === Instance Methods
697
+ # --- restriction_proc
698
+ # Returns the restriction procedure of the set.
699
+ #
700
+ # =end
701
+ #
702
+ # class RestricedSet < Set
703
+ # def initialize(*args, &block)
704
+ # @proc = block or raise ArgumentError, "missing a block"
705
+ #
706
+ # if @proc.arity == 2
707
+ # instance_eval %{
708
+ # def add(o)
709
+ # @hash[o] = true if @proc.call(self, o)
710
+ # self
711
+ # end
712
+ # alias << add
713
+ #
714
+ # def add?(o)
715
+ # if include?(o) || !@proc.call(self, o)
716
+ # nil
717
+ # else
718
+ # @hash[o] = true
719
+ # self
720
+ # end
721
+ # end
722
+ #
723
+ # def replace(enum)
724
+ # enum.respond_to?(:each) or raise ArgumentError, "value must be enumerable"
725
+ # clear
726
+ # enum.each_entry { |o| add(o) }
727
+ #
728
+ # self
729
+ # end
730
+ #
731
+ # def merge(enum)
732
+ # enum.respond_to?(:each) or raise ArgumentError, "value must be enumerable"
733
+ # enum.each_entry { |o| add(o) }
734
+ #
735
+ # self
736
+ # end
737
+ # }
738
+ # else
739
+ # instance_eval %{
740
+ # def add(o)
741
+ # if @proc.call(o)
742
+ # @hash[o] = true
743
+ # end
744
+ # self
745
+ # end
746
+ # alias << add
747
+ #
748
+ # def add?(o)
749
+ # if include?(o) || !@proc.call(o)
750
+ # nil
751
+ # else
752
+ # @hash[o] = true
753
+ # self
754
+ # end
755
+ # end
756
+ # }
757
+ # end
758
+ #
759
+ # super(*args)
760
+ # end
761
+ #
762
+ # def restriction_proc
763
+ # @proc
764
+ # end
765
+ # end
766
+
767
+ # Tests have been moved to test/test_set.rb.