libis-workflow-mongoid 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,833 @@
1
+ module MapWithIndifferentAccess
2
+
3
+ class Map
4
+ extend Forwardable
5
+ include MapWithIndifferentAccess::WrapsCollection
6
+
7
+ def inject(*args, &block)
8
+ inner_map.inject(*args, &block)
9
+ end
10
+
11
+ def to_hash
12
+ inner_map.dup
13
+ end
14
+
15
+ # Try to convert `from_obj` into a {Map}.
16
+ #
17
+ # @return [Map]
18
+ # converted object if `from_obj` is convertible.
19
+ #
20
+ # @return [nil]
21
+ # if `from_obj` cannot be converted for any reason.
22
+ def self.try_convert(from_obj)
23
+ if self === from_obj
24
+ from_obj
25
+ else
26
+ hash = Hash.try_convert( from_obj )
27
+ new( hash ) if hash
28
+ end
29
+ end
30
+
31
+ # Try to convert `obj`, which might be a {Map} into a `Hash`.
32
+ #
33
+ # @return [Hash]
34
+ # converted object if `obj` is convertible.
35
+ #
36
+ # @return [nil]
37
+ # if `obj` cannot be converted for any reason.
38
+ def self.try_deconstruct(obj)
39
+ if self === obj
40
+ obj.inner_map
41
+ elsif obj.respond_to?(:to_hash )
42
+ h = obj.to_hash
43
+ Hash === h ? h : nil
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ # @!attribute inner_array
50
+ # @return [Array]
51
+ #
52
+ # Alias for {#inner_collection}. The encapsulated `Hash`
53
+ # instance.
54
+ alias inner_map inner_collection
55
+
56
+ # @!method to_h
57
+ #
58
+ # Alias for {#inner_collection}. Returns the
59
+ # encapsulated `Hash` instance.
60
+
61
+ # Use class_eval to hide the aliasing from Yard doc.
62
+ class_eval 'alias to_h inner_collection', __FILE__, __LINE__
63
+
64
+ # @!method keys
65
+ # Returns a new `Array` populated with the keys from this
66
+ # {Map}.
67
+ #
68
+ # @return [Array]
69
+ # @see #values
70
+
71
+ # @!method rehash
72
+ # Rebuilds the target's {#inner_map} `Hash` based on the
73
+ # current `#hash` values for each key. If values of key
74
+ # objects have changed since they were inserted, this will
75
+ # re-index that `Hash`.
76
+ #
77
+ # If {#rehash} is called while an iterator is traversing
78
+ # the {Map} or its {#inner_map} `Hash`, a `RuntimeError` will
79
+ # be raised in the iterator.
80
+ #
81
+ # @return [Map]
82
+
83
+ def_delegators(
84
+ :inner_map,
85
+ :keys,
86
+ :rehash,
87
+ )
88
+
89
+ # Initializes a new {Map} that encapsulates a new
90
+ # empty `Array` or the `Array` coerced from the given
91
+ # `basis`.
92
+ #
93
+ # When a {Map} is given as a basis, this results on the given
94
+ # and new instances sharing the same {#inner_map}. There is
95
+ # no obvious reason to do that on purpose, but there is also
96
+ # no likely harm in allowing it to happen.
97
+ #
98
+ # @param [::Hash, MapWithIndifferentAccess::Map, Object] basis
99
+ # A `Hash` or an object that can be implicitly coerced to a
100
+ # `::Hash`
101
+ def initialize(basis={})
102
+ use_basis = basis
103
+ use_basis = basis.inner_map if self.class === basis
104
+ use_basis = Hash.try_convert( use_basis )
105
+ raise ArgumentError, "Could not convert #{basis.inspect} into a Hash" unless use_basis
106
+ @inner_collection = use_basis
107
+ end
108
+
109
+ # Returns the `given_key` object if it is a key in the target's
110
+ # {#inner_map} `Hash` or if neither `given_key` nor its
111
+ # `String`/`Symbol` alternative is a key in the {#inner_map}.
112
+ #
113
+ # When `given_key` is a `String` that is not a key in the
114
+ # target's {#inner_map}, returns the symbolization of
115
+ # `given_key` if that symbolization _is_ a key in the
116
+ # {#inner_map}.
117
+ #
118
+ # When `given_key` is a `Symbol` that is not a key in the
119
+ # target's {#inner_map}, returns the stringification of
120
+ # `given_key` if that stringification _is_ a key in the
121
+ # {#inner_map}.
122
+ def conform_key(given_key)
123
+ case given_key
124
+ when String
125
+ alt_key = inner_map.key?( given_key ) ? given_key : given_key.to_sym
126
+ inner_map.key?( alt_key ) ? alt_key : given_key
127
+ when Symbol
128
+ alt_key = inner_map.key?( given_key ) ? given_key : "#{given_key}"
129
+ inner_map.key?( alt_key ) ? alt_key : given_key
130
+ else
131
+ given_key
132
+ end
133
+ end
134
+
135
+ # @!method any?
136
+ # Iterates over entries in the target {Map}, passing a
137
+ # _`[ key, externalized_value ]`_ `Array` to the block
138
+ # for each of those, and returns `true` when the block
139
+ # returns `true` for any entry.
140
+ #
141
+ # @return [Boolean]
142
+ #
143
+ # @overload any?
144
+ # @yieldparam [Array<(Object, Object)>] pair
145
+ # `[ key, externalized_value ]`
146
+ #
147
+ # @overload any?
148
+ # Due to the behavior of `Enumerable::any?` when no block
149
+ # is given, this is effectively synonymous with
150
+ # `!target_map.empty?`.
151
+ #
152
+ # @see #each
153
+ # @see Enumerable::any?
154
+
155
+
156
+ # Creates an entry or replaces the value of an existing entry
157
+ # in the target's {#inner_map} `Hash`.
158
+ #
159
+ # When the `key` conforms to a key in the target map, then the
160
+ # value of the matching entry in the target's {#inner_map} is
161
+ # replaced with the internalization of `value`.
162
+ #
163
+ # When `key` does not conform to a key in the target map, then
164
+ # a new entry is added using the given `key` and the
165
+ # internalization of `value`.
166
+ #
167
+ # Returns the given `value`.
168
+ #
169
+ # @see #conform_key
170
+ # @see Values.internalize
171
+ def[]=(key, value)
172
+ key = conform_key( key )
173
+ intern_value = Values << value
174
+ inner_map[ key ] = intern_value
175
+ value
176
+ end
177
+
178
+ alias store []=
179
+
180
+ # Returns the externalization of the value from the target's
181
+ # {#inner_map} entry having a key that conforms to the given
182
+ # `key` if applicable.
183
+ #
184
+ # When there is no entry with a conforming key, returns the
185
+ # externalization of the {#inner_map} `Hash`'s default value
186
+ # for the given `key` (normally `nil`).
187
+ #
188
+ # @see #conform_key
189
+ # @see Values.externalize
190
+ def[](key)
191
+ key = conform_key( key )
192
+ value = inner_map[ key ]
193
+ Values >> value
194
+ end
195
+
196
+ def fetch(key, *more_args)
197
+ expect_arity 1..2, key, *more_args
198
+ if block_given? && !more_args.empty?
199
+ warn "#{caller[ 0 ]}: warning: block supersedes default value argument"
200
+ end
201
+
202
+ conformed_key = conform_key( key )
203
+
204
+ value = if inner_map.key?( conformed_key )
205
+ inner_map.fetch( conformed_key )
206
+ elsif block_given?
207
+ inner_map.fetch( key ) {|key| yield key }
208
+ else
209
+ inner_map.fetch( key, *more_args )
210
+ end
211
+
212
+ Values >> value
213
+ end
214
+
215
+ # Return a {List} containing the values of entries matching
216
+ # the given keys.
217
+ #
218
+ # @return [List]
219
+ def values_at(*keys)
220
+ keys = keys.map{ |k| conform_key( k ) }
221
+ inner_result = inner_map.values_at( *keys )
222
+ List.new( inner_result )
223
+ end
224
+
225
+ # Returns `true` if the conformation of `key` is present in
226
+ # the target {Map}.
227
+ #
228
+ # @return [Boolean]
229
+ def key?(key)
230
+ case key
231
+ when String
232
+ inner_map.key?( key ) || inner_map.key?( key.to_sym )
233
+ when Symbol
234
+ inner_map.key?( key ) || inner_map.key?("#{key}")
235
+ else
236
+ inner_map.key?( key )
237
+ end
238
+ end
239
+
240
+ alias has_key? key?
241
+ alias include? key?
242
+ alias member? key?
243
+
244
+ # Returns the key for an entry, the externalization of which
245
+ # is equal to the externalization of `value`. Returns `nil`
246
+ # if no match is found.
247
+ #
248
+ # @return [Object, nil]
249
+ #
250
+ # @see Values.externalize
251
+ def key(value)
252
+ entry = rassoc( value )
253
+ entry ? entry.first : nil
254
+ end
255
+
256
+ # Sets the default value returned from the target's
257
+ # {#inner_map} `Hash` for a key that does not exist to
258
+ # be the internlization of `obj`.
259
+ def default=(obj)
260
+ inner_map.default = Values << obj
261
+ end
262
+
263
+ # Returns the default value, the value that would be returned
264
+ # by `<target>[key]` if the conformation of `key` did not exist
265
+ # in the target.
266
+ #
267
+ # @see #conform_key
268
+ def default(key = nil)
269
+ inner_default = inner_map.default( key )
270
+ Values >> inner_default
271
+ end
272
+
273
+ # Sets the {#inner_map} `Hash`'s default proc to a wrapper
274
+ # around `proc_obj` that passes the target {Map} and the key
275
+ # as parameters and returns the internalization of the
276
+ # wrapped proc's block.
277
+ #
278
+ # When running in Ruby 2.x or newer, the default proc can
279
+ # also be cleared by passing `nil` for `proc_obj`.
280
+ #
281
+ # @param proc_obj [Proc, nil]
282
+ # @see Hash#default_proc=
283
+ def default_proc=(proc_obj)
284
+ inner_proc = ->(_, key){
285
+ Values << proc_obj.call( self, key )
286
+ }
287
+ inner_map.default_proc = inner_proc
288
+ self._default_proc = proc_obj
289
+ self._inner_proc_for_default_proc = inner_proc
290
+ proc_obj
291
+ end
292
+
293
+ # If the target {Map}'s {#inner_map} `Hash` does not have a
294
+ # default proc assigned, then this returns `nil`.
295
+ #
296
+ # If `Proc` has been previously assigned to the target {Map}
297
+ # using {#default_proc=} and is is still applicable, then
298
+ # that `Proc` is returned.
299
+ #
300
+ # If no `Proc` was assigned to the target {Map} or that
301
+ # assignment is no longer applicable, but the {#inner_map}
302
+ # `Hash` has a default proc, then a wrapper around that
303
+ # `Proc` is returned that accepts a `Map` or `Hash`-like
304
+ # object and a key, passing the `Map`-deconstruction of the
305
+ # `Map`/`Hash` and the unmodified key value to the underlying
306
+ # `Proc`, finally returning the externalization of the value
307
+ # returned from the call to the underlying `Proc`.
308
+ #
309
+ # @return (Proc, nil)
310
+ def default_proc
311
+ return nil unless inner_map.default_proc
312
+ unless inner_map.default_proc.equal?( _inner_proc_for_default_proc )
313
+ self._default_proc = nil
314
+ end
315
+ return _default_proc if _default_proc
316
+ _default_proc = ->(map,key){
317
+ hash = self.class.try_deconstruct( map )
318
+ value = inner_map.default_proc.call( hash, key )
319
+ Values >> value
320
+ }
321
+ end
322
+
323
+ # Returns `true` if the entries in `other` (a {Map}, `Hash`,
324
+ # or other `Hash`-like object) are equal in numer and
325
+ # equivalent to the entries in the target {Map}.
326
+ #
327
+ # Entries are equivalent if their keys are equivalent with
328
+ # `String`/`Symbolic` indifference and their externalized
329
+ # values are equal using `==`.
330
+ #
331
+ # @return [Boolean]
332
+ def ==(other)
333
+ return true if equal?( other )
334
+ other = self.class.try_convert( other )
335
+ return false unless other
336
+
337
+ return true if inner_map == other.inner_map
338
+ return false if length != other.length
339
+ each do |(key, value)|
340
+ other_val = other.fetch(key) { return false }
341
+ return false unless value == other_val
342
+ end
343
+
344
+ true
345
+ end
346
+
347
+ # When a block argument is given, calls the block once for
348
+ # each of the target's entries, passing the entry's key and
349
+ # externalized value as parameters, and then returns the
350
+ # target object.
351
+ #
352
+ # When no block argument is given, returns an `Enumerator`.
353
+ #
354
+ # @overload each
355
+ # @yieldparam key
356
+ # @yieldparam value
357
+ # @return [MapWithIndifferentAccess::Map]
358
+ #
359
+ # @overload each
360
+ # @return [Enumerator]
361
+ def each
362
+ return to_enum(:each ) unless block_given?
363
+
364
+ each_key do |key|
365
+ value = fetch( key )
366
+ value = Values >> value
367
+ yield [key, value]
368
+ end
369
+ end
370
+
371
+ alias each_pair each
372
+
373
+ # When a block argument is given, calls the block once for each of the
374
+ # target's keys, passing the key as a parameter, and then returns the
375
+ # target object.
376
+ #
377
+ # When no block argument is given, returns an `Enumerator`.
378
+ #
379
+ # @return [MapWithIndifferentAccess::Map]
380
+ def each_key
381
+ return to_enum(:each_key ) unless block_given?
382
+ inner_map.each_key do |key|
383
+ yield key
384
+ end
385
+ self
386
+ end
387
+
388
+ # When a block argument is given, calls the block once for each of the
389
+ # target's entries, passing externalization the entry value as a parameter,
390
+ # and then returns the target.
391
+ #
392
+ # When no block argument is given, returns an `Enumerator`.
393
+ #
394
+ # @return [MapWithIndifferentAccess::Map]
395
+ def each_value
396
+ return to_enum(:each_value) unless block_given?
397
+
398
+ inner_map.each_value do |value|
399
+ value = Values >> value
400
+ yield value
401
+ end
402
+ self
403
+ end
404
+
405
+ # Returns a {List} containing the entry values from the target {Map}.
406
+ #
407
+ # @return [List]
408
+ def values
409
+ List.new( inner_map.values )
410
+ end
411
+
412
+ # Delete the externalization of the value associated with the
413
+ # conformation of the given `key` or default value.
414
+ #
415
+ # @overload delete(key)
416
+ # Returns the externalization of the value returned from
417
+ # the {#inner_map} `Hash` on deletion.
418
+ #
419
+ # @overload delete(key)
420
+ # @yieldparam key
421
+ #
422
+ # Returns the externalization of the value returned by the
423
+ # given block for the given `key`.
424
+ #
425
+ # @see #conform_key
426
+ # @see Values.externalize
427
+ def delete(key)
428
+ key = conform_key( key )
429
+ value = if block_given?
430
+ inner_map.delete( key ) { |key| yield key }
431
+ else
432
+ inner_map.delete( key )
433
+ end
434
+ Values >> value
435
+ end
436
+
437
+ # Returns a new {Map} consisting of entries for which the
438
+ # block returns `false`, given the entry's key and
439
+ # externalized value.
440
+ #
441
+ # If no block is given, then an `Enumerator` is returned
442
+ # instead.
443
+ #
444
+ # @overload reject
445
+ # @yieldparam key
446
+ # @return [Map]
447
+ #
448
+ # @overload reject
449
+ # @return [Enumerator]
450
+ #
451
+ # @see Values.externalize
452
+ def reject
453
+ return to_enum(:reject ) unless block_given?
454
+
455
+ dup.delete_if{ |key, value|
456
+ yield( key, value )
457
+ }
458
+ end
459
+
460
+ # Equivalent to {#delete_if}, but returns `nil` if no changes
461
+ # were made.
462
+ #
463
+ # @overload reject!
464
+ # @yieldparam key
465
+ # @yieldparam value
466
+ # @return [Map, nil]
467
+ #
468
+ # @overload reject!
469
+ # @return [Enumerator]
470
+ #
471
+ # @see #delete_if
472
+ def reject!
473
+ return to_enum(:reject!) unless block_given?
474
+
475
+ has_rejections = false
476
+ delete_if{ |key, value|
477
+ is_rejected = yield( key, value )
478
+ has_rejections ||= is_rejected
479
+ is_rejected
480
+ }
481
+
482
+ has_rejections ? self : nil
483
+ end
484
+
485
+ # Deletes every entry for which the block evaluates to
486
+ # `true` given the entry's key and externalized value.
487
+ #
488
+ # If no block is given, then an `Enumerator` is returned
489
+ # instead.
490
+ #
491
+ # @overload delete_if
492
+ # @yieldparam key
493
+ # @yieldparam value
494
+ # @return [Map]
495
+ #
496
+ # @overload delete_if
497
+ # @return [Enumerator]
498
+ #
499
+ # @see Values.externalize
500
+ def delete_if
501
+ return to_enum(:delete_if ) unless block_given?
502
+
503
+ inner_map.delete_if do |key, value|
504
+ value = Values >> value
505
+ yield key, value
506
+ end
507
+
508
+ self
509
+ end
510
+
511
+ # Returns a new {Map} consisting of entries for which the
512
+ # block returns `true`, given the entry's key and
513
+ # externalized value.
514
+ #
515
+ # If no block is given, then an `Enumerator` is returned
516
+ # instead.
517
+ #
518
+ # @overload select
519
+ # @yieldparam key
520
+ # @return [Map]
521
+ #
522
+ # @overload select
523
+ # @return [Enumerator]
524
+ #
525
+ # @see Values.externalize
526
+ def select
527
+ return to_enum(:select ) unless block_given?
528
+
529
+ dup.keep_if{ |key, value|
530
+ yield( key, value )
531
+ }
532
+ end
533
+
534
+ # Equivalent to {#keep_if}, but returns `nil` if no changes
535
+ # were made.
536
+ #
537
+ # @overload select!
538
+ # @yieldparam key
539
+ # @yieldparam value
540
+ # @return [Map, nil]
541
+ #
542
+ # @overload select!
543
+ # @return [Enumerator]
544
+ #
545
+ # @see #keep_if
546
+ def select!
547
+ return to_enum(:select!) unless block_given?
548
+
549
+ has_rejections = false
550
+ keep_if{ |key, value|
551
+ is_selected = yield( key, value )
552
+ has_rejections ||= ! is_selected
553
+ is_selected
554
+ }
555
+
556
+ has_rejections ? self : nil
557
+ end
558
+
559
+ # Deletes every entry for which the block evaluates to
560
+ # `false`, given the entry's key and externalized value.
561
+ #
562
+ # If no block is given, then an `Enumerator` is returned
563
+ # instead.
564
+ #
565
+ # @overload keep_if
566
+ # @yieldparam key
567
+ # @yieldparam value
568
+ # @return [Map]
569
+ #
570
+ # @overload keep_if
571
+ # @return [Enumerator]
572
+ #
573
+ # @see Values.externalize
574
+ def keep_if
575
+ return to_enum(:keep_if ) unless block_given?
576
+
577
+ inner_map.keep_if do |key, value|
578
+ value = Values >> value
579
+ yield key, value
580
+ end
581
+
582
+ self
583
+ end
584
+
585
+ # Replace the contents of the target's {#inner_map} `Hash`
586
+ # with the deconstruction of the given `Hash`-like object.
587
+ #
588
+ # @return [Map]
589
+ #
590
+ # @see .try_deconstruct
591
+ def replace(other)
592
+ other_d = self.class.try_deconstruct( other ) || other
593
+ inner_map.replace other_d
594
+ return self
595
+ end
596
+
597
+ # Searches through the map, comparing the conformation of
598
+ # `obj` with each entry's key using `==`. Returns a 2-element
599
+ # array containing the key and externalized value from the
600
+ # matching element or returns or `nil` if no match is found.
601
+ #
602
+ # @return [Array, nil]
603
+ #
604
+ # @see #rassoc
605
+ # @see #conform_key
606
+ def assoc(obj)
607
+ obj = conform_key( obj )
608
+ entry = inner_map.assoc( obj )
609
+ unless entry.nil?
610
+ value = Values >> entry[ 1 ]
611
+ entry[ 1 ] = value
612
+ end
613
+ entry
614
+ end
615
+
616
+ # Returns `true` if the internalization of `value` is present
617
+ # for some key in the target.
618
+ #
619
+ # @return [Boolean]
620
+ #
621
+ # @see Values.internalize
622
+ def has_value?(value)
623
+ value = Values >> value
624
+ each_value.any? { |v| v == value }
625
+ end
626
+
627
+ alias value? has_value?
628
+
629
+ # Searches through the map, comparing the externalization of
630
+ # `value` with the externalized value of each entry using
631
+ # `==.` Returns a 2-element array containing the key and
632
+ # externalized value from the matching element or returns or
633
+ # `nil` if no match is found.
634
+ #
635
+ # @return [Array, nil]
636
+ #
637
+ # @see #assoc
638
+ # @see Values.externalize
639
+ def rassoc(value)
640
+ value = Values >> value
641
+ entry = inner_map.detect { |(k, v)|
642
+ v = Values >> v
643
+ value == v
644
+ }
645
+ if entry
646
+ entry[ 1 ] = Values >> entry[ 1 ]
647
+ entry
648
+ else
649
+ nil
650
+ end
651
+ end
652
+
653
+ # Returns a new {Map} containing the contents of `other` (a
654
+ # {Map}, `Hash`, or other `Hash`-like object) and of the
655
+ # target {Map}.
656
+ #
657
+ # Each entry in `other` with key that is equivalent to a key
658
+ # in the target (with `String`/`Symbol` indifference) is
659
+ # treated as a collision.
660
+ #
661
+ # @overload merge(other)
662
+ # Each collision produces an entry with its key from the
663
+ # entry in target and its value from the entry in
664
+ # `other`.
665
+ #
666
+ # @overload merge(other)
667
+ # @yieldparam key
668
+ # The key from the target-side colliding entry.
669
+ #
670
+ # @yieldparam oldval
671
+ # The externalization of value from the target-side
672
+ # colliding entry.
673
+ #
674
+ # @yieldparam newval
675
+ # The externalization of value from the `other`-side
676
+ # colliding entry.
677
+ #
678
+ # Each collision produces an entry with its key from the
679
+ # target-side entry and its value from the internalization
680
+ # of the block call result.
681
+ #
682
+ # @return [Map]
683
+ #
684
+ # @see #merge!
685
+ # @see Values.externalize
686
+ # @see Values.internalize
687
+ def merge(other)
688
+ if block_given?
689
+ dup.merge!( other ){ |*args| yield *args }
690
+ else
691
+ dup.merge!( other )
692
+ end
693
+ end
694
+
695
+ # Adds the contents of `other` (a {Map}, `Hash`, or other
696
+ # `Hash`-like object) to the target {Map}.
697
+ #
698
+ # Each entry in `other` with key that is equivalent to a key
699
+ # in the target (with `String`/`Symbol` indifference) is
700
+ # treated as a collision.
701
+ #
702
+ # @overload merge!(other)
703
+ # Each collision produces an entry with its key from the
704
+ # entry in target and its value from the entry in
705
+ # `other`.
706
+ #
707
+ # @overload merge!(other)
708
+ # @yieldparam key
709
+ # The key from the target-side colliding entry.
710
+ #
711
+ # @yieldparam oldval
712
+ # The externalization of value from the target-side
713
+ # colliding entry.
714
+ #
715
+ # @yieldparam newval
716
+ # The externalization of value from the `other`-side
717
+ # colliding entry.
718
+ #
719
+ # Each collision produces an entry with its key from the
720
+ # target-side entry and its value from the internalization
721
+ # of the block call result.
722
+ #
723
+ # @return [Map]
724
+ #
725
+ # @see #merge
726
+ # @see Values.externalize
727
+ # @see Values.internalize
728
+ def merge!(other)
729
+ other.each_pair do |(key, value)|
730
+ key = conform_key( key )
731
+ if block_given? && inner_map.key?(key)
732
+ self[key] = yield( key, self[key], value )
733
+ else
734
+ self[key] = value
735
+ end
736
+ end
737
+ self
738
+ end
739
+
740
+ alias update merge!
741
+
742
+ # Removes an entry from the target {Map} and returns a 2-item
743
+ # `Array` _`[ <key>, <externalized value> ]`_ or the
744
+ # externalization of the {Map}'s default value if it is
745
+ # empty.
746
+ #
747
+ # Yes, the behavior when the behavior for an empty {Map} with
748
+ # a non-`nil` default is weird and troublesome, but it is
749
+ # parallel to the similarly weird behavior of `Hash#shift`.
750
+ #
751
+ # @return [Array,Object]
752
+ #
753
+ # @see Values.externalize
754
+ def shift
755
+ if inner_map.empty?
756
+ Values >> inner_map.shift
757
+ else
758
+ inner_result = inner_map.shift
759
+ [
760
+ inner_result[ 0 ],
761
+ Values >> inner_result[ 1 ]
762
+ ]
763
+ end
764
+ end
765
+
766
+ # Returns a new {Map} with an {#inner_map} `Hash` created by
767
+ # using the the target's {#inner_map}'s values as keys and
768
+ # keys as values.
769
+ #
770
+ # @return [Map]
771
+ def invert
772
+ self.class.new( inner_map.invert )
773
+ end
774
+
775
+ # Makes the target's {#inner_map} `Hash` compare its keys by
776
+ # their identities, i.e. it will consider exact same objects
777
+ # as same keys.
778
+ #
779
+ # Not particularly useful for a {Map}, but included for
780
+ # conformance with the `Hash` API.
781
+ #
782
+ # @return [Map]
783
+ def compare_by_identity
784
+ inner_map.compare_by_identity
785
+ self
786
+ end
787
+
788
+ # @!method compare_by_identity?
789
+ # Returns true if the target's {#inner_map} `Hash` will
790
+ # compare its keys by their identities.
791
+ #
792
+ # Not particularly useful for a {Map}, but included for
793
+ # conformance with the `Hash` API.
794
+ #
795
+ # @return [Boolean]
796
+ #
797
+ # @see #compare_by_identity
798
+ def_delegator :inner_map, :compare_by_identity?
799
+
800
+ # Returns a new {List} containing one-dimensional flattening
801
+ # of the target {Map}. That is, for every key or value that
802
+ # is an `Array` in the {#inner_map} `Hash`, extract its
803
+ # elements into the new {List}.
804
+ #
805
+ # Unlike `Array#flatten` or {List#flatten}, this method does
806
+ # not flatten recursively by default. The optional level
807
+ # argument determines the level of recursion to flatten.
808
+ #
809
+ # @return [List]
810
+ #
811
+ # @overload flatten
812
+ #
813
+ # @overload flatten(level)
814
+ # @param level [Fixnum]
815
+ #
816
+ def flatten(*args)
817
+ List.new( inner_map.flatten(*args) )
818
+ end
819
+
820
+ private
821
+
822
+ attr_accessor \
823
+ :_default_proc,
824
+ :_inner_proc_for_default_proc
825
+
826
+ def expect_arity(arity, *args)
827
+ unless arity === args.length
828
+ raise ArgumentError, "wrong number of arguments (#{args.length} for #{arity})"
829
+ end
830
+ end
831
+ end
832
+
833
+ end