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 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