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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de1e116a89071a460417f16918fbc8ea0871ba2217a3b513d90f76028ff789c0
4
- data.tar.gz: d66bf5ca919d2df33b664b5e50d9dab8afd3866a115ce47ab5e458335610d6fc
3
+ metadata.gz: c534b9fef1cf66293f27706a7399215013ca7d41f58b3fd7bbf6e1f4990bc0a8
4
+ data.tar.gz: 16af229a6c5155c34e8fc4e91eac9911fae50c6cfd29e5b102aa14ebae28a07d
5
5
  SHA512:
6
- metadata.gz: 9919c5c93000fa52a3615c41bb579ca202be4805b7d879219b59cb0b941ed214b07bf5d260ae5c3775bd0494d3c4abe808b92fb510942cc277243a575bde7dd8
7
- data.tar.gz: d467d3cadada0ffb8cf7cb7ccc86b32b683a30e97b4a3aab079df1d101583a57c934673553a824544359011c0cdefa1fff2d2969997288a16dbaaf7fe54194d2
6
+ metadata.gz: 3480eb2df25870f7e9fd507847897cdc8cee3037bbef3c25312ef822218bf9ac54e34ecb4e7acfbf5609bc18334300fb8b71f799b5ca107989b14e17368aef12
7
+ data.tar.gz: 2240b2987901d94a39d5407f0b4caa9ad943987d0e0bfe1ae4433cb1dbed18673977a13f92eaa65a4ae14c4dd52c53a70e68b43c0501e3a98ad3f636986d5643
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capsula (0.0.1)
4
+ capsula (0.0.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -82,4 +82,4 @@ DEPENDENCIES
82
82
  simplecov
83
83
 
84
84
  BUNDLED WITH
85
- 1.16.6
85
+ 1.17.3
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> # Capsula's wrapper answers
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
- Also, for key-definition can be used lambdas:
51
+ For key-definition can be used lambdas:
36
52
 
37
53
  ```ruby
38
- src_key: ->(o){ o.some_hash_data.fetch(:fuel_id, default: 'A-95') }
39
- dst_key: ->(o){ o.extact_fuel_id_from_octane_number }
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).plan(:fuel, :oxygen).encapsulate
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
- def initialize items:, opt: {}
66
- @items = items; @opt = opt; @store = [];
67
- end
68
-
69
- # This method is triggered by Capsula
70
- def collect_ids_and_load_relations
71
- ids = @items.map{ |i| i.fuel_id }
72
- @store = Fuel.where(id: ids).to_a
73
- end
74
-
75
- # This method is calling by Capsula during encapsulation
76
- def get_preloads_for_object starship
77
- @store.find { |fuel| starship.fuel_id == fuel.id }
78
- end
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'capsula'
3
- s.version = '0.0.2'
3
+ s.version = '0.0.3'
4
4
  s.date = '2019-02-04'
5
5
  s.summary = 'Encapsulating tool'
6
6
  s.description = 'The tool for encapsulating (preloading, including) related objects'
@@ -98,14 +98,24 @@ module Capsula
98
98
  end
99
99
 
100
100
  def native_preload key, dec, opt
101
- # collect relation ids
102
- ids = @items.map do |o|
103
- get_key(o, dec[:src_key])
104
- end.flatten.uniq.compact
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: (ids.any? ? dec[:dst_loader].call(ids,opt) : []),
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 = get_key(i, dec[:src_key])
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 get_key _object_, key_or_lambda
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capsula
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodion V