association_accessors 1.3.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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/Appraisals +25 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +254 -0
  7. data/Rakefile +27 -0
  8. data/association_accessors.gemspec +39 -0
  9. data/bin/test +21 -0
  10. data/gemfiles/activerecord_4.1.gemfile +7 -0
  11. data/gemfiles/activerecord_4.1.gemfile.lock +67 -0
  12. data/gemfiles/activerecord_4.2.gemfile +7 -0
  13. data/gemfiles/activerecord_4.2.gemfile.lock +67 -0
  14. data/gemfiles/activerecord_5.0.gemfile +7 -0
  15. data/gemfiles/activerecord_5.0.gemfile.lock +63 -0
  16. data/gemfiles/activerecord_5.1.gemfile +7 -0
  17. data/gemfiles/activerecord_5.1.gemfile.lock +63 -0
  18. data/gemfiles/activerecord_5.2.gemfile +7 -0
  19. data/gemfiles/activerecord_5.2.gemfile.lock +63 -0
  20. data/gemfiles/rspec_2.gemfile +7 -0
  21. data/gemfiles/rspec_2.gemfile.lock +58 -0
  22. data/lib/association_accessors.rb +30 -0
  23. data/lib/association_accessors/collection_association.rb +35 -0
  24. data/lib/association_accessors/singular_association.rb +19 -0
  25. data/lib/association_accessors/test/matcher.rb +60 -0
  26. data/lib/association_accessors/version.rb +3 -0
  27. data/spec/association_accessors_spec.rb +5 -0
  28. data/spec/dummy.rb +99 -0
  29. data/spec/matcher_spec.rb +56 -0
  30. data/spec/spec_helper.rb +23 -0
  31. data/spec/with_association/belongs_to_spec.rb +33 -0
  32. data/spec/with_association/has_and_belongs_to_many_spec.rb +45 -0
  33. data/spec/with_association/has_many_spec.rb +45 -0
  34. data/spec/with_association/has_many_through_spec.rb +27 -0
  35. data/spec/with_association/has_one_spec.rb +33 -0
  36. data/spec/with_association/has_one_through_spec.rb +43 -0
  37. data/spec/with_association/polymorphic/belongs_to_spec.rb +38 -0
  38. data/spec/with_association/polymorphic/has_many_spec.rb +44 -0
  39. data/spec/with_association/polymorphic/has_one_spec.rb +33 -0
  40. data/spec/with_association/with_custom_name_spec.rb +33 -0
  41. data/spec/with_attribute_spec.rb +47 -0
  42. metadata +203 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 427e524e67a28002e3e0b010c7536c410597d3d23bdfbb8dd8375743124b4251
