coaster 1.0.4 → 1.1.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 +4 -4
- data/lib/coaster.rb +11 -1
- data/lib/coaster/core_ext/object_translation.rb +7 -12
- data/lib/coaster/core_ext/standard_error.rb +67 -61
- data/lib/coaster/version.rb +1 -1
- data/test/locales/en.yml +3 -0
- data/test/test_helper.rb +9 -0
- data/test/test_object_translation.rb +2 -0
- data/test/test_standard_error.rb +98 -24
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c38985e1f47460405cf2cf2e4f9507d78dd0db1f45d939ad5768269f1e2a6e7a
|
4
|
+
data.tar.gz: 5fcefde9af96868f10520648de4d775f58282d42d33e07e8abbbd76806328a93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d682e58f09d22aff8992360821e7dffc4a02c057882fb9ba9b9603631d76600c591016c1543b2e561190b9c91354049bfeb907c663abe3523b22d1cfc53b0579
|
7
|
+
data.tar.gz: f5e73571a6ede546e38c34c2145c96b3832888cc642bdc60c15e61ac5f91241359e66a5387b501c2f60b0c6153fdc1fb9facff4caf1ff98dfde35e4b2c1ea769
|
data/lib/coaster.rb
CHANGED
@@ -5,7 +5,7 @@ require 'active_support/core_ext/string'
|
|
5
5
|
require 'active_support/core_ext/hash/slice'
|
6
6
|
|
7
7
|
module Coaster
|
8
|
-
|
8
|
+
mattr_writer :logger
|
9
9
|
mattr_writer :default_fingerprint
|
10
10
|
|
11
11
|
DEFAULT_FINGERPRINT = [:default, :class].freeze
|
@@ -18,6 +18,16 @@ module Coaster
|
|
18
18
|
def default_fingerprint
|
19
19
|
@@default_fingerprint ||= DEFAULT_FINGERPRINT
|
20
20
|
end
|
21
|
+
|
22
|
+
def logger
|
23
|
+
return @@logger if defined?(@@logger)
|
24
|
+
return Rails.logger if defined?(Rails)
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger
|
30
|
+
self.class.logger
|
21
31
|
end
|
22
32
|
end
|
23
33
|
|
@@ -4,7 +4,7 @@ class Object
|
|
4
4
|
class << self
|
5
5
|
def _translate(*args)
|
6
6
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
7
|
-
options.merge
|
7
|
+
options = _translate_params.merge(options)
|
8
8
|
options = options.to_hash.symbolize_keys!
|
9
9
|
|
10
10
|
key = args.shift
|
@@ -45,7 +45,10 @@ class Object
|
|
45
45
|
|
46
46
|
if key_class.superclass == Object || key_class == Object
|
47
47
|
return options[:description] if options[:description].present?
|
48
|
-
Coaster.logger
|
48
|
+
if Coaster.logger
|
49
|
+
Coaster.logger.info(options[:original_missing])
|
50
|
+
Coaster.logger.debug(caller.join("\n"))
|
51
|
+
end
|
49
52
|
throw :exception, result if options[:original_throw]
|
50
53
|
missing = options[:original_missing] || result
|
51
54
|
msg = missing.message
|
@@ -61,6 +64,7 @@ class Object
|
|
61
64
|
result = result.dup if result.frozen?
|
62
65
|
result.instance_variable_set(:@translated, true)
|
63
66
|
result.instance_variable_set(:@tkey, options[:tkey])
|
67
|
+
result.instance_variable_set(:@missing, options[:original_missing])
|
64
68
|
result
|
65
69
|
end
|
66
70
|
end
|
@@ -78,16 +82,7 @@ class Object
|
|
78
82
|
def _translate(*args)
|
79
83
|
options = (args.last.is_a?(Hash) ? args.pop : {}).with_indifferent_access
|
80
84
|
key = args.shift || (respond_to?(:tkey) ? tkey : nil)
|
81
|
-
|
82
|
-
if respond_to?(:description) && description.present? && description != 'false' && description != self.class.name
|
83
|
-
if !key.is_a?(String) && key != :force
|
84
|
-
desc = description
|
85
|
-
return desc unless desc.instance_variable_get(:@raw)
|
86
|
-
end
|
87
|
-
options.merge!(description: description)
|
88
|
-
end
|
89
|
-
|
90
|
-
options.merge!(_translate_params)
|
85
|
+
options = _translate_params.merge(options)
|
91
86
|
self.class._translate(key, *args, options)
|
92
87
|
end
|
93
88
|
|
@@ -4,18 +4,29 @@ class StandardError
|
|
4
4
|
cattr_accessor :cleaner, :cause_cleaner
|
5
5
|
|
6
6
|
class << self
|
7
|
-
def status
|
8
|
-
999999 # Unknown
|
9
|
-
end
|
7
|
+
def status; 999999 end # Unknown
|
10
8
|
alias_method :code, :status
|
11
|
-
|
12
|
-
def
|
13
|
-
|
9
|
+
def http_status; 500 end
|
10
|
+
def report?; true end
|
11
|
+
def intentional?; false end
|
12
|
+
def title; _translate('.title') end
|
13
|
+
|
14
|
+
def before_logging(name, &block)
|
15
|
+
@before_logging_blocks ||= {}
|
16
|
+
@before_logging_blocks[name] = block
|
17
|
+
end
|
18
|
+
def before_logging_blocks
|
19
|
+
@before_logging_blocks ||= {}
|
20
|
+
superclass <= StandardError ? superclass.before_logging_blocks.merge(@before_logging_blocks) : @before_logging_blocks
|
14
21
|
end
|
15
22
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
23
|
+
def after_logging(name, &block)
|
24
|
+
@after_logging_blocks ||= {}
|
25
|
+
@after_logging_blocks[name] = block
|
26
|
+
end
|
27
|
+
def after_logging_blocks
|
28
|
+
@after_logging_blocks ||= {}
|
29
|
+
superclass <= StandardError ? superclass.after_logging_blocks.merge(@after_logging_blocks) : @after_logging_blocks
|
19
30
|
end
|
20
31
|
end
|
21
32
|
|
@@ -66,17 +77,11 @@ class StandardError
|
|
66
77
|
super(msg)
|
67
78
|
end
|
68
79
|
|
69
|
-
def safe_message
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
def
|
74
|
-
self.class.status
|
75
|
-
end
|
76
|
-
|
77
|
-
def title
|
78
|
-
attributes[:title] || self.class.title
|
79
|
-
end
|
80
|
+
def safe_message; message || '' end
|
81
|
+
def status; self.class.status end
|
82
|
+
def before_logging_blocks; self.class.before_logging_blocks end
|
83
|
+
def after_logging_blocks; self.class.after_logging_blocks end
|
84
|
+
def root_cause; cause.respond_to?(:root_cause) ? cause.root_cause : self end
|
80
85
|
|
81
86
|
def attributes
|
82
87
|
return @attributes if defined?(@attributes)
|
@@ -88,57 +93,51 @@ class StandardError
|
|
88
93
|
end
|
89
94
|
alias_method :attr, :attributes
|
90
95
|
|
91
|
-
def http_status
|
92
|
-
|
93
|
-
end
|
94
|
-
|
95
|
-
def
|
96
|
-
|
97
|
-
end
|
98
|
-
|
96
|
+
def http_status; attributes[:http_status] || self.class.http_status end
|
97
|
+
def http_status=(value); attributes[:http_status] = value end
|
98
|
+
def code; attributes[:code] || status end
|
99
|
+
def code=(value); attributes[:code] = value end
|
100
|
+
def title; attributes[:title] || self.class.title end
|
101
|
+
def it_might_happen?; attributes[:it] == :might_happen end
|
102
|
+
def it_should_not_happen?; attributes[:it] == :should_not_happen end
|
99
103
|
def report?
|
100
|
-
attributes.key?(:report)
|
104
|
+
return attributes[:report] if attributes.key?(:report)
|
105
|
+
return false if it_might_happen?
|
106
|
+
self.class.report?
|
101
107
|
end
|
102
|
-
|
103
|
-
|
104
|
-
|
108
|
+
def intentional? # not logging in test
|
109
|
+
return attributes[:intentional] if attributes.key?(:intentional)
|
110
|
+
return true if it_should_not_happen?
|
111
|
+
self.class.intentional?
|
105
112
|
end
|
113
|
+
def object; attributes[:object] || attributes[:obj] end
|
114
|
+
alias_method :obj, :object
|
106
115
|
|
107
|
-
|
108
|
-
|
116
|
+
# description is user friendly message as a attribute, do not use error's message
|
117
|
+
# error message is not user friendly in many cases.
|
118
|
+
def description
|
119
|
+
attributes[:description] || attributes[:desc]
|
109
120
|
end
|
121
|
+
alias_method :desc, :description
|
110
122
|
|
111
|
-
def
|
112
|
-
|
123
|
+
def _translate(*args)
|
124
|
+
return description if description.present?
|
125
|
+
super
|
113
126
|
end
|
114
127
|
|
115
|
-
#
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
return dsc if dsc
|
120
|
-
msg = safe_message.dup
|
121
|
-
msg.instance_variable_set(:@raw, true)
|
122
|
-
msg
|
128
|
+
# user friendly message, for overid
|
129
|
+
def user_message
|
130
|
+
return description if description.present?
|
131
|
+
_translate
|
123
132
|
end
|
124
|
-
alias_method :desc, :description
|
125
133
|
|
126
|
-
#
|
134
|
+
# another user friendly messages
|
127
135
|
def descriptions
|
128
136
|
return attributes[:descriptions] if attributes[:descriptions]
|
129
137
|
attributes[:descriptions] = {}
|
130
138
|
attributes[:descriptions]
|
131
139
|
end
|
132
140
|
|
133
|
-
def object
|
134
|
-
attributes[:object] || attributes[:obj]
|
135
|
-
end
|
136
|
-
alias_method :obj, :object
|
137
|
-
|
138
|
-
def root_cause
|
139
|
-
cause.respond_to?(:root_cause) ? cause.root_cause : self
|
140
|
-
end
|
141
|
-
|
142
141
|
def to_hash
|
143
142
|
hash = attributes.merge(
|
144
143
|
type: self.class.name, status: status,
|
@@ -206,13 +205,17 @@ class StandardError
|
|
206
205
|
end
|
207
206
|
|
208
207
|
def logging(options = {})
|
209
|
-
|
210
|
-
|
211
|
-
if
|
212
|
-
|
213
|
-
|
208
|
+
before_logging_blocks.values.each { |blk| instance_exec &blk }
|
209
|
+
|
210
|
+
if !report? || intentional?
|
211
|
+
if defined?(Rails)
|
212
|
+
return if Rails.env.test?
|
213
|
+
else
|
214
|
+
return
|
215
|
+
end
|
214
216
|
end
|
215
|
-
|
217
|
+
|
218
|
+
logger = options[:logger] || Coaster.logger
|
216
219
|
return unless logger
|
217
220
|
|
218
221
|
cl = options[:cleaner] || cleaner
|
@@ -230,5 +233,8 @@ class StandardError
|
|
230
233
|
else
|
231
234
|
logger.error(msg)
|
232
235
|
end
|
236
|
+
msg
|
237
|
+
ensure
|
238
|
+
after_logging_blocks.values.each { |blk| instance_exec &blk }
|
233
239
|
end
|
234
240
|
end
|
data/lib/coaster/version.rb
CHANGED
data/test/locales/en.yml
CHANGED
data/test/test_helper.rb
CHANGED
@@ -37,6 +37,7 @@ module Coaster
|
|
37
37
|
def test_translation_sub
|
38
38
|
assert_equal 'Coaster SampleObject Title (class.Coaster.SampleObject.title)', SampleObject._translate('.title')
|
39
39
|
assert_equal 'Coaster SampleObject Title (class.Coaster.SampleObject.title)', SampleObject._translate(:title)
|
40
|
+
assert_nil SampleObject._translate(:title).instance_variable_get(:@missing)
|
40
41
|
end
|
41
42
|
|
42
43
|
def test_translation_with_key
|
@@ -46,6 +47,7 @@ module Coaster
|
|
46
47
|
def test_translation_inheritance
|
47
48
|
assert_equal 'Coaster SampleObject Translated', Inherited._translate
|
48
49
|
assert_equal 'Coaster SampleObject Title (class.Coaster.Inherited.title)', Inherited._translate(:title)
|
50
|
+
assert Inherited._translate.instance_variable_get(:@missing)
|
49
51
|
end
|
50
52
|
|
51
53
|
def test_interpolation
|
data/test/test_standard_error.rb
CHANGED
@@ -20,6 +20,57 @@ module Coaster
|
|
20
20
|
I18n.enforce_available_locales = false
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_standard_messages
|
24
|
+
e = StandardError.new('asdf')
|
25
|
+
assert_equal 'asdf', e.message
|
26
|
+
assert_nil e.description
|
27
|
+
assert_nil e.desc
|
28
|
+
assert_equal 'standard error translation', e._translate
|
29
|
+
assert_equal 'standard error translation', e.user_message
|
30
|
+
assert_equal 'standard error title', e.title
|
31
|
+
e = StandardError.new(m: 'foo', desc: 'bar')
|
32
|
+
assert_equal 'foo', e.message
|
33
|
+
assert_equal 'bar', e.description
|
34
|
+
assert_equal 'bar', e.desc
|
35
|
+
assert_equal 'bar', e._translate
|
36
|
+
assert_equal 'bar', e.user_message
|
37
|
+
assert_equal 'standard error title', e.title
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_no_translation_class
|
41
|
+
e = UntitledError.new('asdf')
|
42
|
+
assert_equal 'asdf', e.message
|
43
|
+
assert_nil e.description
|
44
|
+
assert_nil e.desc
|
45
|
+
assert_equal 'standard error translation', e._translate
|
46
|
+
assert_equal 'standard error translation', e.user_message
|
47
|
+
assert_equal 'standard error title', e.title
|
48
|
+
e = UntitledError.new(m: 'foo', desc: 'bar')
|
49
|
+
assert_equal 'foo', e.message
|
50
|
+
assert_equal 'bar', e.description
|
51
|
+
assert_equal 'bar', e.desc
|
52
|
+
assert_equal 'bar', e._translate
|
53
|
+
assert_equal 'bar', e.user_message
|
54
|
+
assert_equal 'standard error title', e.title
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_with_translation_class
|
58
|
+
e = SampleError.new('asdf')
|
59
|
+
assert_equal 'asdf', e.message
|
60
|
+
assert_nil e.description
|
61
|
+
assert_nil e.desc
|
62
|
+
assert_equal 'Test sample error', e._translate
|
63
|
+
assert_equal 'Test sample error', e.user_message
|
64
|
+
assert_equal 'Test this title', e.title
|
65
|
+
e = SampleError.new(m: 'foo', desc: 'bar')
|
66
|
+
assert_equal 'foo', e.message
|
67
|
+
assert_equal 'bar', e.description
|
68
|
+
assert_equal 'bar', e.desc
|
69
|
+
assert_equal 'bar', e._translate
|
70
|
+
assert_equal 'bar', e.user_message
|
71
|
+
assert_equal 'Test this title', e.title
|
72
|
+
end
|
73
|
+
|
23
74
|
def test_message
|
24
75
|
raise SampleError, {m: 'beer is proof'}
|
25
76
|
rescue => e
|
@@ -39,16 +90,16 @@ module Coaster
|
|
39
90
|
raise ExampleError, {wat: 'cha'}
|
40
91
|
end
|
41
92
|
rescue => e
|
42
|
-
assert_equal e.to_hash['wat']
|
43
|
-
assert_equal e.to_hash['type']
|
44
|
-
assert_equal e.to_hash['status']
|
45
|
-
assert_equal e.to_hash['http_status']
|
46
|
-
assert_equal e.to_hash['message']
|
47
|
-
assert_equal e.to_hash['cause']['frog']
|
48
|
-
assert_equal e.to_hash['cause']['type']
|
49
|
-
assert_equal e.to_hash['cause']['status']
|
50
|
-
assert_equal e.to_hash['cause']['http_status']
|
51
|
-
assert_equal e.to_hash['cause']['message']
|
93
|
+
assert_equal 'cha', e.to_hash['wat']
|
94
|
+
assert_equal 'Coaster::TestStandardError::ExampleError', e.to_hash['type']
|
95
|
+
assert_equal 20, e.to_hash['status']
|
96
|
+
assert_equal 500, e.to_hash['http_status']
|
97
|
+
assert_equal 'Test sample error', e.to_hash['message']
|
98
|
+
assert_equal 'rams', e.to_hash['cause']['frog']
|
99
|
+
assert_equal 'Coaster::TestStandardError::SampleError', e.to_hash['cause']['type']
|
100
|
+
assert_equal 10, e.to_hash['cause']['status']
|
101
|
+
assert_equal 500, e.to_hash['cause']['http_status']
|
102
|
+
assert_equal 'Test sample error', e.to_hash['cause']['message']
|
52
103
|
end
|
53
104
|
|
54
105
|
def test_cause_attributes
|
@@ -58,9 +109,9 @@ module Coaster
|
|
58
109
|
raise ExampleError, {wat: 'cha'}
|
59
110
|
end
|
60
111
|
rescue => e
|
61
|
-
assert_equal e.cause.attr['frog']
|
62
|
-
assert_equal e.attr['frog']
|
63
|
-
assert_equal e.attr['wat']
|
112
|
+
assert_equal 'rams', e.cause.attr['frog']
|
113
|
+
assert_equal 'rams', e.attr['frog']
|
114
|
+
assert_equal 'cha', e.attr['wat']
|
64
115
|
end
|
65
116
|
|
66
117
|
def test_to_detail
|
@@ -94,19 +145,19 @@ LOG
|
|
94
145
|
def test_translation
|
95
146
|
raise SampleError, {tkey: '.test'}
|
96
147
|
rescue => e
|
97
|
-
assert_equal
|
148
|
+
assert_equal 'Test this translation', e._translate
|
98
149
|
end
|
99
150
|
|
100
151
|
def test_title
|
101
152
|
raise SampleError, 'foobar'
|
102
153
|
rescue => e
|
103
|
-
assert_equal
|
154
|
+
assert_equal 'Test this title', e.title
|
104
155
|
end
|
105
156
|
|
106
157
|
def test_title_missing
|
107
158
|
raise UntitledError, 'untitled'
|
108
159
|
rescue => e
|
109
|
-
|
160
|
+
assert_equal 'standard error title', e.title
|
110
161
|
end
|
111
162
|
|
112
163
|
def root_cause_sample1
|
@@ -129,31 +180,54 @@ LOG
|
|
129
180
|
begin
|
130
181
|
root_cause_sample3
|
131
182
|
rescue => e
|
132
|
-
assert_equal e.root_cause.message
|
183
|
+
assert_equal 'a', e.root_cause.message
|
133
184
|
end
|
134
185
|
end
|
135
186
|
|
136
187
|
def test_raven_notes
|
137
188
|
raise SampleError, m: 'foofoo', something: 'other'
|
138
189
|
rescue => e
|
139
|
-
assert_equal e.notes(the_other: 'something')[:extra][:something]
|
140
|
-
assert_equal e.notes(the_other: 'something')[:extra][:the_other]
|
190
|
+
assert_equal 'other', e.notes(the_other: 'something')[:extra][:something]
|
191
|
+
assert_equal 'something', e.notes(the_other: 'something')[:extra][:the_other]
|
141
192
|
end
|
142
193
|
|
143
194
|
def test_to_hash
|
144
195
|
aa # raise NameError
|
145
196
|
rescue => e
|
146
|
-
assert_equal e.to_hash['type']
|
147
|
-
assert_equal e.to_hash['status']
|
148
|
-
assert_equal e.to_hash['http_status']
|
149
|
-
|
197
|
+
assert_equal 'NameError', e.to_hash['type']
|
198
|
+
assert_equal 999999, e.to_hash['status']
|
199
|
+
assert_equal 500, e.to_hash['http_status']
|
200
|
+
assert_match /undefined local variable or method `aa'/, e.to_hash['message']
|
150
201
|
end
|
151
202
|
|
152
203
|
def test_descriptions
|
153
204
|
raise SampleError
|
154
205
|
rescue => e
|
155
206
|
e.descriptions.merge!(a: 1)
|
156
|
-
assert_equal e.descriptions['a']
|
207
|
+
assert_equal 1, e.descriptions['a']
|
208
|
+
end
|
209
|
+
|
210
|
+
class SampleErrorSub < SampleError; end
|
211
|
+
class SampleErrorSubSub < SampleErrorSub
|
212
|
+
def it_might_happen?; true end
|
213
|
+
end
|
214
|
+
SampleError.after_logging(:blah) do
|
215
|
+
self.attributes[:abc] = 100
|
216
|
+
@blah = 101
|
217
|
+
end
|
218
|
+
def test_before_logging
|
219
|
+
e = SampleErrorSubSub.new(m: 'foo')
|
220
|
+
assert !e.after_logging_blocks[:blah].nil?
|
221
|
+
e.logging
|
222
|
+
assert_equal 100, e.attributes[:abc]
|
223
|
+
assert_equal 101, e.instance_variable_get(:@blah)
|
224
|
+
end
|
225
|
+
class SampleErrorMightHappen < SampleErrorSub
|
226
|
+
def it_might_happen?; true end
|
227
|
+
end
|
228
|
+
def test_might_happen
|
229
|
+
e = SampleErrorMightHappen.new('fbar')
|
230
|
+
assert !e.report?
|
157
231
|
end
|
158
232
|
end
|
159
233
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coaster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- buzz jung
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -226,7 +226,7 @@ signing_key:
|
|
226
226
|
specification_version: 4
|
227
227
|
summary: A little convenient feature for standard library
|
228
228
|
test_files:
|
229
|
-
- test/test_helper.rb
|
230
|
-
- test/test_standard_error.rb
|
231
|
-
- test/locales/en.yml
|
232
229
|
- test/test_object_translation.rb
|
230
|
+
- test/locales/en.yml
|
231
|
+
- test/test_standard_error.rb
|
232
|
+
- test/test_helper.rb
|