ar_lazy_preload 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 69e0b3d4a8e8ac0c7c3824058347406f2ede573183f085b40acfd288e2b43014
4
+ data.tar.gz: d47fa44acb9b48181ac97c4c77138977375e1f593b4eaee4673314895836220f
5
+ SHA512:
6
+ metadata.gz: 73f6f5dd9b745e262d5e2e1e6532f266c65eda63282938e2b08838cbb1bf4e161df8a38d208c436714967d13ef2579a6398c492b3690f98d5d9a082169d93065
7
+ data.tar.gz: 5f084968e4c8aacdf438ab08f94e2768f9090185e91c1ce4e9f7841558d0541b42f8e3b9926df85191d634b01cbcb1aab9e7702b77a2eb438cf0b732017e9322
@@ -0,0 +1,20 @@
1
+ Copyright 2018 DmitryTsepelev
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,63 @@
1
+ # ArLazyPreload [![Cult Of Martians](http://cultofmartians.com/assets/badges/badge.svg)](https://cultofmartians.com/tasks/activerecord-lazy-preload.html) [![Gem Version](https://badge.fury.io/rb/ar_lazy_preload.svg)](https://rubygems.org/gems/ar_lazy_preload) [![Build Status](https://travis-ci.org/DmitryTsepelev/ar_lazy_preload.svg?branch=master)](https://travis-ci.org/DmitryTsepelev/ar_lazy_preload) [![Maintainability](https://api.codeclimate.com/v1/badges/00d04595661820dfba80/maintainability)](https://codeclimate.com/github/DmitryTsepelev/ar_lazy_preload/maintainability) [![Coverage Status](https://coveralls.io/repos/github/DmitryTsepelev/ar_lazy_preload/badge.svg?branch=master)](https://coveralls.io/github/DmitryTsepelev/ar_lazy_preload?branch=master)
2
+
3
+ **ArLazyPreload** is a gem that brings association lazy load functionality to your Rails applications. There is a number of built-in methods to solve [N+1 problem](https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations), but sometimes a list of associations to preload is not obvious–this is when you can get most of this gem.
4
+
5
+ - **Simple**. The only thing you need to change is to use `#lazy_preload` instead of `#includes`, `#eager_load` or `#preload`
6
+ - **Fast**. Take a look at [benchmarks](https://travis-ci.org/DmitryTsepelev/ar_lazy_preload) (`TASK=bench` and `TASK=memory`)
7
+ - **Perfect fit for GraphQL**. Define a list of associations to load at the top-level resolver and let the gem do its job
8
+ - **Auto-preload support**. If you don't want to specify the association list–set `ArLazyPreload.config.auto_preload` to `true`
9
+
10
+ <p align="center">
11
+ <a href="https://evilmartians.com/?utm_source=ar_lazy_preload">
12
+ <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
13
+ </a>
14
+ </p>
15
+
16
+ ## Why should I use it?
17
+
18
+ Lazy loading is super helpful when the list of associations to load is determined dynamically. For instance, in GraphQL this list comes from the API client, and you'll have to inspect the selection set to find out what associations are going to be used.
19
+
20
+ This gem uses a different approach: it won't load anything until the association is called for a first time. When it happens–it loads all the associated records for all records from the initial relation in a single query.
21
+
22
+ ## Usage
23
+
24
+ Let's try `#lazy_preload` in action! The following code will perform a single SQL request (because we've never accessed posts):
25
+
26
+ ```ruby
27
+ users = User.lazy_preload(:posts).limit(10) # => SELECT * FROM users LIMIT 10
28
+ users.map(&:first_name)
29
+ ```
30
+
31
+ However, when we try to load posts, there will be one more request for posts:
32
+
33
+ ```ruby
34
+ users.map(&:posts) # => SELECT * FROM posts WHERE user_id in (...)
35
+ ```
36
+
37
+ ## Auto preloading
38
+
39
+ If you want the gem to be even lazier–you can configure it to load all the associations lazily without specifying them explicitly. To do that you'll need to change the configuration in the following way:
40
+
41
+ ```ruby
42
+ ArLazyPreload.config.auto_preload = true
43
+ ```
44
+
45
+ After that there is no need to call `#lazy_preload` on the association, everything would be loaded lazily.
46
+
47
+ If you want to turn automatic preload off for a specific record, you can call `.skip_preload` before any associations method:
48
+
49
+ ```ruby
50
+ users.first.skip_preload.posts # => SELECT * FROM posts WHERE user_id = ?
51
+ ```
52
+
53
+ ## Installation
54
+
55
+ Add this line to your application's Gemfile, and you're all set:
56
+
57
+ ```ruby
58
+ gem "ar_lazy_preload"
59
+ ```
60
+
61
+ ## License
62
+
63
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,25 @@
1
+ require "appraisal"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+ require "rubocop/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ RuboCop::RakeTask.new
8
+
9
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
10
+ task :default do
11
+ sh "rubocop && appraisal install && rake appraisal spec"
12
+ end
13
+ else
14
+ task default: [:rubocop, :spec]
15
+ end
16
+
17
+ task :bench do
18
+ cmd = %w[bundle exec ruby benchmark/main.rb]
19
+ exit system(*cmd)
20
+ end
21
+
22
+ task :memory do
23
+ cmd = %w[bundle exec ruby benchmark/memory.rb]
24
+ exit system(*cmd)
25
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ar_lazy_preload/configuration"
4
+ require "ar_lazy_preload/railtie"
5
+
6
+ module ArLazyPreload
7
+ class << self
8
+ def config
9
+ @config ||= Configuration.new
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ # ActiveRecord::Association patch with a hook for lazy preloading
5
+ module Association
6
+ def load_target
7
+ owner.try_preload_lazily(reflection.name)
8
+ super
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ # ActiveRecord::AssociationRelation patch for setting up lazy_preload_values based on
5
+ # owner context
6
+ module AssociationRelation
7
+ def initialize(*args)
8
+ super(*args)
9
+ setup_preloading_context unless ArLazyPreload.config.auto_preload?
10
+ end
11
+
12
+ delegate :owner, :reflection, to: :proxy_association
13
+ delegate :lazy_preload_context, to: :owner
14
+
15
+ private
16
+
17
+ def setup_preloading_context
18
+ return if lazy_preload_context.nil?
19
+
20
+ association_tree_builder = AssociationTreeBuilder.new(lazy_preload_context.association_tree)
21
+ subtree = association_tree_builder.subtree_for(reflection.name)
22
+
23
+ lazy_preload!(subtree)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ # ActiveRecord::Base patch with lazy preloading support
5
+ module Base
6
+ def self.included(base)
7
+ base.class.delegate :lazy_preload, to: :all
8
+ end
9
+
10
+ attr_accessor :lazy_preload_context
11
+
12
+ delegate :try_preload_lazily, to: :lazy_preload_context, allow_nil: true
13
+
14
+ def skip_preload
15
+ lazy_preload_context&.records&.delete(self)
16
+ self.lazy_preload_context = nil
17
+ self
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ # ActiveRecord::CollectionAssociation patch with a hook for lazy preloading
5
+ module CollectionAssociation
6
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
7
+ def ids_reader
8
+ return super if owner.lazy_preload_context.blank?
9
+
10
+ primary_key = reflection.association_primary_key.to_sym
11
+ if loaded?
12
+ target.map(&primary_key)
13
+ elsif !target.empty?
14
+ load_target.map(&primary_key)
15
+ else
16
+ @association_ids ||= reader.map(&primary_key)
17
+ end
18
+ end
19
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ # ActiveRecord::CollectionProxy patch for getting records for preload
5
+ module CollectionProxy
6
+ private
7
+
8
+ def ar_lazy_preload_records
9
+ target
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ # ActiveRecord::Relation::Merger patch implementing merge functionality
5
+ # for lazy preloadable relations
6
+ module Merger
7
+ # Enhanced #merge implements merging lazy_preload_values
8
+ def merge
9
+ result = super
10
+
11
+ if other.lazy_preload_values.any?
12
+ if other.klass == relation.klass
13
+ merge_lazy_preloads
14
+ else
15
+ reflect_and_merge_lazy_preloads
16
+ end
17
+ end
18
+
19
+ result
20
+ end
21
+
22
+ private
23
+
24
+ def merge_lazy_preloads
25
+ relation.lazy_preload!(*other.lazy_preload_values)
26
+ end
27
+
28
+ def reflect_and_merge_lazy_preloads
29
+ reflection = relation.klass.reflect_on_all_associations.find do |r|
30
+ r.class_name == other.klass.name
31
+ end
32
+ return unless reflection
33
+
34
+ relation.lazy_preload!(reflection.name => other.lazy_preload_values)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ar_lazy_preload/context"
4
+
5
+ module ArLazyPreload
6
+ # ActiveRecord::Relation patch with lazy preloading support
7
+ module Relation
8
+ # Enhanced #load method will check if association has not been loaded yet and add a context
9
+ # for lazy preloading to loaded each record
10
+ def load
11
+ need_context = !loaded?
12
+ result = super
13
+ if need_context
14
+ Context.register(
15
+ records: ar_lazy_preload_records,
16
+ association_tree: lazy_preload_values
17
+ )
18
+ end
19
+ result
20
+ end
21
+
22
+ # Specify relationships to be loaded lazily when association is loaded for the first time. For
23
+ # example:
24
+ #
25
+ # users = User.lazy_preload(:posts)
26
+ # users.each do |user|
27
+ # user.first_name
28
+ # end
29
+ #
30
+ # will cause only one SQL request to load users, while
31
+ #
32
+ # users = User.lazy_preload(:posts)
33
+ # users.each do |user|
34
+ # user.posts.map(&:id)
35
+ # end
36
+ #
37
+ # will make an additional query.
38
+ def lazy_preload(*args)
39
+ check_if_method_has_arguments!(:lazy_preload, args)
40
+ spawn.lazy_preload!(*args)
41
+ end
42
+
43
+ def lazy_preload!(*args)
44
+ args.flatten!
45
+ self.lazy_preload_values += args
46
+ self
47
+ end
48
+
49
+ def lazy_preload_values
50
+ @lazy_preload_values ||= []
51
+ end
52
+
53
+ private
54
+
55
+ def ar_lazy_preload_records
56
+ @records
57
+ end
58
+
59
+ attr_writer :lazy_preload_values
60
+ end
61
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ar_lazy_preload/association_tree_builder"
4
+
5
+ module ArLazyPreload
6
+ # This class is responsible for building context for associated records. Given a list of records
7
+ # belonging to the same context and association name it will create and attach a new context to
8
+ # the associated records based on the parent association tree.
9
+ class AssociatedContextBuilder
10
+ # Initiates lazy preload context the records loaded lazily
11
+ def self.prepare(*args)
12
+ new(*args).perform
13
+ end
14
+
15
+ attr_reader :parent_context, :association_name
16
+
17
+ # :parent_context - root context
18
+ # :association_name - lazily preloaded association name
19
+ def initialize(parent_context:, association_name:)
20
+ @parent_context = parent_context
21
+ @association_name = association_name
22
+ end
23
+
24
+ # Takes all the associated records for the records, attached to the :parent_context and creates
25
+ # a preloading context for them
26
+ def perform
27
+ associated_records = parent_context.records.flat_map do |record|
28
+ next if record.nil?
29
+
30
+ record_association = record.association(association_name)
31
+ reflection = reflection_cache[record.class]
32
+ reflection.collection? ? record_association.target : record_association.reader
33
+ end
34
+
35
+ Context.register(records: associated_records, association_tree: child_association_tree)
36
+ end
37
+
38
+ private
39
+
40
+ def child_association_tree
41
+ # `association_tree` is unnecessary when auto preload is enabled
42
+ return nil if ArLazyPreload.config.auto_preload?
43
+
44
+ AssociationTreeBuilder.new(parent_context.association_tree).subtree_for(association_name)
45
+ end
46
+
47
+ def reflection_cache
48
+ @reflection_cache ||= Hash.new do |hash, klass|
49
+ hash[klass] = klass.reflect_on_association(association_name)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ # This class is responsible for building association subtrees from a given association tree
5
+ # For instance, given a following tree `[:users, { users: :comments }]`,
6
+ # #subtree_for will build a subtree `[:comments]` when :users argument is passed
7
+ class AssociationTreeBuilder
8
+ attr_reader :association_tree
9
+
10
+ def initialize(association_tree)
11
+ @association_tree =
12
+ case association_tree
13
+ when Array
14
+ association_tree
15
+ when Hash
16
+ [association_tree]
17
+ else
18
+ raise ArgumentError, "unexpected association_tree with class #{association_tree.class}"
19
+ end.select { |node| node.is_a?(Hash) }
20
+ end
21
+
22
+ def subtree_for(association)
23
+ subtree_cache[association]
24
+ end
25
+
26
+ private
27
+
28
+ def subtree_cache
29
+ @subtree_cache ||= Hash.new do |hash, association|
30
+ hash[association] = association_tree.flat_map { |node| node[association] }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ # ArLazyPreload configuration:
5
+ #
6
+ # - `auto_preload` - load all the associations lazily without
7
+ # an explicit lazy_preload call
8
+ class Configuration
9
+ attr_accessor :auto_preload
10
+
11
+ def initialize
12
+ @auto_preload = false
13
+ end
14
+
15
+ alias auto_preload? auto_preload
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ar_lazy_preload/contexts/base_context"
4
+ require "ar_lazy_preload/contexts/auto_preload_context"
5
+ require "ar_lazy_preload/contexts/lazy_preload_context"
6
+
7
+ module ArLazyPreload
8
+ class Context
9
+ # Initiates lazy preload context for given records
10
+ def self.register(records:, association_tree:)
11
+ return if records.empty?
12
+
13
+ if ArLazyPreload.config.auto_preload?
14
+ Contexts::AutoPreloadContext.new(records: records)
15
+ elsif association_tree.any?
16
+ Contexts::LazyPreloadContext.new(
17
+ records: records,
18
+ association_tree: association_tree
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ module Contexts
5
+ # This class is responsible for automatic association preloading
6
+ class AutoPreloadContext < BaseContext
7
+ protected
8
+
9
+ def association_needs_preload?(_association_name)
10
+ true
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "ar_lazy_preload/associated_context_builder"
5
+
6
+ module ArLazyPreload
7
+ module Contexts
8
+ # This is a base context class, which is responsible for holding a connection between a list of
9
+ # ActiveRecord::Base objects which have been loaded by the same instance of
10
+ # ActiveRecord::Relation.
11
+ class BaseContext
12
+ attr_reader :records
13
+
14
+ # :records - array of ActiveRecord instances
15
+ def initialize(records:)
16
+ @records = records.dup
17
+ @records.compact!
18
+ @records.uniq!
19
+ @records.each { |record| record.lazy_preload_context = self }
20
+ end
21
+
22
+ # This method checks if the association should be loaded and preloads it for all
23
+ # objects in the context it if needed.
24
+ def try_preload_lazily(association_name)
25
+ return if association_loaded?(association_name) ||
26
+ !association_needs_preload?(association_name)
27
+
28
+ perform_preloading(association_name)
29
+ end
30
+
31
+ protected
32
+
33
+ def association_needs_preload?(_association_name)
34
+ raise NotImplementedError
35
+ end
36
+
37
+ private
38
+
39
+ def perform_preloading(association_name)
40
+ preloader.preload(records, association_name)
41
+ loaded_association_names.add(association_name)
42
+
43
+ AssociatedContextBuilder.prepare(
44
+ parent_context: self,
45
+ association_name: association_name
46
+ )
47
+ end
48
+
49
+ def association_loaded?(association_name)
50
+ loaded_association_names.include?(association_name)
51
+ end
52
+
53
+ def loaded_association_names
54
+ @loaded_association_names ||= Set.new
55
+ end
56
+
57
+ def preloader
58
+ @preloader ||= ActiveRecord::Associations::Preloader.new
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ module Contexts
5
+ # This class is responsible for lazy preloading. It contains a tree of associations, which were
6
+ # requested to be loaded lazily.
7
+ class LazyPreloadContext < BaseContext
8
+ attr_reader :association_tree
9
+
10
+ # :records - array of ActiveRecord instances
11
+ # :association_tree - list of symbols or hashes representing a tree of preloadable
12
+ # associations
13
+ def initialize(records:, association_tree:)
14
+ @association_tree = association_tree
15
+
16
+ super(records: records)
17
+ end
18
+
19
+ protected
20
+
21
+ def association_needs_preload?(association_name)
22
+ association_tree.any? do |node|
23
+ case node
24
+ when Symbol
25
+ node == association_name
26
+ when Hash
27
+ node.key?(association_name)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ar_lazy_preload/active_record/base"
4
+ require "ar_lazy_preload/active_record/relation"
5
+ require "ar_lazy_preload/active_record/association"
6
+ require "ar_lazy_preload/active_record/collection_association"
7
+ require "ar_lazy_preload/active_record/merger"
8
+ require "ar_lazy_preload/active_record/association_relation"
9
+ require "ar_lazy_preload/active_record/collection_proxy"
10
+
11
+ module ArLazyPreload
12
+ class Railtie < Rails::Railtie
13
+ config.to_prepare do |_app|
14
+ ActiveSupport.on_load(:active_record) do
15
+ ActiveRecord::Base.include(Base)
16
+
17
+ ActiveRecord::Relation.prepend(Relation)
18
+ ActiveRecord::AssociationRelation.prepend(AssociationRelation)
19
+ ActiveRecord::Relation::Merger.prepend(Merger)
20
+
21
+ [
22
+ ActiveRecord::Associations::CollectionAssociation,
23
+ ActiveRecord::Associations::Association
24
+ ].each { |klass| klass.prepend(Association) }
25
+
26
+ ActiveRecord::Associations::CollectionAssociation.prepend(CollectionAssociation)
27
+ ActiveRecord::Associations::CollectionProxy.prepend(CollectionProxy)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArLazyPreload
4
+ VERSION = "0.3.2"
5
+ end
metadata ADDED
@@ -0,0 +1,203 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ar_lazy_preload
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.2
5
+ platform: ruby
6
+ authors:
7
+ - DmitryTsepelev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-07-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
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: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
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: db-query-matchers
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: coveralls
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: database_cleaner
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: factory_bot
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: appraisal
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: memory_profiler
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
+ description: lazy_preload implementation for ActiveRecord models
154
+ email:
155
+ - dmitry.a.tsepelev@gmail.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - MIT-LICENSE
161
+ - README.md
162
+ - Rakefile
163
+ - lib/ar_lazy_preload.rb
164
+ - lib/ar_lazy_preload/active_record/association.rb
165
+ - lib/ar_lazy_preload/active_record/association_relation.rb
166
+ - lib/ar_lazy_preload/active_record/base.rb
167
+ - lib/ar_lazy_preload/active_record/collection_association.rb
168
+ - lib/ar_lazy_preload/active_record/collection_proxy.rb
169
+ - lib/ar_lazy_preload/active_record/merger.rb
170
+ - lib/ar_lazy_preload/active_record/relation.rb
171
+ - lib/ar_lazy_preload/associated_context_builder.rb
172
+ - lib/ar_lazy_preload/association_tree_builder.rb
173
+ - lib/ar_lazy_preload/configuration.rb
174
+ - lib/ar_lazy_preload/context.rb
175
+ - lib/ar_lazy_preload/contexts/auto_preload_context.rb
176
+ - lib/ar_lazy_preload/contexts/base_context.rb
177
+ - lib/ar_lazy_preload/contexts/lazy_preload_context.rb
178
+ - lib/ar_lazy_preload/railtie.rb
179
+ - lib/ar_lazy_preload/version.rb
180
+ homepage: https://github.com/DmitryTsepelev/ar_lazy_preload
181
+ licenses:
182
+ - MIT
183
+ metadata: {}
184
+ post_install_message:
185
+ rdoc_options: []
186
+ require_paths:
187
+ - lib
188
+ required_ruby_version: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '2.3'
193
+ required_rubygems_version: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - ">="
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ requirements: []
199
+ rubygems_version: 3.0.3
200
+ signing_key:
201
+ specification_version: 4
202
+ summary: lazy_preload implementation for ActiveRecord models
203
+ test_files: []