File: memoizable.rb

package info (click to toggle)
ruby-dry-core 0.7.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 396 kB
  • sloc: ruby: 2,126; sh: 4; makefile: 4
file content (119 lines) | stat: -rw-r--r-- 2,557 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# frozen_string_literal: true

RSpec.shared_examples "a memoizable class" do
  subject(:object) do
    Class.new(described_class) do
      include Dry::Core::Memoizable

      attr_reader :falsey_call_count

      def initialize
        @falsey_call_count = 0
      end

      def foo
        %w[a ab abc].max
      end
      memoize :foo

      def bar(_arg)
        {a: "1", b: "2"}
      end
      memoize :bar

      def bar_with_block(&block)
        block.call
      end
      memoize :bar_with_block

      def bar_with_kwargs(*args, **kwargs)
        {args: args, kwargs: kwargs}
      end
      memoize :bar_with_kwargs

      def falsey
        @falsey_call_count += 1
        false
      end
      memoize :falsey
    end.new
  end

  it "memoizes method return value" do
    expect(object.foo).to be(object.foo)
  end

  it "memoizes method return value with an arg" do
    expect(object.bar(:a)).to be(object.bar(:a))
    expect(object.bar(:b)).to be(object.bar(:b))
  end

  it "memoizes falsey values" do
    expect(object.falsey).to be(object.falsey)
    expect(object.falsey_call_count).to eq 1
  end

  describe "keyword arguments" do
    let(:kwargs) { {key: "value"} }
    let(:args) { [1] }

    it "memoizes keyword arguments" do
      expect(object.bar_with_kwargs(*args, **kwargs)).to eq({args: args, kwargs: kwargs})
    end
  end

  describe "with block" do
    let(:spy1) { double(:spy1) }
    let(:spy2) { double(:spy2) }
    let(:block1) { -> { spy1.call } }
    let(:block2) { -> { spy2.call } }
    let(:returns1) { :return_value1 }
    let(:returns2) { :return_value2 }

    before do
      expect(spy1).to receive(:call).and_return(returns1).once
      expect(spy2).to receive(:call).and_return(returns2).once
    end

    let(:results1) do
      2.times.map do
        object.bar_with_block(&block1)
      end
    end

    let(:results2) do
      2.times.map do
        object.bar_with_block(&block2)
      end
    end

    let(:returns) do
      [returns1, returns2] * 2
    end

    subject do
      results1 + results2
    end

    it { is_expected.to match_array(returns) }
  end
end

RSpec.shared_examples "a memoized method" do
  let(:old_meth) { new_meth.super_method }

  describe "new != old" do
    subject { new_meth }
    it { is_expected.not_to eq(old_meth) }
  end

  describe "new.arity == old.arity" do
    subject { new_meth.arity }
    it { is_expected.to eq(old_meth.arity) }
  end

  describe "new.name == old.name" do
    subject { new_meth.name }
    it { is_expected.to eq(old_meth.name) }
  end
end