angus 0.0.1 → 0.0.2
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.
- data/bin/angus +13 -0
- data/lib/angus.rb +6 -4
- data/lib/angus/base.rb +119 -0
- data/lib/angus/base_actions.rb +38 -0
- data/lib/angus/base_resource.rb +14 -0
- data/lib/angus/command.rb +27 -0
- data/lib/angus/generator.rb +141 -0
- data/lib/angus/generator/templates/Gemfile +5 -0
- data/lib/angus/generator/templates/README.md +0 -0
- data/lib/angus/generator/templates/config.ru.erb +10 -0
- data/lib/angus/generator/templates/definitions/messages.yml +0 -0
- data/lib/angus/generator/templates/definitions/operations.yml.erb +21 -0
- data/lib/angus/generator/templates/definitions/representations.yml +0 -0
- data/lib/angus/generator/templates/definitions/service.yml.erb +3 -0
- data/lib/angus/generator/templates/resources/resource.rb.erb +6 -0
- data/lib/angus/generator/templates/services/service.rb.erb +4 -0
- data/lib/angus/marshallings/base.rb +2 -0
- data/lib/angus/marshallings/marshalling.rb +136 -0
- data/lib/angus/marshallings/unmarshalling.rb +29 -0
- data/lib/angus/renders/base.rb +2 -0
- data/lib/angus/renders/html_render.rb +9 -0
- data/lib/angus/renders/json_render.rb +15 -0
- data/lib/angus/request_handler.rb +62 -0
- data/lib/angus/resource_definition.rb +78 -0
- data/lib/angus/response.rb +53 -0
- data/lib/angus/responses.rb +232 -0
- data/lib/angus/rspec/spec_helper.rb +3 -0
- data/lib/angus/rspec/support/examples.rb +64 -0
- data/lib/angus/rspec/support/examples/describe_errors.rb +36 -0
- data/lib/angus/rspec/support/matchers/operation_response_matchers.rb +117 -0
- data/lib/angus/rspec/support/operation_response.rb +57 -0
- data/lib/angus/utils.rb +2 -0
- data/lib/angus/utils/params.rb +24 -0
- data/lib/angus/utils/string.rb +27 -0
- data/lib/angus/version.rb +2 -2
- data/spec/angus/rspec/examples/describe_errors_spec.rb +64 -0
- data/spec/spec_helper.rb +27 -0
- metadata +181 -19
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -22
- data/README.md +0 -29
- data/Rakefile +0 -1
- data/angus.gemspec +0 -23
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Angus
|
5
|
+
module Marshalling
|
6
|
+
|
7
|
+
# Marshal an object
|
8
|
+
#
|
9
|
+
# This method is intended for scalar objects and arrays of scalar objects.
|
10
|
+
#
|
11
|
+
# For more complex objects:
|
12
|
+
# @see Angus::Marshalling.marshal_object
|
13
|
+
#
|
14
|
+
# @param object The object to be marshalled
|
15
|
+
# @return [Array] An object suitable for be converted easily to JSON notation
|
16
|
+
#
|
17
|
+
# If {object} is an array, this method returns an array with all the elements marshalled
|
18
|
+
# Else returns a marshalled representation of the object.
|
19
|
+
def self.marshal(object)
|
20
|
+
if object.is_a?(Array)
|
21
|
+
object.map { |element| marshal(element) }
|
22
|
+
else
|
23
|
+
marshal_scalar(object)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Marshal a complex object.
|
28
|
+
#
|
29
|
+
# @param object The object to be marshalled
|
30
|
+
# @param getters An array of getters / hashes that will be used to obtain the information
|
31
|
+
# from the object.
|
32
|
+
def self.marshal_object(object, getters)
|
33
|
+
result = {}
|
34
|
+
getters.each do |getter|
|
35
|
+
if getter.is_a?(Hash)
|
36
|
+
key = getter.keys[0]
|
37
|
+
value = get_value(object, key)
|
38
|
+
|
39
|
+
#TODO Consider adding ActiveRecord::Relation support
|
40
|
+
#ex: "if value.is_a?(Array) || value.is_a?(ActiveRecord::Relation)"
|
41
|
+
if value.is_a?(Array)
|
42
|
+
result[key] = value.map { |object| marshal_object(object, getter.values[0]) }
|
43
|
+
else
|
44
|
+
result[key] = value.nil? ? nil : marshal_object(value, getter.values[0])
|
45
|
+
end
|
46
|
+
else
|
47
|
+
value = get_value(object, getter)
|
48
|
+
result[getter] = marshal_scalar(value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
return result
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Gets a value from a object for a given getter.
|
57
|
+
#
|
58
|
+
# @param [Object] object The object to get the value from
|
59
|
+
# @param [Symbol, String] getter to request from the object
|
60
|
+
# @raise [InvalidGetterError] when getter is not present
|
61
|
+
# in the object
|
62
|
+
# @return [Object] the requested value
|
63
|
+
def self.get_value(object, getter)
|
64
|
+
if object.is_a?(Hash)
|
65
|
+
get_value_from_hash(object, getter)
|
66
|
+
else
|
67
|
+
get_value_from_object(object, getter)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Gets a value from a object by invoking method.
|
72
|
+
#
|
73
|
+
# @param [Object] object The object to get the value from
|
74
|
+
# @param [Symbol, String] method the method to invoke in the object
|
75
|
+
# @raise [InvalidGetterError] when the object does not responds
|
76
|
+
# to method as public.
|
77
|
+
# @return [Object] the requested value
|
78
|
+
def self.get_value_from_object(object, method)
|
79
|
+
value = object.public_send method.to_sym
|
80
|
+
|
81
|
+
# HACK in order to fix the error:
|
82
|
+
# NoMethodError: undefined method `merge' for #<JSON::Ext::Generator::State:0x257fd086>
|
83
|
+
if value.is_a?(Array)
|
84
|
+
value.to_a
|
85
|
+
else
|
86
|
+
value
|
87
|
+
end
|
88
|
+
# TODO ver si tirar una exception especifica o que hacer?
|
89
|
+
#rescue NoMethodError => error
|
90
|
+
# raise InvalidGetterError.new(method, error.backtrace.first)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Gets a value from a hash for a given key.
|
94
|
+
#
|
95
|
+
# It accepts the key as a symbol or a string,
|
96
|
+
# it looks for the symbol key first.
|
97
|
+
#
|
98
|
+
# @param [Hash] hash The hash to get the value from
|
99
|
+
# @param [Symbol, String] key to get from the hash
|
100
|
+
# @raise [InvalidGetterError] when the key does not
|
101
|
+
# exists in the hash
|
102
|
+
# @return [Object] the requested value
|
103
|
+
def self.get_value_from_hash(hash, key)
|
104
|
+
if hash.has_key?(key.to_sym)
|
105
|
+
hash[key.to_sym]
|
106
|
+
elsif hash.has_key?(key.to_s)
|
107
|
+
hash[key.to_s]
|
108
|
+
else
|
109
|
+
#raise InvalidGetterError.new(key)
|
110
|
+
raise NoMethodError.new(key.to_s)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Marshal a scalar value
|
115
|
+
# @param scalar the scalar value to be marshalled
|
116
|
+
#
|
117
|
+
# If scalar is a Date or DateTime it return a iso8601 string
|
118
|
+
# If scalar is a Symbol it returns the symbol as string
|
119
|
+
# Everything else (string, integer, ...) returns the same object.
|
120
|
+
def self.marshal_scalar(scalar)
|
121
|
+
case scalar
|
122
|
+
when Time
|
123
|
+
scalar.iso8601
|
124
|
+
when DateTime
|
125
|
+
scalar.iso8601
|
126
|
+
when Date
|
127
|
+
scalar.iso8601
|
128
|
+
when Symbol
|
129
|
+
scalar.to_s
|
130
|
+
else
|
131
|
+
scalar
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Angus
|
5
|
+
module Unmarshalling
|
6
|
+
|
7
|
+
def self.unmarshal_scalar(scalar, type)
|
8
|
+
return nil if scalar.nil?
|
9
|
+
|
10
|
+
case type
|
11
|
+
when :string
|
12
|
+
scalar
|
13
|
+
when :integer
|
14
|
+
scalar
|
15
|
+
when :boolean
|
16
|
+
scalar
|
17
|
+
when :date
|
18
|
+
Date.iso8601(scalar)
|
19
|
+
when :date_time
|
20
|
+
DateTime.iso8601(scalar)
|
21
|
+
when :decimal
|
22
|
+
BigDecimal.new(scalar.to_s)
|
23
|
+
else
|
24
|
+
raise ArgumentError, "Unknown type: #{type}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'angus-router'
|
2
|
+
|
3
|
+
require_relative 'response'
|
4
|
+
require_relative 'responses'
|
5
|
+
|
6
|
+
module Angus
|
7
|
+
class RequestHandler
|
8
|
+
|
9
|
+
include Responses
|
10
|
+
|
11
|
+
DEFAULT_RENDER = :json
|
12
|
+
|
13
|
+
attr_reader :env, :request, :response, :params
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@router = Angus::Router.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def router
|
20
|
+
@router
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(env)
|
24
|
+
begin
|
25
|
+
@env = env
|
26
|
+
@response = Response.new
|
27
|
+
|
28
|
+
router.route(env)
|
29
|
+
rescue Angus::Router::NotImplementedError
|
30
|
+
@response.status = HTTP_STATUS_CODE_NOT_FOUND
|
31
|
+
|
32
|
+
render({ 'status' => 'error',
|
33
|
+
'messages' => [{ 'level' => 'error', 'key' => 'RouteNotFound',
|
34
|
+
'dsc' => 'Invalid route' }]
|
35
|
+
}, {format: :json})
|
36
|
+
end
|
37
|
+
|
38
|
+
@response.finish
|
39
|
+
end
|
40
|
+
|
41
|
+
# TODO ver multiples formatos en el futuro
|
42
|
+
def render(content, options = {})
|
43
|
+
format = options[:format] || DEFAULT_RENDER
|
44
|
+
case(format)
|
45
|
+
when :html
|
46
|
+
HtmlRender.render(@response, content)
|
47
|
+
when :json
|
48
|
+
JsonRender.render(@response, content)
|
49
|
+
else
|
50
|
+
raise 'Unknown render format'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# TODO ver esto en el futuro
|
55
|
+
# Use the specified Rack middleware
|
56
|
+
def use(middleware, *args, &block)
|
57
|
+
@prototype = nil
|
58
|
+
@middleware << [middleware, args, block]
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Angus
|
4
|
+
class ResourceDefinition
|
5
|
+
|
6
|
+
def initialize(resource_name, representations)
|
7
|
+
@resource_name = resource_name
|
8
|
+
@resource_class_name = classify_resource(resource_name)
|
9
|
+
@representations = representations || {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def operations
|
13
|
+
@representations.operations[@resource_name.to_s]
|
14
|
+
end
|
15
|
+
|
16
|
+
def canonical_name
|
17
|
+
Angus::String.underscore(@resource_class_name.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def resource_class
|
21
|
+
return @resource_class if @resource_class
|
22
|
+
require resource_path
|
23
|
+
|
24
|
+
@resource_class = Object.const_get(@resource_class_name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def resource_path
|
28
|
+
File.join('resources', canonical_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_response_metadata(response_representation)
|
32
|
+
return {} unless response_representation
|
33
|
+
|
34
|
+
case response_representation
|
35
|
+
when Angus::SDoc::Definitions::Representation
|
36
|
+
result = []
|
37
|
+
|
38
|
+
response_representation.fields.each do |field|
|
39
|
+
result << build_response_metadata(field)
|
40
|
+
end
|
41
|
+
|
42
|
+
result
|
43
|
+
when Array
|
44
|
+
result = []
|
45
|
+
|
46
|
+
response_representation.each do |field|
|
47
|
+
result << build_response_metadata(field)
|
48
|
+
end
|
49
|
+
|
50
|
+
result
|
51
|
+
else
|
52
|
+
field_name = response_representation.name
|
53
|
+
field_type = response_representation.type || response_representation.elements_type
|
54
|
+
|
55
|
+
# TODO fix this
|
56
|
+
representation = representation_by_name(field_type)
|
57
|
+
|
58
|
+
if representation.nil?
|
59
|
+
field_name.to_sym
|
60
|
+
else
|
61
|
+
{field_name.to_sym => build_response_metadata(representation)}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# TODO improve this find
|
67
|
+
def representation_by_name(name)
|
68
|
+
@representations.representations.find { |representation| representation.name == name }
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def classify_resource(resource)
|
74
|
+
Angus::String.camelize(resource)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Angus
|
2
|
+
class Response < Rack::Response
|
3
|
+
def initialize(*)
|
4
|
+
super
|
5
|
+
headers['Content-Type'] ||= 'text/html'
|
6
|
+
end
|
7
|
+
|
8
|
+
def body=(value)
|
9
|
+
value = value.body while Rack::Response === value
|
10
|
+
@body = String === value ? [value.to_str] : value
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
block_given? ? super : enum_for(:each)
|
15
|
+
end
|
16
|
+
|
17
|
+
def finish
|
18
|
+
result = body
|
19
|
+
|
20
|
+
if drop_content_info?
|
21
|
+
headers.delete "Content-Length"
|
22
|
+
headers.delete "Content-Type"
|
23
|
+
end
|
24
|
+
|
25
|
+
if drop_body?
|
26
|
+
close
|
27
|
+
result = []
|
28
|
+
end
|
29
|
+
|
30
|
+
if calculate_content_length?
|
31
|
+
# if some other code has already set Content-Length, don't muck with it
|
32
|
+
# currently, this would be the static file-handler
|
33
|
+
headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
[status.to_i, headers, result]
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def calculate_content_length?
|
42
|
+
headers["Content-Type"] and not headers["Content-Length"] and Array === body
|
43
|
+
end
|
44
|
+
|
45
|
+
def drop_content_info?
|
46
|
+
status.to_i / 100 == 1 or drop_body?
|
47
|
+
end
|
48
|
+
|
49
|
+
def drop_body?
|
50
|
+
[204, 205, 304].include?(status.to_i)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'angus/sdoc'
|
2
|
+
|
3
|
+
module Angus
|
4
|
+
module Responses
|
5
|
+
|
6
|
+
HTTP_STATUS_CODE_OK = 200
|
7
|
+
|
8
|
+
HTTP_STATUS_CODE_FORBIDDEN = 403
|
9
|
+
HTTP_STATUS_CODE_NOT_FOUND = 404
|
10
|
+
HTTP_STATUS_CODE_CONFLICT = 409
|
11
|
+
HTTP_STATUS_CODE_UNPROCESSABLE_ENTITY = 422
|
12
|
+
|
13
|
+
HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR = 500
|
14
|
+
|
15
|
+
# Returns a suitable HTTP status code for the given error
|
16
|
+
#
|
17
|
+
# If error param responds to #errors, then #{HTTP_STATUS_CODE_CONFLICT} will be returned.
|
18
|
+
#
|
19
|
+
# If error param responds to #error_key, then the status_code associated
|
20
|
+
# with the message will be returned.
|
21
|
+
#
|
22
|
+
# @param [#errors, #error_key] error An error object
|
23
|
+
#
|
24
|
+
# @return [Integer] HTTP status code
|
25
|
+
def get_error_status_code(error)
|
26
|
+
if error.respond_to?(:errors)
|
27
|
+
return HTTP_STATUS_CODE_CONFLICT
|
28
|
+
end
|
29
|
+
|
30
|
+
message = get_error_definition(error)
|
31
|
+
|
32
|
+
if message
|
33
|
+
message.status_code
|
34
|
+
else
|
35
|
+
HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the error definition.
|
40
|
+
#
|
41
|
+
# If the error does not responds to error_key nil will be returned, see EvolutionError.
|
42
|
+
#
|
43
|
+
# @param [#error_key] error An error object
|
44
|
+
#
|
45
|
+
# @return [Hash]
|
46
|
+
def get_error_definition(error)
|
47
|
+
error_key = error.class.name
|
48
|
+
|
49
|
+
get_message_definition(error_key, Angus::SDoc::Definitions::Message::ERROR_LEVEL)
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_message_definition(key, level)
|
53
|
+
message = @definitions.messages.find { |name, definition|
|
54
|
+
name == key.to_s && definition.level.downcase == level.downcase
|
55
|
+
}
|
56
|
+
|
57
|
+
message.last if message
|
58
|
+
end
|
59
|
+
|
60
|
+
# Builds a service success response
|
61
|
+
#
|
62
|
+
# @param [Hash<Symbol, Object>] messages Elements to be sent in the response
|
63
|
+
# @param [Array<ResponseMessage] messages Messages to be sent in the response
|
64
|
+
#
|
65
|
+
# @return [String] JSON response
|
66
|
+
def build_success_response(elements = {}, messages = [])
|
67
|
+
elements = {
|
68
|
+
:status => :success,
|
69
|
+
}.merge(elements)
|
70
|
+
|
71
|
+
unless messages.empty?
|
72
|
+
elements[:messages] = messages
|
73
|
+
end
|
74
|
+
|
75
|
+
json(elements)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Builds a service error response
|
79
|
+
def build_error_response(error)
|
80
|
+
error_messages = messages_from_error(error)
|
81
|
+
build_response(:error, *error_messages)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Builds a ResponseMessage object
|
85
|
+
#
|
86
|
+
# @param [#to_s] key Message key
|
87
|
+
# @param [#to_s] level Message level
|
88
|
+
# @param [*Object] params Objects to be used when formatting the message description
|
89
|
+
#
|
90
|
+
# @raise [NameError] when there's no message for the given key and level
|
91
|
+
#
|
92
|
+
# @return [ResponseMessage]
|
93
|
+
def build_message(key, level, *params)
|
94
|
+
message_definition = get_message_definition(key, level)
|
95
|
+
|
96
|
+
unless message_definition
|
97
|
+
raise NameError.new("Could not found message with key: #{key}, level: #{level}")
|
98
|
+
end
|
99
|
+
|
100
|
+
description = if message_definition.text
|
101
|
+
message_definition.text % params
|
102
|
+
else
|
103
|
+
message_definition.description
|
104
|
+
end
|
105
|
+
|
106
|
+
Angus::SDoc::Definitions::Message
|
107
|
+
|
108
|
+
message = Angus::SDoc::Definitions::Message.new
|
109
|
+
message.key = key
|
110
|
+
message.level = level
|
111
|
+
message.description = description
|
112
|
+
|
113
|
+
message
|
114
|
+
end
|
115
|
+
|
116
|
+
# Builds a service success response
|
117
|
+
def build_warning_response(error)
|
118
|
+
error_messages = messages_from_error(error, :warning)
|
119
|
+
build_response(:success, *error_messages)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Builds a success response with the received data
|
123
|
+
#
|
124
|
+
# @param [Hash] data the hash to be returned in the response
|
125
|
+
# @param [Array] attributes the attributes that will be returned
|
126
|
+
# @param [Message, Symbol, String] messages A list of messages, or message keys
|
127
|
+
def build_data_response(data, attributes, messages = [])
|
128
|
+
marshalled_data = Angus::Marshalling.marshal_object(data, attributes)
|
129
|
+
|
130
|
+
messages = build_messages(Angus::SDoc::Definitions::Message::INFO_LEVEL, messages)
|
131
|
+
|
132
|
+
build_success_response(marshalled_data, messages)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Builds a success response with no elements
|
136
|
+
#
|
137
|
+
# The response would include the following:
|
138
|
+
# - status
|
139
|
+
# - messages
|
140
|
+
#
|
141
|
+
# @param [Array<ResponseMessage>, Array<Symbol>] messages Message to be included in the response
|
142
|
+
#
|
143
|
+
# @return [String] JSON response
|
144
|
+
def build_no_data_response(messages = [])
|
145
|
+
messages = build_messages(Angus::SDoc::Definitions::Message::INFO_LEVEL, messages)
|
146
|
+
|
147
|
+
build_success_response({}, messages)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Builds a list of messages with the following level
|
151
|
+
#
|
152
|
+
# ResponseMessage objects contained in messages param won't be modified, this method
|
153
|
+
# only creates ResponseMessage for each Symbol in messages array
|
154
|
+
#
|
155
|
+
# @param [#to_s] level Messages level
|
156
|
+
# @param [Array<ResponseMessage>, Array<Symbol>] messages
|
157
|
+
#
|
158
|
+
# @raise (see #build_message)
|
159
|
+
#
|
160
|
+
# @return [Array<ResponseMessage>]
|
161
|
+
def build_messages(level, messages)
|
162
|
+
(messages || []).map do |message|
|
163
|
+
if message.kind_of?(Angus::SDoc::Definitions::Message)
|
164
|
+
message
|
165
|
+
else
|
166
|
+
build_message(message, level)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Sets the content_type to json and serialize +element+ as json
|
172
|
+
def json(element)
|
173
|
+
#content_type :json
|
174
|
+
JSON(element, :ascii_only => true)
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
# Returns an array of messages errors to be sent in an operation response
|
179
|
+
#
|
180
|
+
# If {error} respond_to? :errors then the method returns one error message
|
181
|
+
# for each one.
|
182
|
+
#
|
183
|
+
# Each message returned is a hash with:
|
184
|
+
# - level
|
185
|
+
# - key
|
186
|
+
# - description
|
187
|
+
#
|
188
|
+
# @param [Exception] error The error to be returned
|
189
|
+
#
|
190
|
+
# @return [Array] an array of messages
|
191
|
+
def messages_from_error(error, level = :error)
|
192
|
+
messages = []
|
193
|
+
|
194
|
+
if error.respond_to?(:errors)
|
195
|
+
error.errors.each do |key, description|
|
196
|
+
messages << {:level => level, :key => key, :dsc => description}
|
197
|
+
end
|
198
|
+
elsif error.respond_to?(:error_key)
|
199
|
+
messages << {:level => level, :key => error.error_key,
|
200
|
+
:dsc => error_message(error)}
|
201
|
+
else
|
202
|
+
messages << {:level => level, :key => error.class.name, :dsc => error.message}
|
203
|
+
end
|
204
|
+
|
205
|
+
messages
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns the message for an error.
|
209
|
+
#
|
210
|
+
# It first tries to get the message from text attribute of the error definition
|
211
|
+
# if no definition is found or if the text attribute is blank it the returns the error
|
212
|
+
# message attribute.
|
213
|
+
#
|
214
|
+
# @param [Exception] error The error to get the message for.
|
215
|
+
#
|
216
|
+
# @return [String] the error message.
|
217
|
+
def error_message(error)
|
218
|
+
error_definition = get_error_definition(error)
|
219
|
+
|
220
|
+
if error_definition && !error_definition.text.blank?
|
221
|
+
error_definition.text
|
222
|
+
else
|
223
|
+
error.message
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def build_response(status, *messages)
|
228
|
+
json(:status => status, :messages => messages)
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
end
|