1212#
1313# The element type is fixed at construction and never changes in place — it can
1414# neither be widened nor narrowed. `narrow` and `widen` return new instances.
15+ #
16+ # Methods that promise an element return `Literal::Undefined` when there is no
17+ # element to return — an out-of-bounds index, an empty array, a value that
18+ # isn't found — never `nil`. `nil` only ever appears when the element type
19+ # actually permits it. For a per-lookup fallback, pass a block —
20+ # `array[index] { fallback }` — or use `fetch` to raise on a missing index.
1521class Literal ::Array
1622 class Generic
1723 include Literal ::Type
@@ -142,19 +148,24 @@ def ==(other)
142148 Literal ::Array === other && @__value__ == other . __value__
143149 end
144150
145- def []( index , length = nil )
146- if length
147- slice = @__value__ [ index , length ]
148- slice && __with__ ( slice )
151+ # Returns the element or slice. When there is nothing at the index — out of
152+ # bounds, or a slice starting beyond the end — yields the index to the block
153+ # if one is given, and returns `Literal::Undefined` otherwise.
154+ def []( index , length = nil , &fallback )
155+ slice = if length
156+ @__value__ [ index , length ]
157+ elsif Range === index
158+ @__value__ [ index ]
149159 else
150- case index
151- when Range
152- slice = @__value__ [ index ]
153- slice && __with__ ( slice )
154- else
155- @__value__ [ index ]
156- end
160+ return @__value__ . fetch ( index , &fallback ) if fallback
161+
162+ return @__value__ . fetch ( index ) { Literal ::Undefined }
157163 end
164+
165+ return __with__ ( slice ) if slice
166+ return yield ( index ) if fallback
167+
168+ Literal ::Undefined
158169 end
159170
160171 def []=( index , value )
@@ -206,16 +217,22 @@ def count(...)
206217 @__value__ . count ( ...)
207218 end
208219
209- def delete ( ...)
210- @__value__ . delete ( ...)
220+ def delete ( value , &block )
221+ return @__value__ . delete ( value , &block ) if block
222+
223+ @__value__ . delete ( value ) { Literal ::Undefined }
211224 end
212225
213- def delete_at ( ...)
214- @__value__ . delete_at ( ...)
226+ def delete_at ( index )
227+ @__value__ . fetch ( index ) { return Literal ::Undefined }
228+
229+ @__value__ . delete_at ( index )
215230 end
216231
217- def dig ( ...)
218- @__value__ . dig ( ...)
232+ def dig ( index , *indexes )
233+ @__value__ . fetch ( index ) { return Literal ::Undefined }
234+
235+ @__value__ . dig ( index , *indexes )
219236 end
220237
221238 def drop ( n )
@@ -254,7 +271,10 @@ def filter_map(type, &block)
254271 end
255272
256273 def first ( n = nil )
257- n ? __with__ ( @__value__ . first ( n ) ) : @__value__ . first
274+ return __with__ ( @__value__ . first ( n ) ) if n
275+ return Literal ::Undefined if @__value__ . empty?
276+
277+ @__value__ . first
258278 end
259279
260280 def flat_map ( type , &block )
@@ -319,7 +339,10 @@ def join(...)
319339 end
320340
321341 def last ( n = nil )
322- n ? __with__ ( @__value__ . last ( n ) ) : @__value__ . last
342+ return __with__ ( @__value__ . last ( n ) ) if n
343+ return Literal ::Undefined if @__value__ . empty?
344+
345+ @__value__ . last
323346 end
324347
325348 def map ( type , &block )
@@ -354,23 +377,35 @@ def map!(&block)
354377 end
355378
356379 def max ( n = nil , &)
357- n ? __with__ ( @__value__ . max ( n , &) ) : @__value__ . max ( &)
380+ return __with__ ( @__value__ . max ( n , &) ) if n
381+ return Literal ::Undefined if @__value__ . empty?
382+
383+ @__value__ . max ( &)
358384 end
359385
360386 def max_by ( n = nil , &block )
361387 raise ArgumentError . new ( "#max_by requires a block." ) unless block
362388
363- n ? __with__ ( @__value__ . max_by ( n , &block ) ) : @__value__ . max_by ( &block )
389+ return __with__ ( @__value__ . max_by ( n , &block ) ) if n
390+ return Literal ::Undefined if @__value__ . empty?
391+
392+ @__value__ . max_by ( &block )
364393 end
365394
366395 def min ( n = nil , &)
367- n ? __with__ ( @__value__ . min ( n , &) ) : @__value__ . min ( &)
396+ return __with__ ( @__value__ . min ( n , &) ) if n
397+ return Literal ::Undefined if @__value__ . empty?
398+
399+ @__value__ . min ( &)
368400 end
369401
370402 def min_by ( n = nil , &block )
371403 raise ArgumentError . new ( "#min_by requires a block." ) unless block
372404
373- n ? __with__ ( @__value__ . min_by ( n , &block ) ) : @__value__ . min_by ( &block )
405+ return __with__ ( @__value__ . min_by ( n , &block ) ) if n
406+ return Literal ::Undefined if @__value__ . empty?
407+
408+ @__value__ . min_by ( &block )
374409 end
375410
376411 def minmax ( &)
@@ -431,7 +466,10 @@ def partition(&block)
431466 end
432467
433468 def pop ( n = nil )
434- n ? __with__ ( @__value__ . pop ( n ) ) : @__value__ . pop
469+ return __with__ ( @__value__ . pop ( n ) ) if n
470+ return Literal ::Undefined if @__value__ . empty?
471+
472+ @__value__ . pop
435473 end
436474
437475 # Returns a Literal::Array of Literal::Tuples with every combination of our
@@ -509,7 +547,10 @@ def rotate!(count = 1)
509547 end
510548
511549 def sample ( n = nil , random : Random )
512- n ? __with__ ( @__value__ . sample ( n , random :) ) : @__value__ . sample ( random :)
550+ return __with__ ( @__value__ . sample ( n , random :) ) if n
551+ return Literal ::Undefined if @__value__ . empty?
552+
553+ @__value__ . sample ( random :)
513554 end
514555
515556 def select ( &block )
@@ -526,7 +567,10 @@ def select!(&block)
526567 end
527568
528569 def shift ( n = nil )
529- n ? __with__ ( @__value__ . shift ( n ) ) : @__value__ . shift
570+ return __with__ ( @__value__ . shift ( n ) ) if n
571+ return Literal ::Undefined if @__value__ . empty?
572+
573+ @__value__ . shift
530574 end
531575
532576 def shuffle ( random : Random )
0 commit comments