/
let.rb
101 lines (96 loc) · 2.55 KB
/
let.rb
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
module RSpec
module Core
module Let
module ClassMethods
# Generates a method whose return value is memoized
# after the first call.
#
# == Examples
#
# describe Thing do
# let(:thing) { Thing.new }
#
# it "does something" do
# # first invocation, executes block, memoizes and returns result
# thing.do_something
#
# # second invocation, returns the memoized value
# thing.should be_something
# end
# end
def let(name, &block)
define_method(name) do
__memoized[name] ||= instance_eval(&block)
end
end
# Just like <tt>let()</tt>, except the block is invoked
# by an implicit <tt>before</tt> hook. This serves a dual
# purpose of setting up state and providing a memoized
# reference to that state.
#
# == Examples
#
# class Thing
# def self.count
# @count ||= 0
# end
#
# def self.count=(val)
# @count += val
# end
#
# def self.reset_count
# @count = 0
# end
#
# def initialize
# self.class.count += 1
# end
# end
#
# describe Thing do
# after(:each) { Thing.reset_count }
#
# context "using let" do
# let(:thing) { Thing.new }
#
# it "is not invoked implicitly" do
# Thing.count.should == 0
# end
#
# it "can be invoked explicitly" do
# thing
# Thing.count.should == 1
# end
# end
#
# context "using let!" do
# let!(:thing) { Thing.new }
#
# it "is invoked implicitly" do
# Thing.count.should == 1
# end
#
# it "returns memoized version on first invocation" do
# thing
# Thing.count.should == 1
# end
# end
# end
def let!(name, &block)
let(name, &block)
before { __send__(name) }
end
end
module InstanceMethods
def __memoized # :nodoc:
@__memoized ||= {}
end
end
def self.included(mod) # :nodoc:
mod.extend ClassMethods
mod.__send__ :include, InstanceMethods
end
end
end
end