roar-jsonapi 0.0.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 +7 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +37 -0
- data/.travis.yml +14 -0
- data/.yardopts +5 -0
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +11 -0
- data/ISSUE_TEMPLATE.md +20 -0
- data/LICENSE +20 -0
- data/README.markdown +127 -0
- data/Rakefile +12 -0
- data/lib/roar/json/json_api.rb +156 -0
- data/lib/roar/json/json_api/declarative.rb +196 -0
- data/lib/roar/json/json_api/defaults.rb +25 -0
- data/lib/roar/json/json_api/document.rb +104 -0
- data/lib/roar/json/json_api/for_collection.rb +35 -0
- data/lib/roar/json/json_api/member_name.rb +57 -0
- data/lib/roar/json/json_api/meta.rb +56 -0
- data/lib/roar/json/json_api/options.rb +98 -0
- data/lib/roar/json/json_api/version.rb +7 -0
- data/roar-jsonapi.gemspec +25 -0
- data/test/jsonapi/collection_render_test.rb +399 -0
- data/test/jsonapi/fieldsets_options_test.rb +161 -0
- data/test/jsonapi/fieldsets_test.rb +293 -0
- data/test/jsonapi/member_name_test.rb +91 -0
- data/test/jsonapi/post_test.rb +78 -0
- data/test/jsonapi/render_test.rb +281 -0
- data/test/jsonapi/representer.rb +112 -0
- data/test/jsonapi/resource_linkage_test.rb +88 -0
- data/test/test_helper.rb +42 -0
- metadata +132 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
Author = Struct.new(:id, :email, :name) do
|
2
|
+
def self.find_by(options)
|
3
|
+
AuthorNine if options[:id].to_s == '9'
|
4
|
+
end
|
5
|
+
end
|
6
|
+
AuthorNine = Author.new(9, '9@nine.to')
|
7
|
+
|
8
|
+
Article = Struct.new(:id, :title, :author, :editor, :comments) do
|
9
|
+
def reviewers
|
10
|
+
['Christian Bernstein']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Comment = Struct.new(:comment_id, :body) do
|
15
|
+
def self.find_by(_options)
|
16
|
+
new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class AuthorDecorator < Roar::Decorator
|
21
|
+
include Roar::JSON::JSONAPI.resource :authors
|
22
|
+
|
23
|
+
attributes do
|
24
|
+
property :email
|
25
|
+
end
|
26
|
+
|
27
|
+
link(:self) { "http://authors/#{represented.id}" }
|
28
|
+
end
|
29
|
+
|
30
|
+
class CommentDecorator < Roar::Decorator
|
31
|
+
include Roar::JSON::JSONAPI.resource(:comments, id_key: :comment_id)
|
32
|
+
|
33
|
+
attributes do
|
34
|
+
property :body
|
35
|
+
end
|
36
|
+
|
37
|
+
link(:self) { "http://comments/#{represented.comment_id}" }
|
38
|
+
end
|
39
|
+
|
40
|
+
class ArticleDecorator < Roar::Decorator
|
41
|
+
include Roar::JSON::JSONAPI.resource :articles
|
42
|
+
|
43
|
+
# top-level link.
|
44
|
+
link :self, toplevel: true do |options|
|
45
|
+
if options
|
46
|
+
"//articles?page=#{options[:page]}&per_page=#{options[:per_page]}"
|
47
|
+
else
|
48
|
+
'//articles'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
meta toplevel: true do
|
53
|
+
property :count
|
54
|
+
end
|
55
|
+
|
56
|
+
attributes do
|
57
|
+
property :title
|
58
|
+
end
|
59
|
+
|
60
|
+
meta do
|
61
|
+
collection :reviewers
|
62
|
+
end
|
63
|
+
|
64
|
+
meta do
|
65
|
+
property :reviewer_initials, getter: ->(_) {
|
66
|
+
reviewers.map { |reviewer|
|
67
|
+
reviewer.split.map { |name| "#{name[0]}." }.join
|
68
|
+
}.join(', ')
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
# resource object links
|
73
|
+
link(:self) { "http://#{represented.class}/#{represented.id}" }
|
74
|
+
|
75
|
+
# relationships
|
76
|
+
has_one :author, class: Author, decorator: AuthorDecorator,
|
77
|
+
populator: ::Representable::FindOrInstantiate do # populator is for parsing, only.
|
78
|
+
|
79
|
+
relationship do
|
80
|
+
link(:self) { "/articles/#{represented.id}/relationships/author" }
|
81
|
+
link(:related) { "/articles/#{represented.id}/author" }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
has_one :editor do
|
86
|
+
type :editors
|
87
|
+
|
88
|
+
relationship do
|
89
|
+
meta do
|
90
|
+
property :peer_reviewed, getter: ->(_) { false }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
attributes do
|
95
|
+
property :email
|
96
|
+
end
|
97
|
+
# No self link for editors because we want to make sure the :links option does not appear in the hash.
|
98
|
+
end
|
99
|
+
|
100
|
+
has_many :comments, class: Comment, decorator: CommentDecorator,
|
101
|
+
populator: ::Representable::FindOrInstantiate do
|
102
|
+
|
103
|
+
relationship do
|
104
|
+
link(:self) { "/articles/#{represented.id}/relationships/comments" }
|
105
|
+
link(:related) { "/articles/#{represented.id}/comments" }
|
106
|
+
|
107
|
+
meta do
|
108
|
+
property :count, as: 'comment-count'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'roar/json/json_api'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
class ResourceLinkageTest < MiniTest::Spec
|
8
|
+
class ChefDecorator < Roar::Decorator
|
9
|
+
include Roar::JSON::JSONAPI.resource :chefs
|
10
|
+
|
11
|
+
attributes do
|
12
|
+
property :name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class IngredientDecorator < Roar::Decorator
|
17
|
+
include Roar::JSON::JSONAPI.resource :ingredients
|
18
|
+
|
19
|
+
attributes do
|
20
|
+
property :name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class RecipeDecorator < Roar::Decorator
|
25
|
+
include Roar::JSON::JSONAPI.resource :recipes
|
26
|
+
|
27
|
+
attributes do
|
28
|
+
property :name
|
29
|
+
end
|
30
|
+
|
31
|
+
has_one :chef, decorator: ChefDecorator
|
32
|
+
has_many :ingredients, decorator: IngredientDecorator
|
33
|
+
|
34
|
+
has_many :reviews do
|
35
|
+
type :review
|
36
|
+
|
37
|
+
attributes do
|
38
|
+
property :text
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Recipe = Struct.new(:id, :name, :chef, :ingredients, :reviews)
|
44
|
+
Chef = Struct.new(:id, :name)
|
45
|
+
Ingredient = Struct.new(:id, :name)
|
46
|
+
|
47
|
+
let(:doc) { RecipeDecorator.new(souffle).to_hash }
|
48
|
+
let(:doc_relationships) { doc['data']['relationships'] }
|
49
|
+
|
50
|
+
describe 'non-empty relationships' do
|
51
|
+
let(:souffle) {
|
52
|
+
Recipe.new(1, 'Cheese soufflé',
|
53
|
+
Chef.new(1, 'Jamie Oliver'),
|
54
|
+
[Ingredient.new(5, 'Eggs'), Ingredient.new(6, 'Gruyère')])
|
55
|
+
}
|
56
|
+
|
57
|
+
it 'renders a single object for non-empty to-one relationships' do
|
58
|
+
doc_relationships['chef'].must_equal('data'=>{ 'type' => 'chefs', 'id' => '1' })
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'renders an array for non-empty to-many relationships' do
|
62
|
+
doc_relationships['ingredients'].must_equal('data' => [
|
63
|
+
{ 'type' => 'ingredients', 'id' => '5' },
|
64
|
+
{ 'type' => 'ingredients', 'id' => '6' }
|
65
|
+
])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'empty (nil) relationships' do
|
70
|
+
let(:souffle) { Recipe.new(1, 'Cheese soufflé', nil, nil) }
|
71
|
+
|
72
|
+
it 'renders null for an empty to-one relationships' do
|
73
|
+
doc_relationships['chef'].must_equal('data' => nil)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'renders an empty array ([]) for empty (nil) to-many relationships' do
|
77
|
+
doc_relationships['ingredients'].must_equal('data' => [])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'empty to-many relationships' do
|
82
|
+
let(:souffle) { Recipe.new(1, 'Cheese soufflé', nil, []) }
|
83
|
+
|
84
|
+
it 'renders an empty array ([]) for empty to-many relationships' do
|
85
|
+
doc_relationships['ingredients'].must_equal('data' => [])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/reporters'
|
3
|
+
Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new
|
4
|
+
|
5
|
+
require 'roar/representer'
|
6
|
+
require 'roar/json'
|
7
|
+
require 'roar/json/json_api'
|
8
|
+
|
9
|
+
require 'representable/debug'
|
10
|
+
require 'pp'
|
11
|
+
|
12
|
+
require_relative 'jsonapi/representer'
|
13
|
+
|
14
|
+
require 'json_spec/configuration'
|
15
|
+
require 'json_spec/helpers'
|
16
|
+
require 'json_spec/exclusion'
|
17
|
+
|
18
|
+
if system('colordiff', __FILE__, __FILE__)
|
19
|
+
MiniTest::Assertions.diff = 'colordiff -u'
|
20
|
+
end
|
21
|
+
|
22
|
+
module JsonSpec
|
23
|
+
extend Configuration
|
24
|
+
|
25
|
+
self.excluded_keys = []
|
26
|
+
end
|
27
|
+
module MiniTest::Assertions
|
28
|
+
def assert_equal_json(actual, expected)
|
29
|
+
assert_equal scrub(actual), scrub(expected)
|
30
|
+
end
|
31
|
+
|
32
|
+
def scrub(json, path = nil)
|
33
|
+
JsonSpec::Helpers.generate_normalized_json(
|
34
|
+
JsonSpec::Exclusion.exclude_keys(
|
35
|
+
JsonSpec::Helpers.parse_json(json, path)
|
36
|
+
)
|
37
|
+
).chomp + "\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
module Minitest::Expectations
|
41
|
+
infect_an_assertion :assert_equal_json, :must_equal_json
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: roar-jsonapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nick Sutterer
|
8
|
+
- Alex Coles
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-01-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: roar
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.1'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.1'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.10.1
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.10.1
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: minitest
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '5.10'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '5.10'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: multi_json
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
description: Object-oriented representers help you define nested JSON API documents
|
71
|
+
which can then be rendered and parsed using one and the same concept.
|
72
|
+
email:
|
73
|
+
- apotonick@gmail.com
|
74
|
+
- alex@alexbcoles.com
|
75
|
+
executables: []
|
76
|
+
extensions: []
|
77
|
+
extra_rdoc_files: []
|
78
|
+
files:
|
79
|
+
- ".gitignore"
|
80
|
+
- ".rubocop.yml"
|
81
|
+
- ".travis.yml"
|
82
|
+
- ".yardopts"
|
83
|
+
- CONTRIBUTING.md
|
84
|
+
- Gemfile
|
85
|
+
- ISSUE_TEMPLATE.md
|
86
|
+
- LICENSE
|
87
|
+
- README.markdown
|
88
|
+
- Rakefile
|
89
|
+
- lib/roar/json/json_api.rb
|
90
|
+
- lib/roar/json/json_api/declarative.rb
|
91
|
+
- lib/roar/json/json_api/defaults.rb
|
92
|
+
- lib/roar/json/json_api/document.rb
|
93
|
+
- lib/roar/json/json_api/for_collection.rb
|
94
|
+
- lib/roar/json/json_api/member_name.rb
|
95
|
+
- lib/roar/json/json_api/meta.rb
|
96
|
+
- lib/roar/json/json_api/options.rb
|
97
|
+
- lib/roar/json/json_api/version.rb
|
98
|
+
- roar-jsonapi.gemspec
|
99
|
+
- test/jsonapi/collection_render_test.rb
|
100
|
+
- test/jsonapi/fieldsets_options_test.rb
|
101
|
+
- test/jsonapi/fieldsets_test.rb
|
102
|
+
- test/jsonapi/member_name_test.rb
|
103
|
+
- test/jsonapi/post_test.rb
|
104
|
+
- test/jsonapi/render_test.rb
|
105
|
+
- test/jsonapi/representer.rb
|
106
|
+
- test/jsonapi/resource_linkage_test.rb
|
107
|
+
- test/test_helper.rb
|
108
|
+
homepage: http://trailblazer.to/gems/roar/jsonapi.html
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 2.5.1
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: Parse and render JSON API documents using representers.
|
132
|
+
test_files: []
|