jsonapi-utils 0.3.5 → 0.4.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
2
  SHA1:
3
- metadata.gz: 1e857579e82b9b5550ec7224bd1c2659b4e06e9f
4
- data.tar.gz: 468183964c826b06cff256ccfd2b4305b43f68bb
3
+ metadata.gz: 768ad917f0e0006484fcca29a138f05c0b2f9a7b
4
+ data.tar.gz: 8be72ed0a02e3e86f0b73edd822a0f791992cb36
5
5
  SHA512:
6
- metadata.gz: 597e131379f735cda8fb5f980256966089d0dacc4d5a552709a20524f30e4b5ab94e8ee01a3a0a22f861911bbeefa470341c35c5946badbc0319437353c34e02
7
- data.tar.gz: 9715af2a8aeae7cda56d8f24e8f43f982774ab9db0d64e0c15aef2ada82a9f7714f4556895adfc06583a8a76539cd5dc2bee0a9b8df4c97d9d8beab8d0711510
6
+ metadata.gz: 3fd1c7fa5ca1e4c2d075be52fe75d058555a840fb0c70b43d94bf687f13fd7740d340f74f50fc6f64c4d90a171493c27425661ca26a6b7a99992472d697bc96a
7
+ data.tar.gz: 3a31efa4514d307eaccaf1c244db587cafccbca885bd2eafbbd8c846829a0d5ed0e4f86697a4e31b5cf46429e8f38b16bf4b0d16e85487dd52d09751ce94f4bc
data/.gitignore CHANGED
@@ -9,6 +9,8 @@
9
9
  /spec/test_db
10
10
  /spec/reports/
11
11
  /tmp/
12
+ /log/
13
+ *.log
12
14
  *.bundle
13
15
  *.so
14
16
  *.sw*
@@ -16,5 +18,5 @@
16
18
  *.a
17
19
  *.gem
18
20
  .DS_Store
19
- mkmf.log
21
+ test_db
20
22
 
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # JSONAPI::Utils
2
2
 
