json_error 0.1.0 → 1.0.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
2
  SHA1:
3
- metadata.gz: 710945ff34e88690adf8b1287c718d8a1452fd22
4
- data.tar.gz: b99fed58240fc196859f26225809d5095d22a119
3
+ metadata.gz: a4322948d35b22110cc1c146b0da8bd3d0f16f94
4
+ data.tar.gz: 55b445035a7813c5e4d73a12e1c270696aac45b9
5
5
  SHA512:
6
- metadata.gz: 05856bbb8024a62a2733bc783ecc06cbd312cffcada7e4e0caf4935845d2b80b8a4c1d6c9150100fde8673a88aeccc15a52c3e3b2ce2ccbcf81a11d0882f7e47
7
- data.tar.gz: 791ffbea2fa34ac4aaa4a4241eeb8ab14d25000c6c6d8e50201b1e05a3f8ca124bd6dd3423e285294ffe993d87f7aae4f512b6e882911390ef0a0ed36c49ca95
6
+ metadata.gz: e8dcdc4ca99ac2245247d35cbecfd2dc1e5e2ced09fd8fcfa303a2a699bd33868dc03fff3cd99daaef8bb734eb24fe19e2dc8c78e092046d54a3a3251241b4d7
7
+ data.tar.gz: fc4668dd5daca19f4a389d0b455617b3ae7958bf5461f5d7c2a5f01e207df5c04a951495a1e3adaf0117b250bfb5638af8ffd289d1d300c30f1025ecdd7c46c2
data/.rubocop.yml CHANGED
@@ -1,2 +1,8 @@
1
+ Metrics/LineLength:
2
+ Max: 90
3
+
1
4
  Style/Documentation:
2
5
  Enabled: false
