honeybadger 1.6.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/honeybadger.gemspec CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
4
4
  s.rubygems_version = '1.3.5'
5
5
 
6
6
  s.name = 'honeybadger'
7
- s.version = '1.6.2'
8
- s.date = '2013-04-10'
7
+ s.version = '1.7.0'
8
+ s.date = '2013-06-07'
9
9
 
10
10
  s.summary = 'Error reports you can be happy about.'
11
11
  s.description = 'Make managing application errors a more pleasant experience.'
data/lib/honeybadger.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'net/http'
2
2
  require 'net/https'
3
3
  require 'json'
4
+ require 'digest'
4
5
  require 'logger'
5
6
 
6
7
  require 'honeybadger/configuration'
@@ -12,7 +13,7 @@ require 'honeybadger/sender'
12
13
  require 'honeybadger/railtie' if defined?(Rails::Railtie)
13
14
 
14
15
  module Honeybadger
15
- VERSION = '1.6.2'
16
+ VERSION = '1.7.0'
16
17
  LOG_PREFIX = "** [Honeybadger] "
17
18
 
18
19
  HEADERS = {
@@ -138,6 +138,10 @@ module Honeybadger
138
138
  as_json.to_json(*a)
139
139
  end
140
140
 
141
+ def to_s
142
+ lines.map(&:to_s).join("\n")
143
+ end
144
+
141
145
  def inspect
142
146
  "<Backtrace: " + lines.collect { |line| line.inspect }.join(", ") + ">"
143
147
  end
@@ -19,16 +19,20 @@ module Honeybadger
19
19
  rake_task = fetch(:honeybadger_deploy_task, 'honeybadger:deploy')
20
20
  local_user = ENV['USER'] || ENV['USERNAME']
21
21
  executable = RUBY_PLATFORM.downcase.include?('mswin') ? fetch(:rake, 'rake.bat') : fetch(:rake, 'rake')
22
+ async_notify = fetch(:honeybadger_async_notify, false)
22
23
  directory = configuration.current_release
23
- notify_command = "cd #{directory}; #{executable} RAILS_ENV=#{rails_env} #{rake_task} TO=#{honeybadger_env} REVISION=#{current_revision} REPO=#{repository} USER=#{local_user}"
24
+ notify_command = "cd #{directory};"
25
+ notify_command << " nohup" if async_notify
26
+ notify_command << " #{executable} RAILS_ENV=#{rails_env} #{rake_task} TO=#{honeybadger_env} REVISION=#{current_revision} REPO=#{repository} USER=#{local_user}"
24
27
  notify_command << " DRY_RUN=true" if dry_run
25
28
  notify_command << " API_KEY=#{ENV['API_KEY']}" if ENV['API_KEY']
29
+ notify_command << " >> /dev/null 2>&1 &" if async_notify
26
30
  logger.info "Notifying Honeybadger of Deploy (#{notify_command})"
27
31
  if configuration.dry_run
28
32
  logger.info "DRY RUN: Notification not actually run."
29
33
  else
30
34
  result = ""
31
- run(notify_command, :once => true) { |ch, stream, data| result << data }
35
+ run(notify_command, :once => true, :pty => false) { |ch, stream, data| result << data }
32
36
  # TODO: Check if SSL is active on account via result content.
33
37
  end
34
38
  logger.info "Honeybadger Notification Complete."
@@ -6,7 +6,7 @@ module Honeybadger
6
6
  :params_filters, :project_root, :port, :protocol, :proxy_host, :proxy_pass,
7
7
  :proxy_port, :proxy_user, :secure, :use_system_ssl_cert_chain, :framework,
8
8
  :user_information, :rescue_rake_exceptions, :source_extract_radius,
9
- :send_request_session, :debug].freeze
9
+ :send_request_session, :debug, :fingerprint].freeze
10
10
 
11
11
  # The API key for your project, found on the project edit form.
12
12
  attr_accessor :api_key
@@ -101,6 +101,9 @@ module Honeybadger
101
101
  # A Proc object used to send notices asynchronously
102
102
  attr_writer :async
103
103
 
104
+ # A Proc object used to generate optional fingerprint
105
+ attr_writer :fingerprint
106
+
104
107
  DEFAULT_PARAMS_FILTERS = %w(password password_confirmation).freeze
105
108
 
106
109
  DEFAULT_BACKTRACE_FILTERS = [
@@ -262,6 +265,24 @@ module Honeybadger
262
265
  end
263
266
  alias :async? :async
264
267
 
268
+ # Public: Generate custom fingerprint (optional)
269
+ #
270
+ # block - An optional block returning object responding to #to_s
271
+ #
272
+ # Examples
273
+ #
274
+ # config.fingerprint = Proc.new { |notice| ... }
275
+ #
276
+ # config.fingerprint do |notice|
277
+ # [notice[:error_class], notice[:component], notice[:backtrace].to_s].join(':')
278
+ # end
279
+ #
280
+ # Returns configured fingerprint generator (should respond to #call(notice))
281
+ def fingerprint
282
+ @fingerprint = Proc.new if block_given?
283
+ @fingerprint
284
+ end
285
+
265
286
  def port
266
287
  @port || default_port
267
288
  end
@@ -8,6 +8,9 @@ module Honeybadger
8
8
  # The backtrace from the given exception or hash.
9
9
  attr_reader :backtrace
10
10
 
11
+ # Custom fingerprint for error, used to group similar errors together (optional)
12
+ attr_reader :fingerprint
13
+
11
14
  # The name of the class of error (such as RuntimeError)
12
15
  attr_reader :error_class
13
16
 
@@ -100,6 +103,7 @@ module Honeybadger
100
103
  self.environment_name = args[:environment_name]
101
104
  self.cgi_data = args[:cgi_data] || args[:rack_env]
102
105
  self.backtrace = Backtrace.parse(exception_attribute(:backtrace, caller), :filters => self.backtrace_filters)
106
+ self.fingerprint = hashed_fingerprint
103
107
  self.error_class = exception_attribute(:error_class) {|exception| exception.class.name }
104
108
  self.error_message = exception_attribute(:error_message, 'Notification') do |exception|
105
109
  "#{exception.class.name}: #{exception.message}"
@@ -121,8 +125,10 @@ module Honeybadger
121
125
 
122
126
  # Public: Send the notice to Honeybadger using the configured sender
123
127
  #
124
- # Returns a reference to the error in Honeybadger
128
+ # Returns a reference to the error in Honeybadger, false if sender isn't
129
+ # configured
125
130
  def deliver
131
+ return false unless Honeybadger.sender
126
132
  Honeybadger.sender.send_to_honeybadger(self)
127
133
  end
128
134
 
@@ -141,7 +147,8 @@ module Honeybadger
141
147
  :class => error_class,
142
148
  :message => error_message,
143
149
  :backtrace => backtrace,
144
- :source => source_extract
150
+ :source => source_extract,
151
+ :fingerprint => fingerprint
145
152
  },
