motion_virtus 1.0.0.beta0

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.
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.