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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac7f83df75c4e52ee59dc85ff6d6d98c863f5963
4
- data.tar.gz: e1ff17c2903f39eac251ee3bbaaa56ab1adfc1e5
3
+ metadata.gz: 69ff93727664c8cb7f6c22d52542521b400f7421
4
+ data.tar.gz: 88f1ad40c4d32591dfcc6b9d3e8c093d1c14a80a
5
5
  SHA512:
6
- metadata.gz: d49c80cd7f0e4b2cefc1861188b84bf9ccd752975d6714d068c8a97798a8e95e615a6192762afe721a6461f9ec23105d66d46651b1cd809fa7c3d6abb577eb8d
7
- data.tar.gz: 9e7bd47dd8b17edba6e3e88fa367bca797654b876fc8a4fb2f87f25189bbb503a3c72e8cca288c301ec6c0876e94a5a693ded4ca8a51031bb90e1649b5e80ec3
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.relations(object, options).merge!(
22
- view.root => [view.data(object, options)]
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Knuckles
4
- VERSION = "0.3.0".freeze
4
+ VERSION = "0.4.0"
5
5
  end
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
@@ -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.3.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-04-07 00:00:00.000000000 Z
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
@@ -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