capsula 0.0.2 → 0.0.3

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 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