require_relative '../spec_helper' require 'dm-core/support/lazy_array' # only needed for specs module LazyArraySpec module GroupMethods def self.extended(base) base.class_inheritable_accessor :loaded end def subject(&block) let(:subject, &block) end def action(&block) let(:action, &block) end def should_respond_to(method) return if loaded it { expect(subject).to respond_to(method) } end def should_return_expected_value(&block) it 'returns expected value' do expect(action).to eql(instance_eval(&block)) end end def should_return_subject should_return_kind_of(LazyArray) it 'returns self' do expect(action).to equal(subject) end end def should_return_kind_of(klass) it { expect(action).to be_a_kind_of(klass) } end def should_return_copy it 'does not return self' do expect(action).not_to equal(subject) end it "eql's self" do expect(action).to eql(subject) end end def should_return_true it 'returns true' do expect(action).to be(true) end end def should_return_false it 'returns false' do expect(action).to be(false) end end def should_return_nil it 'returns nil' do expect(action).to be_nil end end def should_raise_error(klass, message = nil) it { expect { action }.to raise_error(klass, message) } end def should_clear_subject it 'clears self' do expect { action }.to change(subject, :empty?).from(false).to(true) end end def should_yield_to_each_entry it 'yields to each entry' do expect { action }.to change(@accumulator, :entries).from([]).to(subject.entries) end end def should_not_change_subject it 'does not change self' do # XXX: the following does not work with Array#delete_if, even when nothing removed (ruby bug?) # subject.freeze # expect { action }.not_to raise_error(RUBY_VERSION >= '1.9.0' ? RuntimeError : TypeError) expect { action }.not_to change(subject, :entries) end end def should_be_a_kicker return if loaded it 'is a kicker' do expect { action }.to change(subject, :loaded?).from(false).to(true) end end def should_not_be_a_kicker return if loaded it 'is not a kicker' do expect(subject).not_to be_loaded expect { action }.not_to change(subject, :loaded?) end end end end [ false, true ].each do |loaded| describe LazyArray do extend LazyArraySpec::GroupMethods self.loaded = loaded # message describing the object state state = "(#{'not ' unless loaded}loaded)" before do @nancy = 'nancy' @bessie = 'bessie' @steve = 'steve' @lazy_array = LazyArray.new @lazy_array.load_with { |la| la.push(@nancy, @bessie) } @other = LazyArray.new @other.load_with { |la| la.push(@steve) } @lazy_array.entries if loaded end subject { @lazy_array } it 'is an Enumerable' do expect((subject.is_a?(Enumerable))).to be(true) end describe 'when frozen', state do before { subject.freeze } it 'is still able to kick' do expect { subject.entries }.not_to raise_error end it 'does not allow any modifications' do expect { subject << @steve }.to raise_error((RUBY_VERSION >= '1.9.0') ? RuntimeError : TypeError) end end should_respond_to(:<<) describe '#<<' do action { subject << @steve } should_return_subject should_not_be_a_kicker it 'appends an entry' do expect((subject << @steve)).to eq [@nancy, @bessie, @steve] end end should_respond_to(:any?) describe '#any?', state do describe 'when not provided a block' do action { subject.any? } describe 'when the subject has entries that are not loaded' do should_return_true should_be_a_kicker should_not_change_subject end describe 'when the subject has entries that are prepended' do subject { LazyArray.new.unshift(@nancy) } should_return_true should_not_be_a_kicker should_not_change_subject end describe 'when the subject has entries that are appended' do subject { LazyArray.new << @nancy } should_return_true should_not_be_a_kicker should_not_change_subject end describe 'when the subject has no entries' do subject { LazyArray.new } should_return_false should_be_a_kicker should_not_change_subject end end describe 'when provided a block that always returns true' do action { subject.any? { true } } describe 'when the subject has entries that are not loaded' do should_return_true should_be_a_kicker should_not_change_subject end describe 'when the subject has entries that are prepended' do subject { LazyArray.new.unshift(@nancy) } should_return_true should_not_be_a_kicker should_not_change_subject end describe 'when the subject has entries that are appended' do subject { LazyArray.new << @nancy } should_return_true should_not_be_a_kicker should_not_change_subject end describe 'when the subject has no entries' do subject { LazyArray.new } should_return_false should_be_a_kicker should_not_change_subject end end end should_respond_to(:at) describe '#at', state do describe 'with positive index' do action { subject.at(0) } should_return_expected_value { @nancy } should_be_a_kicker should_not_change_subject end describe 'with positive index', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.at(0) } should_return_expected_value { @steve } should_not_be_a_kicker should_not_change_subject end describe 'with negative index' do action { subject.at(-1) } should_return_expected_value { @bessie } should_be_a_kicker should_not_change_subject end describe 'with negative index', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.at(-1) } should_return_expected_value { @steve } should_not_be_a_kicker should_not_change_subject end describe 'with an index not within the LazyArray' do action { subject.at(2) } should_return_nil should_be_a_kicker should_not_change_subject end end should_respond_to(:clear) describe '#clear', state do action { subject.clear } should_return_subject should_be_a_kicker # only marks as loadd, does not lazy load should_clear_subject end %i(collect! map!).each do |method| it { expect(@lazy_array).to respond_to(method) } describe "##{method}", state do before { @accumulator = [] } action { subject.send(method) { |e| @accumulator << e; @steve } } should_return_subject should_yield_to_each_entry should_be_a_kicker it 'updates with the block results' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@steve, @steve]) end end end should_respond_to(:concat) describe '#concat', state do action { subject.concat(@other) } should_return_subject should_not_be_a_kicker it 'concatenates other Enumerable' do expect(subject.concat(@other)).to eq [@nancy, @bessie, @steve] end end should_respond_to(:delete) describe '#delete', state do describe 'with an object within the LazyArray', state do action { subject.delete(@nancy) } should_return_expected_value { @nancy } should_be_a_kicker it 'removes the matching entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@bessie]) end end describe 'with an object not within the LazyArray', 'without a default block' do action { subject.delete(@steve) } should_return_nil should_not_change_subject should_be_a_kicker end describe 'with an object not within the LazyArray', 'with a default block' do action { subject.delete(@steve) { @steve } } should_return_expected_value { @steve } should_not_change_subject should_be_a_kicker end end should_respond_to(:delete_at) describe '#delete_at', state do describe 'with a positive index' do action { subject.delete_at(0) } should_return_expected_value { @nancy } should_be_a_kicker it 'removes the matching entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@bessie]) end end describe 'with a positive index', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.delete_at(0) } should_return_expected_value { @steve } should_not_be_a_kicker it 'removes the matching entry' do expect { action }.to change(subject, :entries).from([@steve, @nancy, @bessie]).to([@nancy, @bessie]) end end describe 'with a negative index' do action { subject.delete_at(-1) } should_return_expected_value { @bessie } should_be_a_kicker it 'removes the matching entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy]) end end describe 'with a negative index', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.delete_at(-1) } should_return_expected_value { @steve } should_not_be_a_kicker it 'removes the matching entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie, @steve]).to([@nancy, @bessie]) end end describe 'with an index not within the LazyArray' do action { subject.delete_at(2) } should_return_nil should_not_change_subject should_be_a_kicker end end should_respond_to(:delete_if) describe '#delete_if', state do before { @accumulator = [] } describe 'with a block that matches an entry' do action { subject.delete_if { |e| @accumulator << e; true } } should_return_subject should_yield_to_each_entry should_not_be_a_kicker it 'updates with the block results' do expect { action }.to change(subject, :empty?).from(false).to(true) end end describe 'with a block that does not match an entry' do action { subject.delete_if { |e| @accumulator << e; false } } should_return_subject should_yield_to_each_entry should_not_be_a_kicker should_not_change_subject end end should_respond_to(:dup) describe '#dup', state do action { subject.dup } should_return_kind_of(LazyArray) should_return_copy should_not_be_a_kicker if loaded it 'is loaded if subject loaded' do expect(action).to be_loaded end end end should_respond_to(:each) describe '#each', state do before { @accumulator = [] } action { subject.each { |e| @accumulator << e } } should_return_subject should_yield_to_each_entry should_be_a_kicker should_not_change_subject end should_respond_to(:each_index) describe '#each_index', state do before { @accumulator = [] } action { subject.each_index { |i| @accumulator << i } } should_return_subject should_be_a_kicker should_not_change_subject it 'yields to each index' do expect { action }.to change(@accumulator, :entries).from([]).to([0, 1]) end end should_respond_to(:each_with_index) describe '#each_with_index', state do before { @accumulator = [] } action { subject.each_with_index { |entry,index| @accumulator << [ entry, index ] } } should_return_subject should_be_a_kicker should_not_change_subject it 'yields to each entry and index' do expect { action }.to change(@accumulator, :entries).from([]).to([[@nancy, 0], [@bessie, 1]]) end end should_respond_to(:empty?) describe '#empty?', state do describe 'when the subject has entries that are not loaded' do action { subject.empty? } should_return_false should_be_a_kicker should_not_change_subject end describe 'when the subject has entries that are prepended' do subject { LazyArray.new.unshift(@nancy) } action { subject.empty? } should_return_false should_not_be_a_kicker should_not_change_subject end describe 'when the subject has entries that are appended' do subject { LazyArray.new << @nancy } action { subject.empty? } should_return_false should_not_be_a_kicker should_not_change_subject end describe 'when the subject has no entries' do subject { LazyArray.new } action { subject.empty? } should_return_true should_be_a_kicker should_not_change_subject end describe 'when the subject has only nil entries' do subject { LazyArray.new << nil } action { subject.empty? } should_return_false should_not_be_a_kicker should_not_change_subject end end [ :eql?, :== ].each do |method| should_respond_to(method) describe "##{method}", state do describe 'with an Enumerable containing the same entries' do before do if method == :eql? @other = LazyArray.new @other.load_with { |la| la.push(@nancy, @bessie) } else @other = [ @nancy, @bessie ] end end action { subject.send(method, @other) } should_return_true should_be_a_kicker should_not_change_subject end describe 'with an Enumerable containing different entries' do action { subject.send(method, @other) } should_return_false should_be_a_kicker should_not_change_subject end describe 'with an Enumerable with different entries than in head' do before { subject.unshift(@nancy) } action { subject.send(method, [ @steve ]) } should_return_false should_not_be_a_kicker should_not_change_subject end describe 'with an Enumerable with different entries than in tail' do before { subject.push(@nancy) } action { subject.send(method, [ @steve ]) } should_return_false should_not_be_a_kicker should_not_change_subject end end end should_respond_to(:fetch) describe '#fetch', state do describe 'with positive index' do action { subject.fetch(0) } should_return_expected_value { @nancy } should_be_a_kicker should_not_change_subject end describe 'with positive index', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.fetch(0) } should_return_expected_value { @steve } should_not_be_a_kicker should_not_change_subject end describe 'with negative index' do action { subject.fetch(-1) } should_return_expected_value { @bessie } should_be_a_kicker should_not_change_subject end describe 'with negative index', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.fetch(-1) } should_return_expected_value { @steve } should_not_be_a_kicker should_not_change_subject end describe 'with an index not within the LazyArray' do action { subject.fetch(2) } should_raise_error(IndexError) end describe 'with an index not within the LazyArray and default' do action { subject.fetch(2, @steve) } should_return_expected_value { @steve } should_be_a_kicker should_not_change_subject end describe 'with an index not within the LazyArray and default block' do action { subject.fetch(2) { @steve } } should_return_expected_value { @steve } should_be_a_kicker should_not_change_subject end end should_respond_to(:freeze) describe '#freeze', state do action { subject.freeze } should_return_subject should_not_be_a_kicker it { expect { action }.to change(subject, :frozen?).from(false).to(true) } end should_respond_to(:first) describe '#first', state do describe 'with no arguments' do action { subject.first } should_return_expected_value { @nancy } should_be_a_kicker should_not_change_subject end describe 'with no arguments', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.first } should_return_expected_value { @steve } should_not_be_a_kicker should_not_change_subject end describe 'with length specified' do action { subject.first(1) } it { expect(action).to eq [@nancy] } should_be_a_kicker should_not_change_subject end describe 'with length specified', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.first(1) } it { expect(action).to eq [@steve] } should_not_be_a_kicker should_not_change_subject end end should_respond_to(:include?) describe '#include?', state do describe 'with an included entry' do action { subject.include?(@nancy) } should_return_true should_be_a_kicker should_not_change_subject end describe 'with an included entry', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.include?(@steve) } should_return_true should_not_be_a_kicker should_not_change_subject end describe 'with an included entry', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.include?(@steve) } should_return_true should_not_be_a_kicker should_not_change_subject end describe 'with an entry not included' do action { subject.include?(@steve) } should_return_false should_be_a_kicker should_not_change_subject end end should_respond_to(:index) describe '#index', state do describe 'with an included entry' do action { subject.index(@nancy) } should_return_expected_value { 0 } should_be_a_kicker should_not_change_subject end describe 'with an included entry', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.index(@steve) } should_return_expected_value { 0 } should_not_be_a_kicker should_not_change_subject end describe 'with an included entry', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.index(@steve) } should_return_expected_value { 2 } should_be_a_kicker # need to kick because first index could be in lazy array should_not_change_subject end describe 'with an entry not included' do action { subject.index(@steve) } should_return_nil should_be_a_kicker should_not_change_subject end end should_respond_to(:insert) describe '#insert', state do describe 'with an index of 0' do action { subject.insert(0, @steve) } should_return_subject should_not_be_a_kicker it 'inserts the entries before the index' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@steve, @nancy, @bessie]) end end describe 'with an positive index greater than the head size' do action { subject.insert(1, @steve) } should_return_subject should_be_a_kicker it 'should insert the entries before the index' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @steve, @bessie]) end end describe 'with an index of -1' do action { subject.insert(-1, @steve) } should_return_subject should_not_be_a_kicker it 'should insert the entries before the index' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, @steve]) end end describe 'with a negative index greater than the tail size' do action { subject.insert(-2, @steve) } should_return_subject should_be_a_kicker it 'should insert the entries before the index' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @steve, @bessie]) end end describe 'with a positive index 1 greater than the maximum index of the LazyArray' do action { subject.insert(2, @steve) } should_return_subject should_be_a_kicker it 'inserts the entries before the index' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, @steve]) end end describe 'with a positive index not within the LazyArray' do action { subject.insert(3, @steve) } should_return_subject should_be_a_kicker it 'inserts the entries before the index, expanding the LazyArray' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, nil, @steve]) end end describe 'with a negative index 1 greater than the maximum index of the LazyArray' do action { subject.insert(-3, @steve) } should_return_subject should_be_a_kicker it 'inserts the entries before the index, expanding the LazyArray' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@steve, @nancy, @bessie]) end end describe 'with a negative index not within the LazyArray' do action { subject.insert(-4, @steve) } should_raise_error(IndexError) end end should_respond_to(:kind_of?) describe '#kind_of' do describe 'when provided a class that is a superclass' do action { subject.kind_of?(Object) } should_return_true should_not_be_a_kicker should_not_change_subject end describe 'when provided a class that is a proxy class superclass' do action { subject.kind_of?(Array) } should_return_true should_not_be_a_kicker should_not_change_subject end describe 'when provided a class that is not a superclass' do action { subject.kind_of?(Hash) } should_return_false should_not_be_a_kicker should_not_change_subject end end should_respond_to(:last) describe '#last', state do describe 'with no arguments' do action { subject.last } should_return_expected_value { @bessie } should_be_a_kicker should_not_change_subject end describe 'with no arguments', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.last } should_return_expected_value { @steve } should_not_be_a_kicker should_not_change_subject end describe 'with length specified' do action { subject.last(1) } it { expect(action).to eq [@bessie] } should_be_a_kicker should_not_change_subject end describe 'with length specified', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.last(1) } it { expect(action).to eq [@steve] } should_not_be_a_kicker should_not_change_subject end end should_respond_to(:loaded?) describe '#loaded?' do if loaded describe 'when loaded' do action { subject.loaded? } should_return_true should_not_change_subject end else describe 'when not loaded' do action { subject.loaded? } should_return_false should_not_change_subject end end end should_respond_to(:nil?) describe '#nil?' do action { subject.nil? } should_return_expected_value { false } should_not_be_a_kicker end should_respond_to(:pop) describe '#pop', state do describe 'without appending to the LazyArray' do action { subject.pop } should_return_expected_value { @bessie } should_be_a_kicker it 'removes the last entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy]) end end describe 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.pop } should_return_expected_value { @steve } should_not_be_a_kicker it 'removes the last entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie, @steve]).to([@nancy, @bessie]) end end end should_respond_to(:push) describe '#push', state do action { subject.push(@steve, @steve) } should_return_subject should_not_be_a_kicker it 'appends entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, @steve, @steve]) end end should_respond_to(:reject!) describe '#reject!', state do before { @accumulator = [] } describe 'with a block that matches an entry' do action { subject.reject! { |e| @accumulator << e; true } } should_return_subject should_yield_to_each_entry should_be_a_kicker it 'updates with the block results' do expect { action }.to change(subject, :empty?).from(false).to(true) end end describe 'with a block that does not match an entry' do action { subject.reject! { |e| @accumulator << e; false } } should_return_nil should_yield_to_each_entry should_be_a_kicker should_not_change_subject end end should_respond_to(:replace) describe '#replace' do action { subject.replace(@other) } should_return_subject should_be_a_kicker it 'replaces with other Enumerable' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@steve]) end end should_respond_to(:reverse) describe '#reverse', state do action { subject.reverse } should_return_kind_of(LazyArray) should_not_be_a_kicker should_not_change_subject it 'returns a reversed LazyArray' do expect(action).to eq [@bessie, @nancy] end end should_respond_to(:reverse!) describe '#reverse!', state do action { subject.reverse! } should_return_subject should_not_be_a_kicker it 'returns a reversed LazyArray' do expect(action).to eq [@bessie, @nancy] end end should_respond_to(:reverse_each) describe '#reverse_each', state do before { @accumulator = [] } action { subject.reverse_each { |e| @accumulator << e } } should_return_subject should_be_a_kicker should_not_change_subject it 'yields to each entry' do expect { action }.to change(@accumulator, :entries).from([]).to([@bessie, @nancy]) end end should_respond_to(:rindex) describe '#rindex', state do describe 'with an included entry' do action { subject.rindex(@nancy) } should_return_expected_value { 0 } should_be_a_kicker # rindex always a kicker should_not_change_subject end describe 'with an included entry', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.rindex(@steve) } should_return_expected_value { 0 } should_be_a_kicker # rindex always a kicker should_not_change_subject end describe 'with an included entry', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.rindex(@steve) } should_return_expected_value { 2 } should_be_a_kicker # rindex always a kicker should_not_change_subject end describe 'with an entry not included' do action { subject.rindex(@steve) } should_return_nil should_be_a_kicker # rindex always a kicker should_not_change_subject end end should_respond_to(:shift) describe '#shift', state do describe 'without prepending to the LazyArray' do action { subject.shift } should_return_expected_value { @nancy } should_be_a_kicker it 'removes the last entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@bessie]) end end describe 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.shift } should_return_expected_value { @steve } should_not_be_a_kicker it 'removes the last entry' do expect { action }.to change(subject, :entries).from([@steve, @nancy, @bessie]).to([@nancy, @bessie]) end end end [ :slice, :[] ].each do |method| should_respond_to(method) describe "##{method}", state do describe 'with a positive index' do action { subject.send(method, 0) } should_return_expected_value { @nancy } should_be_a_kicker should_not_change_subject end describe 'with a positive index', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.send(method, 0) } should_return_expected_value { @steve } should_not_be_a_kicker should_not_change_subject end describe 'with a positive index and length' do action { subject.send(method, 0, 1) } should_return_kind_of(Array) should_return_expected_value { [ @nancy ] } should_be_a_kicker should_not_change_subject end describe 'with a positive index and length', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.send(method, 0, 1) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker should_not_change_subject end describe 'with a positive range' do action { subject.send(method, 0..0) } should_return_kind_of(Array) should_return_expected_value { [ @nancy ] } should_be_a_kicker should_not_change_subject end describe 'with a positive range', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.send(method, 0..0) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker should_not_change_subject end describe 'with a negative index' do action { subject.send(method, -1) } should_return_expected_value { @bessie } should_be_a_kicker should_not_change_subject end describe 'with a negative index', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.send(method, -1) } should_return_expected_value { @steve } should_not_be_a_kicker should_not_change_subject end describe 'with a negative index and length' do action { subject.send(method, -1, 1) } should_return_kind_of(Array) should_return_expected_value { [ @bessie ] } should_be_a_kicker should_not_change_subject end describe 'with a negative index and length', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.send(method, -1, 1) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker should_not_change_subject end describe 'with a negative range' do action { subject.send(method, -1..-1) } should_return_kind_of(Array) should_return_expected_value { [ @bessie ] } should_be_a_kicker should_not_change_subject end describe 'with a negative range', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.send(method, -1..-1) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker should_not_change_subject end describe 'with an index not within the LazyArray' do action { subject.send(method, 2) } should_return_nil should_be_a_kicker should_not_change_subject end describe 'with an index and length not within the LazyArray' do action { subject.send(method, 2, 1) } should_return_kind_of(Array) should_return_expected_value { [] } should_be_a_kicker should_not_change_subject end describe 'with a range not within the LazyArray' do action { subject.send(method, 2..2) } should_return_kind_of(Array) should_return_expected_value { [] } should_be_a_kicker should_not_change_subject end describe 'with invalid arguments' do action { subject.send(method, 1, 1..1) } should_raise_error(ArgumentError) end end end should_respond_to(:slice!) describe '#slice!', state do describe 'with a positive index' do action { subject.slice!(0) } should_return_expected_value { @nancy } should_be_a_kicker it 'removes the matching entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@bessie]) end end describe 'with a positive index', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.slice!(0) } should_return_expected_value { @steve } should_not_be_a_kicker it 'removes the matching entry' do expect { action }.to change(subject, :entries).from([@steve, @nancy, @bessie]).to([@nancy, @bessie]) end end describe 'with a positive index and length' do action { subject.slice!(0, 1) } should_return_kind_of(Array) should_return_expected_value { [ @nancy ] } should_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@bessie]) end end describe 'with a positive index and length', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.slice!(0, 1) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@steve, @nancy, @bessie]).to([@nancy, @bessie]) end end describe 'with a positive range' do action { subject.slice!(0..0) } should_return_kind_of(Array) should_return_expected_value { [ @nancy ] } should_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@bessie]) end end describe 'with a positive range', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.slice!(0..0) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker it 'removes the matching entry' do expect { action }.to change(subject, :entries).from([@steve, @nancy, @bessie]).to([@nancy, @bessie]) end end describe 'with a negative index' do action { subject.slice!(-1) } should_return_expected_value { @bessie } should_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy]) end end describe 'with a negative index', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.slice!(-1) } should_return_expected_value { @steve } should_not_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie, @steve]).to([@nancy, @bessie]) end end describe 'with a negative index and length' do action { subject.slice!(-1, 1) } should_return_kind_of(Array) should_return_expected_value { [ @bessie ] } should_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy]) end end describe 'with a negative index and length', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.slice!(-1, 1) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie, @steve]).to([@nancy, @bessie]) end end describe 'with a negative range' do action { subject.slice!(-1..-1) } should_return_kind_of(Array) should_return_expected_value { [ @bessie ] } should_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy]) end end describe 'with a negative range', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.slice!(-1..-1) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker it 'removes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie, @steve]).to([@nancy, @bessie]) end end describe 'with an index not within the LazyArray' do action { subject.slice!(2) } should_return_nil should_be_a_kicker should_not_change_subject end describe 'with an index and length not within the LazyArray' do action { subject.slice!(2, 1) } should_return_kind_of(Array) should_return_expected_value { [] } should_be_a_kicker should_not_change_subject end describe 'with a range not within the LazyArray' do action { subject.slice!(2..2) } should_return_kind_of(Array) should_return_expected_value { [] } should_be_a_kicker should_not_change_subject end end should_respond_to(:sort!) describe '#sort!', state do describe 'without a block' do action { subject.sort! } should_return_subject should_be_a_kicker it 'sorts the LazyArray inline using default sort order' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@bessie, @nancy]) end end describe 'without a block' do action { subject.sort! { |a,b| a <=> b } } should_return_subject should_be_a_kicker it 'sorts the LazyArray inline using block' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@bessie, @nancy]) end end end [ :splice, :[]= ].each do |method| should_respond_to(method) describe "##{method}", state do before do @jon = 'jon' end describe 'with a positive index and entry' do action { subject.send(method, 0, @jon) } should_return_expected_value { @jon } should_be_a_kicker it 'changes the matching entry' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@jon, @bessie]) end end describe 'with a positive index', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.send(method, 0, @jon) } should_return_expected_value { @jon } should_not_be_a_kicker it 'changes the matching entry' do expect { action }.to change(subject, :entries).from([@steve, @nancy, @bessie]).to([@jon, @nancy, @bessie]) end end describe 'with a positive index and length' do action { subject.send(method, 0, 1, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@jon, @bessie]) end end describe 'with a positive index and length', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.send(method, 0, 1, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_not_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@steve, @nancy, @bessie]).to([@jon, @nancy, @bessie]) end end describe 'with a positive range' do action { subject.send(method, 0..0, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@jon, @bessie]) end end describe 'with a positive range', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.send(method, 0..0, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_not_be_a_kicker it 'changes the matching entry' do expect { action }.to change(subject, :entries).from([@steve, @nancy, @bessie]).to([@jon, @nancy, @bessie]) end end describe 'with a negative index' do action { subject.send(method, -1, @jon) } should_return_expected_value { @jon } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @jon]) end end describe 'with a negative index', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.send(method, -1, @jon) } should_return_expected_value { @jon } should_not_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie, @steve]).to([@nancy, @bessie, @jon]) end end describe 'with a negative index and length' do action { subject.send(method, -1, 1, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @jon]) end end describe 'with a negative index and length', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.send(method, -1, 1, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_not_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie, @steve]).to([@nancy, @bessie, @jon]) end end describe 'with a negative range' do action { subject.send(method, -1..-1, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @jon]) end end describe 'with a negative range', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.send(method, -1..-1, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_not_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie, @steve]).to([@nancy, @bessie, @jon]) end end describe 'with a positive index 1 greater than the maximum index of the LazyArray' do action { subject.send(method, 2, @jon) } should_return_expected_value { @jon } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, @jon]) end end describe 'with a positive index not within the LazyArray' do action { subject.send(method, 3, @jon) } should_return_expected_value { @jon } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, nil, @jon]) end end describe 'with a negative index not within the LazyArray' do action { subject.send(method, -3, @jon) } should_raise_error(IndexError) end describe 'with a positive index and length 1 greater than the maximum index of the LazyArray' do action { subject.send(method, 2, 1, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, @jon]) end end describe 'with a positive index and length not within the LazyArray' do action { subject.send(method, 3, 1, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, nil, @jon]) end end describe 'with a negative index and length not within the LazyArray ' do action { subject.send(method, -3, 1, [ @jon ]) } should_raise_error(IndexError) end describe 'with a positive range 1 greater than the maximum index of the LazyArray' do action { subject.send(method, 2..2, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, @jon]) end end describe 'with a positive range not within the LazyArray' do action { subject.send(method, 3..3, [ @jon ]) } should_return_kind_of(Array) should_return_expected_value { [ @jon ] } should_be_a_kicker it 'changes the matching entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@nancy, @bessie, nil, @jon]) end end describe 'with a negative range not within the LazyArray' do action { subject.send(method, -3..-3, [ @jon ]) } should_raise_error(RangeError) end end end should_respond_to(:to_a) describe '#to_a', state do action { subject.to_a } should_return_kind_of(Array) should_be_a_kicker it 'is equivalent to self' do expect(action).to eq subject end end should_respond_to(:unshift) describe '#unshift', state do action { subject.unshift(@steve, @steve) } should_return_subject should_not_be_a_kicker it 'prepends entries' do expect { action }.to change(subject, :entries).from([@nancy, @bessie]).to([@steve, @steve, @nancy, @bessie]) end end should_respond_to(:values_at) describe '#values_at', state do describe 'with a positive index' do action { subject.values_at(0) } should_return_kind_of(Array) should_return_expected_value { [ @nancy ] } should_be_a_kicker should_not_change_subject end describe 'with a positive index', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.values_at(0) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker should_not_change_subject end describe 'with a positive range' do action { subject.values_at(0..0) } should_return_kind_of(Array) should_return_expected_value { [ @nancy ] } should_be_a_kicker should_not_change_subject end describe 'with a positive range', 'after prepending to the LazyArray' do before { subject.unshift(@steve) } action { subject.values_at(0..0) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker should_not_change_subject end describe 'with a negative index' do action { subject.values_at(-1) } should_return_kind_of(Array) should_return_expected_value { [ @bessie ] } should_be_a_kicker should_not_change_subject end describe 'with a negative index', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.values_at(-1) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker should_not_change_subject end describe 'with a negative range' do action { subject.values_at(-1..-1) } should_return_kind_of(Array) should_return_expected_value { [ @bessie ] } should_be_a_kicker should_not_change_subject end describe 'with a negative range', 'after appending to the LazyArray' do before { subject.push(@steve) } action { subject.values_at(-1..-1) } should_return_kind_of(Array) should_return_expected_value { [ @steve ] } should_not_be_a_kicker should_not_change_subject end describe 'with an index not within the LazyArray' do action { subject.values_at(2) } should_return_kind_of(Array) should_return_expected_value { [ nil ] } should_be_a_kicker should_not_change_subject end describe 'with a range not within the LazyArray' do action { subject.values_at(2..2) } should_return_kind_of(Array) should_return_expected_value { [ nil ] } should_be_a_kicker should_not_change_subject end end describe 'a method mixed into Array' do before :all do Enumerable.class_eval do remove_method :lazy_spec if instance_methods(false).any? { |m| m.to_sym == :lazy_spec } def lazy_spec true end end end it 'delegates to the Array' do expect(subject.lazy_spec).to be(true) end end describe 'an unknown method' do action { subject.unknown } should_raise_error(NameError) end end end