onsi 1.0.1 → 1.1.0

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
- SHA1:
3
- metadata.gz: ad9ea7a61b943a647485d219e1d254c994627321
4
- data.tar.gz: 24638143f81a54ef013f86878c74dfd065912799
2
+ SHA256:
3
+ metadata.gz: 638533886ab71bbcb08509a8fc97847bf8758780f57ec9cd447b7d2e238f2004
4
+ data.tar.gz: 752a3904540d06b5e633440a4e953da4d2df53697bb3d2581c4a513ed575ecbb
5
5
  SHA512:
6
- metadata.gz: b6bf0db1aaaeccf10e1ebd7c3c0d5255cb9906bbfaede640c7b348f2cf315bf69b29d4218a2d9b7b16ebdb333cb37b49023156b64eaf128164e0b03ab5c80e54
7
- data.tar.gz: 17663d785bae35d73a0f460939f36be95c030c7934fe386ce79701f66efd231779b0718d404b8772f4507af550dd415c85ec818d36923fe9dd3b36c7add19cfd
6
+ metadata.gz: 6cdd245d7d1b287869aade512beb827527912054c1d633db3b4adb05d374c1c1bcdeff39014e47a885bddabc3d8f0c304768d204b90b29b21a7822925c382fa8
7
+ data.tar.gz: d164bbedc0824ed6b2650c7994f58167f8c44dc515731b8562de55701479be8f14f63ab18f237b17bcc06f091920f6a1690ff487a83864ef318e10f5423f92d3
data/.circleci/config.yml CHANGED
@@ -19,16 +19,17 @@ jobs:
19
19
  - run: gem install bundler
20
20
  - restore_cache:
21
21
  keys:
22
- - v1-gems-latest-{{ checksum "onsi.gemspec" }}
22
+ - v1-gems-latest-{{ .Branch }}-{{ .Revision }}
23
+ - v1-gems-latest-{{ .Branch }}
23
24
  - v1-gems-latest-
24
25
  - run:
25
26
  name: install gems
26
27
  command: |
27
- bundle install --jobs=4 --retry=3 --path vendor/bundle
28
+ bundle install --jobs=4 --retry=3 --path vendor/bundle-latest
28
29
  - save_cache:
29
- key: v1-gems-latest-{{ checksum "onsi.gemspec" }}
30
+ key: v1-gems-latest-{{ .Branch }}-{{ .Revision }}
30
31
  paths:
31
- - ./vendor/bundle
32
+ - ./vendor/bundle-latest
32
33
  - run:
33
34
  name: Run Specs
34
35
  command: bundle exec rspec spec/**/*.rb
@@ -48,14 +49,15 @@ jobs:
48
49
  - run: gem install bundler
49
50
  - restore_cache:
50
51
  keys:
51
- - v1-gems-build_2_5-{{ checksum "onsi.gemspec" }}
52
+ - v1-gems-build_2_5-{{ .Branch }}-{{ .Revision }}
53
+ - v1-gems-build_2_5-{{ .Branch }}
52
54
  - v1-gems-build_2_5-
53
55
  - run:
54
56
  name: install gems
55
57
  command: |
56
58
  bundle install --jobs=4 --retry=3 --path vendor/bundle-2_5
57
59
  - save_cache:
58
- key: v1-gems-build_2_5-{{ checksum "onsi.gemspec" }}
60
+ key: v1-gems-build_2_5-{{ .Branch }}-{{ .Revision }}
59
61
  paths:
60
62
  - ./vendor/bundle-2_5
61
63
  - run:
@@ -67,17 +69,18 @@ jobs:
67
69
  working_directory: ~/repo
68
70
  steps:
69
71
  - checkout
70
- - run: gem install bundler
72
+ - run: gem install bundler -v 1.17.1
71
73
  - restore_cache:
72
74
  keys:
73
- - v1-gems-build_2_4-{{ checksum "onsi.gemspec" }}
75
+ - v1-gems-build_2_4-{{ .Branch }}-{{ .Revision }}
76
+ - v1-gems-build_2_4-{{ .Branch }}
74
77
  - v1-gems-build_2_4-
75
78
  - run:
76
79
  name: install gems
77
80
  command: |
78
81
  bundle install --jobs=4 --retry=3 --path vendor/bundle-2_4
79
82
  - save_cache:
80
- key: v1-gems-build_2_4-{{ checksum "onsi.gemspec" }}
83
+ key: v1-gems-build_2_4-{{ .Branch }}-{{ .Revision }}
81
84
  paths:
82
85
  - ./vendor/bundle-2_4
83
86
  - run:
@@ -89,17 +92,18 @@ jobs:
89
92
  working_directory: ~/repo
90
93
  steps:
91
94
  - checkout
92
- - run: gem install bundler
95
+ - run: gem install bundler -v 1.17.1
93
96
  - restore_cache:
94
97
  keys:
95
- - v1-gems-build_2_3-{{ checksum "onsi.gemspec" }}
98
+ - v1-gems-build_2_3-{{ .Branch }}-{{ .Revision }}
99
+ - v1-gems-build_2_3-{{ .Branch }}
96
100
  - v1-gems-build_2_3-
97
101
  - run:
98
102
  name: install gems
99
103
  command: |
100
104
  bundle install --jobs=4 --retry=3 --path vendor/bundle-2_3
101
105
  - save_cache:
102
- key: v1-gems-build_2_3-{{ checksum "onsi.gemspec" }}
106
+ key: v1-gems-build_2_3-{{ .Branch }}-{{ .Revision }}
103
107
  paths:
104
108
  - ./vendor/bundle-2_3
105
109
  - run:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ # Version 1.1.0
2
+
3
+ ## Released February 23, 2019
4
+
5
+ ### Changes
6
+
7
+ - Feat: Add CORS headers helpers.
8
+
9
+ - Feat: Allow Params to parse included relationships
10
+
1
11
  # Version 1.0.1
2
12
 
3
13
  ## Released November 21, 2018
data/bin/console CHANGED
@@ -1,14 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'bundler/setup'
4
+ require 'pry'
4
5
  require 'onsi'
5
6
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require 'irb'
14
- IRB.start(__FILE__)
7
+ Pry.start
@@ -0,0 +1,174 @@
1
+ require 'addressable'
2
+ require 'set'
3
+
4
+ module Onsi
5
+ ##
6
+ # Generates CORS Headers using a request env.
7
+ #
8
+ # @example Creating headers in a before_action
9
+ # def assign_cors_headers
10
+ # Onsi::CORSHeaders.generate(request.env) do |header, value|
11
+ # response.headers[header] = value
12
+ # end
13
+ # end
14
+ class CORSHeaders
15
+ ##
16
+ # @private
17
+ #
18
+ # Default Allowed Headers
19
+ CORS_ALLOWED_HEADER = %w[
20
+ Accept
21
+ Authorization
22
+ Content-Type
23
+ If-Match
24
+ If-Modified-Since
25
+ If-None-Match
26
+ If-Unmodified-Since
27
+ Origin
28
+ X-Requested-With
29
+ X-CSRF-Token
30
+ ].freeze
31
+
32
+ ##
33
+ # @private
34
+ #
35
+ # Default Allowed Methods
36
+ CORS_ALLOWED_METHOD = %w[
37
+ GET POST PATCH PUT DELETE OPTIONS
38
+ ].freeze
39
+
40
+ ##
41
+ # @private
42
+ #
43
+ # Default Expose Headers
44
+ CORS_EXPOSE_HEADER = %w[
45
+ ETag Link
46
+ ].freeze
47
+
48
+ ##
49
+ # @private
50
+ #
51
+ # Default Known Origins
52
+ CORS_KNOWN_ORIGIN = %w[
53
+ localhost
54
+ ].freeze
55
+
56
+ ##
57
+ # @private
58
+ #
59
+ # Default Vary
60
+ CORS_VARY = %w[
61
+ Accept Accept-Encoding Origin
62
+ ].freeze
63
+
64
+ ##
65
+ # @private
66
+ #
67
+ # Values that can be customized
68
+ CUSTOMIZED_VALUES = %w[
69
+ allowed_header
70
+ allowed_method
71
+ expose_header
72
+ known_origin
73
+ vary
74
+ ].freeze
75
+
76
+ class << self
77
+ ##
78
+ # Create the CORS headers.
79
+ #
80
+ # @param env [Hash] The request env to generate CORS headers from.
81
+ #
82
+ # @return [Hash]
83
+ def generate(env)
84
+ new(env).generate
85
+ end
86
+
87
+ CUSTOMIZED_VALUES.each do |method|
88
+ define_method("add_#{method}") do |origin|
89
+ send("#{method}s").add(origin)
90
+ end
91
+
92
+ define_method("#{method}s") do
93
+ variable_name = "@#{method}s"
94
+ existing = instance_variable_get(variable_name)
95
+ return existing unless existing.nil?
96
+
97
+ default_values = Object.const_get("Onsi::CORSHeaders::CORS_#{method.upcase}")
98
+
99
+ existing = Set.new(default_values)
100
+
101
+ instance_variable_set(variable_name, existing)
102
+
103
+ existing
104
+ end
105
+ end
106
+ end
107
+
108
+ ##
109
+ # @private
110
+ #
111
+ # The request object.
112
+ #
113
+ # @return [Rack::Request]
114
+ attr_reader :request
115
+
116
+ ##
117
+ # @private
118
+ #
119
+ # @param env [Hash] The request env for CORS Headers
120
+ def initialize(env)
121
+ @request = Rack::Request.new(env)
122
+ end
123
+
124
+ ##
125
+ # @private
126
+ #
127
+ # Generates CORS headers
128
+ def generate
129
+ {}.tap do |headers|
130
+ headers['Access-Control-Allow-Credentials'] = 'true'
131
+ headers['Access-Control-Allow-Origin'] = allowed_origin if allowed_origin
132
+ headers['Access-Control-Expose-Headers'] = self.class.expose_headers.to_a.join(', ')
133
+ headers['Access-Control-Allow-Methods'] = self.class.allowed_methods.to_a.join(', ')
134
+ headers['Vary'] = self.class.varys.to_a.join(', ')
135
+ end
136
+ end
137
+
138
+ private
139
+
140
+ def origin_header
141
+ (request.env['HTTP_ORIGIN'].presence || request.env['Origin'].presence).to_s
142
+ end
143
+
144
+ def origin
145
+ @origin ||= Addressable::URI.parse(origin_header)
146
+ rescue Addressable::URI::InvalidURIError
147
+ Addressable::URI.new
148
+ end
149
+
150
+ def origin_value
151
+ origin.to_s
152
+ end
153
+
154
+ def allowed_origin
155
+ if acceptable_options_request?
156
+ origin_value if request_from_known_origin?
157
+ else
158
+ '*'
159
+ end
160
+ end
161
+
162
+ def acceptable_options_request?
163
+ options_request? && request_from_known_origin?
164
+ end
165
+
166
+ def request_from_known_origin?
167
+ self.class.known_origins.include?(origin.host)
168
+ end
169
+
170
+ def options_request?
171
+ request.request_method == 'OPTIONS'
172
+ end
173
+ end
174
+ end
@@ -11,6 +11,7 @@ module Onsi
11
11
  # - {Onsi::Params::MissingReqiredAttribute}
12
12
  # - {Onsi::Params::RelationshipNotFound}
13
13
  # - {Onsi::Errors::UnknownVersionError}
14
+ # - {Onsi::Errors::IncludedParamError}
14
15
  #
15
16
  # @example
16
17
  # class PeopleController < ApplicationController
@@ -32,6 +33,7 @@ module Onsi
32
33
  rescue_from Onsi::Params::MissingReqiredAttribute, with: :respond_missing_attr_error_400
33
34
  rescue_from Onsi::Params::RelationshipNotFound, with: :respond_missing_relationship_error_400
34
35
  rescue_from Onsi::Errors::UnknownVersionError, with: :respond_invalid_version_error_400
36
+ rescue_from Onsi::Errors::IncludedParamError, with: :respond_included_param_error_400
35
37
  end
36
38
 
37
39
  ##
@@ -100,6 +102,19 @@ module Onsi
100
102
  render_error(response)
101
103
  end
102
104
 
105
+ ##
106
+ # @private
107
+ def respond_included_param_error_400(error)
108
+ response = ErrorResponse.new(400)
109
+ response.add(
110
+ 400,
111
+ 'missing_include',
112
+ details: error.message,
113
+ meta: { source: error.path }
114
+ )
115
+ render_error(response)
116
+ end
117
+
103
118
  ##
104
119
  # @private
105
120
  def respond_missing_relationship_error_400(error)
@@ -221,7 +236,7 @@ module Onsi
221
236
  # @private
222
237
  def renderable
223
238
  {
224
- json: as_json,
239
+ json: as_json,
225
240
  status: status
226
241
  }
227
242
  end
data/lib/onsi/errors.rb CHANGED
@@ -35,5 +35,25 @@ module Onsi
35
35
  @version = version
36
36
  end
37
37
  end
38
+
39
+ ##
40
+ # Included Param Error
41
+ #
42
+ # @author Maddie Schipper
43
+ # @since 1.1.0
44
+ class IncludedParamError < BaseError
45
+ ##
46
+ # The path that failed to parse.
47
+ attr_reader :path
48
+
49
+ ##
50
+ # @private
51
+ #
52
+ # Create a new IncludedParamError
53
+ def initialize(message, path)
54
+ super(message)
55
+ @path = path
56
+ end
57
+ end
38
58
  end
39
59
  end
@@ -0,0 +1,43 @@
1
+ require_relative '../cors_headers'
2
+
3
+ module Onsi
4
+ module Middleware
5
+ ##
6
+ # Auto-Add CORS headers to all requests.
7
+ #
8
+ # @example Setup The middleware
9
+ # # in config/application.rb
10
+ # module CoolApp
11
+ # class Application < Rails::Application
12
+ # config.middleware.use(Onsi::Middleware::CORSHeaders)
13
+ # end
14
+ # end
15
+ class CORSHeaders
16
+ ##
17
+ # @private
18
+ #
19
+ # Create a new instance of the middleware.
20
+ #
21
+ # @param app [] Rack App
22
+ def initialize(app)
23
+ @app = app
24
+ end
25
+
26
+ ##
27
+ # @private
28
+ #
29
+ # Called by the Middleware stack.
30
+ def call(env)
31
+ status, headers, body = @app.call(env)
32
+
33
+ cors_headers = Onsi::CORSHeaders.generate(env)
34
+
35
+ [
36
+ status,
37
+ cors_headers.merge(headers),
38
+ body
39
+ ]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'middleware/cors_headers'
2
+
3
+ module Onsi
4
+ ##
5
+ # Module that contains Rack middleware classes.
6
+ module Middleware
7
+ end
8
+ end
data/lib/onsi/params.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'errors'
2
+ require_relative 'params_parser'
2
3
 
3
4
  module Onsi
4
5
  ##
@@ -71,11 +72,12 @@ module Onsi
71
72
  #
72
73
  # @return [Params] The new params object.
73
74
  def parse(params, attributes = [], relationships = [])
74
- data = params.require(:data)
75
- data.require(:type)
76
- attrs = permit_attributes(data, attributes)
77
- relas = permit_relationships(data, relationships)
78
- new(attrs, relas)
75
+ parser = Onsi::ParamsParser.new(params, attributes, relationships)
76
+ results = parser.parse!
77
+ new(
78
+ results.attributes,
79
+ results.relationships
80
+ )
79
81
  end
80
82
 
81
83
  ##
@@ -95,65 +97,6 @@ module Onsi
95
97
  params = ActionController::Parameters.new(json)
96
98
  parse(params, attributes, relationships)
97
99
  end
98
-
99
- private
100
-
101
- def permit_attributes(data, attributes)
102
- return {} if Array(attributes).empty?
103
-
104
- normalized_attributes = attributes.map(&:to_sym)
105
-
106
- data.require(:attributes).permit!.to_h.select { |k, _| normalized_attributes.include?(k.to_sym) }
107
- end
108
-
109
- def permit_relationships(data, relationships)
110
- return {} if Array(relationships).empty?
111
-
112
- rels = data.require(:relationships)
113
- {}.tap do |obj|
114
- relationships.each do |name|
115
- optional, true_name = parse_relationship_name(name)
116
- next unless rels.key?(true_name)
117
-
118
- resource = fetch_relationship(rels, optional, true_name)
119
- case resource
120
- when nil
121
- obj["#{true_name}_id".to_sym] = nil
122
- when Array
123
- ids = resource.map { |r| parse_relationship(r).last }
124
- obj["#{true_name.to_s.singularize}_ids".to_sym] = ids
125
- else
126
- _type, id = parse_relationship(resource)
127
- obj["#{true_name}_id".to_sym] = id
128
- end
129
- end
130
- end
131
- end
132
-
133
- def fetch_relationship(rels, optional, name)
134
- if optional
135
- payload = rels.require(name).permit!.to_h
136
- if payload[:data].is_a?(Array)
137
- return []
138
- end
139
-
140
- nil
141
- else
142
- rels.require(name).require(:data)
143
- end
144
- end
145
-
146
- def parse_relationship_name(name)
147
- name = name.to_s
148
- [name.start_with?('?'), name.gsub(/\A\?/, '')]
149
- end
150
-
151
- def parse_relationship(data)
152
- [
153
- data.require(:type),
154
- data.require(:id)
155
- ]
156
- end
157
100
  end
158
101
 
159
102
  ##
@@ -188,7 +131,7 @@ module Onsi
188
131
  #
189
132
  # @return [Hash] The flattened attributes and relationships
190
133
  def flatten
191
- attrs_hash.to_h.merge(relationships.to_h).with_indifferent_access
134
+ @flattened ||= attrs_hash.to_h.merge(relationships.to_h).with_indifferent_access
192
135
  end
193
136
 
194
137
  ##
@@ -220,6 +163,15 @@ module Onsi
220
163
  value
221
164
  end
222
165
 
166
+ def require_path(key_path)
167
+ value = flatten.dig(*key_path.split('/'))
168
+ if value.nil?
169
+ raise MissingReqiredAttribute.new("Missing attribute at key_path #{key_path}", key_path)
170
+ end
171
+
172
+ value
173
+ end
174
+
223
175
  ##
224
176
  # Handle finding a relationship's object.
225
177
  #
@@ -0,0 +1,178 @@
1
+ require_relative 'errors'
2
+
3
+ module Onsi
4
+ ##
5
+ # @private
6
+ #
7
+ # Parse a root object.
8
+ class ParamsParseOperation
9
+ MULTI_SOURCE_PATH = '*'.freeze
10
+
11
+ Result = Struct.new(:id, :attributes, :relationships) do
12
+ def flattened
13
+ attributes.merge(relationships)
14
+ end
15
+ end
16
+
17
+ attr_reader :data, :attributes, :relationships, :included, :results
18
+
19
+ def initialize(data, attributes, relationships, included)
20
+ @data = data
21
+ data.require(:type)
22
+ @attributes = Array(attributes).map(&:to_s)
23
+ @relationships = Array(relationships)
24
+ @included = included
25
+ @results = Result.new(data.fetch(:id, 'ambiguous'), {}, {})
26
+ end
27
+
28
+ def perform
29
+ parse_attributes!
30
+ parse_relationships!
31
+ results
32
+ end
33
+
34
+ private
35
+
36
+ def parse_attributes!
37
+ return if attributes.empty?
38
+
39
+ attrs = data.require(:attributes).permit!
40
+ permitted = attrs.to_h.select { |key, _| attributes.include?(key.to_s) }
41
+ results.attributes.merge!(permitted)
42
+ end
43
+
44
+ def parse_relationships!
45
+ return if relationships.empty?
46
+
47
+ relationship_params = data.require(:relationships)
48
+
49
+ relationships.each do |relationship_key|
50
+ case relationship_key
51
+ when String, Symbol
52
+ parse_relationship(relationship_key, relationship_params)
53
+ when Hash
54
+ parse_included(relationship_key, relationship_params)
55
+ else
56
+ raise ArgumentError, "Unexpected type for relationship #{relationship_key}"
57
+ end
58
+ end
59
+ end
60
+
61
+ ############################################################################
62
+ ### Parse Included Relationships
63
+ ############################################################################
64
+
65
+ def parse_included(relationship_key, relationship_params)
66
+ relationship_key.each do |key, value|
67
+ error_message = "Must specify an array of permitted values for relationship #{key}"
68
+ raise ArgumentError, error_message unless value.is_a?(Array)
69
+
70
+ parse_included_relationship(key, value, relationship_params)
71
+ end
72
+ end
73
+
74
+ def parse_included_relationship(key, value, params)
75
+ relationship = params.fetch(key.to_sym, nil)
76
+ return if relationship.nil?
77
+
78
+ included_path = relationship.require(:data).fetch(:source, nil)
79
+ return if included_path.nil?
80
+
81
+ root, type, id = included_path.split('/', 4).reject(&:empty?).map(&:presence)
82
+
83
+ unless root.present?
84
+ raise Onsi::Errors::IncludedParamError.new("Invalid Source: /#{root}", included_path)
85
+ end
86
+
87
+ unless root == 'included'
88
+ raise Onsi::Errors::IncludedParamError.new("Invalid Source: /#{root} is not included", included_path)
89
+ end
90
+
91
+ included_objects = find_included(type, id)
92
+
93
+ if included_objects.nil? || included_objects.empty?
94
+ raise Onsi::Errors::IncludedParamError.new("Invalid Source: Unable to find included.", included_path)
95
+ end
96
+
97
+ if included_objects.count != 1 && id != MULTI_SOURCE_PATH
98
+ raise Onsi::Errors::IncludedParamError.new("Invalid Source: Unable to disambiguate included. #{type}", included_path)
99
+ end
100
+
101
+ attributes = value.reject { |val| val.is_a?(Hash) }.map(&:to_s)
102
+ relationships = value.select { |val| val.is_a?(Hash) }.map { |hash| hash[:relationships] }.flatten
103
+
104
+ parsed_included = included_objects.map do |object|
105
+ self.class.new(object, attributes, relationships, included).perform
106
+ end
107
+
108
+ results.relationships[type] = {}
109
+
110
+ case id
111
+ when nil
112
+ results.relationships[type] = parsed_included.first.flattened
113
+ when MULTI_SOURCE_PATH
114
+ results.relationships[type] = {}
115
+ parsed_included.each do |included|
116
+ results.relationships[type][included.id] = included.flattened
117
+ end
118
+ else
119
+ results.relationships[type] = parsed_included.first.flattened
120
+ end
121
+ end
122
+
123
+ def find_included(type, id)
124
+ included.select do |param|
125
+ next false unless param.require(:type).to_sym == type.to_sym
126
+ next true unless id.present?
127
+ next true if id == MULTI_SOURCE_PATH
128
+
129
+ param.require(:id) == id
130
+ end
131
+ end
132
+
133
+ ############################################################################
134
+ ### Parse Simple Relationships
135
+ ############################################################################
136
+
137
+ def parse_relationship(relationship_key, relationship_params)
138
+ optional, name = parse_relationship_name(relationship_key)
139
+ return unless relationship_params.key?(name)
140
+
141
+ relationship_data = fetch_relationship(optional, name, relationship_params)
142
+
143
+ case relationship_data
144
+ when nil
145
+ results.relationships["#{name}_id".to_sym] = nil
146
+ when Array
147
+ ids = relationship_data.map { |r| parse_relationship_data(r).last }
148
+ results.relationships["#{name.to_s.singularize}_ids".to_sym] = ids
149
+ else
150
+ _type, id = parse_relationship_data(relationship_data)
151
+ results.relationships["#{name}_id".to_sym] = id
152
+ end
153
+ end
154
+
155
+ def parse_relationship_name(name)
156
+ name = name.to_s
157
+ [name.start_with?('?'), name.gsub(/\A\?/, '')]
158
+ end
159
+
160
+ def parse_relationship_data(data)
161
+ [
162
+ data.require(:type),
163
+ data.require(:id)
164
+ ]
165
+ end
166
+
167
+ def fetch_relationship(optional, name, relationships)
168
+ if optional
169
+ payload = relationships.require(name).permit!.to_h
170
+ return [] if payload[:data].is_a?(Array)
171
+
172
+ nil
173
+ else
174
+ relationships.require(name).require(:data)
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'params_parse_operation'
2
+
3
+ module Onsi
4
+ class ParamsParser
5
+ attr_reader :data
6
+ attr_reader :included
7
+ attr_reader :attributes
8
+ attr_reader :relationships
9
+
10
+ def initialize(params, attributes, relationships)
11
+ @data = params.require(:data)
12
+ @included = params.fetch(:included, [])
13
+ @attributes = attributes
14
+ @relationships = relationships
15
+ end
16
+
17
+ def parse!
18
+ operation = Onsi::ParamsParseOperation.new(data, attributes, relationships, included)
19
+ operation.perform
20
+ end
21
+ end
22
+ end
data/lib/onsi/resource.rb CHANGED
@@ -237,7 +237,7 @@ module Onsi
237
237
  subobj[DATA_KEY] = included.map do |inc|
238
238
  {
239
239
  TYPE_KEY => inc[TYPE_KEY],
240
- ID_KEY => inc[ID_KEY]
240
+ ID_KEY => inc[ID_KEY]
241
241
  }
242
242
  end
243
243
  end
data/lib/onsi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Onsi
2
2
  ##
3
3
  # The current version of Onsi
4
- VERSION = '1.0.1'.freeze
4
+ VERSION = '1.1.0'.freeze
5
5
  end
data/lib/onsi.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require 'onsi/controller'
2
+ require 'onsi/cors_headers'
2
3
  require 'onsi/error_responder'
3
4
  require 'onsi/errors'
4
5
  require 'onsi/includes'
6
+ require 'onsi/middleware'
5
7
  require 'onsi/model'
6
8
  require 'onsi/params'
7
9
  require 'onsi/resource'
data/onsi.gemspec CHANGED
@@ -22,10 +22,10 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.required_ruby_version = '>= 2.3'
24
24
 
25
- spec.add_dependency 'rails', '>= 5.0', '< 6.0'
25
+ spec.add_dependency 'addressable', '>= 2.5', '< 3.0'
26
+ spec.add_dependency 'rails', '>= 5.0', '< 6.0'
26
27
 
27
- spec.add_development_dependency 'appraisal', '~> 2.1.0'
28
- spec.add_development_dependency 'bundler', '~> 1.16'
28
+ spec.add_development_dependency 'bundler', '>= 1.16', '< 3.0'
29
29
  spec.add_development_dependency 'database_cleaner', '~> 1.7.0'
30
30
  spec.add_development_dependency 'pry', '~> 0.11.3'
31
31
  spec.add_development_dependency 'rake', '~> 10.0'
metadata CHANGED
@@ -1,63 +1,75 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onsi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maddie Schipper
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-21 00:00:00.000000000 Z
11
+ date: 2019-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: addressable
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '2.5'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6.0'
22
+ version: '3.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '5.0'
29
+ version: '2.5'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6.0'
32
+ version: '3.0'
33
33
  - !ruby/object:Gem::Dependency
34
- name: appraisal
34
+ name: rails
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 2.1.0
40
- type: :development
39
+ version: '5.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '6.0'
43
+ type: :runtime
41
44
  prerelease: false
42
45
  version_requirements: !ruby/object:Gem::Requirement
43
46
  requirements:
44
- - - "~>"
47
+ - - ">="
45
48
  - !ruby/object:Gem::Version
46
- version: 2.1.0
49
+ version: '5.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '6.0'
47
53
  - !ruby/object:Gem::Dependency
48
54
  name: bundler
49
55
  requirement: !ruby/object:Gem::Requirement
50
56
  requirements:
51
- - - "~>"
57
+ - - ">="
52
58
  - !ruby/object:Gem::Version
53
59
  version: '1.16'
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '3.0'
54
63
  type: :development
55
64
  prerelease: false
56
65
  version_requirements: !ruby/object:Gem::Requirement
57
66
  requirements:
58
- - - "~>"
67
+ - - ">="
59
68
  - !ruby/object:Gem::Version
60
69
  version: '1.16'
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '3.0'
61
73
  - !ruby/object:Gem::Dependency
62
74
  name: database_cleaner
63
75
  requirement: !ruby/object:Gem::Requirement
@@ -183,11 +195,16 @@ files:
183
195
  - bin/setup
184
196
  - lib/onsi.rb
185
197
  - lib/onsi/controller.rb
198
+ - lib/onsi/cors_headers.rb
186
199
  - lib/onsi/error_responder.rb
187
200
  - lib/onsi/errors.rb
188
201
  - lib/onsi/includes.rb
202
+ - lib/onsi/middleware.rb
203
+ - lib/onsi/middleware/cors_headers.rb
189
204
  - lib/onsi/model.rb
190
205
  - lib/onsi/params.rb
206
+ - lib/onsi/params_parse_operation.rb
207
+ - lib/onsi/params_parser.rb
191
208
  - lib/onsi/resource.rb
192
209
  - lib/onsi/version.rb
193
210
  - onsi.gemspec
@@ -210,8 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
227
  - !ruby/object:Gem::Version
211
228
  version: '0'
212
229
  requirements: []
213
- rubyforge_project:
214
- rubygems_version: 2.5.2.3
230
+ rubygems_version: 3.0.2
215
231
  signing_key:
216
232
  specification_version: 4
217
233
  summary: Format JSON API Responses