madvertise-logging 0.1.0 → 0.2.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.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private
data/Gemfile CHANGED
@@ -6,5 +6,9 @@ gemspec
6
6
  group :test do
7
7
  gem 'rspec'
8
8
  gem 'simplecov'
9
+ gem 'ruby2ruby', '=1.3.0' # 1.3.1 is broken :(
10
+ gem 'reek'
11
+ gem 'yard'
12
+ gem 'redcarpet'
9
13
  gem 'syslogger', :require => false
10
14
  end
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Madvertise::Logging
2
2
 
3
- TODO: Write a gem description
3
+ The madvertise-logging gem is a collection of classes for logging related
4
+ tasks. The main class (`ImprovedLogger`) is an improved version of DaemonKits
5
+ `AbstractLogger` class including token support, buffer backend and more.
6
+
7
+ [![Build Status](https://secure.travis-ci.org/madvertise/logging.png)](http://travis-ci.org/madvertise/logging)
4
8
 
5
9
  ## Installation
6
10
 
@@ -18,7 +22,7 @@ Or install it yourself as:
18
22
 
19
23
  ## Usage
20
24
 
21
- TODO: Write usage instructions here
25
+ Please refer to the [API documentation](http://rubydoc.info/gems/madvertise-logging/frames).
22
26
 
23
27
  ## Contributing
24
28
 
@@ -3,12 +3,22 @@ require 'stringio'
3
3
 
4
4
  module Madvertise
5
5
  module Logging
6
+
7
+ ##
8
+ # ImprovedLogger is an enhanced version of DaemonKits AbstractLogger class
9
+ # with token support, buffer backend and more.
10
+ #
6
11
  class ImprovedLogger
7
12
 
13
+ # Write a copy of all log messages to STDOUT.
8
14
  attr_accessor :copy_to_stdout
9
- attr_accessor :transaction_token
15
+
16
+ # Program name prefix. Used as ident for syslog backends.
10
17
  attr_accessor :progname
11
18
 
19
+ # Arbitrary token to prefix log messages with.
20
+ attr_accessor :token
21
+
12
22
  @severities = {
13
23
  :debug => Logger::DEBUG,
14
24
  :info => Logger::INFO,
@@ -21,217 +31,211 @@ module Madvertise
21
31
  @silencer = true
22
32
 
23
33
  class << self
34
+ # Hash of Symbol/Fixnum pairs to map Logger levels.
24
35
  attr_reader :severities
36
+
37
+ # Enable/disable the silencer on a global basis. Useful for debugging
38
+ # otherwise silenced code blocks.
25
39
  attr_accessor :silencer
26
40
  end
27
41
 
28
42
  def initialize(logfile = nil, progname = nil)
29
43
  @copy_to_stdout = false
30
44
  @progname = progname || File.basename($0)
31
- self.logger = logfile || STDERR
45
+ self.logger = logfile
32
46
  end
33
47
 
34
- # Silence the logger for the duration of the block.
35
- def silence(temporary_level = :error)
36
- if self.class.silencer
37
- begin
38
- old_level, self.level = self.level, temporary_level
39
- yield self
40
- ensure
41
- self.level = old_level
42
- end
43
- else
44
- yield self
45
- end
48
+ # Get the backend logger.
49
+ #
50
+ # @return [Logger] The currently active backend logger object.
51
+ def logger
52
+ @logger ||= create_backend
46
53
  end
47
54
 
48
- def debug(msg)
49
- add(:debug, msg)
55
+ # Set a different backend.
56
+ #
57
+ # @param [Symbol, String, Logger] value The new logger backend. Either a
58
+ # Logger object, a String containing the logfile path or a Symbol to
59
+ # create a default backend for :syslog or :buffer
60
+ # @return [Logger] The newly created backend logger object.
61
+ def logger=(value)
62
+ @logger.close rescue nil
63
+ @logfile = value.is_a?(String) ? value : nil
64
+ @backend = value.is_a?(Symbol) ? value : :logger
65
+ @logger = value.is_a?(Logger) ? value : create_backend
50
66
  end
51
67
 
52
- def debug?
53
- self.level == :debug
68
+ # Close any connections/descriptors that may have been opened by the
69
+ # current backend.
70
+ def close
71
+ logger.close rescue nil
72
+ @logger = nil
54
73
  end
55
74
 
56
- def info(msg)
57
- add(:info, msg)
75
+ # Retrieve the current buffer in case this instance is a buffered logger.
76
+ #
77
+ # @return [String] Contents of the buffer.
78
+ def buffer
79
+ @logfile.string if @backend == :buffer
80
+ end
81
+
82
+ # Get the current logging level.
83
+ #
84
+ # @return [Symbol] Current logging level.
85
+ def level
86
+ self.class.severities.invert[@logger.level]
58
87
  end
59
88
 
60
- def info?
61
- self.level == :info
89
+ # Set the logging level.
90
+ #
91
+ # @param [Symbol, Fixnum] level New level as Symbol or Fixnum from Logger class.
92
+ # @return [Fixnum] New level converted to Fixnum from Logger class.
93
+ def level=(level)
94
+ level = level.is_a?(Symbol) ? self.class.severities[level] : level
95
+ logger.level = level
62
96
  end
63
97
 
64
- def warn(msg)
65
- add(:warn, msg)
98
+ # Log a debug level message.
99
+ def debug(msg)
100
+ add(:debug, msg)
66
101
  end
67
102
 
68
- def warn?
69
- self.level == :warn
103
+ # Log an info level message.
104
+ def info(msg)
105
+ add(:info, msg)
70
106
  end
71
107
 
72
- def error(msg)
73
- add(:error, msg)
108
+ # Log a warning level message.
109
+ def warn(msg)
110
+ add(:warn, msg)
74
111
  end
75
112
 
76
- def error?
77
- self.level == :error
113
+ # Log an error level message.
114
+ def error(msg)
115
+ add(:error, msg)
78
116
  end
79
117
 
118
+ # Log a fatal level message.
80
119
  def fatal(msg)
81
120
  add(:fatal, msg)
82
121
  end
83
122
 
84
- def fatal?
85
- self.level == :fatal
86
- end
87
-
123
+ # Log a message with unknown level.
88
124
  def unknown(msg)
89
125
  add(:unknown, msg)
90
126
  end
91
127
 
92
- def unknown?
93
- self.level == :unknown
94
- end
95
-
96
- def exception(e)
97
- if e.is_a?(::Exception)
98
- message = "EXCEPTION: #{e.message}: #{clean_trace(e.backtrace)}"
128
+ # Log an exception with error level.
129
+ #
130
+ # @param [Exception, String] exc The exception to log. If exc is a
131
+ # String no backtrace will be generated.
132
+ def exception(exc)
133
+ if exc.is_a?(::Exception)
134
+ message = "EXCEPTION: #{exc.message}: #{clean_trace(exc.backtrace)}"
99
135
  else
100
- message = e
136
+ message = exc
101
137
  end
102
138
  add(:error, message, true)
103
139
  end
104
140
 
105
- def add(severity, message, skip_caller = false)
106
- message = "#{called(caller)}: #{message}" unless skip_caller
107
- message = "[#{@transaction_token}] #{message}" if @transaction_token
108
-
109
- self.logger.add(self.class.severities[severity]) { message }
110
-
111
- STDOUT.puts(message) if self.copy_to_stdout && self.class.severities[severity] >= self.logger.level
112
- end
113
-
114
- def level
115
- self.class.severities.invert[@logger.level]
116
- end
117
-
118
- def level=(level)
119
- level = (Symbol === level ? self.class.severities[level] : level)
120
- self.logger.level = level
121
- end
122
-
123
- def new_transaction(v)
124
- @transaction_token = v
125
- end
126
-
127
- def end_transaction
128
- @transaction_token = nil
129
- end
130
-
131
- def save_transaction(obj)
132
- if @transaction_token && obj
133
- @transactions ||= {}
134
- @transactions[obj.object_id] = @transaction_token
141
+ # Save the current token and associate it with obj#object_id.
142
+ def save_token(obj)
143
+ if @token
144
+ @tokens ||= {}
145
+ @tokens[obj.object_id] = @token
135
146
  end
136
147
  end
137
148
 
138
- def restore_transaction(obj)
139
- @transactions ||= {}
140
- @transaction_token = @transactions.delete(obj.object_id) if obj
141
- end
142
-
143
- def logger
144
- @logger ||= create_logger
149
+ # Restore the token that has been associated with obj#object_id.
150
+ def restore_token(obj)
151
+ @tokens ||= {}
152
+ @token = @tokens.delete(obj.object_id)
145
153
  end
146
154
 
147
- def logger=(value)
148
- @logger.close rescue nil
149
-
150
- if value.is_a?(Logger)
151
- @backend = :logger
152
- @logger = value
153
- elsif value.is_a?(Symbol)
154
- @backend = value
155
- @logger = create_logger
155
+ # Silence the logger for the duration of the block.
156
+ def silence(temporary_level = :error)
157
+ if self.class.silencer
158
+ begin
159
+ old_level, self.level = self.level, temporary_level
160
+ yield self
161
+ ensure
162
+ self.level = old_level
163
+ end
156
164
  else
157
- @backend = :logger
158
- @logfile = value
159
- @logger = create_logger
165
+ yield self
160
166
  end
161
167
  end
162
168
 
169
+ # Remove references to the madvertise-logging gem from exception
170
+ # backtraces.
171
+ #
172
+ # @private
163
173
  def clean_trace(trace)
164
- trace = trace.map { |l| l.gsub(ROOT, '') }
165
- trace = trace.reject { |l| l =~ /gems\/madvertise-logging/ }
166
- trace = trace.reject { |l| l =~ /vendor\/madvertise-logging/ }
167
- trace
168
- end
169
-
170
- def close
171
- case @backend
172
- when :logger
173
- self.logger.close
174
- @logger = nil
175
- end
176
- end
177
-
178
- def buffer
179
- if @backend == :buffer && @buffer
180
- @buffer.string
174
+ trace.map do |line|
175
+ line.gsub(ROOT, '')
176
+ end.reject do |line|
177
+ line =~ /(gems|vendor)\/madvertise-logging/
181
178
  end
182
179
  end
183
180
 
184
181
  private
185
182
 
186
- def called(trace)
187
- l = trace.detect('unknown:0') do |l|
188
- l.index(File.basename(__FILE__)).nil?
183
+ # Return the first callee outside the madvertise-logging gem. Used in add
184
+ # to figure out where in the source code a message has been produced.
185
+ def called_from
186
+ location = caller.detect('unknown:0') do |line|
187
+ line.match(/(improved_logger|multi_logger)\.rb/).nil?
189
188
  end
190
189
 
191
- file, num, _ = l.split(':')
190
+ file, num, discard = location.split(':')
192
191
  [ File.basename(file), num ].join(':')
193
192
  end
194
193
 
195
- def create_logger
194
+ def add(severity, message, skip_caller = false)
195
+ severity = self.class.severities[severity]
196
+ message = "#{called_from}: #{message}" unless skip_caller
197
+ message = "[#{@token}] #{message}" if @token
198
+
199
+ logger.add(severity) { message }
200
+
201
+ STDOUT.puts(message) if self.copy_to_stdout && severity >= @logger.level
202
+ end
203
+
204
+ def create_backend
196
205
  case @backend
197
206
  when :buffer
198
- create_buffering_logger
207
+ create_buffering_backend
199
208
  when :syslog
200
- create_syslog_logger
209
+ create_syslog_backend
201
210
  else
202
- create_standard_logger
211
+ create_standard_backend
203
212
  end
204
213
  end
205
214
 
206
- def create_buffering_logger
207
- @buffer = StringIO.new
208
- Logger.new(@buffer).tap do |l|
209
- l.formatter = Formatter.new
210
- l.progname = progname
211
- end
215
+ def create_buffering_backend
216
+ @logfile = StringIO.new
217
+ create_logger
212
218
  end
213
219
 
214
- def create_standard_logger
215
- @logfile ||= STDERR
216
-
217
- if @logfile.is_a?(String)
218
- logdir = File.dirname(@logfile)
219
-
220
- begin
221
- FileUtils.mkdir_p(logdir)
222
- rescue
223
- STDERR.puts "#{logdir} not writable, using STDERR for logging"
224
- @logfile = STDERR
225
- end
220
+ def create_standard_backend
221
+ begin
222
+ FileUtils.mkdir_p(File.dirname(@logfile))
223
+ rescue
224
+ STDERR.puts "#{@logfile} not writable, using STDERR for logging" if @logfile
225
+ @logfile = STDERR
226
226
  end
227
227
 
228
- Logger.new(@logfile).tap do |l|
229
- l.formatter = Formatter.new
230
- l.progname = progname
228
+ create_logger
229
+ end
230
+
231
+ def create_logger
232
+ Logger.new(@logfile).tap do |logger|
233
+ logger.formatter = Formatter.new
234
+ logger.progname = progname
231
235
  end
232
236
  end
233
237
 
234
- def create_syslog_logger
238
+ def create_syslog_backend
235
239
  begin
236
240
  require 'syslogger'
237
241
  Syslogger.new(progname, Syslog::LOG_PID, Syslog::LOG_LOCAL1)
@@ -241,23 +245,25 @@ module Madvertise
241
245
  end
242
246
  end
243
247
 
248
+ ##
249
+ # The Formatter class is responsible for formatting log messages. The
250
+ # default format is:
251
+ #
252
+ # YYYY:MM:DD HH:MM:SS.MS daemon_name(pid) level: message
253
+ #
244
254
  class Formatter
245
255
 
246
- # YYYY:MM:DD HH:MM:SS.MS daemon_name(pid) level: message
247
256
  @format = "%s %s(%d) [%s] %s\n"
248
257
 
249
258
  class << self
259
+ # Format string for log messages.
250
260
  attr_accessor :format
251
261
  end
252
262
 
263
+ # @private
253
264
  def call(severity, time, progname, msg)
254
- self.class.format % [format_time( time ), progname, $$, severity, msg.to_s]
255
- end
256
-
257
- private
258
-
259
- def format_time(time)
260
- time.strftime("%Y-%m-%d %H:%M:%S.") + time.usec.to_s
265
+ time = time.strftime("%Y-%m-%d %H:%M:%S.") + time.usec.to_s
266
+ self.class.format % [time, progname, $$, severity, msg.to_s]
261
267
  end
262
268
  end
263
269
  end
@@ -1,22 +1,32 @@
1
1
  module Madvertise
2
2
  module Logging
3
+
4
+ ##
5
+ # MultiLogger is a simple class for multiplexing ImprovedLogger objects. It
6
+ # support attach/detach to send messages to any number of loggers.
7
+
3
8
  class MultiLogger
4
9
  def initialize(*loggers)
5
10
  @loggers = loggers
6
11
  end
7
12
 
13
+ # Attach an ImprovedLogger object.
8
14
  def attach(logger)
9
- logger.new_transaction(@loggers.first.transaction_token)
15
+ logger.token = @loggers.first.token
10
16
  @loggers << logger
11
17
  end
12
18
 
19
+ # Detach an ImprovedLogger object.
13
20
  def detach(logger)
14
21
  @loggers.delete(logger)
15
22
  end
16
23
 
24
+ # Delegate all method calls to all attached loggers.
25
+ #
26
+ # @private
17
27
  def method_missing(name, *args)
18
- @loggers.each do |l|
19
- l.send(name, *args)
28
+ @loggers.each do |logger|
29
+ logger.send(name, *args)
20
30
  end
21
31
  end
22
32
  end
@@ -1,5 +1,6 @@
1
1
  module Madvertise
2
2
  module Logging
3
- VERSION = "0.1.0"
3
+ # @private
4
+ VERSION = "0.2.0"
4
5
  end
5
6
  end
@@ -39,62 +39,32 @@ describe ImprovedLogger do
39
39
  @logfile.should have_received_message(/\[DEBUG\].*Debug test/)
40
40
  end
41
41
 
42
- it "should return true if debug level is set" do
43
- @logger.level = :debug
44
- @logger.debug?.should be true
45
- end
46
-
47
42
  it "should log info level messages" do
48
43
  @logger.info("Info test")
49
44
  @logfile.should have_received_message(/\[INFO\].*Info test/)
50
45
  end
51
46
 
52
- it "should return true if info level is set" do
53
- @logger.level = :info
54
- @logger.info?.should be true
55
- end
56
-
57
47
  it "should log warn level messages" do
58
48
  @logger.warn("Warn test")
59
49
  @logfile.should have_received_message(/\[WARN\].*Warn test/)
60
50
  end
61
51
 
62
- it "should return true if warn level is set" do
63
- @logger.level = :warn
64
- @logger.warn?.should be true
65
- end
66
-
67
52
  it "should log error level messages" do
68
53
  @logger.error("Err test")
69
54
  @logfile.should have_received_message(/\[ERROR\].*Err test/)
70
55
  end
71
56
 
72
- it "should return true if error level is set" do
73
- @logger.level = :error
74
- @logger.error?.should be true
75
- end
76
-
77
57
  it "should log fatal level messages" do
78
58
  @logger.fatal("Fatal test")
79
59
 
80
60
  @logfile.should have_received_message(/\[FATAL\].*Fatal test/)
81
61
  end
82
62
 
83
- it "should return true if fatal level is set" do
84
- @logger.level = :fatal
85
- @logger.fatal?.should be true
86
- end
87
-
88
63
  it "should log unknown level messages" do
89
64
  @logger.unknown("Unknown test")
90
65
  @logfile.should have_received_message(/\[ANY\].*Unknown test/)
91
66
  end
92
67
 
93
- it "should return true if unknown level is set" do
94
- @logger.level = :unknown
95
- @logger.unknown?.should be true
96
- end
97
-
98
68
  it "should log the caller file and line number" do
99
69
  f = File.basename(__FILE__)
100
70
  l = __LINE__ + 2
@@ -164,40 +134,39 @@ describe ImprovedLogger do
164
134
  ImprovedLogger.silencer = true
165
135
  end
166
136
 
167
- it "should support a transaction token" do
137
+ it "should support a token" do
168
138
  token = "3d5e27f7-b97c-4adc-b1fd-adf1bd4314e0"
169
139
 
170
- @logger.new_transaction(token)
171
- @logger.info "This should include a transaction token"
140
+ @logger.token = token
141
+ @logger.info "This should include a token"
172
142
  @logfile.should have_received_message(token)
173
143
 
174
- @logger.end_transaction
175
- @logger.info "This should not include a transaction token"
144
+ @logger.token = nil
145
+ @logger.info "This should not include a token"
176
146
  @logfile.should_not have_received_message(token)
177
147
  end
178
148
 
179
- it "should support save/restore on transaction tokens" do
149
+ it "should support save/restore on tokens" do
180
150
  token1 = "3d5e27f7-b97c-4adc-b1fd-adf1bd4314e0"
181
151
  token2 = "1bdef605-34b9-4ec7-9a1c-cb58efc8a635"
182
152
 
183
- obj1 = Object.new
153
+ obj = Object.new
184
154
 
185
- @logger.new_transaction(token1)
186
- @logger.info "This should include transaction token1"
155
+ @logger.token = token1
156
+ @logger.info "This should include token1"
187
157
  @logfile.should have_received_message(token1)
188
158
 
189
- @logger.save_transaction(obj1)
190
- @logger.new_transaction(token2)
191
- @logger.info "This should include transaction token2"
159
+ @logger.save_token(obj)
160
+ @logger.token = token2
161
+ @logger.info "This should include token2"
192
162
  @logfile.should have_received_message(token2)
193
- @logger.end_transaction
194
163
 
195
- @logger.restore_transaction(obj1)
196
- @logger.info "This should include transaction token1"
164
+ @logger.restore_token(obj)
165
+ @logger.info "This should include token1"
197
166
  @logfile.should have_received_message(token1)
198
167
 
199
- @logger.end_transaction
200
- @logger.info "This should not include a transaction token"
168
+ @logger.token = nil
169
+ @logger.info "This should not include a token"
201
170
  @logfile.should_not have_received_message(token1)
202
171
  @logfile.should_not have_received_message(token2)
203
172
  end
@@ -224,6 +193,7 @@ describe ImprovedLogger do
224
193
  syslogger_paths = $:.select { |p| p.match(/gems\/.*syslogger-/) }
225
194
  $:.replace($: - syslogger_paths)
226
195
 
196
+ STDERR.should_receive(:puts).with(/using STDERR for logging/)
227
197
  STDERR.should_receive(:write).with(/reverting to standard logger/)
228
198
  @logger = ImprovedLogger.new(:syslog)
229
199
  @logger.logger.should be_instance_of(Logger)
data/tasks/reek.rake ADDED
@@ -0,0 +1,5 @@
1
+ require 'reek/rake/task'
2
+
3
+ Reek::Rake::Task.new do |t|
4
+ t.fail_on_error = false
5
+ end
data/tasks/rspec.rake CHANGED
@@ -1,20 +1,7 @@
1
- begin
2
- require 'rspec'
3
- rescue LoadError
4
- require 'rubygems'
5
- require 'rspec'
6
- end
7
-
8
- begin
9
- require 'rspec/core/rake_task'
1
+ require 'rspec'
2
+ require 'rspec/core/rake_task'
10
3
 
11
- desc "Run the specs"
12
- RSpec::Core::RakeTask.new do |t|
13
- t.rspec_opts = ['--options', "spec/spec.opts"]
14
- end
15
- rescue LoadError
16
- puts <<-EOS
17
- To use rspec for testing you must install rspec gem:
18
- gem install rspec
19
- EOS
4
+ desc "Run the specs"
5
+ RSpec::Core::RakeTask.new do |t|
6
+ t.rspec_opts = ['--options', "spec/spec.opts"]
20
7
  end
data/tasks/yard.rake ADDED
@@ -0,0 +1,5 @@
1
+ require 'yard'
2
+
3
+ YARD::Rake::YardocTask.new do |t|
4
+ t.files = ['lib/**/*.rb', 'README.rdoc']
5
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: madvertise-logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-19 00:00:00.000000000 Z
12
+ date: 2012-01-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
- requirement: &15364280 !ruby/object:Gem::Requirement
16
+ requirement: &14192340 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *15364280
24
+ version_requirements: *14192340
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &15363560 !ruby/object:Gem::Requirement
27
+ requirement: &14191540 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *15363560
35
+ version_requirements: *14191540
36
36
  description: Advanced logging classes with buffer backend, transactions, multi logger,
37
37
  etc
38
38
  email:
@@ -43,6 +43,8 @@ extra_rdoc_files: []
43
43
  files:
44
44
  - .gitignore
45
45
  - .rvmrc
46
+ - .travis.yml
47
+ - .yardopts
46
48
  - Gemfile
47
49
  - LICENSE
48
50
  - README.md
@@ -56,7 +58,9 @@ files:
56
58
  - spec/multi_logger_spec.rb
57
59
  - spec/spec.opts
58
60
  - spec/spec_helper.rb
61
+ - tasks/reek.rake
59
62
  - tasks/rspec.rake
63
+ - tasks/yard.rake
60
64
  homepage: https://github.com/madvertise/logging
61
65
  licenses: []
62
66
  post_install_message:
@@ -71,7 +75,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
71
75
  version: '0'
72
76
  segments:
73
77
  - 0
74
- hash: 3354586897547183297
78
+ hash: 3732635707387209248
75
79
  required_rubygems_version: !ruby/object:Gem::Requirement
76
80
  none: false
77
81
  requirements:
@@ -80,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
84
  version: '0'
81
85
  segments:
82
86
  - 0
83
- hash: 3354586897547183297
87
+ hash: 3732635707387209248
84
88
  requirements: []
85
89
  rubyforge_project:
86
90
  rubygems_version: 1.8.10
@@ -93,3 +97,4 @@ test_files:
93
97
  - spec/multi_logger_spec.rb
94
98
  - spec/spec.opts
95
99
  - spec/spec_helper.rb
100
+ has_rdoc: