jsonapi-materializer 1.0.0.rc.pre.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
4
  module Materializer
3
5
  module Resource
@@ -9,29 +11,17 @@ module JSONAPI
9
11
  extend(ActiveSupport::Concern)
10
12
  include(ActiveModel::Model)
11
13
 
12
- MIXIN_HOOK = ->(*) do
14
+ MIXIN_HOOK = lambda do |*|
13
15
  @attributes = {}
14
16
  @relations = {}
15
17
 
16
- unless const_defined?("Collection")
18
+ unless const_defined?(:Collection)
17
19
  self::Collection = Class.new do
18
20
  include(JSONAPI::Materializer::Collection)
19
21
  end
20
22
  end
21
23
 
22
- unless const_defined?("Context")
23
- self::Context = Class.new do
24
- include(JSONAPI::Materializer::Context)
25
-
26
- def initialize(**keyword_arguments)
27
- keyword_arguments.keys.each(&singleton_class.method(:attr_accessor))
28
-
29
- super(**keyword_arguments)
30
- end
31
- end
32
- end
33
-
34
- validates_presence_of(:object)
24
+ validates_presence_of(:object, allow_blank: true)
35
25
 
36
26
  origin(JSONAPI::Materializer.configuration.default_origin)
37
27
  identifier(JSONAPI::Materializer.configuration.default_identifier)
@@ -42,7 +32,6 @@ module JSONAPI
42
32
  attr_accessor(:object)
43
33
  attr_writer(:selects)
44
34
  attr_writer(:includes)
45
- attr_writer(:context)
46
35
  attr_reader(:raw)
47
36
 
48
37
  def initialize(**keyword_arguments)
@@ -50,69 +39,38 @@ module JSONAPI
50
39
 
51
40
  @raw = keyword_arguments
52
41
 
53
- context.validate!
54
42
  validate!
55
43
  end
56
44
 
57
45
  def as_data
