knuckles 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|