knuckles 0.3.0 → 0.4.0
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/knuckles/active/hydrator.rb +62 -0
- data/lib/knuckles/stages/renderer.rb +4 -3
- data/lib/knuckles/version.rb +1 -1
- data/lib/knuckles/view.rb +17 -0
- data/lib/knuckles.rb +14 -1
- data/spec/knuckles/active/hydrator_spec.rb +43 -0
- data/spec/knuckles/stages/renderer_spec.rb +20 -0
- data/spec/knuckles/view_spec.rb +10 -0
- metadata +5 -3
- data/lib/knuckles/stages.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69ff93727664c8cb7f6c22d52542521b400f7421
|
4
|
+
data.tar.gz: 88f1ad40c4d32591dfcc6b9d3e8c093d1c14a80a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bff88dba2e59d125dfa1c61ee050f191f690e1f1a12f704729e1f8e29b76bfe7a444e4bc550cd4a09d3777156114a10b8dc319f6594e92e83ca013ea17255aa
|
7
|
+
data.tar.gz: e51e57e0df18ccaef4304ee9f78a47ee0472063be046592b883cf2e6f732ba68cc9803f2f9636ff09ad9e9b48006603fa1c36fb25203405e6d3f2b8144e50844
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## v0.4.0 - 2016-05-11
|
2
|
+
|
3
|
+
* Added: `Knuckles::Active::Hydrator`, a hydrator specifically designed to work
|
4
|
+
with `ActiveRecord`. It converts a relation of minimally loaded `ActiveRecord`
|
5
|
+
models into fully loaded models ready for serialization.
|
6
|
+
* Added: A compatibility layer within the `Renderer` stage to ease in the
|
7
|
+
transition from `ActiveModelSerializers`. Both `Knuckles::View` or `AMS`
|
8
|
+
instances now work when passed as the `view` option.
|
9
|
+
|
1
10
|
## v0.3.0 - 2016-04-07
|
2
11
|
|
3
12
|
* Added: Tons of documentation.
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Knuckles
|
4
|
+
module Active
|
5
|
+
# The active hydrator converts minimal objects in a prepared collection
|
6
|
+
# into fully "hydrated" versions of the same record. For example, the
|
7
|
+
# initial `model` may only have the `id` and `updated_at` timestamp
|
8
|
+
# selected, which is ideal for fetching from the cache. If the object
|
9
|
+
# wasn't in the cache then all of the fields are needed for a complete
|
10
|
+
# rendering, so the hydration call will use the passed relation to fetch
|
11
|
+
# the full model and any associations.
|
12
|
+
#
|
13
|
+
# This `Hydrator` module is specifically designed to work with
|
14
|
+
# `ActiveRecord` relations. The initial objects can be anything that
|
15
|
+
# responds to `id`, but the relation should be an `ActiveRecord` relation.
|
16
|
+
module Hydrator
|
17
|
+
extend self
|
18
|
+
|
19
|
+
# Convert all uncached objects into their full representation.
|
20
|
+
#
|
21
|
+
# @param [Enumerable] prepared The prepared collection for processing
|
22
|
+
# @option [#Relation] :relation An ActiveRecord::Relation, used to
|
23
|
+
# hydrate uncached objects
|
24
|
+
#
|
25
|
+
# @example Hydrating missing objects
|
26
|
+
#
|
27
|
+
# prepared = [Post.new(1), Post.new(2)]
|
28
|
+
# relation = Post.all.preload(:author, :comments)
|
29
|
+
#
|
30
|
+
# Knuckles::Active::Hydrator.call(prepared, relation: relation) #=>
|
31
|
+
# # [{object: #Post<1>, cached?: false, ...
|
32
|
+
#
|
33
|
+
def call(prepared, options)
|
34
|
+
mapping = id_object_mapping(prepared)
|
35
|
+
|
36
|
+
if mapping.any?
|
37
|
+
relation = relation_without_pagination(options)
|
38
|
+
|
39
|
+
relation.where(id: mapping.keys).each do |hydrated|
|
40
|
+
mapping[hydrated.id][:object] = hydrated
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
prepared
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def relation_without_pagination(options)
|
50
|
+
options.fetch(:relation).offset(false).limit(false)
|
51
|
+
end
|
52
|
+
|
53
|
+
def id_object_mapping(objects)
|
54
|
+
objects.each_with_object({}) do |hash, memo|
|
55
|
+
next if hash[:cached?]
|
56
|
+
|
57
|
+
memo[hash[:object].id] = hash
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -18,9 +18,10 @@ module Knuckles
|
|
18
18
|
private
|
19
19
|
|
20
20
|
def do_render(object, view, options)
|
21
|
-
view
|
22
|
-
|
23
|
-
)
|
21
|
+
case view
|
22
|
+
when Knuckles::View then view.render(object, options)
|
23
|
+
else view.new(object, options).as_json
|
24
|
+
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
data/lib/knuckles/version.rb
CHANGED
data/lib/knuckles/view.rb
CHANGED
@@ -43,6 +43,23 @@ module Knuckles
|
|
43
43
|
def root
|
44
44
|
end
|
45
45
|
|
46
|
+
# Convenience for combining the results of data and relations
|
47
|
+
# into a single object.
|
48
|
+
#
|
49
|
+
# @param [Object] _object The object for serializing.
|
50
|
+
# @param [Hash] _options The options to be used during serialization, i.e.
|
51
|
+
# `:scope`
|
52
|
+
#
|
53
|
+
# @return [Hash] A hash representing the serialized object and relations.
|
54
|
+
#
|
55
|
+
# @example Rendering an object
|
56
|
+
#
|
57
|
+
# TagView.render(tag) #=> {tags: [{id: 1, name: "Alpha"}]}
|
58
|
+
#
|
59
|
+
def render(object, options = {})
|
60
|
+
relations(object, options).merge!(root => [data(object, options)])
|
61
|
+
end
|
62
|
+
|
46
63
|
# Serialize an object into a hash. This simply returns an empty hash by
|
47
64
|
# default, it must be overridden by submodules.
|
48
65
|
#
|
data/lib/knuckles.rb
CHANGED
@@ -31,9 +31,22 @@ require "json"
|
|
31
31
|
module Knuckles
|
32
32
|
autoload :Keygen, "knuckles/keygen"
|
33
33
|
autoload :Pipeline, "knuckles/pipeline"
|
34
|
-
autoload :Stages, "knuckles/stages"
|
35
34
|
autoload :View, "knuckles/view"
|
36
35
|
|
36
|
+
module Active
|
37
|
+
autoload :Hydrator, "knuckles/active/hydrator"
|
38
|
+
end
|
39
|
+
|
40
|
+
module Stages
|
41
|
+
autoload :Combiner, "knuckles/stages/combiner"
|
42
|
+
autoload :Dumper, "knuckles/stages/dumper"
|
43
|
+
autoload :Enhancer, "knuckles/stages/enhancer"
|
44
|
+
autoload :Fetcher, "knuckles/stages/fetcher"
|
45
|
+
autoload :Hydrator, "knuckles/stages/hydrator"
|
46
|
+
autoload :Renderer, "knuckles/stages/renderer"
|
47
|
+
autoload :Writer, "knuckles/stages/writer"
|
48
|
+
end
|
49
|
+
|
37
50
|
extend self
|
38
51
|
|
39
52
|
attr_writer :cache, :keygen, :notifications, :serializer
|
@@ -0,0 +1,43 @@
|
|
1
|
+
RSpec.describe Knuckles::Active::Hydrator do
|
2
|
+
class FakeRelation
|
3
|
+
attr_reader :objects
|
4
|
+
|
5
|
+
def initialize(objects)
|
6
|
+
@objects = objects
|
7
|
+
end
|
8
|
+
|
9
|
+
def offset(_bool)
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def limit(_bool)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def where(id:)
|
18
|
+
objects.select { |object| id.include?(object.id) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ".call" do
|
23
|
+
it "is a no-op if all objects are cached" do
|
24
|
+
prepared = prepare([Tag.new(1, "alpha")])
|
25
|
+
|
26
|
+
prepared.each { |prep| prep[:cached?] = true }
|
27
|
+
|
28
|
+
expect(Knuckles::Active::Hydrator.call(prepared, {})).to eq(prepared)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "replaces all objects using the results of a query" do
|
32
|
+
prepared = prepare([Tag.new(1, nil), Tag.new(2, nil)])
|
33
|
+
relation = FakeRelation.new([Tag.new(1, "alpha"), Tag.new(2, "beta")])
|
34
|
+
|
35
|
+
results = Knuckles::Active::Hydrator.call(prepared, relation: relation)
|
36
|
+
|
37
|
+
expect(results.map { |hash| hash[:object] }).to eq([
|
38
|
+
Tag.new(1, "alpha"),
|
39
|
+
Tag.new(2, "beta")
|
40
|
+
])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -28,5 +28,25 @@ RSpec.describe Knuckles::Stages::Renderer do
|
|
28
28
|
]
|
29
29
|
)
|
30
30
|
end
|
31
|
+
|
32
|
+
it "serializes using a class based renderer" do
|
33
|
+
tag = Tag.new(1, "alpha")
|
34
|
+
|
35
|
+
ar_view = Class.new do
|
36
|
+
def initialize(object, _options)
|
37
|
+
@object = object
|
38
|
+
end
|
39
|
+
|
40
|
+
def as_json
|
41
|
+
{tags: [{id: @object.id, name: @object.name}]}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
results = Knuckles::Stages::Renderer.call(prepare([tag]), view: ar_view)
|
46
|
+
|
47
|
+
expect(results[0][:result]).to eq(
|
48
|
+
tags: [{id: 1, name: "alpha"}]
|
49
|
+
)
|
50
|
+
end
|
31
51
|
end
|
32
52
|
end
|
data/spec/knuckles/view_spec.rb
CHANGED
@@ -35,4 +35,14 @@ RSpec.describe Knuckles::View do
|
|
35
35
|
)
|
36
36
|
end
|
37
37
|
end
|
38
|
+
|
39
|
+
describe ".render" do
|
40
|
+
it "performs combined rendering of relations and data" do
|
41
|
+
tag = Tag.new(1, "Alpha")
|
42
|
+
|
43
|
+
expect(TagView.render(tag)).to eq(
|
44
|
+
tags: [{id: 1, name: "Alpha"}]
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
38
48
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knuckles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Parker Selbert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -77,9 +77,9 @@ files:
|
|
77
77
|
- LICENSE.txt
|
78
78
|
- README.md
|
79
79
|
- lib/knuckles.rb
|
80
|
+
- lib/knuckles/active/hydrator.rb
|
80
81
|
- lib/knuckles/keygen.rb
|
81
82
|
- lib/knuckles/pipeline.rb
|
82
|
-
- lib/knuckles/stages.rb
|
83
83
|
- lib/knuckles/stages/combiner.rb
|
84
84
|
- lib/knuckles/stages/dumper.rb
|
85
85
|
- lib/knuckles/stages/enhancer.rb
|
@@ -89,6 +89,7 @@ files:
|
|
89
89
|
- lib/knuckles/stages/writer.rb
|
90
90
|
- lib/knuckles/version.rb
|
91
91
|
- lib/knuckles/view.rb
|
92
|
+
- spec/knuckles/active/hydrator_spec.rb
|
92
93
|
- spec/knuckles/keygen_spec.rb
|
93
94
|
- spec/knuckles/pipeline_spec.rb
|
94
95
|
- spec/knuckles/stages/combiner_spec.rb
|
@@ -128,6 +129,7 @@ signing_key:
|
|
128
129
|
specification_version: 4
|
129
130
|
summary: Simple performance aware data serialization
|
130
131
|
test_files:
|
132
|
+
- spec/knuckles/active/hydrator_spec.rb
|
131
133
|
- spec/knuckles/keygen_spec.rb
|
132
134
|
- spec/knuckles/pipeline_spec.rb
|
133
135
|
- spec/knuckles/stages/combiner_spec.rb
|
data/lib/knuckles/stages.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Knuckles
|
4
|
-
module Stages
|
5
|
-
autoload :Combiner, "knuckles/stages/combiner"
|
6
|
-
autoload :Dumper, "knuckles/stages/dumper"
|
7
|
-
autoload :Enhancer, "knuckles/stages/enhancer"
|
8
|
-
autoload :Fetcher, "knuckles/stages/fetcher"
|
9
|
-
autoload :Hydrator, "knuckles/stages/hydrator"
|
10
|
-
autoload :Renderer, "knuckles/stages/renderer"
|
11
|
-
autoload :Writer, "knuckles/stages/writer"
|
12
|
-
end
|
13
|
-
end
|