ampere 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +51 -0
- data/LICENSE.txt +70 -0
- data/README.md +89 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/features/ampere.feature +9 -0
- data/features/step_definitions/ampere_steps.rb +0 -0
- data/features/support/env.rb +15 -0
- data/lib/ampere.rb +26 -0
- data/lib/ampere/collection.rb +71 -0
- data/lib/ampere/model.rb +315 -0
- data/spec/models/indices_spec.rb +141 -0
- data/spec/models/model_spec.rb +208 -0
- data/spec/models/queries_spec.rb +97 -0
- data/spec/models/relationships/belongs_to_spec.rb +100 -0
- data/spec/models/relationships/has_many_spec.rb +71 -0
- data/spec/models/relationships/has_one_spec.rb +75 -0
- data/spec/models/updates_spec.rb +62 -0
- data/spec/module/ampere_spec.rb +26 -0
- data/spec/module/collections_spec.rb +71 -0
- data/spec/spec_helper.rb +20 -0
- data/test/helper.rb +18 -0
- data/test/test_ampere.rb +7 -0
- metadata +166 -0
@@ -0,0 +1,141 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper.rb")
|
2
|
+
|
3
|
+
describe "Model indices", :indices => true do
|
4
|
+
before :all do
|
5
|
+
Redis.new.flushall
|
6
|
+
Ampere.connect
|
7
|
+
|
8
|
+
class Student < Ampere::Model
|
9
|
+
field :first_name
|
10
|
+
field :last_name
|
11
|
+
field :student_id_num
|
12
|
+
|
13
|
+
index :last_name
|
14
|
+
index :student_id_num, :unique => true
|
15
|
+
end
|
16
|
+
|
17
|
+
@a = Student.create :first_name => "Hannibal",
|
18
|
+
:last_name => "Smith",
|
19
|
+
:student_id_num => "1001"
|
20
|
+
@b = Student.create :first_name => "Cindy",
|
21
|
+
:last_name => "Smith",
|
22
|
+
:student_id_num => "1002"
|
23
|
+
@c = Student.create :first_name => "Emmanuel",
|
24
|
+
:last_name => "Goldstein",
|
25
|
+
:student_id_num => "1003"
|
26
|
+
end
|
27
|
+
|
28
|
+
###
|
29
|
+
|
30
|
+
it 'should know about its own indices' do
|
31
|
+
Student.indices.should include(:last_name)
|
32
|
+
Student.indices.should_not include(:first_name)
|
33
|
+
Student.indices.should include(:student_id_num)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should find an array of values for a non-unique index' do
|
37
|
+
smiths = Student.where(:last_name => "Smith")
|
38
|
+
smiths.should_not be_empty
|
39
|
+
smiths.to_a.map(&:first_name).should include("Hannibal")
|
40
|
+
smiths.to_a.map(&:first_name).should include("Cindy")
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should find a single value for a unique index' do
|
44
|
+
emmanuel = Student.where(:student_id_num => "1003")
|
45
|
+
emmanuel.should_not be_empty
|
46
|
+
emmanuel.first.first_name.should == "Emmanuel"
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should refuse to create an index on a field that does not exist' do
|
50
|
+
(->{
|
51
|
+
class Student < Ampere::Model
|
52
|
+
field :this_field_exists
|
53
|
+
|
54
|
+
index :this_field_exists
|
55
|
+
end
|
56
|
+
}).should_not raise_error
|
57
|
+
(->{
|
58
|
+
class Student < Ampere::Model
|
59
|
+
index :this_field_does_not_exist
|
60
|
+
end
|
61
|
+
}).should raise_error
|
62
|
+
(->{
|
63
|
+
class Student < Ampere::Model
|
64
|
+
field :this_field_exists
|
65
|
+
|
66
|
+
index [:this_field_exists, :but_this_one_does_not]
|
67
|
+
end
|
68
|
+
}).should raise_error
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should enforce the uniqueness of unique single-field indices' do
|
72
|
+
pending
|
73
|
+
# The student_id_num field of Student is unique. If two Students
|
74
|
+
# with the same student_id_num are stored, the second should not
|
75
|
+
# save successfully, throwing an exception instead.
|
76
|
+
(->{
|
77
|
+
Student.create :first_name => "Bobby",
|
78
|
+
:last_name => "Tables",
|
79
|
+
:student_id_num => "2000"
|
80
|
+
}).should_not raise_error
|
81
|
+
(->{
|
82
|
+
Student.create :first_name => "Johnny",
|
83
|
+
:last_name => "Tables",
|
84
|
+
:student_id_num => "2000"
|
85
|
+
}).should raise_error
|
86
|
+
Student.where(:student_id_num => "2000").first.first_name.should == "Bobby"
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'compound indices' do
|
90
|
+
before :all do
|
91
|
+
class Professor < Ampere::Model
|
92
|
+
field :first_name
|
93
|
+
field :last_name
|
94
|
+
field :employee_id_number
|
95
|
+
|
96
|
+
index :employee_id_number
|
97
|
+
index [:last_name, :first_name]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
###
|
102
|
+
|
103
|
+
it 'should define compound indices' do
|
104
|
+
Professor.indices.should include([:first_name, :last_name])
|
105
|
+
|
106
|
+
Ampere.connection.exists("ampere.index.professor.first_name:last_name").should be_false
|
107
|
+
Professor.create :first_name => "Warren",
|
108
|
+
:last_name => "Satterfield",
|
109
|
+
:employee_id_number => "31415926"
|
110
|
+
Professor.count.should == 1
|
111
|
+
Ampere.connection.exists("ampere.index.professor.first_name:last_name").should be_true
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should be able to search on both fields of a compound index' do
|
115
|
+
Professor.create :first_name => "Ava",
|
116
|
+
:last_name => "Jenkins",
|
117
|
+
:employee_id_number => "31415927"
|
118
|
+
Professor.create :first_name => "Lazaro",
|
119
|
+
:last_name => "Adams",
|
120
|
+
:employee_id_number => "31415928"
|
121
|
+
Professor.create :first_name => "Brandi",
|
122
|
+
:last_name => "O'Kon",
|
123
|
+
:employee_id_number => "31415929"
|
124
|
+
|
125
|
+
brandi = Professor.where(:first_name => "Brandi", :last_name => "O'Kon")
|
126
|
+
brandi.count.should == 1
|
127
|
+
brandi.first.employee_id_number.should == "31415929"
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should still be able to search on just one field of a compound index' do
|
131
|
+
pending
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
###
|
136
|
+
|
137
|
+
after :all do
|
138
|
+
Redis.new.flushall
|
139
|
+
Ampere.disconnect
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper.rb")
|
2
|
+
|
3
|
+
describe "Base models", :model => true do
|
4
|
+
context "by themselves" do
|
5
|
+
before :all do
|
6
|
+
Ampere.connect
|
7
|
+
|
8
|
+
# Clear out Redis
|
9
|
+
Redis.new.flushall
|
10
|
+
|
11
|
+
# Define a model class here.
|
12
|
+
class Post < Ampere::Model
|
13
|
+
field :title
|
14
|
+
field :byline
|
15
|
+
field :content
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
# # #
|
21
|
+
|
22
|
+
context 'fields' do
|
23
|
+
it "should define attr accessors and suchlike" do
|
24
|
+
post = Post.new
|
25
|
+
post.should respond_to(:title)
|
26
|
+
post.should respond_to(:"title=")
|
27
|
+
post.should respond_to(:byline)
|
28
|
+
post.should respond_to(:"byline=")
|
29
|
+
post.should respond_to(:content)
|
30
|
+
post.should respond_to(:"content=")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should know about its own fields" do
|
34
|
+
Post.fields.should include(:title)
|
35
|
+
Post.fields.should include(:byline)
|
36
|
+
Post.fields.should include(:content)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have default values definable" do
|
40
|
+
class Comment < Ampere::Model
|
41
|
+
field :subject, :default => "No subject"
|
42
|
+
field :content
|
43
|
+
end
|
44
|
+
|
45
|
+
comment = Comment.new
|
46
|
+
comment.subject.should == "No subject"
|
47
|
+
comment.content.should be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should raise an exception when you try to set a field that doesn't exist" do
|
51
|
+
(->{Post.new :shazbot => "This isn't the right key"}).should raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'types', :types => true do
|
55
|
+
before :all do
|
56
|
+
# Just adding a field with a type to Post
|
57
|
+
class Post < Ampere::Model
|
58
|
+
field :pageviews, :type => Integer, :default => 0
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "shouldn't care what the value types are assigned to a field with no type defined" do
|
63
|
+
pending "Types not implemented yet."
|
64
|
+
# Assign a string to the :make of a motorcycle.
|
65
|
+
(->{
|
66
|
+
Post.create :title => "",
|
67
|
+
:byline => "",
|
68
|
+
:content => "",
|
69
|
+
:pageviews => 1234
|
70
|
+
|
71
|
+
|
72
|
+
}).should_not raise_error
|
73
|
+
|
74
|
+
# Assign an integer to the :make of a motorcycle, for some reason.
|
75
|
+
(->{
|
76
|
+
Motorcycle.create :make => 1234,
|
77
|
+
:model => 'CB450SC',
|
78
|
+
:year => 1986,
|
79
|
+
:displacement => 450.0
|
80
|
+
}).should_not raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should, given a field's type, only accept values for that field of that type", :wip => true do
|
84
|
+
pending "Types not implemented yet."
|
85
|
+
cycle = Motorcycle.create :make => 'Honda',
|
86
|
+
:model => 'CB450SC',
|
87
|
+
:year => 1986,
|
88
|
+
:displacement => 450.0
|
89
|
+
|
90
|
+
# Try to assign a string to :year, raising an error.
|
91
|
+
(->{cycle.year = "this is not a year"}).should raise_error
|
92
|
+
(->{cycle.year = 1996}).should_not raise_error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should have a 'new' method that works like we'd expect" do
|
98
|
+
post = Post.new :title => "Amish Give Up - 'This is bullshit!', Elders Say",
|
99
|
+
:byline => "The Onion",
|
100
|
+
:content => %{
|
101
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing
|
102
|
+
elit, sed do eiusmod tempor incididunt ut labore et
|
103
|
+
dolore magna aliqua.
|
104
|
+
}
|
105
|
+
post.title.should == "Amish Give Up - 'This is bullshit!', Elders Say"
|
106
|
+
post.byline.should == "The Onion"
|
107
|
+
post.content.should =~ /Lorem ipsum dolor/
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should be able to convert itself to a hash" do
|
111
|
+
post = Post.new :title => "A title",
|
112
|
+
:byline => "Max",
|
113
|
+
:content => "Some content"
|
114
|
+
hash = post.attributes
|
115
|
+
hash[:title].should == "A title"
|
116
|
+
hash[:byline].should == "Max"
|
117
|
+
hash[:content].should == "Some content"
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should have a 'save' and 'reload' method that work like we'd expect" do
|
121
|
+
post = Post.new :title => "A title",
|
122
|
+
:byline => "Max",
|
123
|
+
:content => "Some content"
|
124
|
+
|
125
|
+
post.save.should be_true
|
126
|
+
|
127
|
+
post.reload
|
128
|
+
post.title.should == "A title"
|
129
|
+
post.byline.should == "Max"
|
130
|
+
post.content.should == "Some content"
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should refuse to reload a new record, that hasn't yet been saved" do
|
134
|
+
post = Post.new :title => "A title",
|
135
|
+
:byline => "Max",
|
136
|
+
:content => "Some content"
|
137
|
+
(->{post.reload}).should raise_error
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should be able to tell when two records are equivalent" do
|
141
|
+
foo = Post.create :title => "Kitties!", :byline => "Max", :content => "Kitties are awesome."
|
142
|
+
bar = Post.create :title => "Doggies!", :byline => "Max", :content => "Doggies are cool."
|
143
|
+
|
144
|
+
foo.should == foo # Post.new(:title => "Kitties!", :byline => "Max", :content => "Kitties are awesome.")
|
145
|
+
foo.should_not == bar
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should be able to tell when it's new" do
|
150
|
+
post = Post.new :title => "A title",
|
151
|
+
:byline => "Max",
|
152
|
+
:content => "Some content"
|
153
|
+
post.new?.should be_true
|
154
|
+
post.save
|
155
|
+
post.new?.should be_false
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should be deleteable from the model class" do
|
159
|
+
post = Post.create :title => "This post should be deleted",
|
160
|
+
:byline => "because it's awful",
|
161
|
+
:content => "and it doesn't even make sense."
|
162
|
+
id = post.id
|
163
|
+
post.should_not be_nil
|
164
|
+
Post.delete(id).should == 1
|
165
|
+
Post.find(id).should be_nil
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should be destroyable by itself" do
|
169
|
+
another_post = Post.create :title => "This one too, probably.",
|
170
|
+
:byline => "Just seems like one bit",
|
171
|
+
:content => "non sequitor."
|
172
|
+
id = another_post.id
|
173
|
+
another_post.destroy.should == 1
|
174
|
+
Post.find(id).should be_nil
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should be findable by ID" do
|
178
|
+
post = Post.new :title => "foo",
|
179
|
+
:byline => "bar",
|
180
|
+
:content => "baz"
|
181
|
+
post.save
|
182
|
+
Post.find(post.id).should == post
|
183
|
+
# Since we're using GUIDs, this should also be true:
|
184
|
+
post2 = Post.find(post.id)
|
185
|
+
|
186
|
+
post.title.should == post2.title
|
187
|
+
post.byline.should == post2.byline
|
188
|
+
post.content.should == post2.content
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should be able to save itself upon creation" do
|
192
|
+
post = Post.create :title => "Another title",
|
193
|
+
:byline => "Max",
|
194
|
+
:content => "Some other content"
|
195
|
+
Post.find(post.id).should == post
|
196
|
+
end
|
197
|
+
|
198
|
+
# # #
|
199
|
+
|
200
|
+
after :all do
|
201
|
+
# Clear out Redis
|
202
|
+
Redis.new.flushall
|
203
|
+
Ampere.disconnect
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper.rb")
|
2
|
+
|
3
|
+
describe 'queries', :queries => true do
|
4
|
+
before :each do
|
5
|
+
Redis.new.flushall
|
6
|
+
Ampere.connect
|
7
|
+
|
8
|
+
class Kitty < Ampere::Model
|
9
|
+
field :name
|
10
|
+
field :breed
|
11
|
+
field :age
|
12
|
+
field :color
|
13
|
+
|
14
|
+
index :name # => Unique
|
15
|
+
index :color # => Non-unique
|
16
|
+
end
|
17
|
+
|
18
|
+
@kitty_paws = Kitty.create name: 'Kitty Paws',
|
19
|
+
breed: 'Domestic shorthair',
|
20
|
+
age: 19,
|
21
|
+
color: 'orange'
|
22
|
+
@nate = Kitty.create name: 'Nate',
|
23
|
+
breed: 'Domestic shorthair',
|
24
|
+
age: 17,
|
25
|
+
color: 'black'
|
26
|
+
@jinxii = Kitty.create name: 'Jinxii',
|
27
|
+
breed: 'Chartreux',
|
28
|
+
age: 3,
|
29
|
+
color: 'grey'
|
30
|
+
@italics = Kitty.create name: 'Italics',
|
31
|
+
breed: 'Siberian',
|
32
|
+
age: 7,
|
33
|
+
color: 'orange'
|
34
|
+
@serif = Kitty.create name: 'Serif',
|
35
|
+
breed: 'Siberian',
|
36
|
+
age: 5,
|
37
|
+
color: 'grey'
|
38
|
+
[@kitty_paws, @nate, @jinxii, @italics, @serif]. each {|k| k.reload}
|
39
|
+
end
|
40
|
+
|
41
|
+
###
|
42
|
+
|
43
|
+
it 'should pass a basic sanity check' do
|
44
|
+
Kitty.count.should == 5
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should be able to select all kitties' do
|
48
|
+
Kitty.all.map(&:name).should include('Kitty Paws')
|
49
|
+
Kitty.all.map(&:name).should include('Nate')
|
50
|
+
Kitty.all.map(&:name).should include('Jinxii')
|
51
|
+
Kitty.all.map(&:name).should include('Italics')
|
52
|
+
Kitty.all.map(&:name).should include('Serif')
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with no fields' do
|
56
|
+
it 'should return the empty set with no conditions given' do
|
57
|
+
Kitty.where().should be_empty
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with one field' do
|
62
|
+
it 'should be able to find by an indexed field using where()' do
|
63
|
+
Kitty.where(:name => 'Nate').to_a.map(&:name).should include('Nate')
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should be able to find by a non-indexed field using where()' do
|
67
|
+
Kitty.where(:breed => 'Siberian').to_a.map(&:name).should include('Italics')
|
68
|
+
Kitty.where(:breed => 'Siberian').to_a.map(&:name).should include('Serif')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should be able to find by two indexed fields at once' do
|
73
|
+
kitty = Kitty.where(:name => "Kitty Paws", :color => "orange")
|
74
|
+
kitty.count.should == 1
|
75
|
+
kitty.first.name.should == "Kitty Paws"
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should be able to find by two non-indexed fields at once' do
|
79
|
+
# :breed and :age are not indexed
|
80
|
+
Kitty.where(:breed => "Domestic shorthair", :age => "17").count.should == 1
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should be able to find by a mix of indexed and non-indexed fields' do
|
84
|
+
# :color is indexed, :breed is not
|
85
|
+
Kitty.where(:color => "orange").count.should == 2
|
86
|
+
Kitty.where(:breed => "Siberian").count.should == 2
|
87
|
+
Kitty.where(:color => "orange", :breed => "Siberian").count.should == 1
|
88
|
+
Kitty.where(:color => "orange", :breed => "Siberian").first.name.should == "Italics"
|
89
|
+
end
|
90
|
+
|
91
|
+
###
|
92
|
+
|
93
|
+
after :all do
|
94
|
+
Redis.new.flushall
|
95
|
+
Ampere.connect
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "..", "spec_helper.rb")
|
2
|
+
|
3
|
+
describe 'belongs_to relationships', :belongs_to => true do
|
4
|
+
before :all do
|
5
|
+
Redis.new.flushall
|
6
|
+
Ampere.connect
|
7
|
+
|
8
|
+
# These are used by the has_one/belongs_to example below
|
9
|
+
class Car < Ampere::Model
|
10
|
+
field :make
|
11
|
+
field :model
|
12
|
+
field :year
|
13
|
+
|
14
|
+
has_one :engine
|
15
|
+
has_many :passengers
|
16
|
+
end
|
17
|
+
|
18
|
+
class Engine < Ampere::Model
|
19
|
+
field :displacement
|
20
|
+
field :cylinders
|
21
|
+
field :configuration
|
22
|
+
|
23
|
+
belongs_to :car
|
24
|
+
end
|
25
|
+
|
26
|
+
class Passenger < Ampere::Model
|
27
|
+
field :name
|
28
|
+
field :seat
|
29
|
+
|
30
|
+
belongs_to :car
|
31
|
+
end
|
32
|
+
|
33
|
+
@car = Car.create :make => "Lamborghini",
|
34
|
+
:model => "Countach",
|
35
|
+
:year => "1974"
|
36
|
+
@engine = Engine.create :displacement => "5167",
|
37
|
+
:cylinders => "12",
|
38
|
+
:configuration => "V"
|
39
|
+
@driver = Passenger.create :name => "Max",
|
40
|
+
:seat => "driver"
|
41
|
+
@passenger = Passenger.create :name => "Leila",
|
42
|
+
:seat => "passenger"
|
43
|
+
end
|
44
|
+
|
45
|
+
###
|
46
|
+
|
47
|
+
it 'sets accessor methods for a belongs_to relationship' do
|
48
|
+
# Other side of a has_many
|
49
|
+
@driver.should respond_to(:car)
|
50
|
+
# Other side of a has_one
|
51
|
+
@engine.should respond_to(:car)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'sets belongs_to pointer for has_one relationship that is set from the parent' do
|
55
|
+
@car.engine = @engine
|
56
|
+
@car.save
|
57
|
+
@engine.save
|
58
|
+
|
59
|
+
car = Car.find(@car.id)
|
60
|
+
engine = Engine.find(@engine.id)
|
61
|
+
|
62
|
+
car.engine.should == @engine
|
63
|
+
engine.car.should == @car
|
64
|
+
|
65
|
+
# Cleanup
|
66
|
+
@car.engine = nil
|
67
|
+
@engine.car = nil
|
68
|
+
@car.save
|
69
|
+
@engine.save
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'sets belongs_to pointer for has_one relationship that is set from the child' do
|
73
|
+
@engine.car = @car
|
74
|
+
@car.save
|
75
|
+
@engine.save
|
76
|
+
|
77
|
+
car = Car.find(@car.id)
|
78
|
+
engine = Engine.find(@engine.id)
|
79
|
+
|
80
|
+
car.engine.should == @engine
|
81
|
+
engine.car.should == @car
|
82
|
+
|
83
|
+
# Cleanup
|
84
|
+
@car.engine = nil
|
85
|
+
@engine.car = nil
|
86
|
+
@car.save
|
87
|
+
@engine.save
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'sets belongs_to pointer for has_many relationship' do
|
91
|
+
pending
|
92
|
+
end
|
93
|
+
|
94
|
+
###
|
95
|
+
|
96
|
+
after :all do
|
97
|
+
Redis.new.flushall
|
98
|
+
Ampere.connect
|
99
|
+
end
|
100
|
+
end
|