pursuit 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/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) }