diff --git a/lib/rackstash/fields/array.rb b/lib/rackstash/fields/array.rb index 78399a2..a52e3b4 100644 --- a/lib/rackstash/fields/array.rb +++ b/lib/rackstash/fields/array.rb @@ -268,6 +268,37 @@ module Rackstash end alias append push + # Removes the first element of `self` and returns it, shifting all other + # elements down by one. Returns `nil` if the array is empty. + # + # If a number `n` is given, returns an array of the first `n` elements (or + # fewer if the array contains fewer than `n` elements). Afterwards, `self` + # only contains the remainder elements, not including what was shifted to + # the returned array. See also {#unshift} for the opposite effect. + # + # @param n [Integer] the number of elements to shift. + # @return [Object, ::Array] the first element or an array of `n` or + # less elements if `n` is given + def shift(n = nil) + n.nil? ? @raw.shift : new(@raw.shift(n)) + end + + # Prepends objects to the front of `self`, moving other elements upwards. + # See also {#shift} for the opposite effect. + # + # @param values [::Array] a list of values to prepend to the front of + # `self` + # @param scope [Object, nil] if any of the (deeply-nested) values is a + # proc, it will be called in the instance scope of this object (when + # given). + # @return [self] + def unshift(*values, scope: nil) + values.map! { |value| normalize(value, scope: scope) } + @raw.unshift *values + self + end + alias prepend unshift + private def implicit(obj) diff --git a/spec/rackstash/fields/array_spec.rb b/spec/rackstash/fields/array_spec.rb index 24fed31..41454ab 100644 --- a/spec/rackstash/fields/array_spec.rb +++ b/spec/rackstash/fields/array_spec.rb @@ -356,6 +356,43 @@ describe Rackstash::Fields::Array do end end + describe '#unshift' do + it 'prepends objects' do + array[0] = 'first' + array.unshift('foo', 'bar') + + expect(array[0]).to eql 'foo' + expect(array[1]).to eql 'bar' + expect(array[2]).to eql 'first' + end + + it 'normalizes values with the scope' do + array.unshift -> { self + 3 }, scope: 2 + expect(array[0]).to eql 5 + end + end + + describe '#shift' do + before do + array[0] = 'value' + array[1] = 'foo' + array[2] = 'bar' + array[3] = 'baz' + end + + it 'shift a single value' do + expect(array.shift).to eql 'value' + expect(array[0]).to eql 'foo' + end + + it 'shift multiple values' do + expect(array.shift(3)) + .to be_instance_of(described_class) + .and contain_exactly('value', 'foo', 'bar') + expect(array[0]).to eql 'baz' + end + end + describe 'Converter' do it 'creates a new array' do raw = [Time.now, 'foo']