58
46
  {
59
- :id => id,
60
- :type => type,
61
- :attributes => exposed(attributes.except(:id)).
62
- transform_values {|attribute| object.public_send(attribute.from)},
63
- :relationships => exposed(relations).
64
- transform_values {|relation| relation.using(self).as_json},
65
- :links => {
66
- :self => links_self
47
+ id:,
48
+ type:,
49
+ attributes: exposed(attributes.except(:id))
50
+ .transform_values { |attribute| object.public_send(attribute.from) },
51
+ relationships: exposed(relations)
52
+ .transform_values { |relation| relation.using(self).as_json },
53
+ links: {
54
+ self: links_self
67
55
  }
68
56
  }.transform_values(&:presence).compact
69
57
  end
70
-
71
- private def exposed(mapping)
72
- if selects.any?
73
- mapping.
74
- select {|_, value| value.visible?(self)}.
75
- slice(*selects.dig(type))
76
- else
77
- mapping.
78
- select {|_, value| value.visible?(self)}
79
- end
80
- end
58
+ # rubocop:enable Metrics/AbcSize
81
59
 
82
60
  def as_json(*)
83
61
  {
84
- :links => {
85
- :self => links_self
62
+ links: {
63
+ self: links_self
86
64
  },
87
- :data => as_data,
88
- :included => included
65
+ data: as_data,
66
+ included:
89
67
  }.transform_values(&:presence).compact
90
68
  end
91
69
 
92
- private def id
93
- object.public_send(identifier).to_s
94
- end
95
-
96
70
  def type
97
71
  self.class.configuration.type.to_s
98
72
  end
99
73
 
100
- private def attributes
101
- self.class.configuration.attributes
102
- end
103
-
104
- private def origin
105
- self.class.configuration.origin
106
- end
107
-
108
- private def identifier
109
- self.class.configuration.identifier
110
- end
111
-
112
- private def relations
113
- self.class.configuration.relations
114
- end
115
-
116
74
  def attribute(name)
117
75
  self.class.attribute(name)
118
76
  end
@@ -128,35 +86,20 @@ module JSONAPI
128
86
  end
129
87
 
130
88
  def selects
131
- (@selects || {}).transform_values {|list| list.map(&:to_sym)}
89
+ (@selects || {}).transform_values { |list| list.map(&:to_sym) }
132
90
  end
133
91
 
134
92
  def includes
135
93
  @includes || []
136
94
  end
137
95
 
138
- def context
139
- self.class.const_get("Context").new(**@context || {})
140
- end
141
-
142
- private def included
143
- @included ||= includes.flat_map do |path|
144
- path.reduce(self) do |subject, key|
145
- if subject.is_a?(Array)
146
- subject.map {|related_subject| related_subject.relation(key).for(subject)}
147
- else
148
- subject.relation(key).for(subject)
149
- end
150
- end
151
- end.map(&:as_data)
152
- end
153
-
154
96
  included do
155
97
  class_eval(&MIXIN_HOOK) unless @abstract_class
156
98
  end
157
99
 
158
100
  class_methods do
159
101
  def inherited(object)
102
+ super
160
103
  object.class_eval(&MIXIN_HOOK) unless object.instance_variable_defined?(:@abstract_class)
161
104
  end
162
105
 
@@ -172,60 +115,97 @@ module JSONAPI
172
115
  @type = value.to_sym
173
116
  end
174
117
 
175
- def has(name, from: name, visible: true)
118
+ def has(name, from: name)
176
119
  @attributes[name] = Attribute.new(
177
- :owner => self,
178
- :name => name,
179
- :from => from,
180
- :visible => visible
120
+ owner: self,
121
+ name:,
122
+ from:
181
123
  )
182
124
  end
183
125
 
184
- def has_one(name, from: name, class_name:, visible: true)
126
+ # rubocop:disable Naming/PredicateName
127
+ def has_one(name, class_name:, from: name)
185
128
  @relations[name] = Relation.new(
186
- :owner => self,
187
- :type => :one,
188
- :name => name,
189
- :from => from,
190
- :class_name => class_name,
191
- :visible => visible
129
+ owner: self,
130
+ type: :one,
131
+ name:,
132
+ from:,
133
+ class_name:
192
134
  )
193
135
  end
136
+ # rubocop:enable Naming/PredicateName
194
137
 
195
- def has_many(name, from: name, class_name:, visible: true)
138
+ # rubocop:disable Naming/PredicateName
139
+ def has_many(name, class_name:, from: name)
196
140
  @relations[name] = Relation.new(
197
- :owner => self,
198
- :type => :many,
199
- :name => name,
200
- :from => from,
201
- :class_name => class_name,
202
- :visible => visible
141
+ owner: self,
142
+ type: :many,
143
+ name:,
144
+ from:,
145
+ class_name:
203
146
  )
204
147
  end
205
-
206
- def context
207
- const_get("Context")
208
- end
148
+ # rubocop:enable Naming/PredicateName
209
149
 
210
150
  def configuration
211
151
  @configuration ||= Configuration.new(
212
- :owner => self,
213
- :type => @type,
214
- :origin => @origin,
215
- :identifier => @identifier,
216
- :attributes => @attributes,
217
- :relations => @relations
152
+ owner: self,
153
+ type: @type,
154
+ origin: @origin,
155
+ identifier: @identifier,
156
+ attributes: @attributes,
157
+ relations: @relations
218
158
  )
219
159
  end
220
160
 
221
161
  def attribute(name)
222
- configuration.attributes.fetch(name.to_sym) {raise(Error::ResourceRelationshipNotFound, :name => name, :materializer => self)}
162
+ configuration.attributes.fetch(name.to_sym) { raise(Error::ResourceAttributeNotFound, name:, materializer: self) }
223
163
  end
224
164
 
225
165
  def relation(name)
226
- configuration.relations.fetch(name.to_sym) {raise(Error::ResourceRelationshipNotFound, :name => name, :materializer => self)}
166
+ configuration.relations.fetch(name.to_sym) { raise(Error::ResourceRelationshipNotFound, name:, materializer: self) }
167
+ end
168
+ end
169
+
170
+ private def exposed(mapping)
171
+ if selects.any?
172
+ mapping.slice(*selects[type])
173
+ else
174
+ mapping
227
175
  end
228
176
  end
177
+
178
+ private def id
179
+ object.public_send(identifier).to_s
180
+ end
181
+
182
+ private def attributes
183
+ self.class.configuration.attributes
184
+ end
185
+
186
+ private def origin
187
+ self.class.configuration.origin
188
+ end
189
+
190
+ private def identifier
191
+ self.class.configuration.identifier
192
+ end
193
+
194
+ private def relations
195
+ self.class.configuration.relations
196
+ end
197
+
198
+ private def included
199
+ @included ||= includes.flat_map do |path|
200
+ path.reduce(self) do |subject, key|
201
+ if subject.is_a?(Array)
202
+ subject.map { |related_subject| related_subject.relation(key).for(subject) }
203
+ else
204
+ subject.relation(key).for(subject)
205
+ end
206
+ end
207
+ end.map(&:as_data)
208
+ end
229
209
  end
230
210
  end
231
211
  end
@@ -1,18 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require("spec_helper")
2
4
 
3
5
  RSpec.describe(JSONAPI::Materializer::Resource) do
4
- let(:resource) {ArticleMaterializer.new(:object => Article.find(1), :context => {:policy => true})}
6
+ let(:resource) { ArticleMaterializer.new(object: Article.find(1)) }
5
7
 
6
8
  before do
7
- Account.create!(:id => 9, :name => "Dan Gebhardt", :twitter => "dgeb")
8
- Account.create!(:id => 2, :name => "DHH", :twitter => "DHH")
9
- Article.create!(:id => 1, :title => "JSON API paints my bikeshed!", :account => Account.find(9))
10
- Comment.create!(:id => 5, :body => "First!", :article => Article.find(1), :account => Account.find(2))
11
- Comment.create!(:id => 12, :body => "I like XML better", :article => Article.find(1), :account => Account.find(9))
9
+ Account.create!(id: 9, name: "Dan Gebhardt", twitter: "dgeb")
10
+ Account.create!(id: 2, name: "DHH", twitter: "DHH")
11
+ Article.create!(id: 1, title: "JSON API paints my bikeshed!", account: Account.find(9))
12
+ Comment.create!(id: 5, body: "First!", article: Article.find(1), account: Account.find(2))
13
+ Comment.create!(id: 12, body: "I like XML better", article: Article.find(1), account: Account.find(9))
12
14
  end
13
15
 
14
16
  describe("#to_json") do
15
- subject {resource.as_json.deep_stringify_keys}
17
+ subject { resource.as_json.deep_stringify_keys }
16
18
 
17
19
  it("returns a JSON:API standards compliant payload") do
18
20
  expect(subject).to(
@@ -55,7 +57,7 @@ RSpec.describe(JSONAPI::Materializer::Resource) do
55
57
  }
56
58
  },
57
59
  "links" => {
58
- "self" => "http://example.com/articles/1"
60
+ "self" => "http://example.com/articles/1"
59
61
  }
60
62
  }