146
153
  :request => {
147
154
  :url => url,
@@ -212,12 +219,12 @@ module Honeybadger
212
219
 
213
220
  private
214
221
 
215
- attr_writer :exception, :backtrace, :error_class, :error_message,
216
- :backtrace_filters, :parameters, :params_filters, :environment_filters,
217
- :session_data, :project_root, :url, :ignore, :ignore_by_filters,
218
- :notifier_name, :notifier_url, :notifier_version, :component, :action,
219
- :cgi_data, :environment_name, :hostname, :context, :source_extract,
220
- :source_extract_radius, :send_request_session
222
+ attr_writer :exception, :backtrace, :fingerprint, :error_class,
223
+ :error_message, :backtrace_filters, :parameters, :params_filters,
224
+ :environment_filters, :session_data, :project_root, :url, :ignore,
225
+ :ignore_by_filters, :notifier_name, :notifier_url, :notifier_version,
226
+ :component, :action, :cgi_data, :environment_name, :hostname, :context,
227
+ :source_extract, :source_extract_radius, :send_request_session
221
228
 
222
229
  # Private: Arguments given in the initializer
223
230
  attr_accessor :args
@@ -295,6 +302,21 @@ module Honeybadger
295
302
  end
296
303
  end
297
304
 
305
+ def fingerprint_from_args
306
+ if args[:fingerprint].respond_to?(:call)
307
+ args[:fingerprint].call(self)
308
+ else
309
+ args[:fingerprint]
310
+ end
311
+ end
312
+
313
+ def hashed_fingerprint
314
+ fingerprint = fingerprint_from_args
315
+ if fingerprint && fingerprint.respond_to?(:to_s)
316
+ Digest::SHA1.hexdigest(fingerprint.to_s)
317
+ end
318
+ end
319
+
298
320
  def extract_source_from_backtrace
299
321
  if backtrace.lines.empty?
300
322
  nil
@@ -34,12 +34,17 @@ module Honeybadger
34
34
  #
35
35
  # Returns error id from successful response
36
36
  def send_to_honeybadger(notice)
37
+ if api_key.nil?
38
+ log(:error, "API key not found.")
39
+ return nil
40
+ end
41
+
37
42
  data = notice.is_a?(String) ? notice : notice.to_json
38
43
 
39
44
  http = setup_http_connection
40
45
  headers = HEADERS
41
46
 
42
- headers.merge!({ 'X-API-Key' => api_key}) unless api_key.nil?
47
+ headers.merge!({ 'X-API-Key' => api_key})
43
48
 
44
49
  response = begin
45
50
  http.post(url.path, data, headers)
@@ -31,13 +31,14 @@ namespace :honeybadger do
31
31
  namespace :heroku do
32
32
  desc "Install Heroku deploy notifications addon"
33
33
  task :add_deploy_notification => [:environment] do
34
- def heroku_var(var, app_name = nil)
34
+ def heroku_var(var, app_name, default = nil)
35
35
  app = app_name ? "--app #{app_name}" : ''
36
- `heroku config:get #{var} #{app} 2> /dev/null`.strip
36
+ result = `heroku config:get #{var} #{app} 2> /dev/null`.strip
37
+ result.split.find(lambda { default }) {|x| x =~ /\S/ }
37
38
  end
38
39
 
39
- heroku_rails_env = heroku_var('RAILS_ENV', ENV['APP'])
40
- heroku_api_key = heroku_var('HONEYBADGER_API_KEY', ENV['APP']).split.find(Honeybadger.configuration.api_key) {|x| x =~ /\S/ }
40
+ heroku_rails_env = heroku_var('RAILS_ENV', ENV['APP'], Honeybadger.configuration.environment_name)
41
+ heroku_api_key = heroku_var('HONEYBADGER_API_KEY', ENV['APP'], Honeybadger.configuration.api_key)
41
42
 
42
43
  unless heroku_api_key =~ /\S/ && heroku_rails_env =~ /\S/
43
44
  puts "WARNING: We were unable to detect the configuration from your Heroku environment."
@@ -29,6 +29,7 @@ class ConfigurationTest < Test::Unit::TestCase
29
29
  assert_config_default :async, nil
30
30
  assert_config_default :send_request_session, true
31
31
  assert_config_default :debug, false
32
+ assert_config_default :fingerprint, nil
32
33
  end
33
34
 
34
35
  should "configure async as Proc" do
@@ -48,6 +49,19 @@ class ConfigurationTest < Test::Unit::TestCase
48
49
  assert_equal config.async.call('foo'), 'foo'
49
50
  end
50
51
 
52
+ should "configure fingerprint as Proc" do
53
+ config = Honeybadger::Configuration.new
54
+ fingerprint_generator = Proc.new { |n| n[:error_class] }
55
+ config.fingerprint = fingerprint_generator
56
+ assert_equal config.fingerprint.call({ :error_class => 'foo' }), 'foo'
57
+ end
58
+
59
+ should "configure fingerprint with block" do
60
+ config = Honeybadger::Configuration.new
61
+ config.fingerprint { |n| n[:error_class] }
62
+ assert_equal config.fingerprint.call({ :error_class => 'foo' }), 'foo'
63
+ end
64
+
51
65
  should "stub current_user_method" do
52
66
  config = Honeybadger::Configuration.new
53
67
  assert_nothing_raised { config.current_user_method = :foo }
@@ -93,6 +107,7 @@ class ConfigurationTest < Test::Unit::TestCase
93
107
  assert_config_overridable :logger
94
108
  assert_config_overridable :source_extract_radius
95
109
  assert_config_overridable :async
110
+ assert_config_overridable :fingerprint
96
111
  assert_config_overridable :send_request_session
97
112
  assert_config_overridable :debug
98
113
  end
@@ -109,8 +124,8 @@ class ConfigurationTest < Test::Unit::TestCase
109
124
  :ignore_by_filters, :ignore_user_agent, :notifier_name, :notifier_url,
110
125
  :notifier_version, :params_filters, :project_root, :port, :protocol,
111
126
  :proxy_host, :proxy_pass, :proxy_port, :proxy_user, :secure,
112
- :source_extract_radius, :async, :send_request_session, :debug].each do |option|
113
- assert_equal config[option], hash[option], "Wrong value for #{option}"
127
+ :source_extract_radius, :async, :send_request_session, :debug, :fingerprint].each do |option|
128
+ assert_equal config[option], hash[option], "Wrong value for #{option}"
114
129
  end
115
130
  end
116
131
 
@@ -22,14 +22,26 @@ class NoticeTest < Test::Unit::TestCase
22
22
  :env => { 'three' => 'four' } }.update(attrs))
23
23
  end
24
24
 
25
- should "deliver to sender" do
26
- sender = stub_sender!
27
- notice = build_notice
28
- notice.stubs(:to_json => { :foo => 'bar' })
25
+ context '#deliver' do
26
+ context 'sender is configured' do
27
+ should "deliver to sender" do
28
+ sender = stub_sender!
29
+ notice = build_notice
30
+ notice.stubs(:to_json => { :foo => 'bar' })
31
+
32
+ notice.deliver
29
33
 
30
- notice.deliver
34
+ assert_received(sender, :send_to_honeybadger) { |expect| expect.with(notice) }
35
+ end
36
+ end
31
37
 
32
- assert_received(sender, :send_to_honeybadger) { |expect| expect.with(notice) }
38
+ context 'sender is not configured' do
39
+ should "return false" do
40
+ notice = build_notice
41
+ Honeybadger.sender = nil
42
+ assert_equal false, notice.deliver
43
+ end
44
+ end
33
45
  end
34
46
 
35
47
  should "generate json from as_json template" do
@@ -80,6 +92,28 @@ class NoticeTest < Test::Unit::TestCase
80
92
  assert_equal hostname, notice.hostname
81
93
  end
82
94
 
95
+ context "custom fingerprint" do
96
+ should "include nil fingerprint when no fingerprint is specified" do
97
+ notice = build_notice
98
+ assert_equal nil, notice.fingerprint
99
+ end
100
+
101
+ should "accept fingerprint as string" do
102
+ notice = build_notice({ :fingerprint => 'foo' })
103
+ assert_equal '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', notice.fingerprint
104
+ end
105
+
106
+ should "accept fingerprint responding to #call" do
107
+ notice = build_notice({ :fingerprint => mock(:call => 'foo') })
108
+ assert_equal '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', notice.fingerprint
109
+ end
110
+
111
+ should "accept fingerprint using #to_s" do
112
+ notice = build_notice({ :fingerprint => mock(:to_s => 'foo') })
113
+ assert_equal '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', notice.fingerprint
114
+ end
115
+ end
116
+
83
117
  context "with a backtrace" do
84
118
  setup do
85
119
  @source = <<-RUBY
@@ -71,6 +71,12 @@ class SenderTest < Test::Unit::TestCase
71
71
  assert_equal nil, send_exception(:secure => false)
72
72
  end
73
73
 
74
+ should "log missing API key and return nil" do
75
+ sender = build_sender({ :api_key => nil })
76
+ sender.expects(:log).with(:error, includes('API key'))
77
+ assert_equal nil, send_exception(:sender => sender, :secure => false)
78
+ end
79
+
74
80
  should "should log success" do
75
81
  http = stub_http
76
82
  sender = build_sender
metadata CHANGED
@@ -1,32 +1,36 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honeybadger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.2
4
+ version: 1.7.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Joshua Wood
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2013-04-10 00:00:00.000000000 Z
12
+ date: 2013-06-07 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: json
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - '>='
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '0'
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - '>='
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0'
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: cucumber
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
35
  - - ~>
32
36
  - !ruby/object:Gem::Version
@@ -34,6 +38,7 @@ dependencies:
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
43
  - - ~>
39
44
  - !ruby/object:Gem::Version
@@ -41,6 +46,7 @@ dependencies:
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: rspec
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
51
  - - ~>
46
52
  - !ruby/object:Gem::Version
@@ -48,6 +54,7 @@ dependencies:
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
59
  - - ~>
53
60
  - !ruby/object:Gem::Version
@@ -55,6 +62,7 @@ dependencies:
55
62
  - !ruby/object:Gem::Dependency
56
63
  name: fakeweb
57
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
67
  - - ~>
60
68
  - !ruby/object:Gem::Version
@@ -62,6 +70,7 @@ dependencies:
62
70
  type: :development
63
71
  prerelease: false
64
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
75
  - - ~>
67
76
  - !ruby/object:Gem::Version
@@ -69,6 +78,7 @@ dependencies:
69
78
  - !ruby/object:Gem::Dependency
70
79
  name: sham_rack
71
80
  requirement: !ruby/object:Gem::Requirement
81
+ none: false
72
82
  requirements:
73
83
  - - ~>
74
84
  - !ruby/object:Gem::Version
@@ -76,6 +86,7 @@ dependencies:
76
86
  type: :development
77
87
  prerelease: false
78
88
  version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
79
90
  requirements:
80
91
  - - ~>
81
92
  - !ruby/object:Gem::Version
@@ -83,20 +94,23 @@ dependencies:
83
94
  - !ruby/object:Gem::Dependency
84
95
  name: bourne
85
96
  requirement: !ruby/object:Gem::Requirement
97
+ none: false
86
98
  requirements:
87
- - - '>='
99
+ - - ! '>='
88
100
  - !ruby/object:Gem::Version
89
101
  version: '1.0'
90
102
  type: :development
91
103
  prerelease: false
92
104
  version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
93
106
  requirements:
94
- - - '>='
107
+ - - ! '>='
95
108
  - !ruby/object:Gem::Version
96
109
  version: '1.0'
97
110
  - !ruby/object:Gem::Dependency
98
111
  name: shoulda
99
112
  requirement: !ruby/object:Gem::Requirement
113
+ none: false
100
114
  requirements:
101
115
  - - ~>
102
116
  - !ruby/object:Gem::Version
@@ -104,6 +118,7 @@ dependencies:
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
107
122
  requirements:
108
123
  - - ~>
109
124
  - !ruby/object:Gem::Version
@@ -111,71 +126,81 @@ dependencies:
111
126
  - !ruby/object:Gem::Dependency
112
127
  name: capistrano
113
128
  requirement: !ruby/object:Gem::Requirement
129
+ none: false
114
130
  requirements:
115
- - - '>='
131
+ - - ! '>='
116
132
  - !ruby/object:Gem::Version
117
133
  version: '0'
118
134
  type: :development
119
135
  prerelease: false
120
136
  version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
121
138
  requirements:
122
- - - '>='
139
+ - - ! '>='
123
140
  - !ruby/object:Gem::Version
124
141
  version: '0'
125
142
  - !ruby/object:Gem::Dependency
126
143
  name: rake
127
144
  requirement: !ruby/object:Gem::Requirement
145
+ none: false
128
146
  requirements:
129
- - - '>='
147
+ - - ! '>='
130
148
  - !ruby/object:Gem::Version
131
149
  version: '0'
132
150
  type: :development
133
151
  prerelease: false
134
152
  version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
135
154
  requirements:
136
- - - '>='
155
+ - - ! '>='
137
156
  - !ruby/object:Gem::Version
138
157
  version: '0'
139
158
  - !ruby/object:Gem::Dependency
140
159
  name: sinatra
141
160
  requirement: !ruby/object:Gem::Requirement
161
+ none: false
142
162
  requirements:
143
- - - '>='
163
+ - - ! '>='
144
164
  - !ruby/object:Gem::Version
145
165
  version: '0'
146
166
  type: :development
147
167
  prerelease: false
148
168
  version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
149
170
  requirements:
150
- - - '>='
171
+ - - ! '>='
151
172
  - !ruby/object:Gem::Version
152
173
  version: '0'
153
174
  - !ruby/object:Gem::Dependency
154
175
  name: aruba
155
176
  requirement: !ruby/object:Gem::Requirement
177
+ none: false
156
178
  requirements:
157
- - - '>='
179
+ - - ! '>='
158
180
  - !ruby/object:Gem::Version
159
181
  version: '0'
160
182
  type: :development
161
183
  prerelease: false
162
184
  version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
163
186
  requirements:
164
- - - '>='
187
+ - - ! '>='
165
188
  - !ruby/object:Gem::Version
166
189
  version: '0'
167
190
  - !ruby/object:Gem::Dependency
168
191
  name: appraisal
169
192
  requirement: !ruby/object:Gem::Requirement
193
+ none: false
170
194
  requirements:
171
- - - '>='
195
+ - - ! '>='
172
196
  - !ruby/object:Gem::Version
173
197
  version: '0'
174
198
  type: :development
175
199
  prerelease: false
176
200
  version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
177
202
  requirements:
178
- - - '>='
203
+ - - ! '>='
179
204
  - !ruby/object:Gem::Version
180
205
  version: '0'
181
206
  description: Make managing application errors a more pleasant experience.
@@ -267,7 +292,6 @@ files:
267
292
  - test/unit/sender_test.rb
268
293
  homepage: http://www.honeybadger.io
269
294
  licenses: []
270
- metadata: {}
271
295
  post_install_message:
272
296
  rdoc_options:
273
297
  - --charset=UTF-8
@@ -275,18 +299,23 @@ rdoc_options:
275
299
  require_paths:
276
300
  - lib
277
301
  required_ruby_version: !ruby/object:Gem::Requirement
302
+ none: false
278
303
  requirements:
279
- - - '>='
304
+ - - ! '>='
280
305
  - !ruby/object:Gem::Version
281
306
  version: '0'
307
+ segments:
308
+ - 0
309
+ hash: -2239778721023369939
282
310
  required_rubygems_version: !ruby/object:Gem::Requirement
311
+ none: false
283
312
  requirements:
284
- - - '>='
313
+ - - ! '>='
285
314
  - !ruby/object:Gem::Version
286
315
  version: '0'
287
316
  requirements: []
288
317
  rubyforge_project:
289
- rubygems_version: 2.0.3
318
+ rubygems_version: 1.8.23
290
319
  signing_key:
291
320
  specification_version: 2
292
321
  summary: Error reports you can be happy about.