onsi 1.0.1 → 1.1.0

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