61
63
  )
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
4
  module Materializer
3
- VERSION = "1.0.0.rc-1".freeze
5
+ VERSION = "1.0.0"
4
6
  end
5
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require("ostruct")
2
4
  require("addressable")
3
5
  require("active_model")
@@ -8,7 +10,7 @@ require("active_support/core_ext/string")
8
10
  require("active_support/core_ext/module")
9
11
 
10
12
  module JSONAPI
11
- MEDIA_TYPE = "application/vnd.api+json".freeze unless const_defined?("MEDIA_TYPE")
13
+ MEDIA_TYPE = "application/vnd.api+json" unless const_defined?(:MEDIA_TYPE)
12
14
 
13
15
  module Materializer
14
16
  require_relative("materializer/version")
@@ -17,12 +19,11 @@ module JSONAPI
17
19
  require_relative("materializer/controller")
18
20
 
19
21
  @configuration ||= Configuration.new(
20
- :default_invalid_accept_exception => JSONAPI::Materializer::Error::InvalidAcceptHeader,
21
- :default_missing_accept_exception => JSONAPI::Materializer::Error::MissingAcceptHeader,
22
- :default_identifier => :id
22
+ default_invalid_accept_exception: JSONAPI::Materializer::Error::InvalidAcceptHeader,
23
+ default_missing_accept_exception: JSONAPI::Materializer::Error::MissingAcceptHeader,
24
+ default_identifier: :id
23
25
  )
24
26
  require_relative("materializer/collection")
25
- require_relative("materializer/context")
26
27
  require_relative("materializer/resource")
27
28
 
28
29
  def self.configuration
@@ -1,4 +1,3 @@
1
- require("spec_helper")
1
+ # frozen_string_literal: true
2
2
 
3
- RSpec.describe(JSONAPI::Materializer) do
4
- end
3
+ require("spec_helper")
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
4
  require_relative("jsonapi/materializer")
3
5
  end
