capsula 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +45 -20
- data/capsula.gemspec +1 -1
- data/lib/capsula/encapsulator.rb +36 -17
- data/spec/capsula_spec.rb +0 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c534b9fef1cf66293f27706a7399215013ca7d41f58b3fd7bbf6e1f4990bc0a8
|
4
|
+
data.tar.gz: 16af229a6c5155c34e8fc4e91eac9911fae50c6cfd29e5b102aa14ebae28a07d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3480eb2df25870f7e9fd507847897cdc8cee3037bbef3c25312ef822218bf9ac54e34ecb4e7acfbf5609bc18334300fb8b71f799b5ca107989b14e17368aef12
|
7
|
+
data.tar.gz: 2240b2987901d94a39d5407f0b4caa9ad943987d0e0bfe1ae4433cb1dbed18673977a13f92eaa65a4ae14c4dd52c53a70e68b43c0501e3a98ad3f636986d5643
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,16 +3,26 @@ The tool for encapsulating (preloading, including) related objects into **any**
|
|
3
3
|
|
4
4
|
## How to use:
|
5
5
|
|
6
|
+
Add to Gemfile:
|
7
|
+
|
8
|
+
```
|
9
|
+
gem 'capsula'
|
10
|
+
```
|
11
|
+
|
12
|
+
Then:
|
13
|
+
|
6
14
|
```ruby
|
7
15
|
starships = <get_your_space_fleet>
|
8
16
|
|
9
|
-
StarshipsEncapsulator.new(starships).plans(
|
17
|
+
starships = StarshipsEncapsulator.new(starships).plans(
|
10
18
|
:fuel, :oxygen, :food, { spaceman: [:space_suit] }
|
11
19
|
).encapsulate
|
12
20
|
|
13
21
|
# Now let's get a suit for our spaceman:
|
14
22
|
starships.first&.spaceman&.space_suit
|
15
|
-
=> <awesome space suit>
|
23
|
+
=> <awesome space suit>
|
24
|
+
# no actual action was triggered,
|
25
|
+
# immediate result was received from Capsula's wrapper
|
16
26
|
```
|
17
27
|
|
18
28
|
Let's see how `StarshipsEncapsulator` looks:
|
@@ -29,23 +39,38 @@ class StarshipsEncapsulator < Capsula::Base
|
|
29
39
|
# Plans for other relations...
|
30
40
|
end
|
31
41
|
```
|
42
|
+
|
43
|
+
### src_key, dst_key
|
44
|
+
|
45
|
+
**default values:**
|
46
|
+
|
32
47
|
Definition for `src_key` and `dst_key` can be skipped if they values are `:fuel_id` (`<key_name>_id`) and `:id`
|
33
48
|
|
49
|
+
**lambdas:**
|
34
50
|
|
35
|
-
|
51
|
+
For key-definition can be used lambdas:
|
36
52
|
|
37
53
|
```ruby
|
38
|
-
src_key: ->(o){ o.some_hash_data.fetch(:fuel_id,
|
39
|
-
dst_key: ->(o){ o.
|
54
|
+
src_key: ->(o){ o.some_hash_data.fetch(:fuel_id, 'A-95') }
|
55
|
+
dst_key: ->(o){ o.extract_fuel_id_from_octane_number }
|
40
56
|
```
|
41
57
|
|
58
|
+
### dst_loader
|
59
|
+
|
60
|
+
**nested plans:**
|
61
|
+
|
62
|
+
`dst_loader` receive plans in `opt[:plans]` only for related class.
|
63
|
+
|
64
|
+
So, if user request plans for `:fuel, :oxygen, :food, { spaceman: [:space_suit] }`,
|
65
|
+
then `SpacemanEncapsulator` receive `[:space_suit]` plans in `opt[:plans]` and so on.
|
66
|
+
|
42
67
|
## How it works:
|
43
68
|
|
44
69
|
All objects is wrapping into special transparent wrapper which
|
45
70
|
translate all methods to wrapped object, except methods-names which was used for encapsulating before:
|
46
71
|
|
47
72
|
```ruby
|
48
|
-
StarshipsEncapsulator.new(starships).
|
73
|
+
starships = StarshipsEncapsulator.new(starships).plans(:fuel, :oxygen).encapsulate
|
49
74
|
starships.first.oxygen
|
50
75
|
=> <oxygen> # instant response, because already present in Capsula
|
51
76
|
```
|
@@ -62,20 +87,20 @@ For difficult preloading logic can be used custom loader:
|
|
62
87
|
|
63
88
|
```ruby
|
64
89
|
class CustomLoader
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
90
|
+
def initialize items:, opt: {}
|
91
|
+
@items = items; @opt = opt; @store = [];
|
92
|
+
end
|
93
|
+
|
94
|
+
# This method is triggered by Capsula
|
95
|
+
def collect_ids_and_load_relations
|
96
|
+
ids = @items.map{ |i| i.fuel_id }
|
97
|
+
@store = Fuel.where(id: ids).to_a
|
98
|
+
end
|
99
|
+
|
100
|
+
# This method is calling by Capsula during encapsulation
|
101
|
+
def get_preloads_for_object starship
|
102
|
+
@store.find { |fuel| starship.fuel_id == fuel.id }
|
103
|
+
end
|
79
104
|
end
|
80
105
|
|
81
106
|
|
data/capsula.gemspec
CHANGED
data/lib/capsula/encapsulator.rb
CHANGED
@@ -98,14 +98,24 @@ module Capsula
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def native_preload key, dec, opt
|
101
|
-
# collect
|
102
|
-
ids =
|
103
|
-
|
104
|
-
|
101
|
+
# collect ids for preloading
|
102
|
+
ids =
|
103
|
+
@items.map do |o|
|
104
|
+
get_value(o, dec[:src_key])
|
105
|
+
end.flatten.uniq.compact
|
106
|
+
|
107
|
+
# preload and index objects
|
108
|
+
col =
|
109
|
+
if ids.any?
|
110
|
+
preloads = dec[:dst_loader].call(ids,opt)
|
111
|
+
# build hash: {id1 => Obj1, ..., idN => ObjN }
|
112
|
+
index_array_by(preloads) { |el| get_value(el, dec[:dst_key]) }
|
113
|
+
else
|
114
|
+
{}
|
115
|
+
end
|
105
116
|
|
106
|
-
# preload relations
|
107
117
|
@collections[key] = {
|
108
|
-
collection:
|
118
|
+
collection: col,
|
109
119
|
declaration: dec
|
110
120
|
}
|
111
121
|
end
|
@@ -122,24 +132,26 @@ module Capsula
|
|
122
132
|
dec = declaration
|
123
133
|
|
124
134
|
@items.each do |i|
|
125
|
-
src_id =
|
135
|
+
src_id = get_value(i, dec[:src_key])
|
136
|
+
|
137
|
+
val =
|
138
|
+
if src_id.is_a?(Array)
|
139
|
+
# if object has many links to related objects (Array)
|
140
|
+
col.values_at(*src_id)
|
141
|
+
else
|
142
|
+
# only one link
|
143
|
+
col[src_id]
|
144
|
+
end
|
126
145
|
|
127
|
-
val = if src_id.is_a?(Array)
|
128
|
-
# if object has many links to related objects (Array)
|
129
|
-
col.select{|c| src_id.include?(c.id) }
|
130
|
-
else
|
131
|
-
# only one link
|
132
|
-
col.find{|c| get_key(c, dec[:dst_key]) == src_id }
|
133
|
-
end
|
134
146
|
i[plan_key] = val
|
135
147
|
end
|
136
148
|
end
|
137
149
|
|
138
|
-
def
|
150
|
+
def get_value _object_, key_or_lambda
|
139
151
|
case key_or_lambda
|
140
|
-
when Symbol, String
|
152
|
+
when ::Symbol, ::String
|
141
153
|
_object_.send(key_or_lambda)
|
142
|
-
when Proc
|
154
|
+
when ::Proc
|
143
155
|
key_or_lambda.call(_object_)
|
144
156
|
else
|
145
157
|
nil
|
@@ -162,5 +174,12 @@ module Capsula
|
|
162
174
|
end
|
163
175
|
end
|
164
176
|
|
177
|
+
# copypasted from activesupport
|
178
|
+
# https://www.rubydoc.info/github/rails/rails/Enumerable:index_by
|
179
|
+
def index_array_by arr
|
180
|
+
result = {}
|
181
|
+
arr.each { |elem| result[yield(elem)] = elem }
|
182
|
+
result
|
183
|
+
end
|
165
184
|
end
|
166
185
|
end
|
data/spec/capsula_spec.rb
CHANGED
@@ -22,8 +22,6 @@ RSpec.describe Capsula do
|
|
22
22
|
objects = [1,2].map{ |i| a.new(i) }
|
23
23
|
objects = klass.new(objects).plans(:b).encapsulate
|
24
24
|
|
25
|
-
puts objects.first.b
|
26
|
-
|
27
25
|
expect(objects.first).to respond_to(:b)
|
28
26
|
expect(objects.first).to be_a(Capsula::Wrapper)
|
29
27
|
expect(objects.first.b.id).to be == objects.first.b_id
|