6
+
7
+ Style/SignalException:
8
+ EnforcedStyle: only_raise
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # JSONError
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/json_error.svg)](https://badge.fury.io/rb/json_error)
3
4
  [![Code Climate](https://codeclimate.com/github/buszu/json_error/badges/gpa.svg)](https://codeclimate.com/github/buszu/json_error)
4
5
 
5
6
  ## Installation
@@ -7,46 +8,95 @@
7
8
  Add this line to your application's Gemfile:
8
9
 
9
10
  ```ruby
10
- gem 'json_error', github: 'buszu/json_error'
11
+ gem 'json_error'
11
12
  ```
12
13
 
13
14
  And then execute:
14
15
 
15
16
  $ bundle
16
17
 
18
+ ## Introduction
19
+
20
+ ### What is JSONError gem?
21
+ It provides parent class with simple DSL to define API errors. It is based on concept, that error is something that went wrong (_what? = key_), in some circumstances (_when? = context_).
22
+
23
+ ### Why would I use it?
24
+ To design, manage and maintain API's errors JSON responses with ease.
25
+
26
+ ### How to do it?
27
+ Using locale file (e.g. json_errors.en.yml).
28
+
29
+ ```yml
30
+ # json_errors.en.yml example
31
+ en:
32
+ json_errors:
33
+ resource_not_found:
34
+ status: 404
35
+ message: 'Resource %{name} (%{id}) was not found.'
36
+ description: 'Blah blah blah.'
37
+ href: 'https://developers.api.pl/doc/errors/resource_not_found'
38
+ batmans:
39
+ resource_not_found:
40
+ status: 404
41
+ message: 'Resource Batman (%{id}) was not found.'
42
+ description: "Cuz I'm Batman"
43
+ ```
44
+
17
45
  ## Usage
18
46
 
19
- ### Defining JSONErrors
47
+ ### Understading JSONError
48
+
49
+ Let's take a look at example error class definition.
50
+
51
+ ```ruby
52
+ class Error < JSONError.base
53
+ key :error
54
+ translated_properties :message, :href
55
+ custom_properties :details, :some_dependency
56
+ visible_properties :key, :status, :message, :href, :details
57
+ end
58
+ ```
59
+
60
+ *Key* is the error identifier. It's not obligatory to specify its value here - you can also and pass it to the Error initializer when instantiating error object:
61
+ ```ruby
62
+ Error.new(key: :error)
63
+ ```
64
+ however, json errors must have a key. Key is not inherited.
65
+
66
+ *Default properties* are properties included to JSON output by default (:key, status: 500). You can change status in locale.
67
+
68
+ *Translated properties* are error attributes which values will be loaded from locale. Translated properties can be inherited.
69
+
70
+ *Custom properties* are attributes that won't be loaded from locale but passed to JSON output as they stand. It can be for exammple hash of ActiveRecord object validation error messages. Custom properties can be inherited.
71
+
72
+ *Visible properties* is optional whitelist for output JSON properties. By default all default, translated and custom properties are included in output. You can use visible_properties method to include only demanded subset. Visible properties are not inherited.
73
+
74
+ ### Defining JSONError
75
+
76
+ Let's introduce two example error classes now. They will be used in further examples.
20
77
 
21
78
  ```ruby
22
79
  module Errors
23
80
  class ResourceNotFound < JSONError.base
24
- def initialize(options = {})
25
- # Add required :key option
26
- options.merge!(key: :resource_not_found)
27
- super(options)
28
- end
81
+ key :resource_not_found
82
+ translated_properties :message, :href, :description
29
83
  end
30
84
 
31
85
  class OtherError < JSONError.base
32
- # Slice response JSON properties
33
- def self.properties
34
- super - %i(href description)
35
- end
36
-
37
- options.merge!(key: :other_error)
38
- super(options)
86
+ key :other_error
87
+ translated_properties :message
39
88
  end
40
89
  end
41
90
  ```
42
91
 
43
92
  ### Defining JSONError Properties
44
93
 
45
- Add entries below to your locale.
94
+ Just add entries to locale.
46
95
 
47
96
  ```yml
97
+ # config/locales/json_errors.en.yml
48
98
  en:
49
- errors:
99
+ json_errors:
50
100
  resource_not_found:
51
101
  status: 404
52
102
  message: 'Resource %{name} (%{id}) was not found.'
@@ -82,7 +132,6 @@ end
82
132
 
83
133
  ```ruby
84
134
  # Remember to load dependencies
85
-
86
135
  class Application < Sinatra::Base
87
136
  before { content_type :json }
88
137
 
@@ -124,7 +173,7 @@ You can specify different contexts for the same error key.
124
173
  # In locale
125
174
 
126
175
  en:
127
- errors:
176
+ json_errors:
128
177
  resource_not_found:
129
178
  status: 404
130
179
  message: 'Resource %{name} (%{id}) was not found.'
@@ -157,7 +206,7 @@ Errors::ResourceNotFound.new(context: 'batmans', id: 2)
157
206
 
158
207
  ## Contributing
159
208
 
160
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/json_error.
209
+ Questions, propositions, bug reports and pull requests are welcome.
161
210
 
162
211
 
163
212
  ## License
data/bin/console CHANGED
@@ -4,4 +4,6 @@ require 'bundler/setup'
4
4
  require 'json_error'
5
5
 
6
6
  require 'irb'
7
+
8
+ I18n.load_path = Dir['./spec/fixtures/locales/*.yml']
7
9
  IRB.start
@@ -1,43 +1,96 @@
1
1
  module JSONError
2
2
  class Base < StandardError
3
+ DEFAULT_STATUS = 500
3
4
  NULL_TOKEN = '~'
4
5
 
5
6
  attr_reader :context, :key, :options
6
7
 
7
- def initialize(attrs = {})
8
- @context = attrs[:context]
9
- @key = attrs.fetch(:key)
10
- @options = attrs.delete_if { |k, _v| %i(key context).include?(k) }
11
- options.merge!(default: NULL_TOKEN)
12
- super(message)
13
- end
8
+ class << self
9
+ def inherited(base)
10
+ base.instance_variable_set(:@translated_properties, translated_properties)
11
+ base.instance_variable_set(:@custom_properties, custom_properties)
12
+ end
14
13
 
15
- def self.properties
16
- %i(status key message description href)
17
- end
14
+ def base?
15
+ self == JSONError.base
16
+ end
18
17
 
19
- def message
20
- translate(:message)
21
- end
18
+ def disallowed_property_setting!(property)
19
+ raise(Errors::DisallowedPropertySetting, property: property, class: self)
20
+ end
21
+
22
+ def key(key = nil)
23
+ return @key if key.nil?
24
+ disallowed_property_setting!(:key) if base?
25
+
26
+ @key ||= key
27
+ end
28
+
29
+ def properties
30
+ [*default_properties, *translated_properties, *custom_properties]
31
+ end
32
+
33
+ def default_properties
34
+ %i(status key)
35
+ end
36
+
37
+ def translated_properties(*translated_properties)
38
+ return @translated_properties if translated_properties.empty?
39
+ disallowed_property_setting!(:translated_properties) if base?
40
+
41
+ translated_properties.each do |property|
42
+ define_method(property) { translate(property) }
43
+ end
44
+ @translated_properties = [*@translated_properties, *translated_properties].uniq
45
+ end
46
+
47
+ def custom_properties(*custom_properties)
48
+ return @custom_properties if custom_properties.empty?
49
+ disallowed_property_setting!(:custom_properties) if base?
22
50
 
23
- def description
24
- translate(:description)
51
+ attr_accessor(*custom_properties)
52
+ @custom_properties = [*@custom_properties, *custom_properties].uniq
53
+ end
54
+
55
+ def visible_properties(*visible_properties)
56
+ return(@visible_properties || properties) if visible_properties.empty?
57
+ disallowed_property_setting!(:visible_properties) if base?
58
+
59
+ @visible_properties = visible_properties.uniq
60
+ end
25
61
  end
26
62
 
27
- def href
28
- translate(:href)
63
+ def initialize(attrs = {})
64
+ @key = self.class.key || attrs.fetch(:key)
65
+ @context = attrs[:context]
66
+ assign_custom_properties(attrs)
67
+ assign_options(attrs)
68
+ super(message)
29
69
  end
30
70
 
31
71
  def status
32
- translate(:status, default: 500)
72
+ translate(:status, default: DEFAULT_STATUS)
33
73
  end
34
74
 
35
75
  def to_json(*args)
36
- properties.to_json(*args)
76
+ visible_properties_hash.to_json(*args)
37
77
  end
38
78
 
39
79
  private
40
80
 
81
+ def assign_custom_properties(attrs = {})
82
+ attrs = attrs.dup.delete_if { |k, _v| !custom_properties.include?(k) }
83
+ custom_properties.each do |property|
84
+ instance_variable_set("@#{property}", attrs[property])
85
+ end
86
+ end
87
+
88
+ def assign_options(attrs = {})
89
+ reserved_names = %i(key context) + custom_properties
90
+ @options = attrs.dup.delete_if { |k, _v| reserved_names.include?(k) }
91
+ options.merge!(default: NULL_TOKEN)
92
+ end
93
+
41
94
  def translate(node, translation_options = {})
42
95
  translation_options = options.merge(translation_options)
43
96
  translation = I18n.t("#{translation_path}.#{node}", translation_options)
@@ -45,15 +98,19 @@ module JSONError
45
98
  end
46
99
 
47
100
  def translation_path
48
- context.nil? ? "errors.#{key}" : "errors.#{context}.#{key}"
101
+ context.nil? ? "json_errors.#{key}" : "json_errors.#{context}.#{key}"
102
+ end
103
+
104
+ def visible_properties_hash
105
+ Hash[visible_properties.map { |property| [property, send(property)] }]
106
+ end
107
+
108
+ def visible_properties
109
+ self.class.visible_properties
49
110
  end
50
111
 
51
- def properties
52
- { status: status,
53
- key: key,
54
- message: message,
55
- description: description,
56
- href: href }.delete_if { |k, _v| !self.class.properties.include?(k) }
112
+ def custom_properties
113
+ self.class.custom_properties || []
57
114
  end
58
115
  end
59
116
  end
@@ -0,0 +1,11 @@
1
+ module JSONError
2
+ module Errors
3
+ class DisallowedPropertySetting < StandardError
4
+ def initialize(options = {})
5
+ property = options.fetch(:property)
6
+ klass = options.fetch(:class)
7
+ super("Setting #{property} property is disallowed for #{klass}.")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module JSONError
2
- VERSION = '0.1.0'
2
+ VERSION = '1.0.0'
3
3
  end
data/lib/json_error.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'i18n'
2
2
  require 'json'
3
3
  require 'json_error/version'
4
+ require 'json_error/errors/disallowed_property_setting'
4
5
  require 'json_error/base'
5
6
 
6
7
  module JSONError
@@ -0,0 +1,18 @@
1
+ class ResourceNotFound < JSONError.base
2
+ key :resource_not_found
3
+ translated_properties :message, :description, :href
4
+ custom_properties :details
5
+ end
6
+
7
+ class MissingTranslations < JSONError.base
8
+ key :missing_translations
9
+ translated_properties :message, :description, :href
10
+ custom_properties :details
11
+ visible_properties(*default_properties, :message, :details)
12
+ end
13
+
14
+ class ChildError < MissingTranslations
15
+ key :child_error
16
+ translated_properties :additional_translated
17
+ custom_properties :additional_custom
18
+ end
@@ -1,7 +1,13 @@
1
1
  en:
2
- errors:
2
+ json_errors:
3
3
  resource_not_found:
4
4
  status: 404
5
5
  message: 'Resource %{name} (%{id}) was not found.'
6
6
  description: 'Blah blah blah.'
7
7
  href: 'https://developers.api.pl/doc/errors/resource_not_found'
8
+ other:
9
+ resource_not_found:
10
+ status: 400
11
+ message: 'Resource not found.'
12
+ description: 'Bleh bleh bleh.'
13
+ href: 'https://developers.api.pl/doc/errors/resource_not_found?context=other'
@@ -0,0 +1,274 @@
1
+ require 'spec_helper'
2
+
3
+ describe ResourceNotFound do
4
+ context 'as JSONError.base child-class' do
5
+ describe 'NULL_TOKEN' do
6
+ subject { described_class::NULL_TOKEN }
7
+ it { is_expected.to eq('~') }
8
+ end
9
+
10
+ describe '.superclass' do
11
+ subject { described_class.superclass }
12
+ it { is_expected.to be(JSONError.base) }
13
+ end
14
+
15
+ describe '.base?' do
16
+ subject { described_class.base? }
17
+ it { is_expected.to be_falsey }
18
+ end
19
+
20
+ describe '.key' do
21
+ context 'when no key was passed' do
22
+ subject { described_class.key }
23
+ it { is_expected.to eq(:resource_not_found) }
24
+ end
25
+ end
26
+
27
+ describe '.properties' do
28
+ subject { described_class.properties }
29
+ let(:properties) do
30
+ described_class.default_properties + %i(message description href details)
31
+ end
32
+ it { is_expected.to eq(properties) }
33
+ end
34
+
35
+ describe '.default_properties' do
36
+ subject { described_class.default_properties }
37
+ it { is_expected.to eq(%i(status key)) }
38
+ end
39
+
40
+ describe '.translated_properties' do
41
+ subject { described_class.translated_properties }
42
+ context 'when no args were passed' do
43
+ it { is_expected.to eq(%i(message description href)) }
44
+ end
45
+ end
46
+
47
+ describe '.custom_properties' do
48
+ subject { described_class.custom_properties }
49
+
50
+ context 'when no args were passed' do
51
+ it { is_expected.to eq(%i(details)) }
52
+ end
53
+ end
54
+
55
+ describe '.visible_properties' do
56
+ subject { described_class.visible_properties }
57
+ context 'when no args were passed' do
58
+ it { is_expected.to eq(described_class.properties) }
59
+ end
60
+ end
61
+
62
+ describe '.new' do
63
+ context 'called without :key option' do
64
+ subject { described_class.new }
65
+ it { is_expected.to be_a(described_class) }
66
+ describe '#key' do
67
+ it { expect(subject.key).to eq(:resource_not_found) }
68
+ end
69
+ end
70
+
71
+ context 'called with :key option' do
72
+ subject { described_class.new(key: :other_key) }
73
+ it { is_expected.to be_a(described_class) }
74
+ describe '#key' do
75
+ it { expect(subject.key).to eq(:resource_not_found) }
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '#status' do
81
+ context 'for default context' do
82
+ subject { described_class.new.status }
83
+ it { is_expected.to eq(404) }
84
+ end
85
+
86
+ context 'for context "other"' do
87
+ subject { described_class.new(context: 'other').status }
88
+ it { is_expected.to eq(400) }
89
+ end
90
+ end
91
+
92
+ describe '#key' do
93
+ subject { described_class.new.key }
94
+ it { is_expected.to eq(:resource_not_found) }
95
+ end
96
+
97
+ describe '#message' do
98
+ context 'for default context' do
99
+ subject { described_class.new.message }
100
+ it { is_expected.to eq('Resource %{name} (%{id}) was not found.') }
101
+ end
102
+
103
+ context 'for context "other"' do
104
+ subject { described_class.new(context: 'other').message }
105
+ it { is_expected.to eq('Resource not found.') }
106
+ end
107
+ end
108
+
109
+ describe '#description' do
110
+ context 'for default context' do
111
+ subject { described_class.new.description }
112
+ it { is_expected.to eq('Blah blah blah.') }
113
+ end
114
+
115
+ context 'for context "other"' do
116
+ subject { described_class.new(context: 'other').description }
117
+ it { is_expected.to eq('Bleh bleh bleh.') }
118
+ end
119
+ end
120
+
121
+ describe '#href' do
122
+ context 'for default context' do
123
+ subject { described_class.new.href }
124
+ it do
125
+ is_expected.to eq('https://developers.api.pl/doc/errors/resource_not_found')
126
+ end
127
+ end
128
+
129
+ context 'for context "other"' do
130
+ subject { described_class.new(context: 'other').href }
131
+ it do
132
+ is_expected.to eq('https://developers.api.pl/doc/errors/resource_not_found?context=other')
133
+ end
134
+ end
135
+ end
136
+
137
+ describe '#to_json' do
138
+ let(:parse) { -> (s) { JSON.parse(s) } }
139
+ let(:error) { described_class.new }
140
+ subject { error.to_json }
141
+
142
+ describe '#keys' do
143
+ let(:keys) { %w(status key message description href details) }
144
+ it { expect(parse.call(subject).keys).to eq(keys) }
145
+ end
146
+
147
+ context 'when defined in locale' do
148
+ it { is_expected.to be_a(String) }
149
+ describe 'status property' do
150
+ it { expect(parse.call(subject)['status']).to eq(error.status) }
151
+ end
152
+ describe 'key property' do
153
+ it { expect(parse.call(subject)['key']).to eq(error.key.to_s) }
154
+ end
155
+ describe 'message property' do
156
+ it { expect(parse.call(subject)['message']).to eq(error.message.to_s) }
157
+ end
158
+ describe 'description property' do
159
+ it { expect(parse.call(subject)['description']).to eq(error.description.to_s) }
160
+ end
161
+ describe 'href property' do
162
+ it { expect(parse.call(subject)['href']).to eq(error.href.to_s) }
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ describe MissingTranslations do
170
+ context 'as JSONError.base child-class' do
171
+ describe '.visible_properties' do
172
+ subject { described_class.visible_properties }
173
+ context 'when no args were passed' do
174
+ it { is_expected.to eq(%i(status key message details)) }
175
+ end
176
+ end
177
+
178
+ describe '#status' do
179
+ subject { described_class.new.status }
180
+ it { is_expected.to eq(500) }
181
+ end
182
+
183
+ describe '#key' do
184
+ subject { described_class.new.key }
185
+ it { is_expected.to eq(:missing_translations) }
186
+ end
187
+
188
+ describe '#message' do
189
+ subject { described_class.new.message }
190
+ it { is_expected.to be_nil }
191
+ end
192
+
193
+ describe '#description' do
194
+ subject { described_class.new.description }
195
+ it { is_expected.to be_nil }
196
+ end
197
+
198
+ describe '#href' do
199
+ subject { described_class.new.href }
200
+ it { is_expected.to be_nil }
201
+ end
202
+
203
+ describe '#to_json' do
204
+ let(:parse) { -> (s) { JSON.parse(s) } }
205
+ let(:details) { { 'detail' => 'value' } }
206
+ let(:error) { described_class.new(details: details) }
207
+ subject { error.to_json }
208
+
209
+ describe '#keys' do
210
+ let(:keys) { %w(status key message details) }
211
+ it { expect(parse.call(subject).keys).to eq(keys) }
212
+ end
213
+
214
+ context 'when defined in locale' do
215
+ it { is_expected.to be_a(String) }
216
+ describe 'status property' do
217
+ it { expect(parse.call(subject)['status']).to eq(error.status) }
218
+ end
219
+ describe 'key property' do
220
+ it { expect(parse.call(subject)['key']).to eq(error.key.to_s) }
221
+ end
222
+ describe 'message property' do
223
+ it { expect(parse.call(subject)['message']).to be_nil }
224
+ end
225
+ describe 'details property' do
226
+ it { expect(parse.call(subject)['details']).to eq(error.details) }
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ describe ChildError do
234
+ let(:parent_class) { MissingTranslations }
235
+ context 'as MissingTranslations child-class' do
236
+ describe '.visible_properties' do
237
+ subject { described_class.visible_properties.sort }
238
+ context 'when no args were passed' do
239
+ it do
240
+ is_expected.to eq(
241
+ [*parent_class.properties, :additional_translated, :additional_custom].sort
242
+ )
243
+ end
244
+ end
245
+ end
246
+
247
+ describe '.translated_properties' do
248
+ subject { described_class.translated_properties.sort }
249
+ context 'when no args were passed' do
250
+ it do
251
+ is_expected.to eq(
252
+ [*parent_class.translated_properties, :additional_translated].sort
253
+ )
254
+ end
255
+ end
256
+ end
257
+
258
+ describe '.custom_properties' do
259
+ subject { described_class.custom_properties.sort }
260
+ context 'when no args were passed' do
261
+ it do
262
+ is_expected.to eq(
263
+ [*parent_class.custom_properties, :additional_custom].sort
264
+ )
265
+ end
266
+ end
267
+ end
268
+
269
+ describe '#key' do
270
+ subject { described_class.new.key }
271
+ it { is_expected.to eq(:child_error) }
272
+ end
273
+ end
274
+ end
@@ -1,6 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JSONError::Base do
4
+ describe 'DEFAULT_STATUS' do
5
+ subject { described_class::DEFAULT_STATUS }
6
+ it { is_expected.to eq(500) }
7
+ end
8
+
4
9
  describe 'NULL_TOKEN' do
5
10
  subject { described_class::NULL_TOKEN }
6
11
  it { is_expected.to eq('~') }
@@ -11,88 +16,111 @@ describe JSONError::Base do
11
16
  it { is_expected.to be(StandardError) }
12
17
  end
13
18
 
14
- describe '.new' do
15
- context 'called without :key option' do
16
- subject { -> { described_class.new } }
17
- it { is_expected.to raise_error(KeyError) }
19
+ describe '.base?' do
20
+ subject { described_class.base? }
21
+ it { is_expected.to be_truthy }
22
+ end
23
+
24
+ describe '.key' do
25
+ context 'when no key was passed' do
26
+ subject { described_class.key }
27
+ it { is_expected.to be_nil }
18
28
  end
19
29
 
20
- context 'called with :key option' do
21
- subject { described_class.new(key: :resource_not_found) }
22
- it { is_expected.to be_a(described_class) }
30
+ context 'when key were passed' do
31
+ let(:error) { JSONError::Errors::DisallowedPropertySetting }
32
+ subject { -> { described_class.key(:error) } }
33
+ it { is_expected.to raise_error(error) }
23
34
  end
24
35
  end
25
36
 
26
- describe '#status' do
27
- subject { error.status }
37
+ describe '.properties' do
38
+ subject { described_class.properties }
39
+ it { is_expected.to eq(described_class.default_properties) }
40
+ end
28
41
 
29
- context 'when not defined in locale' do
30
- let(:error) { described_class.new(key: :other_error) }
31
- it { is_expected.to eq(500) }
32
- end
42
+ describe '.default_properties' do
43
+ subject { described_class.default_properties }
44
+ it { is_expected.to eq(%i(status key)) }
45
+ end
33
46
 
34
- context 'when defined in locale' do
35
- let(:error) { described_class.new(key: :resource_not_found) }
36
- it { is_expected.to eq(404) }
47
+ describe '.translated_properties' do
48
+ subject { described_class.translated_properties(*args) }
49
+
50
+ context 'when no args were passed' do
51
+ let(:args) { [] }
52
+ it { is_expected.to be_nil }
37
53
  end
38
- end
39
54
 
40
- describe '#key' do
41
- let(:error) { described_class.new(key: :resource_not_found) }
42
- subject { error.key }
43
- it { is_expected.to eq(:resource_not_found) }
55
+ context 'when args were passed' do
56
+ let(:args) { %i(message) }
57
+ let(:error) { JSONError::Errors::DisallowedPropertySetting }
58
+ it { expect { subject }.to raise_error(error) }
59
+ end
44
60
  end
45
61
 
46
- describe '#message' do
47
- subject { error.message }
62
+ describe '.custom_properties' do
63
+ subject { described_class.custom_properties(*args) }
48
64
 
49
- context 'when not defined in locale' do
50
- let(:error) { described_class.new(key: :other_error) }
65
+ context 'when no args were passed' do
66
+ let(:args) { [] }
51
67
  it { is_expected.to be_nil }
52
68
  end
53
69
 
54
- context 'when defined in locale' do
55
- let(:name) { 'stick' }
56
- let(:id) { 1 }
57
- let(:error) do
58
- described_class.new(key: :resource_not_found, name: name, id: id)
59
- end
60
- it { is_expected.to eq("Resource #{name} (#{id}) was not found.") }
70
+ context 'when args were passed' do
71
+ let(:args) { %i(message) }
72
+ let(:error) { JSONError::Errors::DisallowedPropertySetting }
73
+ it { expect { subject }.to raise_error(error) }
61
74
  end
62
75
  end
63
76
 
64
- describe '#description' do
65
- subject { error.description }
77
+ describe '.visible_properties' do
78
+ subject { described_class.visible_properties(*args) }
66
79
 
67
- context 'when not defined in locale' do
68
- let(:error) { described_class.new(key: :other_error) }
69
- it { is_expected.to be_nil }
80
+ context 'when no args were passed' do
81
+ let(:args) { [] }
82
+ it { is_expected.to eq(described_class.properties) }
70
83
  end
71
84
 
72
- context 'when defined in locale' do
73
- let(:error) { described_class.new(key: :resource_not_found) }
74
- it { is_expected.to eq('Blah blah blah.') }
85
+ context 'when args were passed' do
86
+ let(:args) { %i(message) }
87
+ let(:error) { JSONError::Errors::DisallowedPropertySetting }
88
+ it { expect { subject }.to raise_error(error) }
75
89
  end
76
90
  end
77
91
 
78
- describe '#href' do
79
- subject { error.href }
92
+ describe '.new' do
93
+ context 'called without :key option' do
94
+ subject { -> { described_class.new } }
95
+ it { is_expected.to raise_error(KeyError) }
96
+ end
97
+
98
+ context 'called with :key option' do
99
+ subject { described_class.new(key: :resource_not_found) }
100
+ it { is_expected.to be_a(described_class) }
101
+ end
102
+ end
103
+
104
+ describe '#status' do
105
+ subject { error.status }
80
106
 
81
107
  context 'when not defined in locale' do
82
108
  let(:error) { described_class.new(key: :other_error) }
83
- it { is_expected.to be_nil }
109
+ it { is_expected.to eq(500) }
84
110
  end
85
111
 
86
112
  context 'when defined in locale' do
87
113
  let(:error) { described_class.new(key: :resource_not_found) }
88
- it do
89
- is_expected.to eq(
90
- 'https://developers.api.pl/doc/errors/resource_not_found'
91
- )
92
- end
114
+ it { is_expected.to eq(404) }
93
115
  end
94
116
  end
95
117
 
118
+ describe '#key' do
119
+ let(:error) { described_class.new(key: :resource_not_found) }
120
+ subject { error.key }
121
+ it { is_expected.to eq(:resource_not_found) }
122
+ end
123
+
96
124
  describe '#to_json' do
97
125
  let(:parse) { -> (s) { JSON.parse(s) } }
98
126
  subject { error.to_json }
@@ -106,15 +134,6 @@ describe JSONError::Base do
106
134
  describe 'key property' do
107
135
  it { expect(parse.call(subject)['key']).to eq(error.key.to_s) }
108
136
  end
109
- describe 'message property' do
110
- it { expect(parse.call(subject)['message']).to be_nil }
111
- end
112
- describe 'description property' do
113
- it { expect(parse.call(subject)['description']).to be_nil }
114
- end
115
- describe 'href property' do
116
- it { expect(parse.call(subject)['href']).to be_nil }
117
- end
118
137
  end
119
138
 
120
139
  context 'when defined in locale' do
@@ -126,17 +145,6 @@ describe JSONError::Base do
126
145
  describe 'key property' do
127
146
  it { expect(parse.call(subject)['key']).to eq(error.key.to_s) }
128
147
  end
129
- describe 'message property' do
130
- it { expect(parse.call(subject)['message']).to eq(error.message) }
131
- end
132
- describe 'description property' do
133
- it do
134
- expect(parse.call(subject)['description']).to eq(error.description)
135
- end
136
- end
137
- describe 'href property' do
138
- it { expect(parse.call(subject)['href']).to eq(error.href) }
139
- end
140
148
  end
141
149
  end
142
150
  end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe JSONError::Base do
4
+ describe '.superclass' do
5
+ subject { described_class.superclass }
6
+ it { is_expected.to be(StandardError) }
7
+ end
8
+
9
+ describe '.new' do
10
+ let(:no_option_error) { KeyError }
11
+ subject { -> (options) { described_class.new(options) } }
12
+
13
+ it 'requires :property option' do
14
+ expect { subject.call({}) }.to raise_error(no_option_error)
15
+ end
16
+
17
+ it 'requires :class option' do
18
+ expect { subject.call(property: :p) }.to raise_error(no_option_error)
19
+ end
20
+ end
21
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
 
3
3
  require 'i18n'
4
-
5
4
  I18n.load_path = Dir['./spec/fixtures/locales/*.yml']
5
+
6
6
  require 'json_error'
7
+ require './spec/fixtures/json_error_base_children'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_error
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Krzysztof Buszewicz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-11 00:00:00.000000000 Z
11
+ date: 2015-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -100,9 +100,13 @@ files:
100
100
  - json_error.gemspec
101
101
  - lib/json_error.rb
102
102
  - lib/json_error/base.rb
103
+ - lib/json_error/errors/disallowed_property_setting.rb
103
104
  - lib/json_error/version.rb
105
+ - spec/fixtures/json_error_base_children.rb
104
106
  - spec/fixtures/locales/en.yml
107
+ - spec/json_error/base_children_spec.rb
105
108
  - spec/json_error/base_spec.rb
109
+ - spec/json_error/errors/disallowed_property_setting.rb
106
110
  - spec/json_error_spec.rb
107
111
  - spec/spec_helper.rb
108
112
  homepage: https://github.com/buszu/json_error
@@ -130,8 +134,11 @@ signing_key:
130
134
  specification_version: 4
131
135
  summary: JSON errors base for APIs.
132
136
  test_files:
137
+ - spec/fixtures/json_error_base_children.rb
133
138
  - spec/fixtures/locales/en.yml
139
+ - spec/json_error/base_children_spec.rb
134
140
  - spec/json_error/base_spec.rb
141
+ - spec/json_error/errors/disallowed_property_setting.rb
135
142
  - spec/json_error_spec.rb
136
143
  - spec/spec_helper.rb
137
144
  has_rdoc: