spec/memoized_spec.rb in memoized-1.1.0 vs spec/memoized_spec.rb in memoized-1.1.1

- old
+ new

@@ -1,11 +1,17 @@ class MemoizedSpecClass include Memoized def no_params() Date.today; end def with_params?(ndays, an_array) Date.today + ndays + an_array.length; end def returning_nil!() Date.today; nil; end - memoize :no_params, :with_params?, :returning_nil! + def all_param_types(req, opt = 3, *rest, keyreq:, key: 11, **keyrest) + Date.today + (req * opt * rest.inject(&:*) * keyreq * key * keyrest.values.inject(&:*)) + end + def only_kwargs(**keyrest) + Date.today + keyrest.values.inject(&:*) + end + memoize :no_params, :with_params?, :returning_nil!, :all_param_types, :only_kwargs end class Beepbop < MemoizedSpecClass; end describe Memoized do @@ -47,10 +53,44 @@ allow(Date).to receive(:today).and_raise(ArgumentError) expect(object.returning_nil!).to be_nil end end + context "for a method with all param types" do + it "stores memoized value" do + Timecop.freeze(today) + expect(object.all_param_types(2, 3, 5, 5, keyreq: 7, key: 11, **{ first: 13, second: 13 })).to eq(today + 1951950) + Timecop.freeze(tomorrow) + expect(object.all_param_types(2, 3, 5, 5, keyreq: 7, key: 11, **{ first: 13, second: 13 })).to eq(today + 1951950) + end + it "does not confuse one set of inputs for another" do + Timecop.freeze(today) + expect(object.all_param_types(2, 3, 5, 5, keyreq: 7, key: 11, **{ first: 13, second: 13 })).to eq(today + 1951950) + expect(object.all_param_types(2, 9, 5, keyreq: 7, key: 121, **{ first: 13 })).to eq(today + 990990) + Timecop.freeze(tomorrow) + expect(object.all_param_types(2, 3, 5, 5, keyreq: 7, key: 11, **{ first: 13, second: 13 })).to eq(today + 1951950) + expect(object.all_param_types(2, 9, 5, keyreq: 7, key: 121, **{ first: 13 })).to eq(today + 990990) + end + end + + context "for a method with only keyword rest arguments" do + it "stores memoized value" do + Timecop.freeze(today) + expect(object.only_kwargs(**{ first: 2, second: 3 })).to eq(today + 6) + Timecop.freeze(tomorrow) + expect(object.only_kwargs(**{ first: 2, second: 3 })).to eq(today + 6) + end + it "does not confuse one set of inputs for another" do + Timecop.freeze(today) + expect(object.only_kwargs(**{ first: 2, second: 3 })).to eq(today + 6) + expect(object.only_kwargs(**{ first: 7 })).to eq(today + 7) + Timecop.freeze(tomorrow) + expect(object.only_kwargs(**{ first: 2, second: 3 })).to eq(today + 6) + expect(object.only_kwargs(**{ first: 7 })).to eq(today + 7) + end + end + context "for subclasses" do let(:object) { Beepbop.new } it "still memoizes things" do Timecop.freeze(today) expect(object.no_params).to eq(today) @@ -112,11 +152,10 @@ end it 'creates a memoized method with an arity of 0' do expect(Arity0.instance_method(:foo).arity).to eq(0) end - end context 'for methods with an arity of 2' do class Arity2 < MemoizedSpecClass def foo(a, b) @@ -126,11 +165,10 @@ end it 'creates a memoized method with an arity of 2' do expect(Arity2.instance_method(:foo).arity).to eq(2) end - end context 'for methods with splat args' do class AritySplat < MemoizedSpecClass def foo(*args) @@ -140,15 +178,13 @@ end it 'creates a memoized method with an arity of -1' do expect(AritySplat.instance_method(:foo).arity).to eq(-1) end - end context 'for methods with a required and an optional arg' do - class ArityRequiredAndOptional < MemoizedSpecClass def foo(a, b = 'default') return [a, b] end @@ -161,15 +197,13 @@ it "preserves the optional arg's default value" do instance = ArityRequiredAndOptional.new expect(instance.foo('foo')).to eq ['foo', 'default'] end - end context 'for methods with a required arg and splat args' do - class ArityArgAndOptional < MemoizedSpecClass def foo(a, *args) return [a, args] end @@ -182,10 +216,57 @@ it "passes the splat args to the memoized method" do instance = ArityArgAndOptional.new expect(instance.foo('foo', 'bar', 'baz')).to eq ['foo', ['bar', 'baz']] end + end + context 'for methods with all types of args' do + class AllArgTypes < MemoizedSpecClass + def foo(required, optional = 3, *rest, req_keyword:, opt_keyword: 11, **keyrest) + return [required, optional, rest, req_keyword, opt_keyword, keyrest] + end + + memoize :foo + end + + it 'the memoized method has the same arity as the original method' do + expect(AllArgTypes.instance_method(:_unmemoized_foo).arity).to eq(-3) + expect(AllArgTypes.instance_method(:foo).arity).to eq(-3) + end + + it 'the memoized method has the same parameters as the original method' do + expect(AllArgTypes.instance_method(:_unmemoized_foo).parameters) + .to eq([ + [:req, :required], + [:opt, :optional], + [:rest, :rest], + [:keyreq, :req_keyword], + [:key, :opt_keyword], + [:keyrest, :keyrest] + ]) + expect(AllArgTypes.instance_method(:foo).parameters) + .to eq([ + [:req, :required], + [:opt, :optional], + [:rest, :rest], + [:keyreq, :req_keyword], + [:key, :opt_keyword], + [:keyrest, :keyrest] + ]) + end + + it "passes all args to the original method correctly" do + instance = AllArgTypes.new + expect(instance.foo(2, 333, 5, 5, req_keyword: 7, opt_keyword: 1111, first: 13, second: 17)) + .to eq [2, 333, [5, 5], 7, 1111, { first: 13, second: 17 }] + end + + it "preserves the original method's default values" do + instance = AllArgTypes.new + expect(instance.foo(2, req_keyword: 7, third: 19)) + .to eq [2, 3, [], 7, 11, { third: 19 }] + end end end