metadata CHANGED
@@ -1,157 +1,23 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-materializer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc.pre.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kurtis Rainbolt-Greene
8
- autorequire:
9
- bindir: exe
8
+ autorequire:
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-28 00:00:00.000000000 Z
11
+ date: 2023-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activemodel
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 4.0.0
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: '4.2'
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: 5.0.0
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- version: '5.1'
29
- type: :development
30
- prerelease: false
31
- version_requirements: !ruby/object:Gem::Requirement
32
- requirements:
33
- - - ">="
34
- - !ruby/object:Gem::Version
35
- version: 4.0.0
36
- - - ">="
37
- - !ruby/object:Gem::Version
38
- version: '4.2'
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- version: 5.0.0
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- version: '5.1'
45
- - !ruby/object:Gem::Dependency
46
- name: activerecord
47
- requirement: !ruby/object:Gem::Requirement
48
- requirements:
49
- - - ">="
50
- - !ruby/object:Gem::Version
51
- version: 4.0.0
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '4.2'
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- version: 5.0.0
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: '5.1'
61
- type: :development
62
- prerelease: false
63
- version_requirements: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- version: 4.0.0
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- version: '4.2'
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 5.0.0
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- version: '5.1'
77
- - !ruby/object:Gem::Dependency
78
- name: bundler
79
- requirement: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - "~>"
82
- - !ruby/object:Gem::Version
83
- version: '1.16'
84
- type: :development
85
- prerelease: false
86
- version_requirements: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - "~>"
89
- - !ruby/object:Gem::Version
90
- version: '1.16'
91
- - !ruby/object:Gem::Dependency
92
- name: pry
93
- requirement: !ruby/object:Gem::Requirement
94
- requirements:
95
- - - "~>"
96
- - !ruby/object:Gem::Version
97
- version: '0.11'
98
- type: :development
99
- prerelease: false
100
- version_requirements: !ruby/object:Gem::Requirement
101
- requirements:
102
- - - "~>"
103
- - !ruby/object:Gem::Version
104
- version: '0.11'
105
- - !ruby/object:Gem::Dependency
106
- name: pry-doc
107
- requirement: !ruby/object:Gem::Requirement
108
- requirements:
109
- - - "~>"
110
- - !ruby/object:Gem::Version
111
- version: '0.11'
112
- type: :development
113
- prerelease: false
114
- version_requirements: !ruby/object:Gem::Requirement
115
- requirements:
116
- - - "~>"
117
- - !ruby/object:Gem::Version
118
- version: '0.11'
119
- - !ruby/object:Gem::Dependency
120
- name: rake
121
- requirement: !ruby/object:Gem::Requirement
122
- requirements:
123
- - - "~>"
124
- - !ruby/object:Gem::Version
125
- version: '12.2'
126
- type: :development
127
- prerelease: false
128
- version_requirements: !ruby/object:Gem::Requirement
129
- requirements:
130
- - - "~>"
131
- - !ruby/object:Gem::Version
132
- version: '12.2'
133
- - !ruby/object:Gem::Dependency
134
- name: rspec
135
- requirement: !ruby/object:Gem::Requirement
136
- requirements:
137
- - - "~>"
138
- - !ruby/object:Gem::Version
139
- version: '3.7'
140
- type: :development
141
- prerelease: false
142
- version_requirements: !ruby/object:Gem::Requirement
143
- requirements:
144
- - - "~>"
145
- - !ruby/object:Gem::Version
146
- version: '3.7'
147
- - !ruby/object:Gem::Dependency
148
- name: rubocop
14
+ name: activesupport
149
15
  requirement: !ruby/object:Gem::Requirement
150
16
  requirements:
151
17
  - - ">="
152
18
  - !ruby/object:Gem::Version
153
19
  version: '0'
154
- type: :development
20
+ type: :runtime
155
21
  prerelease: false
156
22
  version_requirements: !ruby/object:Gem::Requirement
157
23
  requirements:
@@ -159,79 +25,33 @@ dependencies:
159
25
  - !ruby/object:Gem::Version
160
26
  version: '0'
161
27
  - !ruby/object:Gem::Dependency
162
- name: sqlite3
163
- requirement: !ruby/object:Gem::Requirement
164
- requirements:
165
- - - "~>"
166
- - !ruby/object:Gem::Version
167
- version: '1.3'
168
- type: :development
169
- prerelease: false
170
- version_requirements: !ruby/object:Gem::Requirement
171
- requirements:
172
- - - "~>"
173
- - !ruby/object:Gem::Version
174
- version: '1.3'
175
- - !ruby/object:Gem::Dependency
176
- name: activesupport
28
+ name: addressable
177
29
  requirement: !ruby/object:Gem::Requirement
178
30
  requirements:
179
31
  - - ">="
180
32
  - !ruby/object:Gem::Version
181
- version: 4.0.0
182
- - - ">="
183
- - !ruby/object:Gem::Version
184
- version: '4.2'
185
- - - ">="
186
- - !ruby/object:Gem::Version
187
- version: 5.0.0
188
- - - ">="
189
- - !ruby/object:Gem::Version
190
- version: '5.1'
33
+ version: '0'
191
34
  type: :runtime
192
35
  prerelease: false
193
36
  version_requirements: !ruby/object:Gem::Requirement
194
37
  requirements:
195
38
  - - ">="
196
39
  - !ruby/object:Gem::Version
197
- version: 4.0.0
198
- - - ">="
199
- - !ruby/object:Gem::Version
200
- version: '4.2'
201
- - - ">="
202
- - !ruby/object:Gem::Version
203
- version: 5.0.0
204
- - - ">="
205
- - !ruby/object:Gem::Version
206
- version: '5.1'
207
- - !ruby/object:Gem::Dependency
208
- name: addressable
209
- requirement: !ruby/object:Gem::Requirement
210
- requirements:
211
- - - "~>"
212
- - !ruby/object:Gem::Version
213
- version: '2.5'
214
- type: :runtime
215
- prerelease: false
216
- version_requirements: !ruby/object:Gem::Requirement
217
- requirements:
218
- - - "~>"
219
- - !ruby/object:Gem::Version
220
- version: '2.5'
40
+ version: '0'
221
41
  - !ruby/object:Gem::Dependency
222
42
  name: kaminari
223
43
  requirement: !ruby/object:Gem::Requirement
224
44
  requirements:
225
- - - "~>"
45
+ - - ">="
226
46
  - !ruby/object:Gem::Version
227
- version: '1.1'
47
+ version: '0'
228
48
  type: :runtime
229
49
  prerelease: false
230
50
  version_requirements: !ruby/object:Gem::Requirement
231
51
  requirements:
232
- - - "~>"
52
+ - - ">="
233
53
  - !ruby/object:Gem::Version
234
- version: '1.1'
54
+ version: '0'
235
55
  description: A way to turn data models into outbound json:api responses
236
56
  email:
237
57
  - kurtis@rainbolt-greene.online
@@ -239,6 +59,7 @@ executables: []
239
59
  extensions: []
240
60
  extra_rdoc_files: []
241
61
  files:
62
+ - LICENSE
242
63
  - README.md
243
64
  - Rakefile
244
65
  - lib/jsonapi-materializer.rb
@@ -246,7 +67,6 @@ files:
246
67
  - lib/jsonapi/materializer/collection.rb
247
68
  - lib/jsonapi/materializer/collection_spec.rb
248
69
  - lib/jsonapi/materializer/configuration.rb
249
- - lib/jsonapi/materializer/context.rb
250
70
  - lib/jsonapi/materializer/controller.rb
251
71
  - lib/jsonapi/materializer/error.rb
252
72
  - lib/jsonapi/materializer/error/invalid_accept_header.rb
@@ -260,30 +80,29 @@ files:
260
80
  - lib/jsonapi/materializer/resource/relationship.rb
261
81
  - lib/jsonapi/materializer/resource_spec.rb
262
82
  - lib/jsonapi/materializer/version.rb
263
- - lib/jsonapi/materializer/version_spec.rb
264
83
  - lib/jsonapi/materializer_spec.rb
265
- homepage: http://krainboltgreene.github.io/jsonapi-materializer
84
+ homepage: http://krainboltgreene.github.io/jsonapi-materializer.rb
266
85
  licenses:
267
- - ISC
268
- metadata: {}
269
- post_install_message:
86
+ - HL3
87
+ metadata:
88
+ rubygems_mfa_required: 'true'
89
+ post_install_message:
270
90
  rdoc_options: []
271
91
  require_paths:
272
92
  - lib
273
93
  required_ruby_version: !ruby/object:Gem::Requirement
274
94
  requirements:
275
- - - ">="
95
+ - - "~>"
276
96
  - !ruby/object:Gem::Version
277
- version: '0'
97
+ version: '3.2'
278
98
  required_rubygems_version: !ruby/object:Gem::Requirement
279
99
  requirements:
280
- - - ">"
100
+ - - ">="
281
101
  - !ruby/object:Gem::Version
282
- version: 1.3.1
102
+ version: '0'
283
103
  requirements: []
284
- rubyforge_project:
285
- rubygems_version: 2.7.7
286
- signing_key:
104
+ rubygems_version: 3.4.10
105
+ signing_key:
287
106
  specification_version: 4
288
107
  summary: A way to turn data models into outbound json:api responses
289
108
  test_files: []