redi_search 1.0.5 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +22 -0
  3. data/.github/workflows/tests.yml +49 -0
  4. data/.rubocop.yml +136 -193
  5. data/Appraisals +4 -8
  6. data/Gemfile +4 -4
  7. data/README.md +79 -92
  8. data/Rakefile +15 -3
  9. data/bin/console +29 -0
  10. data/gemfiles/{rails_6.gemfile → activerecord_60.gemfile} +3 -4
  11. data/gemfiles/{rails_51.gemfile → activerecord_61.gemfile} +3 -4
  12. data/lib/redi_search.rb +8 -7
  13. data/lib/redi_search/{alter.rb → add_field.rb} +13 -5
  14. data/lib/redi_search/client.rb +23 -11
  15. data/lib/redi_search/client/response.rb +5 -1
  16. data/lib/redi_search/configuration.rb +1 -11
  17. data/lib/redi_search/create.rb +7 -4
  18. data/lib/redi_search/document.rb +5 -13
  19. data/lib/redi_search/document/display.rb +9 -9
  20. data/lib/redi_search/document/finder.rb +12 -42
  21. data/lib/redi_search/hset.rb +28 -0
  22. data/lib/redi_search/index.rb +24 -22
  23. data/lib/redi_search/lazily_load.rb +6 -11
  24. data/lib/redi_search/log_subscriber.rb +25 -53
  25. data/lib/redi_search/model.rb +37 -39
  26. data/lib/redi_search/schema.rb +3 -3
  27. data/lib/redi_search/schema/field.rb +2 -3
  28. data/lib/redi_search/schema/tag_field.rb +1 -1
  29. data/lib/redi_search/schema/text_field.rb +1 -1
  30. data/lib/redi_search/search.rb +15 -25
  31. data/lib/redi_search/search/clauses.rb +6 -7
  32. data/lib/redi_search/search/clauses/application_clause.rb +20 -5
  33. data/lib/redi_search/search/clauses/boolean.rb +9 -9
  34. data/lib/redi_search/search/clauses/highlight.rb +18 -2
  35. data/lib/redi_search/search/clauses/limit.rb +7 -5
  36. data/lib/redi_search/search/clauses/or.rb +1 -1
  37. data/lib/redi_search/search/clauses/return.rb +1 -1
  38. data/lib/redi_search/search/clauses/slop.rb +1 -1
  39. data/lib/redi_search/search/clauses/sort_by.rb +1 -1
  40. data/lib/redi_search/search/clauses/where.rb +10 -2
  41. data/lib/redi_search/search/result.rb +9 -9
  42. data/lib/redi_search/search/term.rb +7 -6
  43. data/lib/redi_search/spellcheck.rb +3 -4
  44. data/lib/redi_search/spellcheck/result.rb +1 -1
  45. data/lib/redi_search/validatable.rb +49 -0
  46. data/lib/redi_search/validations/inclusion.rb +26 -0
  47. data/lib/redi_search/validations/numericality.rb +45 -0
  48. data/lib/redi_search/validations/presence.rb +29 -0
  49. data/lib/redi_search/version.rb +1 -1
  50. data/redi_search.gemspec +2 -4
  51. metadata +23 -54
  52. data/.travis.yml +0 -31
  53. data/bin/test +0 -7
  54. data/gemfiles/rails_52.gemfile +0 -17
  55. data/lib/redi_search/add.rb +0 -63
data/Appraisals CHANGED
@@ -1,13 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise "rails-6" do
4
- gem "rails", "6.0.0.rc1"
3
+ appraise "activerecord-60" do
4
+ gem "activerecord", "< 6.1", ">= 6.0"
5
5
  end
6
6
 
7
- appraise "rails-52" do
8
- gem "rails", "< 6.0", ">= 5.2"
9
- end
10
-
11
- appraise "rails-51" do
12
- gem "rails", "< 5.2", ">= 5.1"
7
+ appraise "activerecord-61" do
8
+ gem "activerecord", "< 6.2", ">= 6.1"
13
9
  end
data/Gemfile CHANGED
@@ -2,18 +2,18 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
6
 
7
7
  gemspec
8
8
 
9
+ gem "appraisal", "~> 2.2"
9
10
  gem "faker"
10
11
  gem "mocha"
