restful_error 1.0.2 → 1.0.3
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 +4 -4
- data/lib/restful_error/inflector.rb +2 -0
- data/lib/restful_error/railtie.rb +4 -8
- data/lib/restful_error/status.rb +19 -19
- data/lib/restful_error/version.rb +1 -1
- data/lib/restful_error.rb +34 -15
- data/spec/with_rails/exceptions_app_spec.rb +48 -0
- metadata +3 -5
- data/lib/restful_error/engine.rb +0 -9
- data/spec/rack_spec.rb +0 -20
- data/spec/railtie_spec.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4744dd451535b3d85e7ce8b47a76abee9fa33970a72d6748e553f89bb830e9e5
|
4
|
+
data.tar.gz: 6cfc09fbf86294c2453a3effeb1537f83a9c8fef8bed444f24916e3f45c2d470
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d339f3e39861bfdc9bf64fc983d9b03e15708f4323d3f9987da1ae70c7bc973b8cfecb7cc7568a1078957f7eef6ba9a8e1f5c533f50a734b2fcc0005f5c2170
|
7
|
+
data.tar.gz: cbbf4ee06b69b396f79cd351c2659458422090d927af7584f31eab4e8e4fe1bcc4019cb21b90f2695ddbfe2683199afd412a4f6bad11ddf61365cb182a26f55f
|
@@ -12,6 +12,7 @@ module RestfulError
|
|
12
12
|
word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
|
13
13
|
word.tr!("-", "_")
|
14
14
|
word.downcase!
|
15
|
+
word
|
15
16
|
end
|
16
17
|
|
17
18
|
def camelize(word_)
|
@@ -21,6 +22,7 @@ module RestfulError
|
|
21
22
|
word.sub!(/^[a-z\d]*/) { ::Regexp.last_match(0).capitalize }
|
22
23
|
word.gsub!(%r{(?:_|(/))([a-z\d]*)}) { "#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}" }
|
23
24
|
word.gsub!("/", "::")
|
25
|
+
word
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -10,18 +10,14 @@ module RestfulError
|
|
10
10
|
|
11
11
|
def show
|
12
12
|
@exception = request.env["action_dispatch.exception"]
|
13
|
-
|
13
|
+
code = request.path_info[1..].to_i
|
14
|
+
status = RestfulError.build_status_from_symbol_or_code(code)
|
14
15
|
@status_code = status.code
|
15
16
|
@reason_phrase = status.reason_phrase
|
16
|
-
@
|
17
|
-
unless @message
|
18
|
-
class_name = @exception.class.name
|
19
|
-
class_key = RestfulError::Inflector.underscore(class_name)
|
20
|
-
@message = I18n.t class_key, default: [ status.symbol, @reason_phrase ], scope: :restful_error
|
21
|
-
end
|
17
|
+
@response_message = @exception.try(:response_message) || RestfulError.localized_phrase(@exception.class.name, status) || nil
|
22
18
|
|
23
19
|
self.status = status.code
|
24
|
-
render "restful_error/show"
|
20
|
+
render "restful_error/show", formats: request.format.symbol
|
25
21
|
end
|
26
22
|
end
|
27
23
|
|
data/lib/restful_error/status.rb
CHANGED
@@ -4,34 +4,34 @@ require "restful_error/inflector"
|
|
4
4
|
require "rack/utils"
|
5
5
|
|
6
6
|
module RestfulError
|
7
|
+
Status = Data.define(:code, :reason_phrase, :symbol, :const_name)
|
8
|
+
|
7
9
|
STATUS_CODE_TO_SYMBOL = Rack::Utils::SYMBOL_TO_STATUS_CODE.invert
|
8
|
-
|
9
|
-
|
10
|
+
|
11
|
+
def self.build_status_from_const(const_sym)
|
12
|
+
const_name = const_sym.to_s
|
13
|
+
return unless /[A-Z]/.match?(const_name[0])
|
14
|
+
symbol = RestfulError::Inflector.underscore(const_name).to_sym
|
15
|
+
build_status_from_symbol_or_code(symbol)
|
16
|
+
end
|
17
|
+
def self.build_status_from_symbol_or_code(code_or_sym)
|
18
|
+
case code_or_sym
|
10
19
|
when Integer
|
11
|
-
|
20
|
+
code = code_or_sym
|
21
|
+
symbol = STATUS_CODE_TO_SYMBOL[code]
|
22
|
+
const_name = Inflector.camelize(symbol.to_s)
|
23
|
+
reason_phrase = Rack::Utils::HTTP_STATUS_CODES[code]
|
24
|
+
Status.new(code:, symbol:, const_name:, reason_phrase:)
|
12
25
|
when Symbol
|
13
|
-
str = code_or_sym_or_const_name.to_s
|
14
|
-
sym = /[A-Z]/.match?(str[0]) ? RestfulError::Inflector.underscore(str).to_sym : code_or_sym_or_const_name
|
15
26
|
begin
|
16
|
-
Rack::Utils.status_code(
|
27
|
+
build_status_from_symbol_or_code Rack::Utils.status_code(code_or_sym)
|
17
28
|
rescue ArgumentError
|
18
29
|
nil
|
19
30
|
end
|
20
31
|
when /\A\d{3}\z/
|
21
|
-
|
32
|
+
build_status_from_symbol_or_code(code_or_sym.to_i)
|
22
33
|
else
|
23
|
-
raise ArgumentError, "Invalid argument: #{
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
Status = Data.define(:code, :reason_phrase, :symbol, :const_name) do
|
28
|
-
def initialize(code:)
|
29
|
-
reason_phrase = Rack::Utils::HTTP_STATUS_CODES[code]
|
30
|
-
raise ArgumentError, "Invalid status code: #{code}" unless reason_phrase
|
31
|
-
|
32
|
-
symbol = STATUS_CODE_TO_SYMBOL[code]
|
33
|
-
const_name = Inflector.camelize(symbol.to_s)
|
34
|
-
super(code:, reason_phrase:, symbol:, const_name:)
|
34
|
+
raise ArgumentError, "Invalid argument: #{code_or_sym.inspect}"
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/restful_error.rb
CHANGED
@@ -3,43 +3,62 @@
|
|
3
3
|
require "rack/utils"
|
4
4
|
require "restful_error/railtie" if defined? ActionController
|
5
5
|
require "restful_error/status"
|
6
|
-
|
7
|
-
I18n.load_path += Dir["#{File.expand_path("../config/locales")}/*.yml"] if defined? I18n
|
6
|
+
require "restful_error/version"
|
8
7
|
|
9
8
|
module RestfulError
|
10
|
-
class BaseError < StandardError; end
|
11
|
-
|
12
9
|
module Helper
|
13
10
|
def restful
|
14
|
-
|
11
|
+
@restful ||= begin
|
12
|
+
raise NotImplementedError, "http_status must be implemented by including class" unless respond_to?(:http_status)
|
13
|
+
RestfulError.build_status_from_symbol_or_code(http_status)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
def response_message
|
17
|
+
return @response_message unless @response_message.nil?
|
18
|
+
@response_message = RestfulError.localized_phrase(self.class.name, restful)
|
19
|
+
end
|
20
|
+
end
|
15
21
|
|
16
|
-
|
22
|
+
class BaseError < StandardError
|
23
|
+
include RestfulError::Helper
|
24
|
+
def initialize(message = nil)
|
25
|
+
@response_message = message
|
26
|
+
super
|
17
27
|
end
|
18
28
|
end
|
19
29
|
|
20
30
|
@cache = {}
|
21
31
|
class << self
|
22
32
|
def [](code_like)
|
23
|
-
|
24
|
-
@cache[code] ||= build_error_class_for(
|
33
|
+
status = RestfulError.build_status_from_symbol_or_code(code_like)
|
34
|
+
@cache[status.code] ||= build_error_class_for(status)
|
25
35
|
end
|
26
36
|
|
27
37
|
def const_missing(const_name)
|
28
|
-
|
29
|
-
return super unless
|
38
|
+
status = RestfulError.build_status_from_const(const_name)
|
39
|
+
return super unless status
|
40
|
+
|
41
|
+
@cache[status.code] ||= build_error_class_for(status)
|
42
|
+
end
|
30
43
|
|
31
|
-
|
44
|
+
def init_i18n
|
45
|
+
return if @init_i18n
|
46
|
+
I18n.load_path += Dir["#{File.expand_path("./config/locales")}/*.yml"]
|
47
|
+
@init_i18n = true
|
48
|
+
end
|
49
|
+
def localized_phrase(class_name, status)
|
50
|
+
return false unless defined?(I18n)
|
51
|
+
init_i18n
|
52
|
+
class_key = RestfulError::Inflector.underscore(class_name)
|
53
|
+
I18n.t class_key, default: [status.symbol, false], scope: :restful_error
|
32
54
|
end
|
33
55
|
|
34
56
|
private
|
35
57
|
|
36
|
-
def build_error_class_for(
|
37
|
-
status = Status.new(code)
|
38
|
-
message = defined?(I18n) ? I18n.t(status.symbol, default: status.reason_phrase, scope: :restful_error) : status.reason_phrase
|
58
|
+
def build_error_class_for(status)
|
39
59
|
klass = Class.new(BaseError) do
|
40
60
|
define_method(:http_status) { status.code }
|
41
61
|
define_method(:restful) { status }
|
42
|
-
define_method(:message) { message }
|
43
62
|
end
|
44
63
|
const_set(status.const_name, klass)
|
45
64
|
if defined? ActionDispatch::ExceptionWrapper
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_controller"
|
4
|
+
require "i18n"
|
5
|
+
require "spec_helper"
|
6
|
+
require "restful_error/railtie" # require again for run after restful_error_spec
|
7
|
+
|
8
|
+
RSpec.describe RestfulError::ExceptionsController do
|
9
|
+
include Rack::Test::Methods
|
10
|
+
def app = RestfulError.exceptions_app
|
11
|
+
|
12
|
+
shared_context "json" do
|
13
|
+
let(:request) { get "/#{status_code}", {}, 'HTTP_ACCEPT' => 'application/json' }
|
14
|
+
let(:json) { request; JSON.parse(last_response.body) }
|
15
|
+
end
|
16
|
+
|
17
|
+
before do
|
18
|
+
env "action_dispatch.exception", exception
|
19
|
+
end
|
20
|
+
describe RestfulError[404] do
|
21
|
+
let(:status_code) { 404 }
|
22
|
+
include_context "json" do
|
23
|
+
context 'default message' do
|
24
|
+
let(:exception) { described_class.new }
|
25
|
+
it do
|
26
|
+
expect(json).to eq({status_code: 404, reason_phrase: "Not Found", response_message: 'Page not found'}.stringify_keys)
|
27
|
+
expect(last_response.status).to eq status_code
|
28
|
+
end
|
29
|
+
end
|
30
|
+
context 'custom message' do
|
31
|
+
let(:exception) { described_class.new("custom message") }
|
32
|
+
it do
|
33
|
+
expect(json).to eq({status_code:, reason_phrase: "Not Found", response_message: "custom message"}.stringify_keys)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
context ActionController::RoutingError do
|
39
|
+
let(:exception) { described_class.new("no route") }
|
40
|
+
let(:status_code) { 404 }
|
41
|
+
include_context "json" do
|
42
|
+
it do
|
43
|
+
expect(json).to eq({status_code:, reason_phrase: "Not Found", response_message: 'Requested resource is not found'}.stringify_keys)
|
44
|
+
expect(last_response.status).to eq status_code
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restful_error
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kuboon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-01-
|
11
|
+
date: 2025-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -39,15 +39,13 @@ extensions: []
|
|
39
39
|
extra_rdoc_files: []
|
40
40
|
files:
|
41
41
|
- lib/restful_error.rb
|
42
|
-
- lib/restful_error/engine.rb
|
43
42
|
- lib/restful_error/inflector.rb
|
44
43
|
- lib/restful_error/railtie.rb
|
45
44
|
- lib/restful_error/status.rb
|
46
45
|
- lib/restful_error/version.rb
|
47
|
-
- spec/rack_spec.rb
|
48
|
-
- spec/railtie_spec.rb
|
49
46
|
- spec/restful_error_spec.rb
|
50
47
|
- spec/spec_helper.rb
|
48
|
+
- spec/with_rails/exceptions_app_spec.rb
|
51
49
|
homepage: https://github.com/kuboon/restful_error
|
52
50
|
licenses:
|
53
51
|
- MIT
|
data/lib/restful_error/engine.rb
DELETED
data/spec/rack_spec.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'action_controller'
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe 'RestfulError' do
|
5
|
-
describe RestfulError::ExceptionsController do
|
6
|
-
include Rack::Test::Methods
|
7
|
-
def app
|
8
|
-
RestfulError::ExceptionsController.action(:show)
|
9
|
-
end
|
10
|
-
describe '404' do
|
11
|
-
before do
|
12
|
-
env "action_dispatch.exception", RestfulError[404].new
|
13
|
-
end
|
14
|
-
it do
|
15
|
-
get '/404'
|
16
|
-
expect(last_response.status).to eq 404
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/spec/railtie_spec.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "action_controller"
|
4
|
-
require "spec_helper"
|
5
|
-
|
6
|
-
RSpec.describe "RestfulError.exceptions_app" do
|
7
|
-
let(:app) { RestfulError.exceptions_app }
|
8
|
-
let(:env) { {} }
|
9
|
-
let(:request) { Rack::MockRequest.new(app) }
|
10
|
-
|
11
|
-
it "renders 404" do
|
12
|
-
env["action_dispatch.exception"] = ActionController::RoutingError.new("Not Found")
|
13
|
-
env["PATH_INFO"] = "/404"
|
14
|
-
response = request.get("/404", env)
|
15
|
-
expect(response.status).to eq 404
|
16
|
-
expect(response.body).to include "Not Found"
|
17
|
-
end
|
18
|
-
end
|