smart_preloads 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5203b8b2b5dbd92bc5643f6688a3e73571150d85
4
- data.tar.gz: 504790d10fa6b9e43733d5e8ae012fcf2c8e5c03
3
+ metadata.gz: 18f4e3190dc51950fb7a67eb68be6e2f9d8b86a4
4
+ data.tar.gz: f47c16e997076ce9041616ae243d50974b4a57be
5
5
  SHA512:
6
- metadata.gz: 76ca0adc8537ffcf01e1459185ecd2c0143f65d6b74d060d478c0289a310e35a4befaf9b793758d1ff4ae486c11266eba430bfe38edfdc4d96d378915a646fe1
7
- data.tar.gz: d5d259616f5b62597f3eeeeedfa2c7191b04ccee0238817ca2a8b44897472a985e5f586469a57199859dbc1793110adf4766db857ca36c1900895d8df7c781e7
6
+ metadata.gz: 60e9e6f7c3fbc8da1e845ab31ef6e74ca7fca4bc4ca48dd40d43fb303374abea9426bd43ed9b825fce77243709071c1f151cc44f626b94d89884f579368dad39
7
+ data.tar.gz: b3ca7004e8f80ba53a1cea14985767cd210e93d61df45e9ce4b8c525a4252c6d2057c66e0665663610b4c1780ac4be3b7c14082b2e1d76ad773e16c55c4aa662
data/README.md CHANGED
@@ -5,7 +5,15 @@ when you do not have control over which associations are going to be used by
5
5
  the view, like when you provide users customizable views with
6
6
  [Liquid](https://github.com/chamnap/liquid-rails).
7
7
 
8
- ## How it Works
8
+ ## Installation
9
+
10
+ You can use `gem install smart_preloads` to install it manually or use Bundler:
11
+
12
+ ```ruby
13
+ gem 'smart_preloads'
14
+ ```
15
+
16
+ ## Usage
9
17
 
10
18
  You have to call `smart_preloads` at the end of your association. This will
11
19
  generate a smart list of items that will load associations **if and when**
@@ -39,13 +47,24 @@ end
39
47
  #=> SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
40
48
  ```
41
49
 
42
- ## Installation
50
+ ## How it Works
43
51
 
44
- You can use `gem install smart_preloads` to install it manually or use Bundler:
52
+ In order for it to work, `smart_preloads` has a custom list class
53
+ (`SmartPreloads::List`) and a custom item class for each item in a list
54
+ (`SmartPreloads::Item`).
45
55
 
46
- ```ruby
47
- gem 'smart_preloads'
48
- ```
56
+ The List class allows detecting when the collection
57
+ is really used (iterated) so only then the associations will be detected and
58
+ mokey patched in place. This is needed so whenever a call to an association
59
+ is made it will be loaded, even from calls from within the object itself.
60
+
61
+ The Item class monkey patches all association methods in the objects loaded
62
+ to intercept the calls. The monkey patch is **in place**, not global. Only
63
+ the objects in the `smart_preloads` collection will be monkey patched.
64
+
65
+ Note that when you call `Author.all.smart_preloads.first` you will **not**
66
+ have an instance of `Author`. Instead, you will have an instance of
67
+ `SmartPreloads::Item` that delegates calls to the original `Author` object.
49
68
 
50
69
  ## Contributing
51
70
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.0
@@ -3,23 +3,24 @@ module SmartPreloads
3
3
  def initialize(record, loader: nil)
4
4
  super(record)
5
5
  @loader = loader || Loader.new([record])
6
+ _override_associations
7
+ end
6
8
 
7
- record.class.reflections.each do |key, association|
8
- original = method(key)
9
- singleton_class.class_exec do
10
- body = nil
11
- if %i(has_many has_and_belongs_to_many).include?(association.macro)
12
- body = lambda do
13
- List.new(original.call, loader: @loader.nested(key.to_sym))
14
- end
15
- else
16
- body = lambda do
17
- @loader.load(key.to_sym)
18
- original.call
19
- end
9
+ def _override_associations
10
+ __getobj__.class.reflections.each do |key, association|
11
+ body = nil
12
+ loader = @loader
13
+ if %i(has_many has_and_belongs_to_many).include?(association.macro)
14
+ body = lambda do
15
+ List.new(super(), loader: loader.nested(key.to_sym))
16
+ end
17
+ else
18
+ body = lambda do
19
+ loader.load(key.to_sym)
20
+ super()
20
21
  end
21
- define_method(key, &body)
22
22
  end
23
+ __getobj__.define_singleton_method(key, &body)
23
24
  end
24
25
  end
25
26
  end
@@ -9,7 +9,11 @@ module SmartPreloads
9
9
 
10
10
  def each
11
11
  loaded_collection.each do |resource|
12
- yield Item.new(resource, loader: @loader)
12
+ if resource.is_a?(Item)
13
+ yield resource
14
+ else
15
+ yield Item.new(resource, loader: @loader)
16
+ end
13
17
  end
14
18
  end
15
19
 
@@ -21,6 +25,14 @@ module SmartPreloads
21
25
  to_a.size
22
26
  end
23
27
 
28
+ def +(other)
29
+ to_a + other.to_a
30
+ end
31
+
32
+ def [](idx)
33
+ to_a[idx]
34
+ end
35
+
24
36
  protected
25
37
 
26
38
  def loaded_collection
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: smart_preloads 0.0.1 ruby lib
5
+ # stub: smart_preloads 0.1.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "smart_preloads".freeze
9
- s.version = "0.0.1"
9
+ s.version = "0.1.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Diego Aguir Selzlein".freeze]
14
- s.date = "2017-05-02"
14
+ s.date = "2017-05-26"
15
15
  s.description = "Avoid N + 1 queries without having to worry about it at all!".freeze
16
16
  s.email = "diegoselzlein@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
@@ -12,6 +12,10 @@ class Book < ActiveRecord::Base
12
12
  belongs_to :author
13
13
  belongs_to :category
14
14
  has_many :tags, as: :taggable
15
+
16
+ def author_name
17
+ author.try!(:name)
18
+ end
15
19
  end
16
20
 
17
21
  class Tag < ActiveRecord::Base
@@ -78,4 +82,31 @@ describe 'SmartPreloads' do
78
82
  expect(list.first.books.first.association(:category)).to be_loaded
79
83
  expect(list.last.books.first.association(:category)).to be_loaded
80
84
  end
85
+
86
+ it 'supports concatenation' do
87
+ Book.create!(name: 'Rework')
88
+ Book.create!(name: 'Lean Startup')
89
+ Author.create!(books: [Book.first])
90
+ Author.create!(books: [Book.last])
91
+
92
+ list = Book.all.smart_preloads + Author.all.smart_preloads
93
+
94
+ list[2].books.to_a
95
+ expect(list[3].association(:books)).to be_loaded
96
+
97
+ list.first.author
98
+ expect(list[1].association(:author)).to be_loaded
99
+ end
100
+
101
+ it 'works with internal methods' do
102
+ a1 = Author.create!(name: 'John')
103
+ a2 = Author.create!(name: 'Doe')
104
+ Book.create!(name: 'Rework', author: a1)
105
+ Book.create!(name: 'Lean Startup', author: a2)
106
+
107
+ list = Book.all.smart_preloads
108
+
109
+ list.first.author_name
110
+ expect(list[1].association(:author)).to be_loaded
111
+ end
81
112
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_preloads
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Diego Aguir Selzlein
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-02 00:00:00.000000000 Z
11
+ date: 2017-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec