jsonapi-renderer 0.1.1.beta1 → 0.1.1

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
  SHA1:
3
- metadata.gz: 3f02425bfc2d75e4ea21cd4ecb42b6378b4c6939
4
- data.tar.gz: 14400fddf957704ea29b97b422a0f814bad5f3a2
3
+ metadata.gz: 07afefd2fe41039cb8c922578ba39e3aba41f5ec
4
+ data.tar.gz: e269e8a82ad892be4e7f9081e30487301c20d30d
5
5
  SHA512:
6
- metadata.gz: 57a9d3c9d252fa70c29ee3734b322c8254b527b13661c226184cd3d4304eaaf9ae12b88a9c105a21f826b61f07fc71f6cd02e31f19c3a634001a4f178e204a26
7
- data.tar.gz: c620d458eb042cc288c5b461af20181acc0e75dd9d0c0509c9f3bc6b9cb7edb1711db86bdbc1aa5c5805f882c148a1c4d57e708bcccfcb6fa4962a2b628c0555
6
+ metadata.gz: 2b79ebe7aa3d18209658d89042d8dfcc06d5a2a837688b57c9d3495b173aa50f65e6f35a0db0d4bb7c40b1fc0915db5b7733f016a4643e3b684b0878db9aac40
7
+ data.tar.gz: e320d995609cb5a3064533b08b01cf86133a513932ce22bfdc5eeede5c64d2b2c0899fcab2907d10251927910bb4ffd780f641377e722056aff80bb7a616253a
data/README.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # jsonapi-renderer
2
2
  Ruby gem for rendering [JSON API](http://jsonapi.org) documents.
3
3
 
4
+ ## Status
5
+
6
+ [![Gem Version](https://badge.fury.io/rb/jsonapi-renderer.svg)](https://badge.fury.io/rb/jsonapi-renderer)
7
+ [![Build Status](https://secure.travis-ci.org/jsonapi-rb/jsonapi-renderer.svg?branch=master)](http://travis-ci.org/jsonapi-rb/renderer?branch=master)
8
+ [![codecov](https://codecov.io/gh/jsonapi-rb/jsonapi-renderer/branch/master/graph/badge.svg)](https://codecov.io/gh/jsonapi-rb/renderer)
9
+ [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/jsonapi-rb/Lobby)
10
+
4
11
  ## Installation
5
12
  ```ruby
6
13
  # In Gemfile
@@ -35,25 +42,26 @@ class ResourceInterface
35
42
  # @return [String]
36
43
  def jsonapi_id; end
37
44
 
38
- # Returns a hash containing, for each included relationship, the resource(s)
39
- # to be included from that one.
45
+ # Returns a hash containing, for each included relationship, an array of the
46
+ # resources to be included from that one.
40
47
  # @param [Array<Symbol>] included_relationships The keys of the relationships
41
48
  # to be included.
42
- # @return [Hash{Symbol => #ResourceInterface, Array<#ResourceInterface>}]
49
+ # @return [Hash{Symbol => Array<#ResourceInterface>}]
43
50
  def jsonapi_related(included_relationships); end
44
51
 
45
52
  # Returns a JSON API-compliant representation of the resource as a hash.
46
53
  # @param [Hash] options
47
54
  # @option [Array<Symbol>, Nil] fields The requested fields, or nil.
48
- # @option [Array<Symbol>, Nil] included The requested included
49
- # relationships, or nil.
55
+ # @option [Array<Symbol>] include The requested relationships to
56
+ # include (defaults to []).
50
57
  # @return [Hash]
51
58
  def as_jsonapi(options = {}); end
59
+ end
52
60
  ```
53
61
 
54
62
  #### Rendering a single resource
55
63
  ```ruby
56
- JSONAPI.render(resource,
64
+ JSONAPI.render(data: resource,
57
65
  include: include_string,
58
66
  fields: fields_hash,
59
67
  meta: meta_hash,
@@ -64,7 +72,7 @@ This returns a JSON API compliant hash representing the described document.
64
72
 
65
73
  #### Rendering a collection of resources
66
74
  ```ruby
67
- JSONAPI.render(resources,
75
+ JSONAPI.render(data: resources,
68
76
  include: include_string,
69
77
  fields: fields_hash,
70
78
  meta: meta_hash,
@@ -76,7 +84,7 @@ This returns a JSON API compliant hash representing the described document.
76
84
  ### Rendering errors
77
85
 
78
86
  ```ruby
79
- JSONAPI.render_errors(errors,
87
+ JSONAPI.render_errors(errors: errors,
80
88
  meta: meta_hash,
81
89
  links: links_hash)
82
90
  ```
@@ -0,0 +1,59 @@
1
+ require 'jsonapi/include_directive'
2
+ require 'jsonapi/renderer/resources_processor'
3
+
4
+ module JSONAPI
5
+ module Renderer
6
+ class Document
7
+ def initialize(params = {})
8
+ @data = params.fetch(:data, :no_data)
9
+ @errors = params.fetch(:errors, [])
10
+ @meta = params.fetch(:meta, nil)
11
+ @links = params.fetch(:links, {})
12
+ @fields = _symbolize_fields(params.fetch(:fields, {}))
13
+ @jsonapi = params.fetch(:jsonapi, nil)
14
+ @include = JSONAPI::IncludeDirective.new(params.fetch(:include, {}))
15
+ end
16
+
17
+ def to_hash
18
+ @hash ||= document_hash
19
+ end
20
+ alias to_h to_hash
21
+
22
+ private
23
+
24
+ def document_hash
25
+ {}.tap do |hash|
26
+ if @data != :no_data
27
+ hash.merge!(data_hash)
28
+ elsif @errors.any?
29
+ hash.merge!(errors_hash)
30
+ end
31
+ hash[:links] = @links if @links.any?
32
+ hash[:meta] = @meta unless @meta.nil?
33
+ hash[:jsonapi] = @jsonapi unless @jsonapi.nil?
34
+ end
35
+ end
36
+
37
+ def data_hash
38
+ primary, included =
39
+ ResourcesProcessor.new(Array(@data), @include, @fields).process
40
+ {}.tap do |hash|
41
+ hash[:data] = @data.respond_to?(:each) ? primary : primary[0]
42
+ hash[:included] = included if included.any?
43
+ end
44
+ end
45
+
46
+ def errors_hash
47
+ {}.tap do |hash|
48
+ hash[:errors] = @errors.map(&:as_jsonapi)
49
+ end
50
+ end
51
+
52
+ def _symbolize_fields(fields)
53
+ fields.each_with_object({}) do |(k, v), h|
54
+ h[k.to_sym] = v.map(&:to_sym)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,87 @@
1
+ require 'set'
2
+
3
+ module JSONAPI
4
+ module Renderer
5
+ class ResourcesProcessor
6
+ def initialize(resources, include, fields)
7
+ @resources = resources
8
+ @include = include
9
+ @fields = fields
10
+ end
11
+
12
+ def process
13
+ traverse_resources
14
+ process_resources
15
+
16
+ [@primary, @included]
17
+ end
18
+
19
+ private
20
+
21
+ def traverse_resources
22
+ @traversed = Set.new # [type, id, prefix]
23
+ @include_rels = {} # [type, id => Set]
24
+ @queue = []
25
+ @primary = []
26
+ @included = []
27
+
28
+ initialize_queue
29
+ traverse_queue
30
+ end
31
+
32
+ def initialize_queue
33
+ @resources.each do |res|
34
+ @traversed.add([res.jsonapi_type, res.jsonapi_id, ''])
35
+ traverse_resource(res, @include.keys, true)
36
+ enqueue_related_resources(res, '', @include)
37
+ end
38
+ end
39
+
40
+ def traverse_queue
41
+ until @queue.empty?
42
+ res, prefix, include_dir = @queue.shift
43
+ traverse_resource(res, include_dir.keys, false)
44
+ enqueue_related_resources(res, prefix, include_dir)
45
+ end
46
+ end
47
+
48
+ def traverse_resource(res, include_keys, primary)
49
+ ri = [res.jsonapi_type, res.jsonapi_id]
50
+ if @include_rels.include?(ri)
51
+ @include_rels[ri].merge!(include_keys)
52
+ else
53
+ @include_rels[ri] = Set.new(include_keys)
54
+ (primary ? @primary : @included) << res
55
+ end
56
+ end
57
+
58
+ def enqueue_related_resources(res, prefix, include_dir)
59
+ res.jsonapi_related(include_dir.keys).each do |key, data|
60
+ data.each do |child_res|
61
+ next if child_res.nil?
62
+ child_prefix = "#{prefix}.#{key}"
63
+ enqueue_resource(child_res, child_prefix, include_dir[key])
64
+ end
65
+ end
66
+ end
67
+
68
+ def enqueue_resource(res, prefix, include_dir)
69
+ return unless @traversed.add?([res.jsonapi_type,
70
+ res.jsonapi_id,
71
+ prefix])
72
+ @queue << [res, prefix, include_dir]
73
+ end
74
+
75
+ def process_resources
76
+ [@primary, @included].each do |resources|
77
+ resources.map! do |res|
78
+ ri = [res.jsonapi_type, res.jsonapi_id]
79
+ include_dir = @include_rels[ri]
80
+ fields = @fields[res.jsonapi_type.to_sym]
81
+ res.as_jsonapi(include: include_dir, fields: fields)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,118 +1,25 @@
1
- require 'jsonapi/include_directive'
1
+ require 'jsonapi/renderer/document'
2
2
 
3
3
  module JSONAPI
4
- class Renderer
5
- def initialize(resources, options = {})
6
- @resources = resources
7
- @errors = options[:errors] || false
8
- @meta = options[:meta] || nil
9
- @links = options[:links] || {}
10
- @fields = options[:fields] || {}
11
- # NOTE(beauby): Room for some nifty defaults on those.
12
- @jsonapi = options[:jsonapi_object] || nil
13
- @include = JSONAPI::IncludeDirective.new(options[:include] || {})
14
- end
15
-
16
- def as_json
17
- return @json unless @json.nil?
18
-
19
- process_resources
20
- @json = {}
21
-
22
- if @errors
23
- @json[:errors] = @resources.map(&:as_jsonapi)
24
- else
25
- @json[:data] = @resources.respond_to?(:each) ? @primary : @primary[0]
26
- @json[:included] = @included if @included.any?
27
- end
28
- @json[:links] = @links if @links.any?
29
- @json[:meta] = @meta unless @meta.nil?
30
- @json[:jsonapi] = @jsonapi unless @jsonapi.nil?
31
-
32
- @json
33
- end
34
-
35
- private
36
-
37
- def process_resources
38
- @primary = []
39
- @included = []
40
- @hashes = {}
41
- @processed = Set.new # NOTE(beauby): Set of [type, id, prefix].
42
- @queue = []
43
-
44
- Array(@resources).each do |res|
45
- process_resource(res, '', @include, true)
46
- @processed.add([res.jsonapi_type, res.jsonapi_id, ''])
47
- end
48
- until @queue.empty?
49
- res, prefix, include_dir = @queue.pop
50
- process_resource(res, prefix, include_dir, false)
51
- end
52
- end
53
-
54
- def merge_resources!(a, b)
55
- b[:relationships].each do |name, rel|
56
- a[:relationships][name][:data] ||= rel[:data] if rel.key?(:data)
57
- (a[:relationships][name][:links] ||= {})
58
- .merge!(rel[:links]) if rel.key?(:links)
59
- end
60
- end
61
-
62
- def process_resource(res, prefix, include_dir, is_primary)
63
- ri = [res.jsonapi_type, res.jsonapi_id]
64
- hash = res.as_jsonapi(fields: @fields[res.jsonapi_type.to_sym],
65
- include: include_dir.keys)
66
- if @hashes.key?(ri)
67
- merge_resources!(@hashes[ri], hash)
68
- else
69
- (is_primary ? @primary : @included) << (@hashes[ri] = hash)
70
- end
71
- process_relationships(res, prefix, include_dir)
72
- end
73
-
74
- def process_relationships(res, prefix, include_dir)
75
- res.jsonapi_related(include_dir.keys).each do |key, data|
76
- Array(data).each do |child_res|
77
- child_prefix = "#{prefix}.#{key}"
78
- next unless @processed.add?([child_res.jsonapi_type,
79
- child_res.jsonapi_id,
80
- child_prefix])
81
- @queue << [child_res, child_prefix, include_dir[key]]
82
- end
83
- end
84
- end
85
- end
86
-
87
4
  module_function
88
5
 
89
- # Render a success JSON API document.
90
- #
91
- # @param [(#jsonapi_id, #jsonapi_type, #jsonapi_related, #as_jsonapi),
92
- # Array<(#jsonapi_id, #jsonapi_type, #jsonapi_related, #as_jsonapi)>,
93
- # nil] resources The primary resource(s) to be rendered.
94
- # @param [Hash] options All optional.
95
- # @option [String, Hash{Symbol => Hash}] include Relationships to be
96
- # included.
97
- # @option [Hash{Symbol, Array<Symbol>}] fields List of requested fields
98
- # for some or all of the resource types.
99
- # @option [Hash] meta Non-standard top-level meta information to be
100
- # included.
101
- # @option [Hash] links Top-level links to be included.
102
- # @option [Hash] jsonapi_object JSON API object.
103
- def render(resources, options = {})
104
- Renderer.new(resources, options).as_json
105
- end
106
-
107
- # Render an error JSON API document.
6
+ # Render a JSON API document.
108
7
  #
109
- # @param [Array<#jsonapi_id>] errors Errors to be rendered.
110
- # @param [Hash] options All optional.
8
+ # @param [Hash] params
9
+ # @option [(#jsonapi_id, #jsonapi_type, #jsonapi_related, #as_jsonapi),
10
+ # Array<(#jsonapi_id, #jsonapi_type, #jsonapi_related,
11
+ # #as_jsonapi)>,
12
+ # nil] data Primary resource(s) to be rendered.
13
+ # @option [Array<#jsonapi_id>] errors Errors to be rendered.
14
+ # @option include Relationships to be included. See
15
+ # JSONAPI::IncludeDirective.
16
+ # @option [Hash{Symbol, Array<Symbol>}, Hash{String, Array<String>}] fields
17
+ # List of requested fields for some or all of the resource types.
111
18
  # @option [Hash] meta Non-standard top-level meta information to be
112
19
  # included.
113
20
  # @option [Hash] links Top-level links to be included.
114
21
  # @option [Hash] jsonapi_object JSON API object.
115
- def render_errors(errors)
116
- Renderer.new(errors, errors: true).as_json
22
+ def render(params)
23
+ Renderer::Document.new(params).to_hash
117
24
  end
118
25
  end
metadata CHANGED
@@ -1,16 +1,58 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-renderer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1.beta1
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Hosseini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-02 00:00:00.000000000 Z
12
- dependencies: []
13
- description: Low-level renderer for JSONAPI documents.
11
+ date: 2016-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '11.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '11.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: codecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.1'
55
+ description: Efficiently render JSON API documents.
14
56
  email: lucas.hosseini@gmail.com
15
57
  executables: []
16
58
  extensions: []
@@ -20,7 +62,9 @@ files:
20
62
  - lib/jsonapi/include_directive.rb
21
63
  - lib/jsonapi/include_directive/parser.rb
22
64
  - lib/jsonapi/renderer.rb
23
- homepage: https://github.com/beauby/jsonapi
65
+ - lib/jsonapi/renderer/document.rb
66
+ - lib/jsonapi/renderer/resources_processor.rb
67
+ homepage: https://github.com/jsonapi-rb/jsonapi-renderer
24
68
  licenses:
25
69
  - MIT
26
70
  metadata: {}
@@ -35,12 +79,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
35
79
  version: '0'
36
80
  required_rubygems_version: !ruby/object:Gem::Requirement
37
81
  requirements:
38
- - - ">"
82
+ - - ">="
39
83
  - !ruby/object:Gem::Version
40
- version: 1.3.1
84
+ version: '0'
41
85
  requirements: []
42
86
  rubyforge_project:
43
- rubygems_version: 2.5.1
87
+ rubygems_version: 2.6.8
44
88
  signing_key:
45
89
  specification_version: 4
46
90
  summary: Render JSONAPI documents.