diff --git a/lib/rackstash/fields/array.rb b/lib/rackstash/fields/array.rb index f91a1e8..8cc16e0 100644 --- a/lib/rackstash/fields/array.rb +++ b/lib/rackstash/fields/array.rb @@ -126,6 +126,37 @@ module Rackstash @raw.length end + # Set Union — Add value from `array` to `self` excluding any duplicates + # and preserving the order from `self`. + # + # @param array [Array, ::Array, Proc] an array of values. Each value is + # normalized before being added to `self`. + # @param scope [Object, nil] if `array` or any of its (deeply-nested) + # values is a proc, it will be called in the instance scope of this + # object (when given). + # @return [self] + # + # @see #merge + def merge(array, scope: nil) + new(@raw | normalize(array, wrap: false, scope: scope)) + end + + # Set Union — Add value from `array` to `self` excluding any duplicates + # and preserving the order from `self`. + # + # @param array [Array, ::Array, Proc] an array of values. Each value is + # normalized before being added to `self`. + # @param scope [Object, nil] if `array` or any of its (deeply-nested) + # values is a proc, it will be called in the instance scope of this + # object (when given). + # @return [self] + # + # @see #merge + def merge!(array, scope: nil) + @raw.replace(@raw | normalize(array, wrap: false, scope: scope)) + self + end + private def Array(obj) diff --git a/spec/rackstash/fields/array_spec.rb b/spec/rackstash/fields/array_spec.rb index 111160c..ea9d34a 100644 --- a/spec/rackstash/fields/array_spec.rb +++ b/spec/rackstash/fields/array_spec.rb @@ -14,7 +14,8 @@ describe Rackstash::Fields::Array do it 'returns the addition of elements' do array[0] = 'existing' expect(array + ['existing', -> { 'new' }, [:nested]]) - .to contain_exactly 'existing', 'existing', 'new', ['nested'] + .to contain_exactly('existing', 'existing', 'new', ['nested']) + .and be_a(Rackstash::Fields::Array) end it 'returns a new Array' do @@ -225,6 +226,44 @@ describe Rackstash::Fields::Array do end end + describe '#merge' do + it 'returns the union of elements' do + array[0] = 'existing' + expect(array.merge ['new', :existing, -> { 123 }]) + .to contain_exactly('existing', 'new', 123) + .and be_a(Rackstash::Fields::Array) + end + + it 'returns a new Array' do + expect(array.merge [:foo]).to be_a(Rackstash::Fields::Array) + expect(array.merge [:foo]).not_to equal array + end + + it 'resolves nested procs with a custom scope' do + expect( + array.merge(-> { [self, -> { self.to_s.upcase } ] }, scope: :stuff) + ).to contain_exactly 'stuff', 'STUFF' + end + end + + describe '#merge!' do + it 'sets the union of elements to self' do + array[0] = 'existing' + expect(array.merge! ['new', :existing, -> { 123 }]) + .to contain_exactly 'existing', 'new', 123 + end + + it 'returns self' do + expect(array.merge! [:foo]).to equal array + end + + it 'resolves nested procs with a custom scope' do + expect( + array.merge!(-> { [self, -> { self.to_s.upcase } ] }, scope: :stuff) + ).to contain_exactly 'stuff', 'STUFF' + end + end + describe 'Converter' do it 'creates a new array' do raw = [Time.now, 'foo']