libis-workflow-mongoid 2.0.2 → 2.0.3

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