coaster 1.0.4 → 1.1.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
  SHA256:
3
- metadata.gz: 1efdff11e3158914f521590fb64642e9c1834987317b896db24896c31e772bcf
4
- data.tar.gz: 3fcdb6480424ddcc27cc50c0568e6b8d9967bf494f8118d174d82e9072c03974
3
+ metadata.gz: c38985e1f47460405cf2cf2e4f9507d78dd0db1f45d939ad5768269f1e2a6e7a
4
+ data.tar.gz: 5fcefde9af96868f10520648de4d775f58282d42d33e07e8abbbd76806328a93
5
5
  SHA512:
6
- metadata.gz: 270b1faeeae2fe9fcccd3e0f2c4d9d8234c7d0288ee949ea29b7faac70e711e5394b2cb06b14da11a6e71fe770c46416e9e8e10fadca2303470171986e6a3911
7
- data.tar.gz: c895e44a856beae32d2b46f09547d5c69aba008a46581ee096f9b069e6909251574f6dccf62f899fa3e51771e48acc1ad601f0a46e07a87cb5c8e59b706ea1f4
6
+ metadata.gz: d682e58f09d22aff8992360821e7dffc4a02c057882fb9ba9b9603631d76600c591016c1543b2e561190b9c91354049bfeb907c663abe3523b22d1cfc53b0579
7
+ data.tar.gz: f5e73571a6ede546e38c34c2145c96b3832888cc642bdc60c15e61ac5f91241359e66a5387b501c2f60b0c6153fdc1fb9facff4caf1ff98dfde35e4b2c1ea769
@@ -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
- mattr_accessor :logger
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!(_translate_params)
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 && Coaster.logger.warn(result)
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 http_status
13
- 500
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 title
17
- t = _translate('.title')
18
- t.instance_variable_defined?(:@missing) ? nil : t
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
- message || ''
71
- end
72
-
73
- def status
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
- attributes[:http_status] || self.class.http_status
93
- end
94
-
95
- def http_status=(value)
96
- attributes[:http_status] = value
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) ? attributes[:report] : true
104
+ return attributes[:report] if attributes.key?(:report)
105
+ return false if it_might_happen?
106
+ self.class.report?
101
107
  end
102
-
103
- def intentional?
104
- attributes[:intentional]
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
- def code
108
- attributes[:code] || status
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 code=(value)
112
- attributes[:code] = value
123
+ def _translate(*args)
124
+ return description if description.present?
125
+ super
113
126
  end
114
127
 
115
- # description is user friendly messages, do not use error's message
116
- # error message is not user friendly in many cases.
117
- def description
118
- dsc = attributes[:description] || attributes[:desc]
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
- # more user friendly messages
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
- return unless report?
210
- logger = nil
211
- if defined?(Rails)
212
- return if Rails.env.test? && intentional?
213
- logger = Rails.logger
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
- logger = options[:logger] || Coaster.logger || logger
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
@@ -1,3 +1,3 @@
1
1
  module Coaster
2
- VERSION = '1.0.4'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -1,5 +1,8 @@
1
1
  en:
2
2
  class:
3
+ StandardError:
4
+ self: 'standard error translation'
5
+ title: 'standard error title'
3
6
  Coaster:
4
7
  self: 'Coaster Translated'
5
8
  SampleObject:
@@ -6,3 +6,12 @@ require 'pry'
6
6
  require 'rubygems'
7
7
  require 'bundler/setup'
8
8
  require 'coaster'
9
+ require 'logger'
10
+
11
+ class Raven
12
+ def self.capture_exception(*args)
13
+ end
14
+ end
15
+
16
+ Coaster.logger = Logger.new(STDOUT)
17
+ Coaster.logger.level = Logger::WARN
@@ -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
@@ -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'], 'cha'
43
- assert_equal e.to_hash['type'], 'Coaster::TestStandardError::ExampleError'
44
- assert_equal e.to_hash['status'], 20
45
- assert_equal e.to_hash['http_status'], 500
46
- assert_equal e.to_hash['message'], 'Test sample error'
47
- assert_equal e.to_hash['cause']['frog'], 'rams'
48
- assert_equal e.to_hash['cause']['type'], 'Coaster::TestStandardError::SampleError'
49
- assert_equal e.to_hash['cause']['status'], 10
50
- assert_equal e.to_hash['cause']['http_status'], 500
51
- assert_equal e.to_hash['cause']['message'], 'Test sample error'
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'], 'rams'
62
- assert_equal e.attr['frog'], 'rams'
63
- assert_equal e.attr['wat'], 'cha'
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 e._translate, 'Test this translation'
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 e.title, 'Test this title'
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
- assert_nil e.title
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, 'a'
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], 'other'
140
- assert_equal e.notes(the_other: 'something')[:extra][:the_other], 'something'
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'], 'NameError'
147
- assert_equal e.to_hash['status'], 999999
148
- assert_equal e.to_hash['http_status'], 500
149
- assert e.to_hash['message'] =~ /undefined local variable or method `aa'/
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'], 1
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
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-07-08 00:00:00.000000000 Z
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