roar-jsonapi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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: []