11
12
  gem "pry"
12
- gem "pry-rails"
13
13
  gem "rubocop"
14
+ gem "rubocop-minitest"
14
15
  gem "rubocop-performance"
15
- gem "rubocop-rails"
16
16
  gem "simplecov"
17
17
  gem "sqlite3"
18
18
 
19
- gem "rails", "6.0.0.rc1"
19
+ gem "activerecord", "~> 6.1"
data/README.md CHANGED
@@ -6,8 +6,7 @@
6
6
 
7
7
  # RediSearch
8
8
 
9
- [![Build Status](https://travis-ci.com/npezza93/redi_search.svg?branch=master)](https://travis-ci.com/npezza93/redi_search)
10
- [![Test Coverage](https://api.codeclimate.com/v1/badges/c6437acac5684de2549d/test_coverage)](https://codeclimate.com/github/npezza93/redi_search/test_coverage)
9
+ ![Build Status](https://github.com/npezza93/redi_search/workflows/tests/badge.svg)
11
10
  [![Maintainability](https://api.codeclimate.com/v1/badges/c6437acac5684de2549d/maintainability)](https://codeclimate.com/github/npezza93/redi_search/maintainability)
12
11
 
13
12
  A simple, but powerful, Ruby wrapper around RediSearch, a search engine on top of
@@ -24,11 +23,13 @@ macOS or Linux you can install via Homebrew.
24
23
 
25
24
  To install RediSearch check out,
26
25
  [https://oss.redislabs.com/redisearch/Quick_Start.html](https://oss.redislabs.com/redisearch/Quick_Start.html).
27
- Once you have RediSearch built, you can update your redis.conf file to always
28
- load the redisearch module with `loadmodule /path/to/redisearch.so`. (On macOS
29
- the redis.conf file can be found `/usr/local/etc/redis.conf`)
26
+ Once you have RediSearch built, if you are not using Docker, you can update your
27
+ redis.conf file to always load the RediSearch module with
28
+ `loadmodule /path/to/redisearch.so`. (On macOS the redis.conf file can be found
29
+ at `/usr/local/etc/redis.conf`)
30
30
 
31
- After Redis and RediSearch are up and running, add this line to your Gemfile:
31
+ After Redis and RediSearch are up and running, add the following line to your
32
+ Gemfile:
32
33
 
33
34
  ```ruby
34
35
  gem 'redi_search'
@@ -51,7 +52,7 @@ require 'redi_search'
51
52
 
52
53
  Once the gem is installed and required you'll need to configure it with your
53
54
  Redis configuration. If you're on Rails, this should go in an initializer
54
- (`config/initializers/redi_search.rb`)
55
+ (`config/initializers/redi_search.rb`).
55
56
 
56
57
  ```ruby
57
58
  RediSearch.configure do |config|
@@ -74,7 +75,7 @@ end
74
75
 
75
76
  ## Preface
76
77
  RediSearch revolves around a search index, so lets start with
77
- defining what a search index is. According to [Switype](https://swiftype.com):
78
+ defining what a search index is. According to [Swiftype](https://swiftype.com):
78
79
  > A search index is a body of structured data that a search engine refers to
79
80
  > when looking for results that are relevant to a specific query. Indexes are a
80
81
  > critical piece of any search system, since they must be tailored to the
@@ -242,40 +243,35 @@ With no options: `{ place: :geo }`
242
243
 
243
244
  ## Document
244
245
 
245
- A `Document` is the Ruby representation of a RediSearch document.
246
+ A `Document` is the Ruby representation of a Redis hash.
246
247
 
247
- You can fetch a `Document` using `.get` or `mget` class methods.
248
- - `get(index, document_id)` fetches a single document in an `Index` for a given
249
- `document_id`.
250
- - `mget(index, *document_ids)` fetches a collection of `Document`s
251
- in an `Index` for the given `document_ids`.
248
+ You can fetch a `Document` using `.get` class methods.
249
+ - `get(index, document_id)` fetches a single `Document` in an `Index` for a
250
+ given `document_id`.
252
251
 
253
252
  You can also make a `Document` instance using the
254
253
  `.for_object(index, record, serializer: nil, only: [])` class method. It takes
255
- an `Index` instance and a ruby object. That object must respond to all the
256
- fields specified in the indexes schema or pass a serializer class that accepts
257
- the object and responds to all the fields specified in the indexes schema.
258
- `only` accepts an array of fields from the schema and limits the fields that are
259
- passed to the `Document`.
254
+ an `Index` instance and a Ruby object. That object must respond to all the
255
+ fields specified in the `Index`'s `Schema` or pass a serializer class that
256
+ accepts the object and responds to all the fields specified in the `Index`'s
257
+ `Schema`. `only` accepts an array of fields from the schema and limits the
258
+ fields that are passed to the `Document`.
260
259
 
261
260
  Once you have an instance of a `Document`, it responds to all the fields
262
- specified in the indexes schema as methods and `document_id`. `document_id` is
263
- automatically prepended with the indexes names unless it already is to ensure
264
- uniqueness. We prepend the index name because if you have two documents with the
265
- same id in different indexes we don't want the documents to override each other.
266
- There is also a `#document_id_without_index` method which removes the prepended
267
- index name.
268
-
269
- Finally there is a `#del` method that will remove the document from the index.
270
- It optionally accepts a `delete_document` named argument that signifies whether
271
- the document should be completely removed from the Redis instance vs just the
272
- index.
261
+ specified in the `Index`'s `Schema` as methods and `document_id`. `document_id`
262
+ is automatically prepended with the `Index`'s names unless it already is to
263
+ ensure uniqueness. We prepend the `Index` name because if you have two
264
+ `Document`s with the same id in different `Index`s we don't want the `Document`s
265
+ to override each other. There is also a `#document_id_without_index` method
266
+ which removes the prepended index name.
273
267
 
268
+ Finally there is a `#del` method that will remove the `Document` from the
269
+ `Index`.
274
270
 
275
271
  ## Index
276
272
 
277
- To initialize an index, pass the name of the index as a string or symbol and the
278
- schema.
273
+ To initialize an `Index`, pass the name of the `Index` as a string or symbol
274
+ and the `Schema`.
279
275
 
280
276
  ```ruby
281
277
  RediSearch::Index.new(name_of_index, schema)
@@ -291,7 +287,7 @@ RediSearch::Index.new(name_of_index, schema)
291
287
  - For efficiency, RediSearch encodes indexes differently if they are
292
288
  created with less than 32 text fields. This option forces RediSearch
293
289
  to encode indexes as if there were more than 32 text fields, which
294
- allows you to add additional fields (beyond 32) using `alter`.
290
+ allows you to add additional fields (beyond 32) using `add_field`.
295
291
  - `no_offsets: #{true || false}`
296
292
  - If set, we do not store term offsets for documents (saves memory, does
297
293
  not allow exact searches or highlighting). Implies `no_highlight`.
@@ -312,50 +308,39 @@ RediSearch::Index.new(name_of_index, schema)
312
308
  - If set, we avoid saving the term frequencies in the index. This saves
313
309
  memory but does not allow sorting based on the frequencies of a given
314
310
  term within the document.
315
- - `drop`
316
- - Drops the index from the Redis instance, returns a boolean. Has an
311
+ - `drop(keep_docs: false)`
312
+ - Drops the `Index` from the Redis instance, returns a boolean. Has an
317
313
  accompanying bang method that will raise an exception upon failure. Will
318
- return `false` if the index has already been dropped.
314
+ return `false` if the `Index` has already been dropped. Takes an option
315
+ keyword arg, `keep_docs`, that will by default remove all the document
316
+ hashes in Redis.
319
317
  - `exist?`
320
- - Returns a boolean signifying index existence.
318
+ - Returns a boolean signifying `Index` existence.
321
319
  - `info`
322
- - Returns a struct object with all the information about the index.
320
+ - Returns a struct object with all the information about the `Index`.
323
321
  - `fields`
324
- - Returns an array of the field names in the index.
325
- - `add(document, score: 1.0, replace: {}, language: nil, no_save: false)`
326
- - Takes a `Document` object and options. Has an
322
+ - Returns an array of the field names in the `Index`.
323
+ - `add(document)`
324
+ - Takes a `Document` object. Has an
327
325
  accompanying bang method that will raise an exception upon failure.
328
- - `score` -> The document's rank, a value between 0.0 and 1.0
329
- - `language` -> Use a stemmer for the supplied language during indexing.
330
- - `no_save` -> Don't save the actual document in the database and only index it.
331
- - `replace` -> Accepts a boolean or a hash. If a truthy value is passed, we
332
- will do an UPSERT style insertion - and delete an older version of the
333
- document if it exists.
334
- - `replace: { partial: true }` -> Allows you to not have to specify all
335
- fields for reindexing. Fields not given to the command will be loaded from
336
- the current version of the document.
337
- - `add_multiple!(documents, score: 1.0, replace: {}, language: nil, no_save: false)`
326
+ - `add_multiple(documents)`
338
327
  - Takes an array of `Document` objects. This provides a more performant way to
339
- add multiple documents to the index. Accepts the same options as `add`.
340
- - `del(document, delete_document: false)`
341
- - Removes a document from the index. `delete_document` signifies whether the
342
- document should be completely removed from the Redis instance vs just the
343
- index.
328
+ add multiple documents to the `Index`. Accepts the same options as `add`.
329
+ - `del(document)`
330
+ - Removes a `Document` from the `Index`.
344
331
  - `document_count`
345
- - Returns the number of documents in the index
346
- - `alter(field_name, schema)`
347
- - Adds a new field to the index. Ex: `index.alter(:first_name, text: { phonetic: "dm:en" })`
348
- - `reindex(documents, recreate: false, **options)`
349
- - If `recreate` is `true` the index will be dropped and recreated
350
- - `options` accepts the same options as `add`
332
+ - Returns the number of `Document`s in the `Index`
333
+ - `add_field(field_name, schema)`
334
+ - Adds a new field to the `Index`. Ex: `index.add_field(:first_name, text: { phonetic: "dm:en" })`
335
+ - `reindex(documents, recreate: false)`
336
+ - If `recreate` is `true` the `Index` will be dropped and recreated
351
337
 
352
338
 
353
339
  ## Searching
354
340
 
355
341
  Searching is initiated off a `RediSearch::Index` instance with clauses that can
356
342
  be chained together. When searching, an array of `Document`s is returned
357
- which has public reader methods for all the schema fields and a `document_id`
358
- method which returns the id of the document prefixed with the index name.
343
+ which has public reader methods for all the schema fields.
359
344
 
360
345
  ```ruby
361
346
  main ❯ index = RediSearch::Index.new("user_idx", name: { text: { phonetic: "dm:en" } })
@@ -440,15 +425,15 @@ index.search.where(number: -Float::INFINITY..0)
440
425
  phrase terms. (i.e the slop for exact phrases is 0)
441
426
  - `in_order`
442
427
  - Usually used in conjunction with `slop`. We make sure the query terms appear
443
- in the same order in the document as in the query, regardless of the offsets
444
- between them.
428
+ in the same order in the `Document` as in the query, regardless of the
429
+ offsets between them.
445
430
  - `no_content`
446
- - Only return the document ids and not the content. This is useful if
447
- RediSearch is being used on a Rails model where the document attributes
448
- don't matter and it's being converted into ActiveRecord objects.
431
+ - Only return the `Document` ids and not the content. This is useful if
432
+ RediSearch is being used on a Rails model where the `Document` attributes
433
+ don't matter and it's being converted into `ActiveRecord` objects.
449
434
  - `language(language)`
450
435
  - Stemmer to use for the supplied language during search for query expansion.
451
- If querying documents in Chinese, this should be set to chinese in order to
436
+ If querying `Document`s in Chinese, this should be set to chinese in order to
452
437
  properly tokenize the query terms. If an unsupported language is sent, the
453
438
  command returns an error.
454
439
  - `sort_by(field, order: :asc)`
@@ -459,7 +444,7 @@ index.search.where(number: -Float::INFINITY..0)
459
444
  - Limit the results to the specified `num` at the `offset`. The default limit
460
445
  is set to `10`.
461
446
  - `count`
462
- - Returns the number of documents found in the search query
447
+ - Returns the number of `Document`s found in the search query
463
448
  - `highlight(fields: [], opening_tag: "<b>", closing_tag: "</b>")`
464
449
  - Use this option to format occurrences of matched text. `fields` are an
465
450
  array of fields to be highlighted.
@@ -469,16 +454,14 @@ index.search.where(number: -Float::INFINITY..0)
469
454
  - `no_stop_words`
470
455
  - Do not filter stopwords from the query.
471
456
  - `with_scores`
472
- - Include the relative internal score of each document. This can be used to
457
+ - Include the relative internal score of each `Document`. This can be used to
473
458
  merge results from multiple instances. This will add a `score` method to the
474
459
  returned `Document` instances.
475
460
  - `return(*fields)`
476
- - Limit which fields from the document are returned.
461
+ - Limit which fields from the `Document` are returned.
477
462
  - `explain`
478
463
  - Returns the execution plan for a complex query. In the returned response,
479
464
  a + on a term is an indication of stemming.
480
- - `to_redis`
481
- - Returns the command to be executed without executing it.
482
465
 
483
466
 
484
467
  ## Spellcheck
@@ -507,8 +490,8 @@ main ❯ index.spellcheck("jimy", distance: 2).first.suggestions
507
490
 
508
491
  ## Rails Integration
509
492
 
510
- Integration with Rails is super easy! Call `redi_search` with the schema keyword
511
- arg from inside your model. Ex:
493
+ Integration with Rails is super easy! Call `redi_search` with the `schema`
494
+ keyword argument from inside your model. Ex:
512
495
 
513
496
  ```ruby
514
497
  class User < ApplicationRecord
@@ -522,10 +505,9 @@ end
522
505
  This will automatically add `User.search` and `User.spellcheck`
523
506
  methods which behave the same as if you called them on an `Index` instance.
524
507
 
525
- `User.reindex(only: [], **options)` is also added and behaves similarly to `RediSearch::Index#reindex`. Some of the differences include:
526
- - By default does an upsert for all documents added using the
527
- option `replace: { partial: true }`.
528
- - `Document`s do not to be passed as the first parameter. The `search_import`
508
+ `User.reindex(recreate: false, only: [])` is also added and behaves
509
+ similarly to `RediSearch::Index#reindex`. Some of the differences include:
510
+ - `Document`s do not need to be passed as the first parameter. The `search_import`
529
511
  scope is automatically called and all the records are converted
530
512
  to `Document`s.
531
513
  - Accepts an optional `only` parameter where you can specify a limited number
@@ -552,8 +534,8 @@ class UserSerializer < SimpleDelegator
552
534
  end
553
535
  ```
554
536
 
555
- You can create a scope on the model to eager load relationships when indexing or
556
- it can be used to limit the records to index.
537
+ You can override the `search_import` scope on the model to eager load
538
+ relationships when indexing or it can be used to limit the records to index.
557
539
 
558
540
  ```ruby
559
541
  class User < ApplicationRecord
@@ -561,7 +543,11 @@ class User < ApplicationRecord
561
543
  end
562
544
  ```
563
545
 
564
- The default index name for model indexes is
546
+ When searching, by default a collection of `Document`s is returned. Calling
547
+ `#results` on the search query will execute the search, and then look up all the
548
+ found records in the database and return an ActiveRecord relation.
549
+
550
+ The default `Index` name for model `Index`s is
565
551
  `#{model_name.plural}_#{RediSearch.env}`. The `redi_search` method takes an
566
552
  optional `index_prefix` argument which gets prepended to the index name:
567
553
 
@@ -578,15 +564,16 @@ User.redi_search_index.name
578
564
  ```
579
565
 
580
566
  When integrating RediSearch into a model, records will automatically be indexed
581
- after creating and updating and will be removed from the index upon destruction.
567
+ after creating and updating and will be removed from the `Index` upon
568
+ destruction.
582
569
 
583
- There are few more convenience methods that are publicly available:
570
+ There are a few more convenience methods that are publicly available:
584
571
  - `redi_search_document`
585
572
  - Returns the record as a `RediSearch::Document` instance
586
573
  - `redi_search_delete_document`
587
- - Removes the record from the index
574
+ - Removes the record from the `Index`
588
575
  - `redi_search_add_document`
589
- - Adds the record to the index
576
+ - Adds the record to the `Index`
590
577
  - `redi_search_index`
591
578
  - Returns the `RediSearch::Index` instance
592
579
 
@@ -594,15 +581,15 @@ There are few more convenience methods that are publicly available:
594
581
  ## Development
595
582
 
596
583
  After checking out the repo, run `bin/setup` to install dependencies. Then, run
597
- `rake test` to run the tests. You can also run `bin/console` for an interactive
598
- prompt that will allow you to experiment. You can also start a rails console if
599
- you `cd` into `test/dummy`.
584
+ `rake test` to run the both unit and integration tests. To run them individually
585
+ you can run `rake test:unit` or `rake test:integration`. You can also run
586
+ `bin/console` for an interactive prompt that will allow you to experiment.
600
587
 
601
588
  To install this gem onto your local machine, run `bundle exec rake install`. To
602
589
  release a new version, execute `bin/publish (major|minor|patch)` which will
603
590
  update the version number in `version.rb`, create a git tag for the version,
604
591
  push git commits and tags, and push the `.gem` file to
605
- [rubygems.org](https://rubygems.org).
592
+ [rubygems.org](https://rubygems.org) and GitHub.
606
593
 
607
594
  ## Contributing
608
595
 
data/Rakefile CHANGED
@@ -1,12 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
4
5
  require "rake/testtask"
5
6
 
6
- Rake::TestTask.new(:test) do |t|
7
+ RuboCop::RakeTask.new(:rubocop) do |t|
8
+ t.options = ["--display-cop-names"]
9
+ end
10
+
11
+ Rake::TestTask.new("test:unit") do |t|
12
+ t.libs << "test"
13
+ t.libs << "lib"
14
+ t.test_files = FileList["test/unit/**/*_test.rb"]
15
+ end
16
+
17
+ Rake::TestTask.new("test:integration") do |t|
7
18
  t.libs << "test"
8
19
  t.libs << "lib"
9
- t.test_files = FileList["test/**/*_test.rb"]
20
+ t.test_files = FileList["test/integration/**/*_test.rb"]
10
21
  end
11
22
 
12
- task default: :test
23
+ task test: [:default]
24
+ task default: ["test:integration", "test:unit", :rubocop]
data/bin/console CHANGED
@@ -4,5 +4,34 @@
4
4
  require "bundler/setup"
5
5
  require "redi_search"
6
6
 
7
+ require "faker"
7
8
  require "pry"
9
+ require "active_support/logger"
10
+ require "active_record"
11
+
12
+ ActiveSupport::LogSubscriber.logger = ActiveSupport::Logger.new(STDOUT)
13
+
14
+ ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
15
+
16
+ ActiveRecord::Migration.create_table :users do |t|
17
+ t.string :first
18
+ t.string :last
19
+ end
20
+
21
+ class User < ActiveRecord::Base
22
+ redi_search schema: {
23
+ first: { text: { phonetic: "dm:en" } },
24
+ last: { text: { phonetic: "dm:en" } }
25
+ }
26
+ end
27
+
28
+ def seed_users(count = 10_000)
29
+ User.insert_all(
30
+ Array.new(count).map do
31
+ { first: Faker::Name.first_name, last: Faker::Name.last_name }
32
+ end
33
+ )
34
+ User.reindex
35
+ end
36
+
8
37
  Pry.start
@@ -2,16 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "appraisal", "~> 2.2"
5
6
  gem "faker"
6
- gem "minitest", "~> 5.0"
7
7
  gem "mocha"
8
8
  gem "pry"
9
- gem "pry-rails"
10
9
  gem "rubocop"
10
+ gem "rubocop-minitest"
11
11
  gem "rubocop-performance"
12
- gem "rubocop-rails"
13
12
  gem "simplecov"
14
13
  gem "sqlite3"
15
- gem "rails", "6.0.0.rc1"
14
+ gem "activerecord", "< 6.1", ">= 6.0"
16
15
 
17
16
  gemspec path: "../"
@@ -2,16 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "appraisal", "~> 2.2"
5
6
  gem "faker"
6
- gem "minitest", "~> 5.0"
7
7
  gem "mocha"
8
8
  gem "pry"
9
- gem "pry-rails"
10
9
  gem "rubocop"
10
+ gem "rubocop-minitest"
11
11
  gem "rubocop-performance"
12
- gem "rubocop-rails"
13
12
  gem "simplecov"
14
13
  gem "sqlite3"
15
- gem "rails", "< 5.2", ">= 5.1"
14
+ gem "activerecord", "< 6.2", ">= 6.1"
16
15
 
17
16
  gemspec path: "../"