pursuit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/pursuit.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'pursuit/constants'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'pursuit'
10
+ spec.version = Pursuit::VERSION
11
+ spec.authors = ['Nialto Services']
12
+ spec.email = ['support@nialtoservices.co.uk']
13
+
14
+ spec.summary = 'Advanced key-based searching for ActiveRecord objects.'
15
+ spec.homepage = 'https://github.com/nialtoservices/pursuit'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.metadata['yard.run'] = 'yri'
23
+
24
+ spec.add_runtime_dependency 'activerecord', '>= 5.2.0', '< 6.1.0'
25
+ spec.add_runtime_dependency 'activesupport', '>= 5.2.0', '< 6.1.0'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 2.0'
28
+ spec.add_development_dependency 'combustion', '~> 1.1'
29
+ spec.add_development_dependency 'guard-rspec', '~> 4.7'
30
+ spec.add_development_dependency 'rake', '~> 13.0'
31
+ spec.add_development_dependency 'rspec', '~> 3.8'
32
+ spec.add_development_dependency 'rspec-rails', '~> 3.8'
33
+ spec.add_development_dependency 'rubocop', '~> 0.77.0'
34
+ spec.add_development_dependency 'yard', '~> 0.9.20'
35
+ spec.add_development_dependency 'sqlite3', '~> 1.4'
36
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Product < ActiveRecord::Base
4
+ has_many :variations, class_name: 'ProductVariation', inverse_of: :product
5
+
6
+ has_search relationships: { variations: %i[title stock_status] },
7
+ keyed_attributes: %i[title description rating],
8
+ unkeyed_attributes: %i[title description]
9
+
10
+ validates :title, presence: true
11
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ProductVariation < ActiveRecord::Base
4
+ belongs_to :product
5
+
6
+ enum stock_status: { in_stock: 1, low_stock: 2, out_of_stock: 3 }
7
+
8
+ validates :title, presence: true
9
+
10
+ validates :currency, presence: true
11
+ validates :amount, presence: true, numericality: true
12
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/test.sqlite3
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveRecord::Schema.define do
4
+ create_table :products, force: true do |t|
5
+ t.string :title, null: false
6
+
7
+ t.text :description
8
+
9
+ t.integer :rating, limit: 1
10
+
11
+ t.timestamps null: false
12
+ end
13
+
14
+ create_table :product_variations, force: true do |t|
15
+ t.belongs_to :product, null: false, foreign_key: true
16
+
17
+ t.string :title, null: false
18
+
19
+ t.string :currency, null: false, default: 'USD'
20
+ t.integer :amount, null: false, default: 0
21
+
22
+ t.integer :stock_status, limit: 1
23
+
24
+ t.timestamps null: false
25
+ end
26
+ end
File without changes
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Pursuit::ActiveRecordDSL do
4
+ subject(:product) { Product.new }
5
+
6
+ it { is_expected.to respond_to(:search) }
7
+ end
@@ -0,0 +1,442 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Pursuit::ActiveRecordSearch do
4
+ subject(:active_record_search) do
5
+ described_class.new(
6
+ Product,
7
+ relationships: { variations: %i[title stock_status] },
8
+ keyed_attributes: %i[title description rating],
9
+ unkeyed_attributes: %i[title description]
10
+ )
11
+ end
12
+
13
+ describe '#search' do
14
+ subject(:search) { active_record_search.search(query) }
15
+
16
+ context 'when passed a blank query' do
17
+ let(:query) { '' }
18
+
19
+ let(:product_a) { Product.create!(title: 'Alpha') }
20
+ let(:product_b) { Product.create!(title: 'Beta') }
21
+
22
+ before do
23
+ product_a
24
+ product_b
25
+ end
26
+
27
+ it 'is expected to contain all records' do
28
+ expect(search).to contain_exactly(product_a, product_b)
29
+ end
30
+ end
31
+
32
+ context 'when passed an unkeyed query' do
33
+ let(:query) { 'shirt' }
34
+
35
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
36
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
37
+ let(:product_c) { Product.create!(title: 'Socks') }
38
+
39
+ before do
40
+ product_a
41
+ product_b
42
+ product_c
43
+ end
44
+
45
+ it 'is expected to contain the matching records' do
46
+ expect(search).to contain_exactly(product_a, product_b)
47
+ end
48
+ end
49
+
50
+ context 'when passed an `equal to` keyed attribute query' do
51
+ let(:query) { 'title=="Funky Shirt"' }
52
+
53
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
54
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
55
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4') }
56
+
57
+ before do
58
+ product_a
59
+ product_b
60
+ product_c
61
+ end
62
+
63
+ it 'is expected to contain the matching records' do
64
+ expect(search).to contain_exactly(product_b)
65
+ end
66
+ end
67
+
68
+ context 'when passed a `not equal to` keyed attribute query' do
69
+ let(:query) { 'title!="Funky Shirt"' }
70
+
71
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
72
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
73
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4') }
74
+
75
+ before do
76
+ product_a
77
+ product_b
78
+ product_c
79
+ end
80
+
81
+ it 'is expected to contain the matching records' do
82
+ expect(search).to contain_exactly(product_a, product_c)
83
+ end
84
+ end
85
+
86
+ context 'when passed a `match` keyed attribute query' do
87
+ let(:query) { 'title*=shirt' }
88
+
89
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
90
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
91
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4') }
92
+
93
+ before do
94
+ product_a
95
+ product_b
96
+ product_c
97
+ end
98
+
99
+ it 'is expected to contain the matching records' do
100
+ expect(search).to contain_exactly(product_a, product_b)
101
+ end
102
+ end
103
+
104
+ context 'when passed a `not match` keyed attribute query' do
105
+ let(:query) { 'title!*=socks' }
106
+
107
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
108
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
109
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4') }
110
+
111
+ before do
112
+ product_a
113
+ product_b
114
+ product_c
115
+ end
116
+
117
+ it 'is expected to contain the matching records' do
118
+ expect(search).to contain_exactly(product_a, product_b)
119
+ end
120
+ end
121
+
122
+ context 'when passed a `not equal to` keyed attribute query' do
123
+ let(:query) { 'rating!=2' }
124
+
125
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
126
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
127
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4', rating: 5) }
128
+
129
+ before do
130
+ product_a
131
+ product_b
132
+ product_c
133
+ end
134
+
135
+ it 'is expected to contain the matching records' do
136
+ expect(search).to contain_exactly(product_b, product_c)
137
+ end
138
+ end
139
+
140
+ context 'when passed a `greater than` keyed attribute query' do
141
+ let(:query) { 'rating>2' }
142
+
143
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
144
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
145
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4', rating: 5) }
146
+
147
+ before do
148
+ product_a
149
+ product_b
150
+ product_c
151
+ end
152
+
153
+ it 'is expected to contain the matching records' do
154
+ expect(search).to contain_exactly(product_b, product_c)
155
+ end
156
+ end
157
+
158
+ context 'when passed a `greater than or equal to` keyed attribute query' do
159
+ let(:query) { 'rating>=4' }
160
+
161
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
162
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
163
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4', rating: 5) }
164
+
165
+ before do
166
+ product_a
167
+ product_b
168
+ product_c
169
+ end
170
+
171
+ it 'is expected to contain the matching records' do
172
+ expect(search).to contain_exactly(product_b, product_c)
173
+ end
174
+ end
175
+
176
+ context 'when passed a `less than` keyed attribute query' do
177
+ let(:query) { 'rating<5' }
178
+
179
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
180
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
181
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4', rating: 5) }
182
+
183
+ before do
184
+ product_a
185
+ product_b
186
+ product_c
187
+ end
188
+
189
+ it 'is expected to contain the matching records' do
190
+ expect(search).to contain_exactly(product_a, product_b)
191
+ end
192
+ end
193
+
194
+ context 'when passed a `less than or equal to` keyed attribute query' do
195
+ let(:query) { 'rating<=4' }
196
+
197
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
198
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
199
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4', rating: 5) }
200
+
201
+ before do
202
+ product_a
203
+ product_b
204
+ product_c
205
+ end
206
+
207
+ it 'is expected to contain the matching records' do
208
+ expect(search).to contain_exactly(product_a, product_b)
209
+ end
210
+ end
211
+
212
+ context 'when passed a `greater than` and `less than` keyed attribute query' do
213
+ let(:query) { 'rating>2 rating<5' }
214
+
215
+ let(:product_a) { Product.create!(title: 'Plain Shirt', rating: 2) }
216
+ let(:product_b) { Product.create!(title: 'Funky Shirt', rating: 4) }
217
+ let(:product_c) { Product.create!(title: 'Socks - Pack of 4', rating: 5) }
218
+
219
+ before do
220
+ product_a
221
+ product_b
222
+ product_c
223
+ end
224
+
225
+ it 'is expected to contain the matching records' do
226
+ expect(search).to contain_exactly(product_b)
227
+ end
228
+ end
229
+
230
+ context 'when passed a `match` relationship search query' do
231
+ let(:query) { 'variations*=green' }
232
+
233
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
234
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
235
+
236
+ let(:product_variation_a) { ProductVariation.create!(product: product_a, title: 'Red') }
237
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
238
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
239
+
240
+ before do
241
+ product_a
242
+ product_b
243
+
244
+ product_variation_a
245
+ product_variation_b
246
+ product_variation_c
247
+ end
248
+
249
+ it 'is expected to contain the matching records' do
250
+ expect(search).to contain_exactly(product_b)
251
+ end
252
+ end
253
+
254
+ context 'when passed an `equal to` relationship count query' do
255
+ let(:query) { 'variations==1' }
256
+
257
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
258
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
259
+ let(:product_c) { Product.create!(title: 'Socks') }
260
+
261
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
262
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
263
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
264
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
265
+
266
+ before do
267
+ product_a
268
+ product_b
269
+ product_c
270
+
271
+ product_variation_a
272
+ product_variation_b
273
+ product_variation_c
274
+ product_variation_d
275
+ end
276
+
277
+ it 'is expected to contain the matching records' do
278
+ expect(search).to contain_exactly(product_c)
279
+ end
280
+ end
281
+
282
+ context 'when passed a `greater than` relationship count query' do
283
+ let(:query) { 'variations>1' }
284
+
285
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
286
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
287
+ let(:product_c) { Product.create!(title: 'Socks') }
288
+
289
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
290
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
291
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
292
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
293
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
294
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
295
+
296
+ before do
297
+ product_a
298
+ product_b
299
+ product_c
300
+
301
+ product_variation_a
302
+ product_variation_b
303
+ product_variation_c
304
+ product_variation_d
305
+ product_variation_e
306
+ product_variation_f
307
+ end
308
+
309
+ it 'is expected to contain the matching records' do
310
+ expect(search).to contain_exactly(product_a, product_b)
311
+ end
312
+ end
313
+
314
+ context 'when passed a `greater than or equal to` relationship count query' do
315
+ let(:query) { 'variations>=2' }
316
+
317
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
318
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
319
+ let(:product_c) { Product.create!(title: 'Socks') }
320
+
321
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
322
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
323
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
324
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
325
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
326
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
327
+
328
+ before do
329
+ product_a
330
+ product_b
331
+ product_c
332
+
333
+ product_variation_a
334
+ product_variation_b
335
+ product_variation_c
336
+ product_variation_d
337
+ product_variation_e
338
+ product_variation_f
339
+ end
340
+
341
+ it 'is expected to contain the matching records' do
342
+ expect(search).to contain_exactly(product_a, product_b)
343
+ end
344
+ end
345
+
346
+ context 'when passed a `less than` relationship count query' do
347
+ let(:query) { 'variations<3' }
348
+
349
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
350
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
351
+ let(:product_c) { Product.create!(title: 'Socks') }
352
+
353
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
354
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
355
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
356
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
357
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
358
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
359
+
360
+ before do
361
+ product_a
362
+ product_b
363
+ product_c
364
+
365
+ product_variation_a
366
+ product_variation_b
367
+ product_variation_c
368
+ product_variation_d
369
+ product_variation_e
370
+ product_variation_f
371
+ end
372
+
373
+ it 'is expected to contain the matching records' do
374
+ expect(search).to contain_exactly(product_a, product_c)
375
+ end
376
+ end
377
+
378
+ context 'when passed a `less than or equal to` relationship count query' do
379
+ let(:query) { 'variations<=2' }
380
+
381
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
382
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
383
+ let(:product_c) { Product.create!(title: 'Socks') }
384
+
385
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
386
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
387
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
388
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
389
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
390
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
391
+
392
+ before do
393
+ product_a
394
+ product_b
395
+ product_c
396
+
397
+ product_variation_a
398
+ product_variation_b
399
+ product_variation_c
400
+ product_variation_d
401
+ product_variation_e
402
+ product_variation_f
403
+ end
404
+
405
+ it 'is expected to contain the matching records' do
406
+ expect(search).to contain_exactly(product_a, product_c)
407
+ end
408
+ end
409
+
410
+ context 'when passed a `greater than` and `less than` relationship count query' do
411
+ let(:query) { 'variations>1 variations<3' }
412
+
413
+ let(:product_a) { Product.create!(title: 'Plain Shirt') }
414
+ let(:product_b) { Product.create!(title: 'Funky Shirt') }
415
+ let(:product_c) { Product.create!(title: 'Socks') }
416
+
417
+ let(:product_variation_a) { ProductVariation.create!(product: product_b, title: 'Red') }
418
+ let(:product_variation_b) { ProductVariation.create!(product: product_b, title: 'Green') }
419
+ let(:product_variation_c) { ProductVariation.create!(product: product_b, title: 'Blue') }
420
+ let(:product_variation_d) { ProductVariation.create!(product: product_c, title: 'White') }
421
+ let(:product_variation_e) { ProductVariation.create!(product: product_a, title: 'Black') }
422
+ let(:product_variation_f) { ProductVariation.create!(product: product_a, title: 'Gray') }
423
+
424
+ before do
425
+ product_a
426
+ product_b
427
+ product_c
428
+
429
+ product_variation_a
430
+ product_variation_b
431
+ product_variation_c
432
+ product_variation_d
433
+ product_variation_e
434
+ product_variation_f
435
+ end
436
+
437
+ it 'is expected to contain the matching records' do
438
+ expect(search).to contain_exactly(product_a)
439
+ end
440
+ end
441
+ end
442
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Pursuit do
4
+ describe '::VERSION' do
5
+ subject { described_class::VERSION }
6
+
7
+ it 'is semantic' do
8
+ expect(subject).to match(/[0-9]+\.[0-9]+\.[0-9]+/)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Pursuit::TermParser do
4
+ subject(:term_parser) { described_class.new(query, keys: keys) }
5
+
6
+ let(:keys) { %i[title description rating stock_status] }
7
+ let(:query) do
8
+ "plain title!='Socks' description*=\"green\" stock_status==in_stock shirt rating>=2 other*=thing rating<5"
9
+ end
10
+
11
+ describe '#unkeyed_term' do
12
+ subject(:unkeyed_term) { term_parser.unkeyed_term }
13
+
14
+ it 'is expected to eq the correct unkeyed term' do
15
+ expect(unkeyed_term).to eq('plain shirt other*=thing')
16
+ end
17
+ end
18
+
19
+ describe '#keyed_terms' do
20
+ subject(:keyed_terms) { term_parser.keyed_terms }
21
+
22
+ it 'is expected to eq the correct keyed terms' do
23
+ expect(keyed_terms).to eq([
24
+ Pursuit::TermParser::KeyedTerm.new('title', '!=', 'Socks'),
25
+ Pursuit::TermParser::KeyedTerm.new('description', '*=', 'green'),
26
+ Pursuit::TermParser::KeyedTerm.new('stock_status', '==', 'in_stock'),
27
+ Pursuit::TermParser::KeyedTerm.new('rating', '>=', '2'),
28
+ Pursuit::TermParser::KeyedTerm.new('rating', '<', '5')
29
+ ])
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Conventionally, all specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
4
+ # The `.rspec` file contains `--require spec_helper` which will cause this file to always be loaded,
5
+ # without a need to explicitly require it in any files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as light-weight as possible.
8
+ # Requiring heavyweight dependencies from this file will add to the boot time of your test suite on EVERY test run,
9
+ # even for an individual file that may not need all of that loaded. Instead, consider making a separate helper file
10
+ # that requires the additional dependencies and performs the additional setup, and require it from the spec files
11
+ # that actually need it.
12
+ #
13
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
14
+
15
+ require 'combustion'
16
+ Combustion.initialize! :active_record
17
+
18
+ require 'bundler'
19
+ Bundler.require :default, :development
20
+
21
+ require 'rspec/rails'
22
+
23
+ RSpec.configure do |config|
24
+ # rspec-expectations config goes here. You can use an alternate assertion/expectation library such as wrong or the
25
+ # stdlib/minitest assertions if you prefer.
26
+ config.expect_with :rspec do |expectations|
27
+ # This option will default to `true` in RSpec 4.
28
+ # It makes the `description` and `failure_message` of custom matchers include text for helper methods defined using
29
+ # `chain`, e.g.:
30
+ # be_bigger_than(2).and_smaller_than(4).description
31
+ # # => "be bigger than 2 and smaller than 4"
32
+ # ...rather than:
33
+ # # => "be bigger than 2"
34
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
35
+ end
36
+
37
+ # rspec-mocks config goes here. You can use an alternate test double library (such as bogus or mocha) by changing the
38
+ # `mock_with` option here.
39
+ config.mock_with :rspec do |mocks|
40
+ # Prevents you from mocking or stubbing a method that does not exist on a real object.
41
+ # This is generally recommended, and will default to `true` in RSpec 4.
42
+ mocks.verify_partial_doubles = true
43
+ end
44
+
45
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will have no way to turn it off -- the option
46
+ # exists only for backwards compatibility in RSpec 3).
47
+ # It causes shared context metadata to be inherited by the metadata hash of host groups and examples, rather than
48
+ # triggering implicit auto-inclusion in groups with matching metadata.
49
+ config.shared_context_metadata_behavior = :apply_to_host_groups
50
+
51
+ # This allows you to limit a spec run to individual examples or groups you care about by tagging them with `:focus`
52
+ # metadata. When nothing is tagged with `:focus`, all examples get run.
53
+ # RSpec also provides aliases for `it`, `describe`, and `context` that include `:focus` metadata: `fit`, `fdescribe`
54
+ # and `fcontext`, respectively.
55
+ config.filter_run_when_matching :focus
56
+
57
+ # Allows RSpec to persist some state between runs in order to support the `--only-failures` and `--next-failure` CLI
58
+ # options. We recommend you configure your source control system to ignore this file.
59
+ config.example_status_persistence_file_path = 'spec/examples.txt'
60
+
61
+ # Limits the available syntax to the non-monkey patched syntax that is recommended. For more details, see:
62
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
63
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
64
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
65
+ config.disable_monkey_patching!
66
+
67
+ # Retrieve the default formatter from the current environment.
68
+ default_formatter = ENV['RSPEC_DEFAULT_FORMATTER']
69
+
70
+ if default_formatter.is_a?(String) && !default_formatter.empty?
71
+ config.default_formatter = default_formatter
72
+ elsif config.files_to_run.one?
73
+ # Use the documentation formatter for detailed output when running an individual spec file, unless a formatter has
74
+ # already been configured (e.g. via a command-line flag or using the RSPEC_DEFAULT_FORMAT environment variable).
75
+ config.default_formatter = 'doc'
76
+ end
77
+
78
+ config.use_transactional_fixtures = true
79
+
80
+ # Print the 10 slowest examples and example groups at the end of the spec run, to help surface which specs are
81
+ # running particularly slow.
82
+ # config.profile_examples = 10
83
+
84
+ # Run specs in random order to surface order dependencies. If you find an order dependency and want to debug it, you
85
+ # can fix the order by providing the seed, which is printed after each run.
86
+ # --seed 1234
87
+ config.order = :random
88
+
89
+ # Seed global randomization in this process using the `--seed` CLI option.
90
+ # Setting this allows you to use `--seed` to deterministically reproduce test failures related to randomization by
91
+ # passing the same `--seed` value as the one that triggered the failure.
92
+ Kernel.srand config.seed
93
+ end
94
+
95
+ Dir[File.expand_path('support/**/*.rb', __dir__)].each { |path| require(path) }