Changeset 280
- Timestamp:
- 07/07/08 06:23:15 (3 months ago)
- Files:
-
- trunk/FaerieMUD.tmproj (modified) (9 diffs)
- trunk/lib/fm/logger.rb (modified) (15 diffs)
- trunk/lib/fm/logger/fileoutputter.rb (modified) (2 diffs)
- trunk/lib/fm/logger/outputter.rb (modified) (5 diffs)
- trunk/lib/fm/mixins.rb (modified) (2 diffs)
- trunk/spec/fm/logger_spec.rb (modified) (6 diffs)
- trunk/spec/lib/helpers.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/FaerieMUD.tmproj
r278 r280 22 22 <key>metaData</key> 23 23 <dict> 24 <key>lib/fm.rb</key>25 <dict>26 <key>caret</key>27 <dict>28 <key>column</key>29 <integer>0</integer>30 <key>line</key>31 <integer>34</integer>32 </dict>33 <key>columnSelection</key>34 <false/>35 <key>firstVisibleColumn</key>36 <integer>0</integer>37 <key>firstVisibleLine</key>38 <integer>0</integer>39 <key>selectFrom</key>40 <dict>41 <key>column</key>42 <integer>0</integer>43 <key>line</key>44 <integer>31</integer>45 </dict>46 <key>selectTo</key>47 <dict>48 <key>column</key>49 <integer>0</integer>50 <key>line</key>51 <integer>34</integer>52 </dict>53 </dict>54 24 <key>lib/fm/character.rb</key> 55 25 <dict> … … 66 36 <integer>86</integer> 67 37 </dict> 68 <key>lib/fm/ utils.rb</key>38 <key>lib/fm/logger.rb</key> 69 39 <dict> 70 40 <key>caret</key> … … 73 43 <integer>0</integer> 74 44 <key>line</key> 75 <integer> 0</integer>45 <integer>491</integer> 76 46 </dict> 77 47 <key>firstVisibleColumn</key> 78 48 <integer>0</integer> 79 49 <key>firstVisibleLine</key> 80 <integer> 0</integer>50 <integer>407</integer> 81 51 </dict> 82 52 <key>lib/fm/verbs/simple.rb</key> … … 94 64 <integer>0</integer> 95 65 </dict> 96 <key>spec/fm/logger .tests.rb</key>66 <key>spec/fm/logger_spec.rb</key> 97 67 <dict> 98 68 <key>caret</key> … … 101 71 <integer>0</integer> 102 72 <key>line</key> 103 <integer> 0</integer>73 <integer>141</integer> 104 74 </dict> 105 75 <key>firstVisibleColumn</key> 106 76 <integer>0</integer> 107 77 <key>firstVisibleLine</key> 108 <integer>0</integer> 109 </dict> 110 <key>spec/fm/logger_spec.rb</key> 111 <dict> 112 <key>caret</key> 113 <dict> 114 <key>column</key> 115 <integer>14</integer> 116 <key>line</key> 117 <integer>53</integer> 118 </dict> 119 <key>firstVisibleColumn</key> 120 <integer>0</integer> 121 <key>firstVisibleLine</key> 122 <integer>43</integer> 78 <integer>123</integer> 123 79 </dict> 124 80 <key>tools/web/fmobjinspector.cgi</key> … … 139 95 <key>openDocuments</key> 140 96 <array> 141 <string>lib/fm.rb</string>142 97 <string>spec/fm/logger_spec.rb</string> 143 <string> spec/fm/logger.tests.rb</string>98 <string>lib/fm/logger.rb</string> 144 99 </array> 145 100 <key>showFileHierarchyDrawer</key> … … 153 108 <key>subItems</key> 154 109 <dict> 155 <key>acceptance</key>156 <dict>157 <key>isExpanded</key>158 <true/>159 <key>subItems</key>160 <dict/>161 </dict>162 <key>bin</key>163 <dict>164 <key>isExpanded</key>165 <true/>166 <key>subItems</key>167 <dict/>168 </dict>169 <key>lib</key>170 <dict>171 <key>isExpanded</key>172 <true/>173 <key>subItems</key>174 <dict/>175 </dict>176 110 <key>spec</key> 177 111 <dict> … … 187 121 <dict/> 188 122 </dict> 189 <key>lib</key>190 <dict>191 <key>isExpanded</key>192 <true/>193 <key>subItems</key>194 <dict/>195 </dict>196 123 </dict> 197 124 </dict> … … 200 127 </dict> 201 128 <key>windowFrame</key> 202 <string>{{ 662, 68}, {1242, 1510}}</string>129 <string>{{726, 68}, {1242, 1510}}</string> 203 130 </dict> 204 131 </plist> trunk/lib/fm/logger.rb
r277 r280 6 6 # A hierarchical logging class for FaerieMUD. It provides a generalized means 7 7 # of logging from inside FaerieMUD classes, and then selectively 8 # outputting/formatting log messages from points within the hierarchy.8 # outputting/formatting log messages from points within the class hierarchy. 9 9 # 10 10 # A lot of concepts in this class were stolen from Log4r, though it's all … … 13 13 # == Synopsis 14 14 # 15 # require 'fm/gameobject' 16 # require 'fm/logger' 17 # 18 # logger = FaerieMUD::Logger.global 19 # logfile = File.open( "global.log", "a" ) 20 # logger.outputters << FaerieMUD::Logger::Outputter.new(logfile) 21 # logger.level = :debug 22 # 23 # class MyClass < FaerieMUD::Object 24 # 25 # def self::fooMethod 26 # FaerieMUD::Logger.debug( "In server start routine" ) 27 # FaerieMUD::Logger.info( "Server is not yet configured." ) 28 # FaerieMUD::Logger.notice( "Server is starting up." ) 29 # end 30 # 31 # def initialize 32 # self.log.info( "Initializing another MyClass object." ) 33 # end 34 # end 35 # 15 # require 'fm/gameobject' 16 # require 'fm/mixins' 17 # require 'fm/logger' 18 # 19 # class MyServer 20 # 21 # # Hook up the Logger to this class through the #log and ::log methods. 22 # include FaerieMUD::Loggable 23 # 24 # # Log some stuff from various methods 25 # def self::start 26 # self.log.notice "Server is starting up." 27 # self.new.launch 28 # end 29 # 30 # def initialize 31 # self.log.debug "Initializing another MyServer object." 32 # end 33 # 34 # def launch 35 # self.log.info "Launching server %p" % [ self ] 36 # end 37 # end 38 # 39 # MyServer.log.outputter = FaerieMUD::Logger::Outputter.create( 'file', 'stderr' ) 40 # MyServer.log.level = :debug 41 # 42 # MyServer.start # => 43 # 36 44 # == Subversion Id 37 45 # … … 88 96 ############################################################# 89 97 90 @global_logger = nil 98 @class_loggers = {} 99 class << self 100 attr_reader :class_loggers 101 end 102 103 104 ### Create a new FaerieMUD::Logger for the given +mod+ if one doesn't already exist, 105 ### or return the existing one if it does. 106 def new( mod, *args ) 107 return @class_loggers[ mod ] if @class_loggers.key?( mod ) 108 logger = self.allocate 109 logger.initialize( mod, *args ) 110 111 return logger 112 end 113 91 114 92 115 ### Configure logging from the 'logging' section of the config. … … 152 175 ### Module object, a Symbol, or a String. 153 176 def self::[]( mod=nil ) 154 modname = mod.to_s 155 return self.global if modname.empty? 156 157 names = modname.split( /::/ ) 158 159 # Create the global logger if it isn't already created 160 self.global 161 162 names.inject( @global_logger ) {|logger,key| logger[key]} 177 return self.global unless mod 178 mod = mod.class unless mod.is_a?( Module ) 179 return self.class_loggers[ mod ] ||= new( mod ) 163 180 end 164 181 … … 167 184 ### already. 168 185 def self::global 169 # debug_msg "Creating the global logger" unless @global_logger 170 @global_logger ||= new( '' ) 186 @class_loggers[ nil ] ||= new() 171 187 end 172 188 … … 175 191 ### their associated outputters. 176 192 def self::reset 177 # debug_msg "Resetting the global logger" 178 @global_logger = nil 193 @class_loggers.clear 179 194 end 180 195 … … 191 206 end 192 207 193 self. global.send( sym, *args )208 self.method( sym ).call( sym, *args ) 194 209 end 195 210 … … 199 214 ############################################################# 200 215 201 ### Create and return a new FaerieMUD::Logger object with the given +name+ 202 ### at the specified +level+, with the specified +superlogger+. Any 203 ### +outputters+ that are specified will be added. 204 def initialize( name, level=:info, superlogger=nil, *outputters ) 205 if name.empty? 206 # debug_msg "Creating global logger" 207 else 208 # debug_msg "Creating logger for #{name}" 209 end 210 211 @name = name 212 @outputters = outputters 213 @subloggers = {} 214 @superlogger = superlogger 215 @trace = false 216 @level = nil 217 218 self.level = level 216 ### Create and return a new FaerieMUD::Logger object for the specified +logged_class+ 217 ### at the specified +level+. Any +outputters+ that are specified will be added. 218 def initialize( logged_class=nil, level=:info, *outputters ) 219 @logged_class = logged_class 220 @outputters = outputters 221 @superlogger = superlogger 222 @trace = false 223 @level = nil 224 225 self.level = level 219 226 end 220 227 … … 224 231 ###### 225 232 226 # The name ofthis logger227 attr_reader : name233 # The Class associated with this logger 234 attr_reader :logged_class 228 235 229 236 # The outputters attached to this branch of the logger tree. 230 237 attr_accessor :outputters 231 232 # The logger object that is this logger's parent (if any).233 attr_reader :superlogger234 235 # The branches of the logging hierarchy that fall below this one.236 attr_accessor :subloggers237 238 238 239 # Set to a true value to turn tracing on … … 272 273 end 273 274 274 unless self.subloggers.empty?275 details << "Subloggers:" <<276 self.subloggers.values.map {|sl| sl.inspect_details(level + 1) }277 end278 279 275 details = details.flatten.compact.map {|line| indent + line } 280 276 … … 289 285 ### Return the name of the logger formatted to be suitable for reading. 290 286 def readable_name 291 logname = self.name.sub( /^::/, '' ) 292 logname = '(global)' if logname.empty? 293 294 return logname 287 if klass = self.logged_class 288 return klass.name.sub( /^::/, '' ) 289 else 290 return '(global)' 291 end 295 292 end 296 293 … … 328 325 end 329 326 327 328 ### Return the FaerieMUD::Logger object associated with the parent of the 329 ### class associated with the receiver, the global logger if received by the 330 ### Logger for Object or a Module, or +nil+ if received by the global 331 ### logger. 332 def superlogger 333 klass = self.logged_class or return nil 334 335 return FaerieMUD::Logger.global unless klass.respond_to?( :superclass ) 336 return FaerieMUD::Logger[ klass.superclass ] 337 end 338 330 339 331 340 … … 341 350 level = LEVELS[ level ] if level.is_a?( Symbol ) 342 351 343 # debug_msg "Searching for loggers in the hierarchy above %s" % 344 # [ logger.name.empty? ? "[Global]" : logger.name ] 352 debug_msg "Searching for loggers in the hierarchy above %s" % logger.readable_name 345 353 346 354 # Traverse the logger hierarchy upward (more general), looking for ones … … 352 360 # When one is found, add it to the ones being returned and yield it 353 361 # if there's a block 354 #debug_msg "hierloggers: added %s" % logger.readable_name355 loggers.push( logger )356 yield( logger ) if block_given?362 debug_msg "hierloggers: added %s" % logger.readable_name 363 loggers.push( logger ) 364 yield( logger ) if block_given? 357 365 358 366 end while (( logger = lastlogger.superlogger )) … … 414 422 415 423 416 ### Return the sublogger for the given module +mod+ (a Module, a String,417 ### or a Symbol) under this logger. A new one will instantiated if it418 ### does not already exist.419 def []( mod )420 # debug_msg "creating sublogger for '#{mod}'" unless @subloggers.key?( mod.to_s )421 @subloggers[ mod.to_s ] ||=422 self.class.new( @name + "::" + mod.to_s, self.level, self )423 end424 425 426 424 ### Append the given +obj+ to the logger at +:debug+ level. This is for 427 425 ### compatibility with objects that append to $stderr for their logging trunk/lib/fm/logger/fileoutputter.rb
r277 r280 37 37 38 38 # The default description 39 D efaultDescription= "File Outputter"39 DEFAULT_DESCRIPTION = "File Outputter" 40 40 41 41 # The default format (copied from the superclass) 42 D efaultFormat = FaerieMUD::Logger::Outputter::DefaultFormat42 DEFAULT_FORMAT = FaerieMUD::Logger::Outputter::DEFAULT_FORMAT 43 43 44 44 … … 53 53 ### object is created which appends to the file handle matching that 54 54 ### descriptor. 55 def initialize( uri, description=D efaultDescription, format=DefaultFormat)55 def initialize( uri, description=DEFAULT_DESCRIPTION, format=DEFAULT_FORMAT ) 56 56 if uri.hierarchical? 57 57 @io = File.open( uri.path, File::WRONLY|File::CREAT ) trunk/lib/fm/logger/outputter.rb
r277 r280 1 1 #!/usr/bin/ruby 2 # 3 # This file contains the FaerieMUD::Logger::Outputter class, which is the abstract 4 # base class for objects that control where logging output is sent in an 5 # FaerieMUD::Logger object. 2 3 require 'uri' 4 require 'pluginfactory' 5 6 require 'fm/utils' 7 require 'fm/exceptions' 8 require 'fm/logger' 9 require 'fm/mixins' 10 11 # The FaerieMUD::Logger::Outputter class, which is the abstract base class for 12 # objects that control where logging output is sent in an FaerieMUD::Logger 13 # object. 6 14 # 7 15 # == Subversion Id … … 19 27 # Please see the file COPYRIGHT in the 'docs' directory for licensing details. 20 28 # 21 22 require 'uri'23 require 'pluginfactory'24 25 require 'fm/utils'26 require 'fm/exceptions'27 require 'fm/logger'28 require 'fm/mixins'29 30 ### This class is the abstract base class for logging outputters for31 ### FaerieMUD::Logger.32 29 class FaerieMUD::Logger::Outputter 33 30 include PluginFactory … … 43 40 44 41 # The default description 45 D efaultDescription= "Logging Outputter"42 DEFAULT_DESCRIPTION = "Logging Outputter" 46 43 47 44 # The default interpolatable string that's used to build the message to 48 45 # output 49 D efaultFormat=46 DEFAULT_FORMAT = 50 47 %q{#{time.strftime('%Y/%m/%d %H:%M:%S')} [#{level}]: #{name} } + 51 48 %q{#{frame ? '('+frame+')' : ''}: #{msg[0,1024]}} … … 57 54 58 55 ### Specify the directory to look for the derivatives of this class in. 59 def self::derivative Dirs56 def self::derivative_dirs 60 57 ["fm/logger"] 61 58 end … … 86 83 ### Create a new Arrow::Logger::Outputter object with the given +uri+, 87 84 ### +description+ and sprintf-style +format+. 88 def initialize( uri, description=D efaultDescription, format=DefaultFormat)85 def initialize( uri, description=DEFAULT_DESCRIPTION, format=DEFAULT_FORMAT ) 89 86 @description = description 90 87 @format = format trunk/lib/fm/mixins.rb
r277 r280 200 200 end 201 201 202 203 ######### 204 protected 205 ######### 202 ###### 203 public 204 ###### 206 205 207 206 ### Return the FaerieMUD::Logger object for the receiving class. … … 610 609 ### return the same object instance. 611 610 def fetch( *args ) 612 if self::respond_to?( :flyweight Args )613 key = args[ 0, self ::flyweightArgs ]611 if self::respond_to?( :flyweight_args ) 612 key = args[ 0, self.flyweight_args ] 614 613 @__pool__[key] ||= new( *args ) 615 614 else trunk/spec/fm/logger_spec.rb
r277 r280 17 17 require 'spec/runner' 18 18 require 'spec/lib/helpers' 19 require 'spec/lib/matchers' 19 20 require 'fm/logger' 20 21 require 'fm/mixins' … … 24 25 include FaerieMUD::Loggable 25 26 27 class InnerClass 28 class InnerInnerClass 29 end 30 end 31 32 26 33 def debug_log( msg ) 27 34 self.log.debug( msg ) … … 56 63 end 57 64 end 65 66 67 class SubclassOfTestObject < TestObject; end 68 class GrandchildClassOfTestObject < SubclassOfTestObject; end 58 69 59 70 … … 80 91 81 92 describe FaerieMUD::Logger do 82 include FaerieMUD::SpecHelpers 93 include FaerieMUD::SpecHelpers, 94 FaerieMUD::SpecMatchers 83 95 84 96 after( :all ) do … … 91 103 92 104 93 94 105 it "has a global logger object that can be used to log stuff from anywhere" do 106 FaerieMUD::Logger.global.should be_an_instance_of( FaerieMUD::Logger ) 107 95 108 FaerieMUD::Logger.global.level = :debug 96 109 FaerieMUD::Logger.global.outputters << @outputter … … 113 126 FaerieMUD::Logger[ TestObject ].should be_an_instance_of( FaerieMUD::Logger ) 114 127 end 128 129 130 it "uses the global logger's level for global log messages" do 131 FaerieMUD::Logger.global.level = :warning 132 FaerieMUD::Logger.global.outputters << @outputter 133 134 FaerieMUD::Logger.global.debug "Debugging message" 135 FaerieMUD::Logger.global.info "Info message" 136 FaerieMUD::Logger.global.notice "Notice message" 137 FaerieMUD::Logger.global.warning "Warning message" 138 FaerieMUD::Logger.global.error "Error message" 139 FaerieMUD::Logger.global.crit "Crit message" 140 FaerieMUD::Logger.global.alert "Alert message" 141 FaerieMUD::Logger.global.emerg "Emerg message" 142 143 @outputter.should have(5).messages 144 @outputter.messages.all? {|msg| msg =~ /(global)/ }.should be_true 145 end 146 147 148 it "sends output to an outputter attached to the global logger for instance messages" do 149 obj = TestObject.new 150 outputter = TestOutputter.new 151 152 FaerieMUD::Logger.global.outputters << outputter 153 154 FaerieMUD::Logger::LEVELS.keys.each do |level| 155 FaerieMUD::Logger.global.level = level 156 157 obj.log.send( level, "test message" ) 158 159 outputter.should have(1).messages 160 outputter.messages.all? {|msg|msg =~ /test message/ } 161 outputter.clear 162 end 163 164 end 165 166 167 it "knows how to make a readable name out of the logged class" do 168 FaerieMUD::Logger[ TestObject ].readable_name.should == "TestObject" 169 end 170 171 172 it "formats the global logger's readable name appropriately" do 173 FaerieMUD::Logger.global.readable_name.should == '(global)' 174 end 175 176 177 it "knows what the corresponding Symbol for a logging level is" do 178 FaerieMUD::Logger[ TestObject ].level = :notice 179 FaerieMUD::Logger[ TestObject ].readable_level.should == :notice 180 end 181 182 183 it "knows which loggers belong to more-general classes than the logged class" do 184 loggers = GrandchildClassOfTestObject.log.hierloggers 185 186 loggers.should have(5).members 187 loggers.should include( 188 FaerieMUD::Logger[ GrandchildClassOfTestObject ], 189 FaerieMUD::Logger[ SubclassOfTestObject ], 190 FaerieMUD::Logger[ Object ], 191 FaerieMUD::Logger.global 192 ) 193 end 194 195 196 it "logs to outputters on more-general classes when logging to a subclass" do 197 baselogger = FaerieMUD::Logger.global 198 baselogger.level = :debug 199 baseoutputter = TestOutputter.new 200 baselogger.outputters << baseoutputter 201 202 superlogger = TestObject.log 203 superlogger.level = :info 204 superoutputter = TestOutputter.new 205 superlogger.outputters << superoutputter 206 207 sublogger = SubclassOfTestObject.log 208 sublogger.level = :notice 209 suboutputter = TestOutputter.new 210 sublogger.outputters << suboutputter 211 212 subsublogger = GrandchildClassOfTestObject.log 213 subsublogger.level = :notice 214 215 obj = GrandchildClassOfTestObject.new 216 217 obj.debug_log "debug message" 218 obj.info_log "info message" 219 obj.notice_log "notice message" 220 221 suboutputter.output_calls.should have(1).members 222 suboutputter.messages. 223 should include_matches_for( "notice message" ) 224 225 superoutputter.output_calls.should have(2).members 226 superoutputter.messages. 227 should include_matches_for( "notice message", "info message" ) 228 229 baseoutputter.output_calls.should have(3).members 230 baseoutputter.messages. 231 should include_matches_for( "notice message", "info message", "debug message" ) 232 end 233 234 235 ################################################################# 236 ### L E F T T O P O R T : 237 ################################################################# 238 239 def test_messages_should_only_be_output_once_per_outputter 240 outputter = TestOutputter.new( "single outputter" ) 241 242 for klass in [FaerieMUD, FaerieMUD::TestObject, FaerieMUD::TestObject::SubObject] 243 FaerieMUD::Logger[ klass ].level = :debug 244 FaerieMUD::Logger[ klass ].outputters << outputter 245 end 246 247 FaerieMUD::Logger.global.level = :debug 248 FaerieMUD::Logger.global.outputters << outputter 249 250 FaerieMUD::TestObject::SubObject.new.debug_log "message" 251 252 assert_equal 1, outputter.output_calls.nitems 253 end 254 255 def test_logging_an_exception_should_include_its_backtrace 256 outputter = TestOutputter.new 257 FaerieMUD::Logger.global.outputters << outputter 258 259 obj = TestObject.new 260 261 begin 262 throw "Glah." 263 rescue => err 264 obj.error_log( err ) 265 end 266 267 assert_include self.name.sub( /\(.*/, '' ), outputter.output 268 end 269 270 271 def test_parse_log_setting_should_just_return_level_if_its_a_single_word 272 level = uri = nil 273 274 assert_nothing_raised do 275 level, uri = FaerieMUD::Logger.parse_log_setting( "debug" ) 276 end 277 278 assert_equal :debug, level 279 assert_equal nil, uri 280 end 281 282 283 def test_parse_log_setting_should_return_a_uri_if_setting_has_two_words 284 level = uri = nil 285 286 assert_nothing_raised do 287 level, uri = FaerieMUD::Logger.parse_log_setting( "info apache" ) 288 end 289 290 assert_equal :info, level 291 assert_kind_of URI::Generic, uri 292 end 293 294 def test_parse_log_setting_should_return_a_uri_if_setting_includes_complex_uri 295 level = uri = nil 296 complexuri = 'dbi://www:password@localhost/www.errorlog?driver=postgresql' 297 298 assert_nothing_raised do 299 level, uri = FaerieMUD::Logger.parse_log_setting( "error #{complexuri}" ) 300 end 301 302 assert_equal :error, level 303 assert_kind_of URI::Generic, uri 304 end 305 306 def test_configure_should_use_apache_log_outputter_if_none_specified 307 FaerieMUD::Logger.configure( {:global => 'debug'}, nil ) 308 309 assert_instance_of FaerieMUD::Logger::ApacheOutputter, 310 FaerieMUD::Logger.global.outputters.first 311 assert_equal :debug, FaerieMUD::Logger.global.readable_level 312 end 313 314 def test_configure_with_file_uri_should_use_fileouputter 315 FaerieMUD::Logger.configure( {:global => 'error file:stderr'}, nil ) 316 317 assert_instance_of FaerieMUD::Logger::FileOutputter, 318 FaerieMUD::Logger.global.outputters.first 319 assert_equal :error, FaerieMUD::Logger.global.readable_level 320 end 321 322 def test_configure_with_simple_class_name_should_prepend_arrow_namespace 323 FaerieMUD::Logger.configure( {:applet => 'notice file:stderr'}, nil ) 324 325 assert_instance_of FaerieMUD::Logger::FileOutputter, 326 FaerieMUD::Logger[FaerieMUD::Applet].outputters.first 327 assert_equal :notice, FaerieMUD::Logger[FaerieMUD::Applet].readable_level 328 end 329 330 def test_configure_with_full_class_name_should_create_a_logger_for_that_class 331 FaerieMUD::Logger.configure( {:"FaerieMUD::Applet" => 'info file:stderr'}, nil ) 332 333 assert_instance_of FaerieMUD::Logger::FileOutputter, 334 FaerieMUD::Logger[FaerieMUD::Applet].outputters.first 335 assert_equal :info, FaerieMUD::Logger[FaerieMUD::Applet].readable_level 336 end 337 338 def test_configure_with_full_class_name_should_create_a_logger_for_non_arrow_class 339 FaerieMUD::Logger.configure( {:"String" => 'warning file:stderr'}, nil ) 340 341 assert_instance_of FaerieMUD::Logger::FileOutputter, 342 FaerieMUD::Logger[String].outputters.first 343 assert_equal :warning, FaerieMUD::Logger[String].readable_level 344 end 115 345 116 346 trunk/spec/lib/helpers.rb
r277 r280 54 54 55 55 end 56 57 56 58 57 59
