Skip to content
Browse files

ST: Writing own adapters is simpler now with some fancy DSL

  • Loading branch information...
1 parent 85091ce commit bd0b44e23ca7c67742ab4a588cbb8303f7686dfc @rudionrails committed Apr 12, 2012
View
22 Rakefile
@@ -4,20 +4,26 @@ require 'bundler'
Bundler::GemHelper.install_tasks
task :examples do
- Dir[ './examples/*.rb' ].each do |file|
- begin
- puts "**** Running #{file}"
+ require 'benchmark'
- require file
- rescue Exception => e
- puts "#{e.class}: #{e.message}:\n\t#{e.backtrace.join("\n\t")}"
+ seconds = Benchmark.realtime do
+ Dir[ './examples/*.rb' ].sort.each do |file|
+ begin
+ puts "\n*** Running #{file}"
- exit 1
+ require file
+ rescue Exception => e
+ puts "#{e.class}: #{e.message}:\n\t#{e.backtrace.join("\n\t")}"
+
+ exit 1
+ end
end
end
+
+ puts "\n\t[ Examples took #{seconds} seconds to run ]"
end
-# === RSpec
+# RSpec
begin
require 'rspec/core/rake_task'
View
136 lib/yell/adapters/base.rb
@@ -3,16 +3,115 @@
module Yell #:nodoc:
module Adapters #:nodoc:
- # This class provides the basic interface for all allowed
- # operations on any adapter implementation.
+ # This class provides the basic interface for all allowed operations on any
+ # adapter implementation. Other adapters should inherit from it for the methods
+ # used by the {Yell::Logger}.
#
- # Other adapters should inherit from it for the methods used
- # by the {Yell::Logger}.
+ # Writing your own adapter is really simple. Inherit from the base class and use
+ # the `setup`, `write` and `close` methods. Yell requires the `write` method to be
+ # specified (`setup` and `close` are optional).
+ #
+ #
+ # The following example shows how to define a basic Adapter to format and print
+ # log events to STDOUT:
+ #
+ # class PutsAdapter < Yell::Adapters::Base
+ # include Yell::Formatter::Helpers
+ #
+ # setup do |options|
+ # self.format = options[:format]
+ # end
+ #
+ # write do |event|
+ # message = format.format(event)
+ #
+ # STDOUT.puts message
+ # end
+ # end
+ #
+ #
+ # After the Adapter has been written, we need to register it to Yell:
+ #
+ # Yell::Adapters.register :puts, PutsAdapter
+ #
+ # Now, we can use it like so:
+ #
+ # logger = Yell.new :puts
+ # logger.info "Hello World!"
class Base
include Yell::Level::Helpers
+ class << self
+ # Setup your adapter with this helper method.
+ #
+ # @example
+ # setup do |options|
+ # @file_handle = File.new( '/dev/null', 'w' )
+ # end
+ def setup( &block )
+ compile!( :setup!, &block )
+ end
+
+ # Define your write method with this helper.
+ #
+ # @example Printing messages to file
+ # write do |event|
+ # @file_handle.puts event.message
+ # end
+ def write( &block )
+ compile!( :write!, &block )
+ end
+
+ # Define your close method with this helper.
+ #
+ # @example Closing a file handle
+ # close do
+ # @file_handle.close
+ # end
+ def close( &block )
+ compile!( :close!, &block )
+ end
+
+
+ private
+
+ # Pretty funky code block, I know but here is what it basically does:
+ #
+ # @example
+ # compile! :write! do |event|
+ # puts event.message
+ # end
+ #
+ # # Is actually defining the `:write!` instance method with a call to super:
+ #
+ # def write!( event )
+ # puts event.method
+ # super
+ # end
+ def compile!( name, &block )
+ # Get the already defined method
+ m = instance_method name
+
+ # Create a new method with leading underscore
+ define_method "_#{name}", &block
+ _m = instance_method "_#{name}"
+ remove_method "_#{name}"
+
+ # Define instance method
+ if block.arity == 0
+ define_method(name) { _m.bind(self).call; m.bind(self).call }
+ else
+ define_method(name) { |*args| _m.bind(self).call(*args); m.bind(self).call(*args) }
+ end
+ end
+ end
+
+
+ # Initializes a new Adapter.
+ #
+ # You should not overload the constructor, use #setup instead.
def initialize( options = {}, &block )
- self.level = options[:level]
+ setup!(options)
block.call(self) if block
end
@@ -23,25 +122,46 @@ def initialize( options = {}, &block )
# actually write or not.
def write( event )
write!( event ) if write?( event )
+ rescue Exception => e
+ # make sure the adapter is closed and re-raise the exception
+ close
+
+ raise( e )
end
# Close the adapter (stream, connection, etc).
#
# Adapter classes should provide their own implementation
# of this method.
def close
- raise 'Not implemented'
+ close!
end
private
- # The perform the actual write.
+ # Setup the adapter instance.
#
# Adapter classes should provide their own implementation
+ # of this method (if applicable).
+ def setup!( options )
+ self.level = options[:level]
+ end
+
+ # Perform the actual write.
+ #
+ # Adapter classes must provide their own implementation
# of this method.
def write!( event )
- raise 'Not implemented'
+ # Not implemented
+ end
+
+ # Perform the actual close.
+ #
+ # Adapter classes should provide their own implementation
+ # of this method.
+ def close!
+ # Not implemented
end
# Determine whether to write at the given severity.
View
25 lib/yell/adapters/datefile.rb
@@ -10,34 +10,26 @@ class Datefile < Yell::Adapters::File
# The default date pattern, e.g. "19820114" (14 Jan 1982)
DefaultDatePattern = "%Y%m%d"
- def initialize( options = {}, &block )
+ setup do |options|
@date_pattern = options[:date_pattern] || DefaultDatePattern
@file_basename = options[:filename] || default_filename
options[:filename] = @file_basename
@date = nil # default; do not override --R
-
- super
end
- # @overload Reset the file handle
- def close
- @filename = new_filename
+ write do |event|
+ close if close?
+ end
- super
+ close do
+ @filename = @file_basename.sub( /(\.\w+)?$/, ".#{@date}\\1" )
end
private
- # @overload Close the file if date is expired
- def write!( event )
- close if close?
-
- super( event )
- end
-
# Determines whether to close the file handle or not.
#
# It is based on the `:date_pattern` (can be passed as option upon initialize).
@@ -54,11 +46,6 @@ def close?
false
end
- # Sets the filename with the `:date_pattern` appended to it.
- def new_filename
- @file_basename.sub( /(\.\w+)?$/, ".#{@date}\\1" )
- end
-
end
register( :datefile, Yell::Adapters::Datefile )
View
10 lib/yell/adapters/file.rb
@@ -7,20 +7,18 @@ module Adapters #:nodoc:
# for logging into files.
class File < Yell::Adapters::Io
- def initialize( options = {}, &block )
+ setup do |options|
@filename = options.fetch(:filename, default_filename)
-
- super( options, &block )
end
+
+ private
+
# @overload Lazily open the file handle
def stream
@stream ||= ::File.open( @filename, ::File::WRONLY|::File::APPEND|::File::CREAT )
end
-
- private
-
def default_filename #:nodoc:
::File.directory?("log") ? "log/#{Yell.env}.log" : "#{Yell.env}.log"
end
View
56 lib/yell/adapters/io.rb
@@ -17,38 +17,13 @@ class Io < Yell::Adapters::Base
'DEFAULT' => "\e[0m" # NONE
}
- attr_accessor :colors
-
- def initialize( options = {}, &block )
+ setup do |options|
self.colors = options[:colors]
self.format = options[:format]
-
- super( options, &block )
- end
-
- # The IO stream
- #
- # Adapter classes should provide their own implementation
- # of this method.
- def stream
- raise 'Not implemented'
end
- # Close the io stream
- def close
- @stream.close if @stream.respond_to? :close
-
- @stream = nil
- end
-
- # Shortcut to enable colors
- def colorize!; @colors = true; end
-
- private
-
- # The method formats the message and writes it to the file handle.
- def write!( event )
- message = @format.format( event )
+ write do |event|
+ message = format.format(event)
# colorize if applicable
if colors and color = Colors[event.level]
@@ -59,11 +34,28 @@ def write!( event )
stream.print( message )
stream.flush
- # rescue Exception => e
- # close
+ end
+
+ close do
+ @stream.close if @stream.respond_to? :close
+ @stream = nil
+ end
+
+
+ attr_accessor :colors
+
+ # Shortcut to enable colors
+ def colorize!; @colors = true; end
+
- # # re-raise the exception
- # raise( e, caller )
+ private
+
+ # The IO stream
+ #
+ # Adapter classes should provide their own implementation
+ # of this method.
+ def stream
+ raise 'Not implemented'
end
end
View
4 lib/yell/adapters/streams.rb
@@ -5,6 +5,8 @@ module Adapters #:nodoc:
class Stdout < Yell::Adapters::Io
+ private
+
# @overload Lazily open the STDOUT stream
def stream
@stream ||= $stdout.clone
@@ -13,6 +15,8 @@ def stream
class Stderr < Yell::Adapters::Io
+ private
+
# @overload Lazily open the STDERR stream
def stream
@stream ||= $stderr.clone
View
8 spec/yell/adapters/base_spec.rb
@@ -55,13 +55,5 @@
end
end
- context :close do
- subject { Yell::Adapters::Base.new.close }
-
- it "should raise" do
- lambda { subject }.should raise_error("Not implemented" )
- end
- end
-
end
View
2 spec/yell/adapters/file_spec.rb
@@ -10,7 +10,7 @@
it { should be_kind_of Yell::Adapters::Io }
context :stream do
- subject { Yell::Adapters::File.new.stream }
+ subject { Yell::Adapters::File.new.send :stream }
it { should be_kind_of File }
end
View
2 spec/yell/adapters/io_spec.rb
@@ -42,7 +42,7 @@
context :stream do
it "should raise" do
- lambda { Yell::Adapters::Io.new.stream }.should raise_error("Not implemented" )
+ lambda { Yell::Adapters::Io.new.send :stream }.should raise_error("Not implemented" )
end
end
View
4 spec/yell/adapters/streams_spec.rb
@@ -5,7 +5,7 @@
it { should be_kind_of Yell::Adapters::Io }
context :stream do
- subject { Yell::Adapters::Stdout.new.stream }
+ subject { Yell::Adapters::Stdout.new.send :stream }
it { should be_kind_of IO }
end
@@ -17,7 +17,7 @@
it { should be_kind_of Yell::Adapters::Io }
context :stream do
- subject { Yell::Adapters::Stderr.new.stream }
+ subject { Yell::Adapters::Stderr.new.send :stream }
it { should be_kind_of IO }
end

0 comments on commit bd0b44e

Please sign in to comment.
Something went wrong with that request. Please try again.