deep_preloader 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 60cc928760d63a608b81e43c8888d1ba827bd82fe928ee8d3ece46f06306e885
4
+ data.tar.gz: 0dcec8c15e0dd6f51127ba9b8f868091ce775a67fc5585786b446ac673875b50
5
+ SHA512:
6
+ metadata.gz: e96854b66b2aeda406e0f7b6da7d7a61b6de93da257b1aeb4392b7710182cdc861574871336278c743e614f47c20bc15e10251538ea3214c03a89c09c6dc3307
7
+ data.tar.gz: 2aa7588b8d4ab4a2052866ef96b93a46c6f2ac0ed9c6c10aed86088b4b8a13a3d102da7734d240ac0ec33d38ed3bc4872724f44574c0c2fedc8f8b693d95f4e9
@@ -0,0 +1,103 @@
1
+ version: 2.1
2
+
3
+ executors:
4
+ ruby:
5
+ parameters:
6
+ ruby-version:
7
+ type: string
8
+ default: "2.6"
9
+ gemfile:
10
+ type: string
11
+ default: "Gemfile"
12
+ docker:
13
+ - image: circleci/ruby:<< parameters.ruby-version >>
14
+ environment:
15
+ BUNDLE_JOBS: 3
16
+ BUNDLE_RETRY: 3
17
+ BUNDLE_PATH: vendor/bundle
18
+ RAILS_ENV: test
19
+ BUNDLE_GEMFILE: << parameters.gemfile >>
20
+
21
+ jobs:
22
+ test:
23
+ parameters:
24
+ ruby-version:
25
+ type: string
26
+ gemfile:
27
+ type: string
28
+ executor:
29
+ name: ruby
30
+ ruby-version: << parameters.ruby-version >>
31
+ gemfile: << parameters.gemfile >>
32
+ parallelism: 1
33
+ steps:
34
+ - checkout
35
+
36
+ - run:
37
+ # Remove the non-appraisal gemfile for safety: we never want to use it.
38
+ name: Prepare bundler
39
+ command: bundle -v
40
+
41
+ - run:
42
+ name: Compute a gemfile lock
43
+ command: bundle lock && cp "${BUNDLE_GEMFILE}.lock" /tmp/gem-lock
44
+
45
+ - restore_cache:
46
+ keys:
47
+ - deep_preloader-<< parameters.ruby-version >>-{{ checksum "/tmp/gem-lock" }}
48
+ - deep_preloader-
49
+
50
+ - run:
51
+ name: Bundle Install
52
+ command: bundle check || bundle install
53
+
54
+ - save_cache:
55
+ key: deep_preloader-<< parameters.ruby-version >>-{{ checksum "/tmp/gem-lock" }}
56
+ paths:
57
+ - vendor/bundle
58
+
59
+ - run:
60
+ name: Run rspec
61
+ command: bundle exec rspec --profile 10 --format RspecJunitFormatter --out test_results/rspec.xml --format progress
62
+
63
+ - store_test_results:
64
+ path: test_results
65
+
66
+ publish:
67
+ executor: ruby
68
+ steps:
69
+ - checkout
70
+ - run:
71
+ name: Setup Rubygems
72
+ command: |
73
+ mkdir ~/.gem &&
74
+ echo -e "---\r\n:rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials &&
75
+ chmod 0600 ~/.gem/credentials
76
+ - run:
77
+ name: Publish to Rubygems
78
+ command: |
79
+ gem build deep_preloader.gemspec
80
+ gem push deep_preloader-*.gem
81
+
82
+ workflows:
83
+ version: 2.1
84
+ build:
85
+ jobs:
86
+ - test:
87
+ name: 'ruby 2.5 ActiveRecord 5.2'
88
+ ruby-version: "2.5"
89
+ gemfile: gemfiles/activerecord_5_2.gemfile
90
+ - test:
91
+ name: 'ruby 2.6 ActiveRecord 5.2'
92
+ ruby-version: "2.6"
93
+ gemfile: gemfiles/activerecord_5_2.gemfile
94
+ - test:
95
+ name: 'ruby 2.6 ActiveRecord 6.0-beta'
96
+ ruby-version: "2.6"
97
+ gemfile: gemfiles/activerecord_6_0_beta.gemfile
98
+ - publish:
99
+ filters:
100
+ branches:
101
+ only: master
102
+ tags:
103
+ ignore: /.*/
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ gemfiles/*.gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ dist: trusty
2
+ sudo: false
3
+ language: ruby
4
+ rvm:
5
+ - 2.5
6
+ gemfile:
7
+ - gemfiles/activerecord_5_2.gemfile
8
+ notifications:
9
+ email: false
data/Appraisals ADDED
@@ -0,0 +1,7 @@
1
+ appraise "activerecord-5-2" do
2
+ gem "activerecord", "~> 5.2.0"
3
+ end
4
+
5
+ appraise 'activerecord-6-0-beta' do
6
+ gem 'activerecord', '~> 6.0.0.beta'
7
+ end
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in deep_preloader.gemspec
4
+ gemspec
5
+ gem 'rspec_junit_formatter'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 DMM.com
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ # DeepPreloader
2
+ [![Build Status](https://travis-ci.org/iknow/deep_preloader.svg?branch=master)](https://travis-ci.org/iknow/deep_preloader)
3
+
4
+ An explicit preloader for ActiveRecord, supporting traversal of polymorphic relationships.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "deep_preloader"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'deep_preloader/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "deep_preloader"
8
+ spec.version = DeepPreloader::VERSION
9
+ spec.authors = ["iKnow Team"]
10
+ spec.email = ["dev@iknow.jp"]
11
+
12
+ spec.summary = %q{Explicit preloader for ActiveRecord}
13
+ spec.homepage = "http://github.com/iknow/deep_preloader"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activerecord", '>= 5.0.0'
22
+
23
+ spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "database_cleaner"
27
+ spec.add_development_dependency "minitest"
28
+
29
+ spec.add_development_dependency "byebug"
30
+ spec.add_development_dependency "pry"
31
+ spec.add_development_dependency "method_source"
32
+ spec.add_development_dependency "appraisal"
33
+ spec.add_development_dependency "sqlite3"
34
+ end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec_junit_formatter"
6
+ gem "activerecord", "~> 5.2.0"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec_junit_formatter"
6
+ gem "activerecord", "~> 6.0.0.beta"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,5 @@
1
+ class DeepPreloader::AbstractSpec
2
+ def for_type(clazz)
3
+ raise ArgumentError.new("Cannot type dispatch on non-polymorphic preload spec #{self.inspect}")
4
+ end
5
+ end
@@ -0,0 +1,56 @@
1
+ require 'deep_preloader/abstract_spec'
2
+
3
+ class DeepPreloader::PolymorphicSpec < DeepPreloader::AbstractSpec
4
+ attr_reader :specs_by_type
5
+
6
+ def self.parse(data)
7
+ if data.is_a?(Hash)
8
+ specs = data.each_with_object({}) do |(k, v), h|
9
+ h[k.to_s] = DeepPreloader::Spec.parse(v)
10
+ end
11
+ self.new(specs)
12
+ else
13
+ raise ArgumentError.new("Invalid polymorphic spec: '#{data.inspect}' is not a hash")
14
+ end
15
+ end
16
+
17
+ def initialize(specs_by_type = {})
18
+ @specs_by_type = specs_by_type
19
+ end
20
+
21
+ def for_type(clazz)
22
+ specs_by_type[clazz.name]
23
+ end
24
+
25
+ def merge!(other)
26
+ case other
27
+ when nil
28
+ return
29
+ when DeepPreloader::PolymorphicSpec
30
+ other.specs_by_type.each do |k, v|
31
+ if specs_by_type[k]
32
+ specs_by_type[k].merge!(v)
33
+ else
34
+ specs_by_type[k] = v
35
+ end
36
+ end
37
+ else
38
+ raise ArgumentError.new("Cannot merge #{other.class.name} into #{self.inspect}")
39
+ end
40
+ self
41
+ end
42
+
43
+ def hash
44
+ [self.class, self.specs_by_type].hash
45
+ end
46
+
47
+ def ==(other)
48
+ self.class == other.class && self.specs_by_type == other.specs_by_type
49
+ end
50
+
51
+ alias eql? ==
52
+
53
+ def inspect
54
+ "PolySpec#{specs_by_type.inspect}"
55
+ end
56
+ end
@@ -0,0 +1,63 @@
1
+ require 'deep_preloader/abstract_spec'
2
+
3
+ class DeepPreloader::Spec < DeepPreloader::AbstractSpec
4
+ attr_reader :association_specs
5
+
6
+ def self.parse(data)
7
+ case data
8
+ when Array
9
+ data.inject(self.new) do |acc, v|
10
+ acc.merge!(parse(v))
11
+ end
12
+ when Hash
13
+ assoc_specs = data.each_with_object({}) do |(k, v), h|
14
+ h[k.to_sym] = parse(v)
15
+ end
16
+ self.new(assoc_specs)
17
+ when String, Symbol
18
+ self.new({ data.to_sym => nil })
19
+ when DeepPreloader::AbstractSpec
20
+ data
21
+ when nil
22
+ nil
23
+ else
24
+ raise ArgumentError.new("Cannot parse invalid hash preload spec: #{hash.inspect}")
25
+ end
26
+ end
27
+
28
+ def initialize(association_specs = {})
29
+ @association_specs = association_specs
30
+ end
31
+
32
+ def merge!(other)
33
+ case other
34
+ when nil
35
+ return
36
+ when DeepPreloader::Spec
37
+ other.association_specs.each do |k, v|
38
+ if association_specs[k]
39
+ association_specs[k].merge!(v)
40
+ else
41
+ association_specs[k] = v
42
+ end
43
+ end
44
+ else
45
+ raise ArgumentError.new("Cannot merge #{other.class.name} into #{self.inspect}")
46
+ end
47
+ self
48
+ end
49
+
50
+ def hash
51
+ [self.class, self.association_specs].hash
52
+ end
53
+
54
+ def ==(other)
55
+ self.class == other.class && self.association_specs == other.association_specs
56
+ end
57
+
58
+ alias eql? ==
59
+
60
+ def inspect
61
+ "Spec#{association_specs.inspect}"
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ class DeepPreloader
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,271 @@
1
+ require "deep_preloader/version"
2
+ require "deep_preloader/spec"
3
+ require "deep_preloader/polymorphic_spec"
4
+ require "active_record"
5
+
6
+ DEBUG = ENV['DEBUG'].present?
7
+
8
+ class DeepPreloader
9
+ def self.preload(models, spec, lock: nil)
10
+ return if spec.nil? || models.blank?
11
+
12
+ worker = PreloadWorker.new(lock: lock)
13
+ spec = Spec.parse(spec) unless spec.is_a?(AbstractSpec)
14
+
15
+ models_by_class = Array.wrap(models).group_by(&:class)
16
+
17
+ case spec
18
+ when Spec
19
+ unless models_by_class.size == 1
20
+ raise ArgumentError.new("Provided multiple model types to non-polymorphic preload spec")
21
+ end
22
+
23
+ model_class, models = models_by_class.first
24
+ worker.add_associations_from_spec(models, model_class, spec)
25
+ when PolymorphicSpec
26
+ models_by_class.each do |model_class, models|
27
+ model_spec = spec.for_type(model_class)
28
+ next unless model_spec
29
+ worker.add_associations_from_spec(models, model_class, model_spec)
30
+ end
31
+ end
32
+
33
+ worker.run!
34
+ models
35
+ end
36
+
37
+ class PreloadWorker
38
+ def initialize(lock:)
39
+ @lock = lock
40
+ @worklist = {}
41
+ end
42
+
43
+ def add_associations_from_spec(models, model_class, spec)
44
+ spec.association_specs.each do |association_name, child_spec|
45
+ association_reflection = model_class.reflect_on_association(association_name)
46
+ if association_reflection.nil?
47
+ raise ArgumentError.new("Preloading error: couldn't find association #{association_name} on model class #{model_class.name}")
48
+ end
49
+
50
+ if association_reflection.polymorphic?
51
+ add_polymorphic_association(models, association_reflection, child_spec)
52
+ else
53
+ add_association(models, association_reflection, child_spec)
54
+ end
55
+ end
56
+ end
57
+
58
+ def run!
59
+ while(@worklist.present?)
60
+ context, entries = @worklist.shift
61
+ ActiveRecord::Base.logger.debug("Preloading children in context #{context}") if DEBUG
62
+
63
+ loaded_entries, unloaded_entries = entries.partition(&:loaded?)
64
+
65
+ unloaded_keys = unloaded_entries.map(&:key).to_set.delete(nil)
66
+
67
+ ActiveRecord::Base.logger.debug("Need to load children for following keys: #{unloaded_keys.to_a}") if DEBUG
68
+
69
+ found_children = {}
70
+
71
+ if unloaded_keys.present?
72
+ # When :belongs_to, children could be shared with already loaded
73
+ # entries - use what we already have.
74
+ loaded_entries.each do |entry|
75
+ next unless entry.belongs_to?
76
+
77
+ if entry.belongs_to? && unloaded_keys.delete?(entry.key)
78
+ found_children[entry.key] = entry.children
79
+ end
80
+ end
81
+ ActiveRecord::Base.logger.debug("found loaded children for keys #{found_children.keys}") if DEBUG
82
+ end
83
+
84
+ if unloaded_keys.present?
85
+ fetched_children = context.load_children(unloaded_keys.to_a, lock: @lock)
86
+ ActiveRecord::Base.logger.debug("fetched children for keys #{fetched_children.keys}") if DEBUG
87
+ found_children.merge!(fetched_children)
88
+ end
89
+
90
+ unloaded_entries.each do |entry|
91
+ children = found_children.fetch(entry.key, [])
92
+ entry.children = children
93
+ end
94
+
95
+ entries.each do |entry|
96
+ children = entry.children
97
+ child_spec = entry.child_spec
98
+ next unless child_spec && children.present?
99
+ child_class = children.first.class # children of a given parent are all of the same type
100
+ add_associations_from_spec(children, child_class, child_spec)
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+
107
+ private
108
+
109
+ def add_polymorphic_association(models, association_reflection, polymorphic_child_spec)
110
+ assoc_name = association_reflection.name
111
+
112
+ # If a model belongs_to a polymorphic child, we know what type it is.
113
+ # Group models by the type of their associated child and add each
114
+ # separately.
115
+ models_by_child_class = models.group_by { |m| m.association(assoc_name).klass }
116
+
117
+ # For models with no child there's nothing to preload, but we still need
118
+ # to set the association target. Since we can't infer a class for
119
+ # `add_association`, set it up here.
120
+ models_by_child_class.delete(nil)&.each do |model|
121
+ model.association(assoc_name).loaded!
122
+ end
123
+
124
+ models_by_child_class.each do |child_class, child_class_models|
125
+ child_preload_spec = polymorphic_child_spec&.for_type(child_class)
126
+ add_association(child_class_models, association_reflection, child_preload_spec, type: child_class)
127
+ end
128
+ end
129
+
130
+ def add_association(models, association_reflection, child_preload_spec, type: association_reflection.klass)
131
+ key_col = child_key_column(association_reflection)
132
+ child_constraints = child_constraints(association_reflection)
133
+
134
+ context = WorklistContext.new(type, key_col, child_constraints)
135
+ models.each do |model|
136
+ entry = WorklistEntry.new(model, association_reflection, child_preload_spec)
137
+ worklist_add(context, entry)
138
+ end
139
+ end
140
+
141
+ def worklist_add(key, entry)
142
+ (@worklist[key] ||= []) << entry
143
+ end
144
+
145
+ def child_constraints(association_reflection)
146
+ constraints = []
147
+ if association_reflection.options[:as]
148
+ # each parent model is pointed to from a child type that could also belong to other types of parent. Constrain the search to this parent.
149
+ constraints << [association_reflection.type, association_reflection.active_record.base_class.sti_name]
150
+ end
151
+
152
+ unless association_reflection.constraints.blank?
153
+ raise ArgumentError.new("Preloading conditional associations not supported: #{association_reflection.name}")
154
+ end
155
+
156
+ unless association_reflection.scope.blank?
157
+ raise ArgumentError.new("Preloading scoped associations not supported: #{association_reflection.name}")
158
+ end
159
+
160
+ constraints
161
+ end
162
+
163
+ def child_key_column(association_reflection)
164
+ case association_reflection.macro
165
+ when :belongs_to
166
+ association_reflection.active_record_primary_key
167
+ when :has_one, :has_many
168
+ association_reflection.foreign_key
169
+ else
170
+ raise "Unsupported association type #{association_reflection.macro}"
171
+ end
172
+ end
173
+ end
174
+
175
+ # entries need to be grouped by:
176
+ # child_type - look up in same table
177
+ # child_key - compare the same keys
178
+ # child_search_constraints - where constraints on child lookup such as polymorphic type or association scope.
179
+ WorklistContext = Struct.new(:child_type, :child_key_column, :child_constraints) do
180
+ def load_children(keys, lock: nil)
181
+ scope = child_constraints.inject(child_type.unscoped) do |sc, (col, val)|
182
+ sc.where(col => val)
183
+ end
184
+
185
+ if lock
186
+ scope = scope.order(:id).lock(lock)
187
+ end
188
+
189
+ scope.where(child_key_column => keys).group_by { |c| c.read_attribute(child_key_column) }
190
+ end
191
+ end
192
+
193
+ class WorklistEntry
194
+ attr_reader :model, :association_reflection, :child_spec
195
+
196
+ def initialize(model, association_reflection, child_spec)
197
+ @model = model
198
+ @association_reflection = association_reflection
199
+ @child_spec = child_spec
200
+ end
201
+
202
+ def association_name
203
+ @association_reflection.name
204
+ end
205
+
206
+ def association_macro
207
+ @association_reflection.macro
208
+ end
209
+
210
+ def loaded?
211
+ model.association(association_name).loaded?
212
+ end
213
+
214
+ def belongs_to?
215
+ association_macro == :belongs_to
216
+ end
217
+
218
+ def collection?
219
+ association_macro == :has_many
220
+ end
221
+
222
+ def key
223
+ model.read_attribute(parent_key_column)
224
+ end
225
+
226
+ # Conceal the difference between singular and collection associations so
227
+ # that `load_children` can always `group_by` the key
228
+ def children
229
+ target = model.association(association_name).target
230
+
231
+ if collection?
232
+ target
233
+ elsif target
234
+ [target]
235
+ else
236
+ []
237
+ end
238
+ end
239
+
240
+ def children=(targets)
241
+ if collection?
242
+ target = targets
243
+ else
244
+ if targets.size > 1
245
+ raise RuntimeError.new("Internal preloader error: attempted to attach multiple children to a singular association")
246
+ end
247
+ target = targets.first
248
+ end
249
+
250
+ ActiveRecord::Base.logger.debug("attaching children to #{model.inspect}.#{association_name}: #{targets}") if DEBUG
251
+
252
+ association = model.association(association_name)
253
+ association.loaded!
254
+ association.target = target
255
+ targets.each { |t| association.set_inverse_instance(t) }
256
+ targets
257
+ end
258
+
259
+ def parent_key_column
260
+ case association_macro
261
+ when :belongs_to
262
+ @association_reflection.foreign_key
263
+ when :has_one, :has_many
264
+ @association_reflection.active_record_primary_key
265
+ else
266
+ raise "Unsupported association type #{@association_reflection.macro}"
267
+ end
268
+ end
269
+ end
270
+
271
+ end
metadata ADDED
@@ -0,0 +1,216 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deep_preloader
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - iKnow Team
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-04-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: database_cleaner
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: method_source
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: appraisal
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: sqlite3
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description:
168
+ email:
169
+ - dev@iknow.jp
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".circleci/config.yml"
175
+ - ".gitignore"
176
+ - ".rspec"
177
+ - ".travis.yml"
178
+ - Appraisals
179
+ - Gemfile
180
+ - LICENSE.txt
181
+ - README.md
182
+ - Rakefile
183
+ - bin/console
184
+ - bin/setup
185
+ - deep_preloader.gemspec
186
+ - gemfiles/activerecord_5_2.gemfile
187
+ - gemfiles/activerecord_6_0_beta.gemfile
188
+ - lib/deep_preloader.rb
189
+ - lib/deep_preloader/abstract_spec.rb
190
+ - lib/deep_preloader/polymorphic_spec.rb
191
+ - lib/deep_preloader/spec.rb
192
+ - lib/deep_preloader/version.rb
193
+ homepage: http://github.com/iknow/deep_preloader
194
+ licenses:
195
+ - MIT
196
+ metadata: {}
197
+ post_install_message:
198
+ rdoc_options: []
199
+ require_paths:
200
+ - lib
201
+ required_ruby_version: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - ">="
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ required_rubygems_version: !ruby/object:Gem::Requirement
207
+ requirements:
208
+ - - ">="
209
+ - !ruby/object:Gem::Version
210
+ version: '0'
211
+ requirements: []
212
+ rubygems_version: 3.0.3
213
+ signing_key:
214
+ specification_version: 4
215
+ summary: Explicit preloader for ActiveRecord
216
+ test_files: []