3
+ [![Code Climate](https://codeclimate.com/github/b2beauty/jsonapi-utils/badges/gpa.svg)](https://codeclimate.com/github/b2beauty/jsonapi-utils)
4
+ [![Gem Version](https://badge.fury.io/rb/jsonapi-utils.svg)](https://badge.fury.io/rb/jsonapi-utils)
5
+
3
6
  JSON::Utils is a simple way to get a full-featured [JSON API](jsonapi.org) serialization in your
4
7
  controller's responses. This gem works on top of the awesome gem [jsonapi-resources](https://github.com/cerebris/jsonapi-resources),
5
8
  bringing to controllers a Rails-native way to render data.
@@ -9,7 +12,7 @@ bringing to controllers a Rails-native way to render data.
9
12
  Add these lines to your application's Gemfile:
10
13
 
11
14
  ```ruby
12
- gem 'jsonapi-resources', '~> 0.5.7'
15
+ gem 'jsonapi-resources', '~> 0.7.0'
13
16
  gem 'jsonapi-utils'
14
17
  ```
15
18
 
@@ -10,20 +10,24 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["tiagopog@gmail.com", "douglas@beautydate.com.br"]
11
11
 
12
12
  spec.summary = %q{JSON::Utils is a simple way to get a full-featured JSON API serialization for your controller's responses.}
13
- spec.description = %q{A Rails way to get your API's data following the JSON API's specs (http://jsosapi.org)}
13
+ spec.description = %q{A Rails way to get your API's data serialized through JSON API's specs (http://jsosapi.org)}
14
14
  spec.homepage = "https://github.com/b2beauty/jsonapi-utils"
15
15
  spec.license = "MIT"
16
16
 
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
18
  spec.bindir = "exe"
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
- spec.require_paths = ["lib"]
20
+ spec.require_paths = ['lib']
21
21
 
22
22
  spec.add_development_dependency 'bundler', '~> 1.10'
23
23
  spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rspec'
24
25
  spec.add_development_dependency 'rspec-rails'
26
+ spec.add_development_dependency 'smart_rspec'
27
+ spec.add_development_dependency 'pry'
25
28
  spec.add_development_dependency 'sqlite3'
26
29
  spec.add_development_dependency 'factory_girl', '~> 4.5'
27
- spec.add_development_dependency 'jsonapi-resources', '~> 0.5.7'
28
- spec.add_development_dependency 'rails', '>= 4.0'
30
+ spec.add_development_dependency 'jsonapi-resources', '~> 0.7.0'
31
+
32
+ spec.add_dependency 'rails', '>= 4.0'
29
33
  end
data/lib/jsonapi/utils.rb CHANGED
@@ -1,9 +1,11 @@
1
1
  require 'jsonapi/utils/version'
2
+ require 'active_support/concern'
2
3
  require 'jsonapi/utils/exceptions'
4
+ require 'pry'
3
5
 
4
6
  module JSONAPI
5
7
  module Utils
6
- extend ActiveSupport::Concern
8
+ extend ::ActiveSupport::Concern
7
9
 
8
10
  include do
9
11
  helper_method :jsonapi_serialize
@@ -13,7 +15,14 @@ module JSONAPI
13
15
  if options.has_key?(:json)
14
16
  response = jsonapi_serialize(options[:json], options[:options] || {})
15
17
  render json: response, status: options[:status] || :ok
18
+ else
19
+ raise ArgumentError.new('":json" key must be set to JSONAPI::Utils#jsonapi_render')
16
20
  end
21
+ rescue => e
22
+ raise e unless e.class.name.starts_with?('JSONAPI::Exceptions')
23
+ handle_exceptions(e)
24
+ ensure
25
+ headers['Content-Type'] = JSONAPI::MEDIA_TYPE
17
26
  end
18
27
 
19
28
  def jsonapi_render_errors(exception)
@@ -33,8 +42,8 @@ module JSONAPI
33
42
  jsonapi_render_errors(::JSONAPI::Utils::Exceptions::BadRequest.new)
34
43
  end
35
44
 
36
- def jsonapi_render_not_found(exception)
37
- id = exception.message.match(/=(\d+)/)[1]
45
+ def jsonapi_render_not_found
46
+ id = extract_ids(@request.params)
38
47
  jsonapi_render_errors(JSONAPI::Exceptions::RecordNotFound.new(id))
39
48
  end
40
49
 
@@ -43,17 +52,18 @@ module JSONAPI
43
52
  end
44
53
 
45
54
  def jsonapi_serialize(records, options = {})
55
+ setup_request
46
56
  results = JSONAPI::OperationResults.new
47
57
 
48
58
  fix_request_options(params, records)
49
59
 
50
60
  if records.respond_to?(:to_ary)
51
- records = fix_when_hash(records, options) if needs_to_be_fixed?(records)
52
- @_records = build_collection(records, options)
53
- results.add_result(JSONAPI::ResourcesOperationResult.new(:ok, @_records, result_options(records, options)))
61
+ records = fix_when_hash(records, options) if needs_to_be_fixed?(records)
62
+ @resources = build_collection(records, options)
63
+ results.add_result(JSONAPI::ResourcesOperationResult.new(:ok, @resources, result_options(options)))
54
64
  else
55
- @_record = turn_into_resource(records, options)
56
- results.add_result(JSONAPI::ResourceOperationResult.new(:ok, @_record))
65
+ @resource = turn_into_resource(records, options)
66
+ results.add_result(JSONAPI::ResourceOperationResult.new(:ok, @resource))
57
67
  end
58
68
 
59
69
  create_response_document(results).contents
@@ -61,6 +71,11 @@ module JSONAPI
61
71
 
62
72
  private
63
73
 
74
+ def extract_ids(hash)
75
+ ids = hash.keys.select { |e| e =~ /id$/i }.map { |e| hash[e] }
76
+ ids.first rescue '(id not identified)'
77
+ end
78
+
64
79
  def fix_request_options(params, records)
65
80
  return if request.method !~ /get/i ||
66
81
  params.nil? ||
@@ -73,142 +88,87 @@ module JSONAPI
73
88
  records.is_a?(Array) && records.all? { |e| e.is_a?(Hash) }
74
89
  end
75
90
 
76
- def result_options(records, options)
77
- {}.tap do |data|
78
- if JSONAPI.configuration.top_level_links_include_pagination
79
- data[:pagination_params] = pagination_params(records, options)
80
- end
91
+ def result_options(options)
92
+ hash = {}
81
93
 
82
- if JSONAPI.configuration.top_level_meta_include_record_count
83
- data[:record_count] = count_records(records, options)
84
- end
94
+ if JSONAPI.configuration.top_level_links_include_pagination
95
+ hash[:pagination_params] = pagination_params(options)
85
96
  end
86
- end
87
97
 
88
- def pagination_params(records, options)
89
- data = {}
90
- if @_paginator && JSONAPI.configuration.top_level_links_include_pagination
91
- @_paginator.class.requires_record_count &&
92
- data[:record_count] = count_records(records, options)
93
- @_paginator.links_page_params(data)
94
- else
95
- data
98
+ if JSONAPI.configuration.top_level_meta_include_record_count
99
+ hash[:record_count] = count_records(@resources, options)
96
100
  end
97
- end
98
101
 
99
- def build_collection(records, options = {})
100
- records = apply_filter(records, options)
101
- records = apply_pagination(records, options)
102
- records = apply_sort(records)
103
- records.respond_to?(:to_ary) ? records.map { |record| turn_into_resource(record, options) } : []
102
+ hash
104
103
  end
105
104
 
106
- def turn_into_resource(record, options = {})
107
- if options[:resource]
108
- options[:resource].to_s.constantize.new(record)
105
+ def pagination_params(options)
106
+ @paginator ||= paginator(params)
107
+ if @paginator && JSONAPI.configuration.top_level_links_include_pagination
108
+ options = {}
109
+ @paginator.class.requires_record_count &&
110
+ options[:record_count] = count_records(@resources, options)
111
+ @paginator.links_page_params(options)
109
112
  else
110
- @request.resource_klass.new(record)
111
- end
112
- end
113
-
114
- def apply_filter(records, options = {})
115
- if apply_filter?(records, options)
116
- records.where(filter_params)
117
- else
118
- records
113
+ {}
119
114
  end
120
115
  end
121
116
 
122
- def apply_filter?(records, options = {})
123
- params[:filter].present? && records.respond_to?(:where) &&
124
- (options[:filter].nil? || options[:filter])
125
- end
126
-
127
- def filter_params
128
- @_filter_params =
129
- params[:filter].keys.each_with_object({}) do |resource, hash|
130
- hash[resource] = params[:filter][resource]
131
- end
132
- end
133
-
134
- def apply_pagination(records, options = {})
135
- return records unless apply_pagination?(options)
136
- pagination = set_pagination(options)
117
+ def paginator(params)
118
+ page_params = ActionController::Parameters.new(params[:page])
137
119
 
138
- records =
139
- if records.is_a?(Array)
140
- records[pagination[:range]]
141
- else
142
- pagination[:paginator].apply(records, nil)
120
+ @paginator ||=
121
+ if JSONAPI.configuration.default_paginator == :paged
122
+ PagedPaginator.new(page_params)
123
+ elsif JSONAPI.configuration.default_paginator == :offset
124
+ OffsetPaginator.new(page_params)
143
125
  end
144
126
  end
145
127
 
146
- def apply_sort(records)
147
- return records unless params[:sort].present?
148
-
149
- if records.is_a?(Array)
150
- records.sort { |a, b| comp = 0; eval(sort_criteria) }
151
- elsif records.respond_to?(:order)
152
- records.order(sort_params)
153
- end
154
- end
155
-
156
- def sort_criteria
157
- sort_params.reduce('') do |sum, hash|
158
- foo = ["a[:#{hash[0]}]", "b[:#{hash[0]}]"]
159
- foo.reverse! if hash[1] == :desc
160
- sum + "comp = comp == 0 ? #{foo.join(' <=> ')} : comp; "
128
+ def build_collection(records, options = {})
129
+ unless JSONAPI.configuration.default_paginator == :none
130
+ records = paginator(@request.params).apply(records, nil)
161
131
  end
132
+ records.respond_to?(:to_ary) ? records.map { |record| turn_into_resource(record, options) } : []
162
133
  end
163
134
 
164
- def sort_params
165
- @_sort_params ||=
166
- params[:sort].split(',').each_with_object({}) do |criteria, hash|
167
- order, field = criteria.match(/(\-?)(\w+)/i)[1..2]
168
- hash[field] = order == '-' ? :desc : :asc
169
- end
170
- end
171
-
172
- def set_pagination(options)
173
- page_params = ActionController::Parameters.new(@request.params[:page])
174
- if JSONAPI.configuration.default_paginator == :paged
175
- @_paginator ||= PagedPaginator.new(page_params)
176
- number = page_params['number'].to_i.nonzero? || 1
177
- size = page_params['size'].to_i.nonzero? || JSONAPI.configuration.default_page_size
178
- { paginator: @_paginator, range: (number - 1) * size..number * size - 1 }
179
- elsif JSONAPI.configuration.default_paginator == :offset
180
- @_paginator ||= OffsetPaginator.new(page_params)
181
- offset = page_params['offset'].to_i.nonzero? || 0
182
- limit = page_params['limit'].to_i.nonzero? || JSONAPI.configuration.default_page_size
183
- { paginator: @_paginator, range: offset..offset + limit - 1 }
135
+ def turn_into_resource(record, options = {})
136
+ if options[:resource]
137
+ options[:resource].to_s.constantize.new(record, context)
184
138
  else
185
- {}
139
+ @request.resource_klass.new(record, context)
186
140
  end
187
141
  end
188
142
 
189
- def apply_pagination?(options)
190
- JSONAPI.configuration.default_paginator != :none &&
191
- (options[:paginate].nil? || options[:paginate])
192
- end
193
-
194
143
  def fix_when_hash(records, options)
195
144
  return [] unless options[:model]
196
145
  records.map { |hash| options[:model].new(hash) }
197
- rescue ActiveRecord::UnknownAttributeError
146
+ rescue
198
147
  ids = records.map { |e| e[:id] || e['id'] }
199
148
  scope = options[:scope] ? options[:model].send(options[:scope]) : options[:model]
200
149
  scope.where(id: ids)
201
150
  end
202
151
 
203
152
  def count_records(records, options)
204
- if options[:count].present?
205
- options[:count]
206
- elsif records.is_a?(Array)
207
- records.length
153
+ if records.size.zero? then 0
154
+ elsif options[:count] then options[:count]
155
+ elsif options[:model] && options[:scope] then options[:model].send(options[:scope]).count
156
+ elsif options[:model] then options[:model].count
208
157
  else
209
- records = apply_filter(records, options) if params[:filter].present?
210
- records.except(:group, :order).count("DISTINCT #{records.table.name}.id")
158
+ record = records.first
159
+ model = record.try(:model) || record.try(:_model)
160
+ model.class.count
211
161
  end
212
162
  end
163
+
164
+ def setup_request
165
+ @request ||=
166
+ JSONAPI::Request.new(
167
+ params,
168
+ context: context,
169
+ key_formatter: key_formatter,
170
+ server_error_callbacks: (self.class.server_error_callbacks || [])
171
+ )
172
+ end
213
173
  end
214
174
  end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Utils
3
- VERSION = '0.3.5'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Guedes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-04-04 00:00:00.000000000 Z
12
+ date: 2016-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
41
  version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: rspec-rails
44
58
  requirement: !ruby/object:Gem::Requirement
@@ -53,6 +67,34 @@ dependencies:
53
67
  - - ">="
54
68
  - !ruby/object:Gem::Version
55
69
  version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: smart_rspec
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
56
98
  - !ruby/object:Gem::Dependency
57
99
  name: sqlite3
58
100
  requirement: !ruby/object:Gem::Requirement
@@ -87,14 +129,14 @@ dependencies:
87
129
  requirements:
88
130
  - - "~>"
89
131
  - !ruby/object:Gem::Version
90
- version: 0.5.7
132
+ version: 0.7.0
91
133
  type: :development
92
134
  prerelease: false
93
135
  version_requirements: !ruby/object:Gem::Requirement
94
136
  requirements:
95
137
  - - "~>"
96
138
  - !ruby/object:Gem::Version
97
- version: 0.5.7
139
+ version: 0.7.0
98
140
  - !ruby/object:Gem::Dependency
99
141
  name: rails
100
142
  requirement: !ruby/object:Gem::Requirement
@@ -102,14 +144,15 @@ dependencies:
102
144
  - - ">="
103
145
  - !ruby/object:Gem::Version
104
146
  version: '4.0'
105
- type: :development
147
+ type: :runtime
106
148
  prerelease: false
107
149
  version_requirements: !ruby/object:Gem::Requirement
108
150
  requirements:
109
151
  - - ">="
110
152
  - !ruby/object:Gem::Version
111
153
  version: '4.0'
112
- description: A Rails way to get your API's data following the JSON API's specs (http://jsosapi.org)
154
+ description: A Rails way to get your API's data serialized through JSON API's specs
155
+ (http://jsosapi.org)
113
156
  email:
114
157
  - tiagopog@gmail.com
115
158
  - douglas@beautydate.com.br
@@ -151,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
194
  version: '0'
152
195
  requirements: []
153
196
  rubyforge_project:
154
- rubygems_version: 2.6.2
197
+ rubygems_version: 2.4.5.1
155
198
  signing_key:
156
199
  specification_version: 4
157
200
  summary: JSON::Utils is a simple way to get a full-featured JSON API serialization