4
+ data.tar.gz: ec24e909df781cdd00d70035451aaec6420617827fa8244531faf2381b09633c
5
+ SHA512:
6
+ metadata.gz: b787c454deb6947cd9f71f8fc7f710024dadebb8587e9ef6da762ca2124b463ef16e03c6b99897f09e28f9489bb3ca2166290d6e63cec81c9b27b8271da9f4d5
7
+ data.tar.gz: dae9c1963ff3c53f2aca2081b41b23e0a22d0e3b05a3ac63ed9363a4ca4631d8291a691880c9bdcd931fd54f77ba093f13f556662a7ec3985f08f35e78b3ca4b
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Appraisals ADDED
@@ -0,0 +1,25 @@
1
+ if RUBY_VERSION < '2.4'
2
+ appraise 'activerecord-4.1' do
3
+ gem 'activerecord', '4.1.7'
4
+ end
5
+ end
6
+
7
+ appraise 'activerecord-4.2' do
8
+ gem 'activerecord', '4.2.0'
9
+ end
10
+
11
+ appraise 'activerecord-5.0' do
12
+ gem 'activerecord', '5.0.3'
13
+ end
14
+
15
+ appraise 'activerecord-5.1' do
16
+ gem 'activerecord', '5.1.5'
17
+ end
18
+
19
+ appraise 'activerecord-5.2' do
20
+ gem 'activerecord', '5.2.2'
21
+ end
22
+
23
+ appraise 'rspec-2' do
24
+ gem 'rspec', '~> 2.0'
25
+ end
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in association_accessors.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Szijjártó Nagy Misu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,254 @@
1
+ # AssociationAccessors
2
+
3
+ **association_accessors** is a tool for generating accessors for `ActiveRecord` model associations based on columns other than the `id` (primary key).
4
+
5
+ ## Dependencies
6
+
7
+ * **ruby** `'>=2.3'`
8
+ * **activerecord** `'>=4.1', '<6.0'`
9
+ * **rspec** `'>= 2.0'` (for the test matcher)
10
+
11
+ ## Table of Contents
12
+
13
+ * [AssociationAccessors](#associationaccessors)
14
+ * [Dependencies](#dependencies)
15
+ * [Table of Contents](#table-of-contents)
16
+ * [The Challenge](#the-challenge)
17
+ * [Installation](#installation)
18
+ * [Config](#config)
19
+ * [Usage](#usage)
20
+ * [With belongs_to](#with-belongs_to)
21
+ * [With has_one](#with-has_one)
22
+ * [With has_many](#with-has_many)
23
+ * [With has_and_belongs_to_many](#with-has_and_belongs_to_many)
24
+ * [With custom association names](#with-custom-association-names)
25
+ * [With polymorphic associations](#with-polymorphic-associations)
26
+ * [Test matcher](#test-matcher)
27
+ * [Contributing](#contributing)
28
+ * [Development](#development)
29
+ * [License](#license)
30
+
31
+ ## The Challenge
32
+
33
+ You have the following tables:
34
+
35
+ ```ruby
36
+ ActiveRecord::Schema.define do
37
+ create_table :companies, force: true do |t|
38
+ t.string :serial
39
+ t.string :name
40
+ # ...
41
+ end
42
+
43
+ create_table :users, force: true do |t|
44
+ t.string :serial
45
+ t.integer :company_id
46
+ t.string :name
47
+ # ...
48
+ end
49
+ end
50
+ ```
51
+
52
+ For security reasons it is decided that the frontend must not see the `id`s, only the `serial`s. So, when you want to change the company of a user, `params` will contain something like this:
53
+
54
+ ```ruby
55
+ # <ActionController::Parameters { "serial": "9jco5RMp4K", "user": { company_serial: "MbyDB18lCi" } } permitted: false>
56
+ ```
57
+
58
+ Now, if the `User` model has `#company_serial=` method, you can simply permit `:company_serial`.
59
+
60
+ Using **association_accessors** it amounts to this:
61
+
62
+ ```ruby
63
+ class User < ActiveRecord::Base
64
+ include AssociationAccessors
65
+
66
+ belongs_to :company
67
+ association_accessor_for :company, with_attribute: :serial
68
+ end
69
+ ```
70
+
71
+ ## Installation
72
+
73
+ Add this line to your application's Gemfile:
74
+
75
+ ```ruby
76
+ gem 'association_accessors'
77
+ ```
78
+
79
+ And then execute:
80
+
81
+ $ bundle
82
+
83
+ ## Config
84
+
85
+ It is possible to set a default value for the keyword `with_attribute:`, for example in an initializer:
86
+
87
+ ```ruby
88
+ # config/initializers/association_accessors.rb
89
+ AssociationAccessors.default_attribute = :serial
90
+ ```
91
+
92
+ ## Usage
93
+
94
+ 1. include the module `AssociationAccessors`.
95
+ 2. define the associations
96
+ 3. call `.association_accessor_for` method with the association name and the identifier attribute to generate the accessor methods:
97
+ * for singular associations it will generate a reader and a writer along the rule `[association_name]_[attribute_name]`
98
+ * for collection associations it will generate the methods along the rule `[singular_association_name]_[plural_attribute_name]`
99
+
100
+ These accessors work more or less the same way as the `id` accessors generated by default for the associations.
101
+
102
+ There are a few exceptions and some gotchas, though.
103
+
104
+ ### With `belongs_to`
105
+
106
+ ```ruby
107
+ # AssociationAccessors is included in the ApplicationRecord
108
+ class User < ApplicationRecord
109
+ belongs_to :company, optional: true # only to demonstrate that it works with the association `nil`
110
+ association_accessor_for :company, with_attribute: :serial
111
+ end
112
+ ```
113
+
114
+ You have the methods `#company_id` and `#company_id=` because of the foreign key column. `association_accessors` generates the methods `#company_serial` and `#company_serial=`.
115
+
116
+ These work in a similar way with the following differences:
117
+ * `#company_id` is a column, `#company_serial` is a computed value (the `serial` of the `company`) - where `#company_id` can return value other than `nil` even without really having a `company`, `#company_serial` can only return the `serial` of the `company` (if any)
118
+ * `#company_id=` does not break if there is no company with the given id, only `#company` will return `nil` - whereas calling `#company_serial=` with a not existing serial will raise `ActiveRecord::RecordNotFound`
119
+
120
+ ```ruby
121
+ user.company # => #<Company id: 10, serial: "HVuPpK">
122
+ user.company_id # => 10
123
+ user.company_serial # => "HVuPpK"
124
+
125
+ user.company_id = 100 # there is no company with id=100
126
+ user.company # => nil
127
+ user.company_id # => 100
128
+ user.company_serial # => nil
129
+
130
+ user.company_serial = 'EeNRM'
131
+ # ActiveRecord::RecordNotFound (Couldn't find Company)
132
+ ```
133
+
134
+ ### With `has_one`
135
+
136
+ ```ruby
137
+ class User < ApplicationRecord
138
+ has_one :address
139
+ association_accessor_for :address, with_attribute: :serial
140
+ end
141
+ ```
142
+
143
+ There is no `#address_id` or `#address_id=` method for a `has_one` association. The generated methods (`#address_serial`, `#address_serial=`) behave the following way:
144
+ * `#address_serial` returns the `serial` of the `address` if any
145
+ * `#address_serial=`
146
+ * changes the `user_id` column of the `adress`(es) setting it to `null` or to the `id` of the user as required
147
+ * raises `ActiveRecord::RecordNotFound` if the given `serial` does not exist
148
+ * raises `ActiveRecord::HasOneThroughCantAssociateThroughHasOneOrManyReflection` if association is defined with `through:` option
149
+
150
+ ### With `has_many`
151
+
152
+ ```ruby
153
+ class Company < ApplicationRecord
154
+ has_many :users
155
+ association_accessor_for :users, with_attribute: :serial
156
+ end
157
+ ```
158
+
159
+ The generated methods (`#user_serials` and `#user_serials=`) will behave exactly the same way the [`collection_singular_ids`](https://guides.rubyonrails.org/association_basics.html#methods-added-by-has-many) accessor generated by `rails`:
160
+ * `#user_ids` will return the `id`s of the `users` - `#user_serials` will return the `serial`s of the `users`
161
+ * `#user_ids=` and `#user_serials=` will both
162
+ * update the `company_id` column of the users: setting it to `null` or to the `id` of the company as required
163
+ * raise `ActiveRecord::RecordNotFound` if any of the given `id`s or `serial`s is non-existing
164
+ * raise `ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection` if association is defined with `:through` option
165
+
166
+ ### With `has_and_belongs_to_many`
167
+
168
+ ```ruby
169
+ class User < ApplicationRecord
170
+ has_and_belongs_to_many :tasks
171
+ association_accessor_for :tasks, with_attribute: :serial
172
+ end
173
+ ```
174
+
175
+ The generated methods (`#task_serials` and `#task_serials=`) will behave exactly the same way the [`collection_singular_ids`](https://guides.rubyonrails.org/association_basics.html#methods-added-by-has-and-belongs-to-many) accessor generated by `rails`:
176
+ * `#task_ids` will return the `id`s of the `tasks` - `#task_serials` will return the `serial`s of the `tasks`
177
+ * `#task_ids=` and `#task_serials=` will both
178
+ * update the join table adding or deleting records as required
179
+ * raise `ActiveRecord::RecordNotFound` if any of the given `id`s or `serial`s is non-existing
180
+
181
+ ### With custom association names
182
+
183
+ ```ruby
184
+ class Node < ApplicationRecord
185
+ belongs_to :parent, class_name: 'Node'
186
+ association_accessor_for :parent, with_attribute: :serial
187
+
188
+ has_many :children, class_name: 'Node', foreign_key: :parent_id
189
+ association_accessor_for :children, with_attribute: :serial
190
+ end
191
+ ```
192
+
193
+ The generated methods (`#parent_serial`, `#parent_serial=`, `#child_serials` and `#child_serials=`) work the same way, as they rely on the association, not the column.
194
+
195
+ ### With polymorphic associations
196
+
197
+ ```ruby
198
+ class User < ApplicationRecord
199
+ has_one :image, as: :imageable
200
+ association_accessor_for :image, with_attribute: :serial
201
+ end
202
+
203
+ class Task < ApplicationRecord
204
+ has_many :images, as: :imageable
205
+ association_accessor_for :images, with_attribute: :serial
206
+ end
207
+
208
+ class Image < ApplicationRecord
209
+ belongs_to :imageable, polymorphic: true
210
+ end
211
+ ```
212
+
213
+ * The `has_one` and `has_many` parts work just fine, setting the `imageable_type` and `imageable_id` to `nil` or the class name and the `id` of the required record
214
+ * It is **not** recommended to use `association_accessors` for the `belongs_to` part of polymorphic associations, as the associated class is derived from the actual value of `[association_name]_type` column, causing unpredictable behavior and raising `NoMethodError` when it is `nil`
215
+
216
+ ## Test matcher
217
+
218
+ **association_accessors** ships a test matcher too: `#have_association_accessor_for`. It surely works with [rspec](https://relishapp.com/rspec).
219
+
220
+ ```ruby
221
+ RSpec.configure do |config|
222
+ config.include AssociationAccessors::Test, type: :model
223
+ end
224
+
225
+ RSpec.describe User, type: :model do
226
+ it { should have_association_accessor_for(:company).with_attribute(:serial) }
227
+ end
228
+ ```
229
+
230
+ So far, it checks if the reader and writer methods are defined on the subject, nothing more.
231
+
232
+ ## Contributing
233
+
234
+ Bug reports and pull requests are welcome on GitHub at https://github.com/SzNagyMisu/association_accessors.
235
+
236
+ ## Development
237
+
238
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
239
+
240
+ To test against other `activerecord` or `rspec` versions, check the `./Appraisals` file and choose one:
241
+
242
+ $ bundle exec appraisal activerecord-5.0 bin/console
243
+ $ bundle exec appraisal activerecord-5.0 rspec
244
+
245
+ To run a full test suite (including multiple ruby, activerecord and rspec versions), run:
246
+
247
+ $ rake full_test
248
+ $ RUBY_VERSIONS=2.5.3,2.6.1 rake full_test
249
+
250
+ Setting the environment variable `RUBY_VERSIONS` overrides the default (`2.3.7`, `2.4.1`, `2.5.1`) ruby versions to test against. Note that while the ruby versions must be installed for the test to run, the gems are handled by [appraisal](https://github.com/thoughtbot/appraisal).
251
+
252
+ ## License
253
+
254
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ DEFAULT_RUBY_VERSIONS = [ '2.3.7', '2.4.1', '2.5.1' ].freeze
5
+
6
+ desc "Test against multiple ruby, activerecord and rspec versions - " +
7
+ "set RUBY_VERSIONS to the version(s) to test with (default: #{DEFAULT_RUBY_VERSIONS.join(',').inspect})"
8
+ task :full_test do
9
+ versions = ENV['RUBY_VERSIONS'] ? ENV['RUBY_VERSIONS'].split(',') : DEFAULT_RUBY_VERSIONS
10
+ started_at = Time.now
11
+
12
+ versions.each do |version|
13
+ sh "./bin/test #{version}"
14
+ end
15
+
16
+ time_elapsed = (Time.now - started_at).to_i
17
+ hours = time_elapsed / 3600
18
+ minutes = time_elapsed / 60 % 60
19
+ seconds = time_elapsed % 60
20
+ puts "\nTest suit complete\n" +
21
+ " ruby versions: #{versions.join(', ')}\n" +
22
+ " run in #{hours}h #{minutes}m #{seconds}s\n"
23
+ end
24
+
25
+ RSpec::Core::RakeTask.new(:spec)
26
+
27
+ task :default => :spec
@@ -0,0 +1,39 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "association_accessors/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "association_accessors"
8
+ spec.version = AssociationAccessors::VERSION
9
+ spec.authors = ["Szijjártó Nagy Misu"]
10
+ spec.email = ["szijjartonagy.misu@gmail.com"]
11
+
12
+ spec.summary = 'Handling AR associations with other attributes than primary key'
13
+ spec.description = 'Provides association accessors like `Company#user_serials` and `User#company_serial` where `Company.has_many :users` and `User.belongs_to :company`.'
14
+ spec.homepage = 'https://github.com/SzNagyMisu/association_accessors'
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = spec.homepage
22
+ else
23
+ raise "RubyGems 2.0 or newer is required to protect against " \
24
+ "public gem pushes."
25
+ end
26
+
27
+ spec.files = `git ls-files -- lib/*`.split("\n") + %w[ README.md LICENSE.txt association_accessors.gemspec ]
28
+ spec.test_files = `git ls-files -- gemfiles/* spec/*`.split("\n") + %w[ Appraisals Gemfile Rakefile .rspec bin/test ]
29
+ spec.bindir = "bin"
30
+ spec.executables = []
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.16"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ spec.add_development_dependency "activerecord", "~> 5.2"
37
+ spec.add_development_dependency "sqlite3", "~> 1.3"
38
+ spec.add_development_dependency "appraisal", "~> 2.2"
39
+ end
data/bin/test ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ if [ $1 ]; then
6
+ # see https://rvm.io/workflow/scripting
7
+ if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
8
+ source "$HOME/.rvm/scripts/rvm"
9
+ elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
10
+ source "/usr/local/rvm/scripts/rvm"
11
+ else
12
+ printf "ERROR: An RVM installation was not found."
13
+ fi
14
+ rvm use $1
15
+ fi
16
+
17
+ bundle install
18
+ bundle exec appraisal install
19
+ bundle exec appraisal rspec
20
+
21
+ echo 'Success!'
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "4.1.7"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ association_accessors (1.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (4.1.7)
10
+ activesupport (= 4.1.7)
11
+ builder (~> 3.1)
12
+ activerecord (4.1.7)
13
+ activemodel (= 4.1.7)
14
+ activesupport (= 4.1.7)
15
+ arel (~> 5.0.0)
16
+ activesupport (4.1.7)
17
+ i18n (~> 0.6, >= 0.6.9)
18
+ json (~> 1.7, >= 1.7.7)
19
+ minitest (~> 5.1)
20
+ thread_safe (~> 0.1)
21
+ tzinfo (~> 1.1)
22
+ appraisal (2.2.0)
23
+ bundler
24
+ rake
25
+ thor (>= 0.14.0)
26
+ arel (5.0.1.20140414130214)
27
+ builder (3.2.3)
28
+ concurrent-ruby (1.1.4)
29
+ diff-lcs (1.3)
30
+ i18n (0.9.5)
31
+ concurrent-ruby (~> 1.0)
32
+ json (1.8.6)
33
+ minitest (5.11.3)
34
+ rake (10.5.0)
35
+ rspec (3.8.0)
36
+ rspec-core (~> 3.8.0)
37
+ rspec-expectations (~> 3.8.0)
38
+ rspec-mocks (~> 3.8.0)
39
+ rspec-core (3.8.0)
40
+ rspec-support (~> 3.8.0)
41
+ rspec-expectations (3.8.2)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.8.0)
44
+ rspec-mocks (3.8.0)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.8.0)
47
+ rspec-support (3.8.0)
48
+ sqlite3 (1.3.13)
49
+ thor (0.20.3)
50
+ thread_safe (0.3.6)
51
+ tzinfo (1.2.5)
52
+ thread_safe (~> 0.1)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ activerecord (= 4.1.7)
59
+ appraisal (~> 2.2)
60
+ association_accessors!
61
+ bundler (~> 1.16)
62
+ rake (~> 10.0)
63
+ rspec (~> 3.0)
64
+ sqlite3 (~> 1.3)
65
+
66
+ BUNDLED WITH
67
+ 1.16.6