[DRE-commits] [ruby-yell] 01/03: Imported Upstream version 2.0.5

Michael Crusoe misterc-guest at moszumanska.debian.org
Wed Sep 30 06:37:09 UTC 2015


This is an automated email from the git hooks/post-receive script.

misterc-guest pushed a commit to branch master
in repository ruby-yell.

commit ea93ca102be93d294e34f896838d7e63393bb900
Author: Michael R. Crusoe <michael.crusoe at gmail.com>
Date:   Sun Sep 20 00:05:57 2015 -0700

    Imported Upstream version 2.0.5
---
 .gitignore                                         |  13 +
 .travis.yml                                        |  18 ++
 Gemfile                                            |  26 ++
 LICENSE.txt                                        |  21 ++
 README.md                                          | 219 +++++++++++++++++
 Rakefile                                           |  14 ++
 examples/001-basic-usage.rb                        |  25 ++
 examples/002.1-log-level-basics.rb                 |  25 ++
 .../002.2-log-level-on-certain-severities-only.rb  |  28 +++
 examples/002.3-log-level-within-range.rb           |  28 +++
 examples/003.1-formatting-DefaultFormat.rb         |  22 ++
 examples/003.2-formatting-BasicFormat.rb           |  22 ++
 examples/003.3-formatting-ExtendedFormat.rb        |  21 ++
 examples/003.4-formatting-on-your-own.rb           |  21 ++
 examples/004.1-colorizing-the-log-output.rb        |  23 ++
 examples/005.1-repository.rb                       |  21 ++
 examples/006.1-the-loggable-module.rb              |  37 +++
 .../006.2-the-loggable-module-with-inheritance.rb  |  41 ++++
 lib/core_ext/logger.rb                             |  18 ++
 lib/yell.rb                                        | 151 ++++++++++++
 lib/yell/adapters.rb                               |  88 +++++++
 lib/yell/adapters/base.rb                          | 231 ++++++++++++++++++
 lib/yell/adapters/datefile.rb                      | 194 +++++++++++++++
 lib/yell/adapters/file.rb                          |  36 +++
 lib/yell/adapters/io.rb                            | 102 ++++++++
 lib/yell/adapters/streams.rb                       |  32 +++
 lib/yell/configuration.rb                          |  25 ++
 lib/yell/event.rb                                  | 130 ++++++++++
 lib/yell/formatter.rb                              | 242 +++++++++++++++++++
 lib/yell/helpers/adapter.rb                        |  46 ++++
 lib/yell/helpers/base.rb                           |  19 ++
 lib/yell/helpers/formatter.rb                      |  32 +++
 lib/yell/helpers/level.rb                          |  40 +++
 lib/yell/helpers/silencer.rb                       |  31 +++
 lib/yell/helpers/tracer.rb                         |  48 ++++
 lib/yell/level.rb                                  | 214 ++++++++++++++++
 lib/yell/loggable.rb                               |  37 +++
 lib/yell/logger.rb                                 | 163 +++++++++++++
 lib/yell/repository.rb                             |  72 ++++++
 lib/yell/silencer.rb                               |  86 +++++++
 lib/yell/version.rb                                |   7 +
 metadata.yml                                       | 130 ++++++++++
 spec/compatibility/activesupport_logger_spec.rb    |  35 +++
 spec/compatibility/formatter_spec.rb               |  23 ++
 spec/compatibility/level_spec.rb                   |  18 ++
 spec/fixtures/yell.yml                             |   7 +
 spec/spec_helper.rb                                |  56 +++++
 spec/threaded/yell_spec.rb                         | 101 ++++++++
 spec/yell/adapters/base_spec.rb                    |  43 ++++
 spec/yell/adapters/datefile_spec.rb                | 168 +++++++++++++
 spec/yell/adapters/file_spec.rb                    |  75 ++++++
 spec/yell/adapters/io_spec.rb                      |  72 ++++++
 spec/yell/adapters/streams_spec.rb                 |  26 ++
 spec/yell/adapters_spec.rb                         |  45 ++++
 spec/yell/configuration_spec.rb                    |  36 +++
 spec/yell/dsl_spec.rb                              |  49 ++++
 spec/yell/event_spec.rb                            |  97 ++++++++
 spec/yell/formatter_spec.rb                        | 146 +++++++++++
 spec/yell/level_spec.rb                            | 200 +++++++++++++++
 spec/yell/loggable_spec.rb                         |  20 ++
 spec/yell/logger_spec.rb                           | 268 +++++++++++++++++++++
 spec/yell/repository_spec.rb                       |  70 ++++++
 spec/yell/silencer_spec.rb                         |  38 +++
 spec/yell_spec.rb                                  | 102 ++++++++
 yell.gemspec                                       |  23 ++
 65 files changed, 4517 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..effd518
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+pkg/*
+*.gem
+.bundle
+.idea
+
+# bundler
+Gemfile.lock
+
+# vim
+*.swp
+
+# coverage
+/coverage
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..1a83dfd
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+language: ruby
+
+script: "rspec"
+
+rvm:
+  - 1.8.7
+  - 1.9.3
+  - 2.0.0
+  - 2.1.1
+  - jruby-18mode
+  - jruby-19mode
+  - rbx-2
+  - ree
+
+notifications:
+  email:
+    - me at rudionrails.com
+
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..0f588d4
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,26 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in yell.gemspec
+gemspec
+
+group :development, :test do
+  gem "rake"
+
+  gem 'rspec-core', '~> 2'
+  gem 'rspec-expectations', '~> 2'
+  gem "rr"
+
+  if RUBY_VERSION < "1.9"
+    gem 'timecop', '0.6.0'
+    gem 'activesupport', '~> 3'
+  else
+    gem 'timecop'
+    gem 'activesupport'
+
+    gem 'pry'
+  end
+
+  gem 'simplecov', :require => false, :platform => :ruby_20
+  gem 'coveralls', :require => false, :platform => :ruby_20
+end
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..885a9a8
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,21 @@
+Copyright (c) 2011-2014 Rudolf Schmidt
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..602e0ee
--- /dev/null
+++ b/README.md
@@ -0,0 +1,219 @@
+# Yell [![Gem Version](https://badge.fury.io/rb/yell.png)](http://badge.fury.io/rb/yell) [![Build Status](https://travis-ci.org/rudionrails/yell.png?branch=master)](https://travis-ci.org/rudionrails/yell) [![Code Climate](https://codeclimate.com/github/rudionrails/yell.png)](https://codeclimate.com/github/rudionrails/yell) [![Coverage Status](https://coveralls.io/repos/rudionrails/yell/badge.png?branch=master)](https://coveralls.io/r/rudionrails/yell)
+
+
+**Yell - Your Extensible Logging Library** is a comprehensive logging replacement for Ruby.
+
+Yell works and is tested with ruby 1.8.7, 1.9.x, 2.0.0, jruby 1.8 and 1.9 mode, rubinius 1.8 and 1.9 as well as ree.
+
+If you want to conveniently use Yell with Rails, then head over to [yell-rails](https://github.com/rudionrails/yell-rails). You'll find all the documentation in this repository, though.
+
+
+## Installation
+
+System wide:
+
+```console
+gem install yell
+```
+
+Or in your Gemfile:
+
+```ruby
+gem "yell"
+```
+
+
+## Usage
+
+On the basics, you can use Yell just like any other logging library with a more 
+sophisticated message formatter.
+
+```ruby
+logger = Yell.new STDOUT
+
+logger.info "Hello World"
+#=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World"
+#    ^                         ^       ^       ^
+#    ISO8601 Timestamp         Level   Pid     Message
+```
+
+The strength of Yell, however, comes when using multiple adapters. The already built-in 
+ones are IO-based and require no further configuration. Also, there are additional ones 
+available as separate gems. Please consult the [wiki](https://github.com/rudionrails/yell/wiki) 
+on that - they are listed there.
+
+The standard adapters are:
+
+`:stdout` : Messages will be written to STDOUT  
+`:stderr` : Messages will be written to STDERR  
+`:file` : Messages will be written to a file  
+`:datefile` : Messages will be written to a timestamped file  
+
+
+Here are some short examples on how to combine them:
+
+##### Example: Notice messages go into `STDOUT` and error messages into `STDERR`
+
+```ruby
+logger = Yell.new do |l|
+  l.adapter STDOUT, level: [:debug, :info, :warn]
+  l.adapter STDERR, level: [:error, :fatal]
+end
+```
+
+##### Example: Typical production Logger
+
+We setup a logger that starts passing messages at the `:info` level. Severities 
+below `:error` go into the 'production.log', whereas anything higher is written 
+into the 'error.log'.
+
+```ruby
+logger = Yell.new do |l|
+  l.level = 'gte.info' # will only pass :info and above to the adapters
+
+  l.adapter :datefile, 'production.log', level: 'lte.warn' # anything lower or equal to :warn
+  l.adapter :datefile, 'error.log', level: 'gte.error' # anything greater or equal to :error
+end
+```
+
+##### Example: Typical production Logger for Heroku
+
+When deploying to Heroku, the "rails_log_stdout" gem gets injected to your Rails project.
+Yell does not need that when properly configured (see [yell-rails](https://github.com/rudionrails/yell-rails)
+for a more convenient integration with Rails).
+
+```ruby
+logger = Yell.new do |l|
+  l.level = 'gte.info'
+
+  l.adapter :stdout, level: 'lte.warn'
+  l.adapter :stderr, level: 'gte.error'
+end
+```
+
+### But I'm used to Log4r and I don't want to move on
+
+One of the really nice features of Log4r is its repository. The following example is 
+taken from the official Log4r [documentation](http://log4r.rubyforge.org/manual.html#outofbox).
+
+```ruby
+require 'log4r'
+include Log4r
+
+# create a logger named 'mylog' that logs to stdout
+mylog = Logger.new 'mylog'
+mylog.outputters = Outputter.stdout
+
+# later in the code, you can get the logger back
+Logger['mylog']
+```
+
+With Yell you can do the same thing with less:
+
+```ruby
+require 'yell'
+
+# create a logger named 'mylog' that logs to stdout
+Yell.new :stdout, name: 'mylog'
+
+# later in the code, you can get the logger back
+Yell['mylog']
+```
+
+There is no need to define outputters separately and you don't have to taint 
+you global namespace with Yell's subclasses.
+
+### Adding a logger to an existing class
+
+Yell comes with a simple module: +Yell::Loggable+. Simply include this in a class and 
+you are good to go.
+
+```ruby
+# Before you can use it, you will need to define a logger and 
+# provide it with the `:name` of your class.
+Yell.new :stdout, name: 'Foo'
+
+class Foo
+  include Yell::Loggable
+end
+
+# Now you can log
+Foo.logger.info "Hello World"
+Foo.new.logger.info "Hello World"
+```
+
+It even works with class inheritance:
+
+```ruby
+# Given the above example, we inherit from Foo
+class Bar < Foo
+end
+
+# The logger will fallback to the Foo superclass
+Bar.logger.info "Hello World"
+Bar.new.logger.info "Hello World"
+```
+
+### Adding a logger to all classes at once (global logger)
+
+Derived from the example above, simply do the following.
+
+```ruby
+# Define a logger and pass `Object` as name. Internally, Yell adds this
+# logger to the repository where you can access it later on.
+Yell.new :stdout, name: Object
+
+# Enable logging for the class that (almost) every Ruby class inherits from
+Object.send :include, Yell::Loggable
+
+# now you are good to go... from wherever you are
+logger.info "Hello from anything"
+Integer.logger.info "Hello from Integer"
+```
+
+### Suppress log messages with silencers
+
+In case you woul like to suppress certain log messages, you may define
+silencers with Yell. Use this to get control of a noisy log environment. For
+instance, you can suppress logging messages that contain secure information or
+more simply, to skip information about serving your Rails assets. Provide a
+string or a regular expression of the message patterns you would like to exclude.
+
+```ruby
+logger = Yell.new do |l|
+  l.silence /^Started GET "\/assets/
+  l.silence /^Served asset/
+end
+
+logger.debug 'Started GET "/assets/logo.png" for 127.0.0.1 at 2013-06-20 10:18:38 +0200'
+logger.debug 'Served asset /logo.png - 304 Not Modified (0ms)'
+```
+
+### Alter log messages with modifiers
+
+
+## Further Readings
+
+[How To: Setting The Log Level](https://github.com/rudionrails/yell/wiki/101-setting-the-log-level)  
+[How To: Formatting Log Messages](https://github.com/rudionrails/yell/wiki/101-formatting-log-messages)  
+[How To: Using Adapters](https://github.com/rudionrails/yell/wiki/101-using-adapters)  
+[How To: The Datefile Adapter](https://github.com/rudionrails/yell/wiki/101-the-datefile-adapter)  
+[How To: Different Adapters for Different Log Levels](https://github.com/rudionrails/yell/wiki/101-different-adapters-for-different-log-levels)  
+
+
+### Additional Adapters
+[Syslog](https://github.com/rudionrails/yell/wiki/additional-adapters-syslog)  
+[Graylog2 (GELF)](https://github.com/rudionrails/yell/wiki/additional-adapters-gelf)  
+[Fluentd](https://github.com/red5studios/yell-adapters-fluentd)  
+
+
+### Development
+
+[How To: Writing Your Own Adapter](https://github.com/rudionrails/yell/wiki/Writing-your-own-adapter)  
+
+You can find further examples and additional adapters in the [wiki](https://github.com/rudionrails/yell/wiki).
+or have a look into the examples folder.
+
+
+Copyright © 2011-2014 Rudolf Schmidt, released under the MIT license
+
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..d31c466
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,14 @@
+require 'bundler/gem_tasks'
+
+# Run stuff in the examples folder
+desc "Run examples"
+task :examples do
+  require 'benchmark'
+
+  seconds = Benchmark.realtime do
+    Dir[ './examples/*.rb' ].each { |file| puts "\n\n=== Running #{file} ==="; require file }
+  end
+
+  puts "\n\t[ Examples took #{seconds} seconds to run ]"
+end
+
diff --git a/examples/001-basic-usage.rb b/examples/001-basic-usage.rb
new file mode 100644
index 0000000..a982c28
--- /dev/null
+++ b/examples/001-basic-usage.rb
@@ -0,0 +1,25 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# On the basics, Yell works just like any other logging library. 
+#
+# However, it enriches your log messages to make it more readable. By default, 
+# it will format the given message as follows:
+
+logger = Yell.new STDOUT
+logger.info "Hello World!"
+
+#=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!"
+#    ^                         ^       ^       ^
+#    ISO8601 Timestamp         Level   Pid     Message
+
+
+EOS
+
+puts "=== actual example ==="
+logger = Yell.new STDOUT
+logger.info "Hello World!"
+
diff --git a/examples/002.1-log-level-basics.rb b/examples/002.1-log-level-basics.rb
new file mode 100644
index 0000000..e3da483
--- /dev/null
+++ b/examples/002.1-log-level-basics.rb
@@ -0,0 +1,25 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# Like many other logging libraries, Yell allows you to define from which level 
+# onwards you want to write your log message. 
+
+logger = Yell.new STDOUT, :level => :info
+
+logger.debug "This is a :debug message"
+#=> nil 
+
+logger.info "This is a :info message"
+#=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : This is a :info message"
+
+
+EOS
+
+puts "=== actual example ==="
+logger = Yell.new STDOUT, :level => :info
+
+logger.debug "This is a :debug message"
+logger.info "This is a :info message"
diff --git a/examples/002.2-log-level-on-certain-severities-only.rb b/examples/002.2-log-level-on-certain-severities-only.rb
new file mode 100644
index 0000000..05c9536
--- /dev/null
+++ b/examples/002.2-log-level-on-certain-severities-only.rb
@@ -0,0 +1,28 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# The Yell::Level parser allows you to exactly specify on which levels to log, 
+# ignoring all the others. For instance: If we want to only log at the :debug 
+# and :warn levels we simply providing an array:
+
+logger = Yell.new STDOUT, :level => [:debug, :warn]
+
+[:debug, :info, :warn, :error, :fatal].each do |level| 
+  logger.send( level, level )
+end
+#=> "2012-02-29T09:30:00+01:00 [DEBUG] 65784 : debug"
+#=> "2012-02-29T09:30:00+01:00 [ WARN] 65784 : warn"
+
+
+EOS
+
+puts "=== actual example ==="
+logger = Yell.new STDOUT, :level => [:debug, :warn]
+
+[:debug, :info, :warn, :error, :fatal].each do |level| 
+  logger.send( level, level )
+end
+
diff --git a/examples/002.3-log-level-within-range.rb b/examples/002.3-log-level-within-range.rb
new file mode 100644
index 0000000..81fa555
--- /dev/null
+++ b/examples/002.3-log-level-within-range.rb
@@ -0,0 +1,28 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# Additionally to writing only on specific levels, you may pass a range to 
+# the :level option:
+
+logger = Yell.new STDOUT, :level => (:debug..:warn)
+
+[:debug, :info, :warn, :error, :fatal].each do |level| 
+  logger.send( level, level )
+end
+#=> "2012-02-29T09:30:00+01:00 [DEBUG] 65784 : debug"
+#=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : info"
+#=> "2012-02-29T09:30:00+01:00 [ WARN] 65784 : warn"
+
+
+EOS
+
+puts "=== actuale example ==="
+logger = Yell.new STDOUT, :level => (:debug..:warn)
+
+[:debug, :info, :warn, :error, :fatal].each do |level| 
+  logger.send( level, level )
+end
+
diff --git a/examples/003.1-formatting-DefaultFormat.rb b/examples/003.1-formatting-DefaultFormat.rb
new file mode 100644
index 0000000..b597845
--- /dev/null
+++ b/examples/003.1-formatting-DefaultFormat.rb
@@ -0,0 +1,22 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# The default formatting string looks like: %d [%5L] %p : %m and is used when 
+# nothing else is defined.
+
+logger = Yell.new STDOUT, :format => Yell::DefaultFormat
+logger.info "Hello World!"
+#=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!"
+#    ^                         ^       ^       ^
+#    ISO8601 Timestamp         Level   Pid     Message
+
+
+EOS
+
+puts "=== actuale example ==="
+logger = Yell.new STDOUT, :format => Yell::DefaultFormat
+logger.info "Hello World!"
+
diff --git a/examples/003.2-formatting-BasicFormat.rb b/examples/003.2-formatting-BasicFormat.rb
new file mode 100644
index 0000000..8d1e159
--- /dev/null
+++ b/examples/003.2-formatting-BasicFormat.rb
@@ -0,0 +1,22 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# The basic formating string looks like: %l, %d: %m.
+
+logger = Yell.new STDOUT, :format => Yell::BasicFormat
+logger.info "Hello World!"
+#=> "I, 2012-02-29T09:30:00+01:00 : Hello World!"
+#    ^  ^                          ^
+#    ^  ISO8601 Timestamp          Message
+#    Level (short)
+
+
+EOS
+
+puts "=== actuale example ==="
+logger = Yell.new STDOUT, :format => Yell::BasicFormat
+logger.info "Hello World!"
+
diff --git a/examples/003.3-formatting-ExtendedFormat.rb b/examples/003.3-formatting-ExtendedFormat.rb
new file mode 100644
index 0000000..5bc919b
--- /dev/null
+++ b/examples/003.3-formatting-ExtendedFormat.rb
@@ -0,0 +1,21 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# The extended formatting string looks like: %d [%5L] %p %h : %m.
+
+logger = Yell.new STDOUT, :format => Yell::ExtendedFormat
+logger.info "Hello World!"
+#=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 localhost : Hello World!"
+#    ^                          ^      ^     ^           ^
+#    ISO8601 Timestamp          Level  Pid   Hostname    Message
+
+
+EOS
+
+puts "=== actuale example ==="
+logger = Yell.new STDOUT, :format => Yell::ExtendedFormat
+logger.info "Hello World!"
+
diff --git a/examples/003.4-formatting-on-your-own.rb b/examples/003.4-formatting-on-your-own.rb
new file mode 100644
index 0000000..33097c1
--- /dev/null
+++ b/examples/003.4-formatting-on-your-own.rb
@@ -0,0 +1,21 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# The extended formatting string looks like: %d [%5L] %p %h : %m.
+
+logger = Yell.new STDOUT, :format => "[%f:%n in `%M'] %m", :trace => true
+logger.info "Hello World!"
+#=> [003.4-formatting-on-your-own.rb:20 in `<main>'] Hello World!
+#    ^                               ^      ^        ^
+#    filename                        line   method   message
+
+
+EOS
+
+puts "=== actuale example ==="
+logger = Yell.new STDOUT, :format => "[%f:%n in `%M'] %m", :trace => true
+logger.info "Hello World!"
+
diff --git a/examples/004.1-colorizing-the-log-output.rb b/examples/004.1-colorizing-the-log-output.rb
new file mode 100644
index 0000000..13e784e
--- /dev/null
+++ b/examples/004.1-colorizing-the-log-output.rb
@@ -0,0 +1,23 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+You may colorize the log output on your io-based loggers loke so:
+
+logger = Yell.new STDOUT, :colors => true
+
+Yell::Severities.each do |level|
+  logger.send level.downcase, level
+end
+
+EOS
+
+puts "=== actuale example ==="
+logger = Yell.new STDOUT, :colors => true
+
+Yell::Severities.each do |level|
+  logger.send level.downcase, level
+end
+
diff --git a/examples/005.1-repository.rb b/examples/005.1-repository.rb
new file mode 100644
index 0000000..f17715a
--- /dev/null
+++ b/examples/005.1-repository.rb
@@ -0,0 +1,21 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# You can add a logger to the global repository.
+#
+# create a logger named 'mylog' that logs to stdout
+Yell.new :stdout, :name => 'mylog'
+
+# Later in the code, you can get your logger back
+Yell['mylog'].info "Hello World!"
+
+
+EOS
+
+puts "=== actuale example ==="
+Yell.new :stdout, :name => 'mylog'
+Yell['mylog'].info "Hello World!"
+
diff --git a/examples/006.1-the-loggable-module.rb b/examples/006.1-the-loggable-module.rb
new file mode 100644
index 0000000..7adc0b8
--- /dev/null
+++ b/examples/006.1-the-loggable-module.rb
@@ -0,0 +1,37 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# You can add logging to any class by including the Yell::Loggable module.
+#
+# When including the module, your class will get a :logger method. Before you
+# can use it, though, you will need to define a logger providing the :name of
+# your class.
+
+Yell.new :stdout, :name => 'Foo'
+
+# Define the class
+class Foo
+  include Yell::Loggable
+end
+
+foo = Foo.new
+foo.logger.info "Hello World!"
+#=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!"
+
+
+EOS
+
+puts "=== actual example ==="
+
+Yell.new :stdout, :name => 'Foo'
+
+class Foo
+  include Yell::Loggable
+end
+
+foo = Foo.new
+foo.logger.info "Hello World!"
+
diff --git a/examples/006.2-the-loggable-module-with-inheritance.rb b/examples/006.2-the-loggable-module-with-inheritance.rb
new file mode 100644
index 0000000..0c899c9
--- /dev/null
+++ b/examples/006.2-the-loggable-module-with-inheritance.rb
@@ -0,0 +1,41 @@
+# encoding: utf-8
+
+require_relative '../lib/yell'
+
+puts <<-EOS
+
+# You can add logging to any class by including the Yell::Loggable module.
+#
+# When including the module, your class will get a :logger method. Before you
+# can use it, though, you will need to define a logger providing the :name of
+# your class.
+
+Yell.new :stdout, :name => 'Foo'
+
+# Define the class
+class Foo
+  include Yell::Loggable
+end
+
+class Bar < Foo; end
+
+bar = Bar.new
+bar.logger.info "Hello World!"
+#=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!"
+
+
+EOS
+
+puts "=== actual example ==="
+
+Yell.new :stdout, :name => 'Foo'
+
+class Foo
+  include Yell::Loggable
+end
+
+class Bar < Foo; end
+
+bar = Bar.new
+bar.logger.info "Hello World!"
+
diff --git a/lib/core_ext/logger.rb b/lib/core_ext/logger.rb
new file mode 100644
index 0000000..3e1ddba
--- /dev/null
+++ b/lib/core_ext/logger.rb
@@ -0,0 +1,18 @@
+require 'logger'
+
+class Logger
+
+  def level_with_yell=( level )
+    self.level_without_yell= Integer(level)
+  end
+  alias_method :level_without_yell=, :level=
+  alias_method :level=, :level_with_yell=
+
+  def add_with_yell( severity, message = nil, progname = nil, &block )
+    add_without_yell(Integer(severity), message, progname, &block)
+  end
+  alias_method :add_without_yell, :add
+  alias_method :add, :add_with_yell
+
+end
+
diff --git a/lib/yell.rb b/lib/yell.rb
new file mode 100644
index 0000000..5c681e7
--- /dev/null
+++ b/lib/yell.rb
@@ -0,0 +1,151 @@
+# encoding: utf-8
+
+# Copyright (c) 2011-2014 Rudolf Schmidt
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module Yell #:nodoc:
+
+  # Holds all Yell severities
+  Severities = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'UNKNOWN'].freeze
+
+  class << self
+    # Creates a new logger instance.
+    #
+    # Refer to #Yell::Loggger for usage.
+    #
+    # @return [Yell::Logger] The logger instance
+    def new( *args, &block )
+      Yell::Logger.new(*args, &block)
+    end
+
+    # Shortcut to Yell::Level.new
+    #
+    # @return [Yell::Level] The level instance
+    def level( val = nil )
+      Yell::Level.new(val)
+    end
+
+    # Shortcut to Yell::Repository[]
+    #
+    # @return [Yell::Logger] The logger instance
+    def []( name )
+      Yell::Repository[name]
+    end
+
+    # Shortcut to Yell::Repository[]=
+    #
+    # @return [Yell::Logger] The logger instance
+    def []=( name, logger )
+      Yell::Repository[name] = logger
+    end
+
+    # Shortcut to Yell::Fomatter.new
+    #
+    # @return [Yell::Formatter] A Yell::Formatter instance
+    def format( pattern = nil, date_pattern = nil, &block )
+      Yell::Formatter.new(pattern, date_pattern, &block)
+    end
+
+    # Loads a config from a YAML file
+    #
+    # @return [Yell::Logger] The logger instance
+    def load!( file )
+      Yell.new Yell::Configuration.load!(file)
+    end
+
+    # Shortcut to Yell::Adapters.register
+    def register( name, klass )
+      Yell::Adapters.register(name, klass)
+    end
+
+    # @private
+    def env
+      return ENV['YELL_ENV']  if ENV.key? 'YELL_ENV'
+      return ENV['RACK_ENV']  if ENV.key? 'RACK_ENV'
+      return ENV['RAILS_ENV'] if ENV.key? 'RAILS_ENV'
+
+      if defined?(Rails)
+        Rails.env
+      else
+        'development'
+      end
+    end
+
+    # @private
+    def __deprecate__( version, message, options = {} ) #:nodoc:
+      messages = ["Deprecation Warning (since v#{version}): #{message}" ]
+      messages << "  before: #{options[:before]}" if options[:before]
+      messages << "  after:  #{options[:after]}" if options[:after]
+
+      __warn__(*messages)
+    end
+
+    # @private
+    def __warn__( *messages ) #:nodoc:
+      $stderr.puts "[Yell] " + messages.join("\n")
+    rescue Exception => e
+      # do nothing
+    end
+
+    # @private
+    def __fetch__( hash, *args )
+      options = args.last.is_a?(Hash) ? args.pop : {}
+      value = args.map { |key| hash.fetch(key.to_sym, hash[key.to_s]) }.compact.first
+
+      value.nil? ? options[:default] : value
+    end
+
+  end
+
+end
+
+# helpers
+require File.dirname(__FILE__) + '/yell/helpers/base'
+require File.dirname(__FILE__) + '/yell/helpers/adapter'
+require File.dirname(__FILE__) + '/yell/helpers/formatter'
+require File.dirname(__FILE__) + '/yell/helpers/level'
+require File.dirname(__FILE__) + '/yell/helpers/tracer'
+require File.dirname(__FILE__) + '/yell/helpers/silencer'
+
+# classes
+require File.dirname(__FILE__) + '/yell/configuration'
+require File.dirname(__FILE__) + '/yell/repository'
+require File.dirname(__FILE__) + '/yell/event'
+require File.dirname(__FILE__) + '/yell/level'
+require File.dirname(__FILE__) + '/yell/formatter'
+require File.dirname(__FILE__) + '/yell/silencer'
+require File.dirname(__FILE__) + '/yell/adapters'
+require File.dirname(__FILE__) + '/yell/logger'
+
+# modules
+require File.dirname(__FILE__) + '/yell/loggable'
+
+# core extensions
+require File.dirname(__FILE__) + '/core_ext/logger'
+
+# register known adapters
+Yell.register :null, Yell::Adapters::Base # adapter that does nothing (for convenience only)
+Yell.register :file, Yell::Adapters::File
+Yell.register :datefile, Yell::Adapters::Datefile
+Yell.register :stdout, Yell::Adapters::Stdout
+Yell.register :stderr, Yell::Adapters::Stderr
+
+
diff --git a/lib/yell/adapters.rb b/lib/yell/adapters.rb
new file mode 100644
index 0000000..4de0260
--- /dev/null
+++ b/lib/yell/adapters.rb
@@ -0,0 +1,88 @@
+# encoding: utf-8
+module Yell #:nodoc:
+
+  # AdapterNotFound is raised whenever you want to instantiate an 
+  # adapter that does not exist.
+  class AdapterNotFound < StandardError; end
+
+  # This module provides the interface to attaching adapters to
+  # the logger. You should not have to call the corresponding classes
+  # directly.
+  module Adapters
+
+    class Collection
+      def initialize( options = {} )
+        @options = options
+        @collection = []
+      end
+
+      def add( type = :file, *args, &block )
+        options = [@options, *args].inject(Hash.new) do |h, c|
+          h.merge( [String, Pathname].include?(c.class) ? {:filename => c} : c  )
+        end
+
+        # remove possible :null adapters
+        @collection.shift if @collection.first.instance_of?(Yell::Adapters::Base)
+
+        new_adapter = Yell::Adapters.new(type, options, &block)
+        @collection.push(new_adapter)
+
+        new_adapter
+      end
+
+      def empty?
+        @collection.empty?
+      end
+
+      # @private
+      def write( event )
+        @collection.each { |c| c.write(event) }
+        true
+      end
+
+      # @private
+      def close
+        @collection.each { |c| c.close }
+      end
+    end
+
+    # holds the list of known adapters
+    @adapters = {}
+
+    # Register your own adapter here
+    #
+    # @example
+    #   Yell::Adapters.register( :myadapter, MyAdapter )
+    def self.register( name, klass )
+      @adapters[name.to_sym] = klass
+    end
+
+    # Returns an instance of the given processor type.
+    #
+    # @example A simple file adapter
+    #   Yell::Adapters.new( :file )
+    def self.new( name, options = {}, &block )
+      return name if name.is_a?(Yell::Adapters::Base)
+
+      adapter = case name
+      when STDOUT then @adapters[:stdout]
+      when STDERR then @adapters[:stderr]
+      else @adapters[name.to_sym]
+      end
+
+      raise AdapterNotFound.new(name) if adapter.nil?
+      adapter.new(options, &block)
+    end
+
+  end
+end
+
+# Base for all adapters
+require File.dirname(__FILE__) + '/adapters/base'
+
+# IO based adapters
+require File.dirname(__FILE__) + '/adapters/io'
+require File.dirname(__FILE__) + '/adapters/streams'
+require File.dirname(__FILE__) + '/adapters/file'
+require File.dirname(__FILE__) + '/adapters/datefile'
+
diff --git a/lib/yell/adapters/base.rb b/lib/yell/adapters/base.rb
new file mode 100644
index 0000000..cd2ed35
--- /dev/null
+++ b/lib/yell/adapters/base.rb
@@ -0,0 +1,231 @@
+# encoding: utf-8
+
+require 'monitor'
+
+module Yell #:nodoc:
+  module Adapters #:nodoc:
+
+    # 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}.
+    #
+    # 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.call(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 < Monitor
+      include Yell::Helpers::Base
+      include Yell::Helpers::Level
+
+      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 open method with this helper.
+        #
+        # @example Open a file handle
+        #   open do
+        #     @stream = ::File.open( 'test.log', ::File::WRONLY|::File::APPEND|::File::CREAT )
+        #   end
+        def open( &block )
+          compile!(:open!, &block)
+        end
+
+        # Define your close method with this helper.
+        #
+        # @example Closing a file handle
+        #   close do
+        #     @stream.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
+          define!(name, _m, m, &block)
+        end
+
+        # Define instance method by given name and call the unbound
+        # methods in order with provided block.
+        def define!( name, _m, m, &block )
+          if block.arity == 0
+            define_method(name) do
+              _m.bind(self).call
+              m.bind(self).call
+            end
+          else
+            define_method(name) do |*args|
+              _m.bind(self).call(*args)
+              m.bind(self).call(*args)
+            end
+          end
+        end
+      end
+
+
+      # Initializes a new Adapter.
+      #
+      # You should not overload the constructor, use #setup instead.
+      def initialize( options = {}, &block )
+        super() # init the monitor superclass
+
+        reset!
+        setup!(options)
+
+        # eval the given block
+        block.arity > 0 ? block.call(self) : instance_eval(&block) if block_given?
+      end
+
+      # The main method for calling the adapter.
+      #
+      # The method receives the log `event` and determines whether to 
+      # actually write or not.
+      def write( event )
+        synchronize { write!(event) } if write?(event)
+      rescue Exception => e
+        # make sure the adapter is closed and re-raise the exception
+        synchronize { close }
+
+        raise(e)
+      end
+
+      # Close the adapter (stream, connection, etc).
+      #
+      # Adapter classes should provide their own implementation 
+      # of this method.
+      def close
+        close!
+      end
+
+      # Get a pretty string representation of the adapter, including
+      def inspect
+        inspection = inspectables.map { |m| "#{m}: #{send(m).inspect}" }
+        "#<#{self.class.name} #{inspection * ', '}>"
+      end
+
+
+      private
+
+      # Setup the adapter instance.
+      #
+      # Adapter classes should provide their own implementation 
+      # of this method (if applicable).
+      def setup!( options )
+        self.level = Yell.__fetch__(options, :level)
+      end
+
+      # Perform the actual write.
+      #
+      # Adapter classes must provide their own implementation 
+      # of this method.
+      def write!( event )
+        # Not implemented
+      end
+
+      # Perform the actual open.
+      #
+      # Adapter classes should provide their own implementation 
+      # of this method.
+      def open!
+        # 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.
+      #
+      # @example
+      #   write? Yell::Event.new( 'INFO', 'Hwllo Wold!' )
+      #
+      # @param [Yell::Event] event The log event
+      #
+      # @return [Boolean] true or false
+      def write?( event )
+        level.nil? || level.at?(event.level)
+      end
+
+      # Get an array of inspected attributes for the adapter.
+      def inspectables
+        [:level]
+      end
+
+    end
+
+  end
+end
+
diff --git a/lib/yell/adapters/datefile.rb b/lib/yell/adapters/datefile.rb
new file mode 100644
index 0000000..7b42be6
--- /dev/null
+++ b/lib/yell/adapters/datefile.rb
@@ -0,0 +1,194 @@
+# encoding: utf-8
+
+module Yell #:nodoc:
+  module Adapters #:nodoc:
+
+    # The +Datefile+ adapter is similar to the +File+ adapter. However, it
+    # rotates the file at midnight (by default).
+    class Datefile < Yell::Adapters::File
+
+      # The default date pattern, e.g. "19820114" (14 Jan 1982)
+      DefaultDatePattern = "%Y%m%d"
+
+      # Metadata
+      Header = lambda { |date, pattern| "# -*- #{date.iso8601} (#{date.to_f}) [#{pattern}] -*-" }
+      HeaderRegexp = /^# -\*- (.+) \((\d+\.\d+)\) \[(.+)\] -\*-$/
+
+      # The pattern to be used for the files
+      #
+      # @example
+      #   date_pattern = "%Y%m%d"       # default
+      #   date_pattern = "%Y-week-%V"
+      attr_accessor :date_pattern
+
+      # Tell the adapter to create a symlink onto the currently 
+      # active (timestamped) file. Upon rollover, the symlink is 
+      # set to the newly created file, and so on.
+      #
+      # @example
+      #   symlink = true
+      attr_accessor :symlink
+
+      # Set the amount of logfiles to keep when rolling over.
+      # By default, no files will be cleaned up.
+      #
+      # @example Keep the last 5 logfiles
+      #   keep = 5
+      #   keep = '10'
+      #
+      # @example Do not clean up any files
+      #   keep = 0
+      attr_accessor :keep
+
+      # You can suppress the first line of the logfile that contains
+      # the metadata. This is important upon rollover, because on *nix 
+      # systems, it is not possible to determine the creation time of a file, 
+      # on the last access time. The header compensates this.
+      #
+      # @example
+      #   header = false
+      attr_accessor :header
+
+
+      private
+
+      # @overload setup!( options )
+      def setup!( options )
+        self.header = Yell.__fetch__(options, :header, :default => true)
+        self.date_pattern = Yell.__fetch__(options, :date_pattern, :default => DefaultDatePattern)
+        self.keep = Yell.__fetch__(options, :keep, :default => false)
+        self.symlink = Yell.__fetch__(options, :symlink, :default => true)
+
+        @original_filename  = ::File.expand_path(Yell.__fetch__(options, :filename, :default => default_filename))
+        options[:filename]  = @original_filename
+
+        @date = Time.now
+        @date_strftime = @date.strftime(date_pattern)
+
+        super
+      end
+
+      # @overload write!( event )
+      def write!( event )
+        # do nothing when not closing
+        return super unless close?
+        close
+
+        # exit when file ready present
+        return super if ::File.exist?(@filename)
+
+        header! if header?
+        symlink! if symlink?
+        cleanup! if cleanup?
+
+        super
+      end
+
+      # @overload close!
+      def close!
+        @filename = filename_for(@date)
+
+        super
+      end
+
+      # Determine whether to close the file handle or not.
+      #
+      # It is based on the `:date_pattern` (can be passed as option upon initialize). 
+      # If the current time hits the pattern, it closes the file stream.
+      #
+      # @return [Boolean] true or false
+      def close?
+        _date           = Time.now
+        _date_strftime  = _date.strftime(date_pattern)
+
+        if @stream.nil? or _date_strftime != @date_strftime
+          @date, @date_strftime = _date, _date_strftime
+
+          return true
+        end
+
+        false
+      end
+
+      # Removes old logfiles of the same date pattern.
+      #
+      # By reading the header of the files that match the date pattern, the
+      # adapter determines whether to remove them or not. If no header is present, 
+      # it makes the best guess by checking the last access time (which may result 
+      # in false cleanups).
+      def cleanup!
+        files = Dir[ @original_filename.sub(/(\.\w+)?$/, ".*\\1") ].sort.select do |file|
+          _, pattern = header_from(file)
+
+          # Select if the date pattern is nil (no header info available within the file) or
+          # when the pattern matches.
+          pattern.nil? || pattern == self.date_pattern
+        end
+
+        ::File.unlink( *files[0..-keep-1] )
+      end
+
+      # Cleanup old logfiles?
+      #
+      # @return [Boolean] true or false
+      def cleanup?
+        !!keep && keep.to_i > 0
+      end
+
+      # Symlink the current filename to the original one.
+      def symlink!
+        # do nothing, because symlink is already correct
+        return if ::File.symlink?(@original_filename) && ::File.readlink(@original_filename) == @filename
+
+        ::File.unlink(@original_filename) if ::File.exist?(@original_filename) || ::File.symlink?(@original_filename)
+        ::File.symlink(@filename, @original_filename)
+      end
+
+      # Symlink the original filename?
+      #
+      # @return [Boolean] true or false
+      def symlink?
+        !!symlink
+      end
+
+      # Write the header information into the file
+      def header!
+        stream.puts( Header.call(@date, date_pattern) )
+      end
+
+      # Write header into the file?
+      #
+      # @return [Boolean] true or false
+      def header?
+        !!header
+      end
+
+      # Sets the filename with the `:date_pattern` appended to it.
+      def filename_for( date )
+        @original_filename.sub(/(\.\w+)?$/, ".#{date.strftime(date_pattern)}\\1")
+      end
+
+      # Fetch the header form the file
+      def header_from( file )
+        if m = ::File.open(file, &:readline).match(HeaderRegexp)
+          # in case there is a Header present, we can just read from it
+          [ Time.at(m[2].to_f), m[3] ]
+        else
+          # In case there is no header: we need to take a good guess
+          #
+          # Since the pattern can not be determined, we will just return the Posix ctime. 
+          # That is NOT the creatint time, so the value will potentially be wrong!
+          [::File.ctime(file), nil]
+        end
+      end
+
+      # @overload inspectables
+      def inspectables
+        super.concat [:date_pattern, :header, :keep, :symlink ]
+      end
+
+    end
+
+  end
+end
+
diff --git a/lib/yell/adapters/file.rb b/lib/yell/adapters/file.rb
new file mode 100644
index 0000000..76fd2e7
--- /dev/null
+++ b/lib/yell/adapters/file.rb
@@ -0,0 +1,36 @@
+# encoding: utf-8
+
+module Yell #:nodoc:
+  module Adapters #:nodoc:
+
+    # The +File+ adapter is the most basic. As one would expect, it's used 
+    # for logging into files.
+    class File < Yell::Adapters::Io
+
+      private
+
+      # @overload setup!( options )
+      def setup!( options )
+        @filename = ::File.expand_path(Yell.__fetch__(options, :filename, :default => default_filename))
+
+        super
+      end
+
+      # @overload open!
+      def open!
+        @stream = ::File.open(@filename, ::File::WRONLY|::File::APPEND|::File::CREAT)
+
+        super
+      end
+
+      def default_filename #:nodoc:
+        logdir = ::File.expand_path("log")
+
+        ::File.expand_path(::File.directory?(logdir) ? "#{logdir}/#{Yell.env}.log" : "#{Yell.env}.log")
+      end
+
+    end
+
+  end
+end
+
diff --git a/lib/yell/adapters/io.rb b/lib/yell/adapters/io.rb
new file mode 100644
index 0000000..904a873
--- /dev/null
+++ b/lib/yell/adapters/io.rb
@@ -0,0 +1,102 @@
+# encoding: utf-8
+
+module Yell #:nodoc:
+  module Adapters #:nodoc:
+
+    class Io < Yell::Adapters::Base
+      include Yell::Helpers::Formatter
+
+      # The possible unix log colors
+      TTYColors = {
+        0   => "\033[1;32m",  # green
+        1   => "\033[0m",     # normal
+        2   => "\033[1;33m",  # yellow
+        3   => "\033[1;31m",  # red
+        4   => "\033[1;35m",  # magenta
+        5   => "\033[1;36m",  # cyan
+        -1  => "\033[0m"      # normal
+      }
+
+      # Sets the “sync mode” to true or false.
+      #
+      # When true (default), every log event is immediately written to the file. 
+      # When false, the log event is buffered internally.
+      attr_accessor :sync
+
+      # Sets colored output on or off (default off)
+      #
+      # @example Enable colors
+      #   colors = true
+      #
+      # @example Disable colors
+      #   colors = false
+      attr_accessor :colors
+
+      # Shortcut to enable colors.
+      #
+      # @example
+      #   colorize!
+      def colorize!; @colors = true; end
+
+
+      private
+
+      # @overload setup!( options )
+      def setup!( options )
+        @stream = nil
+
+        self.colors = Yell.__fetch__(options, :colors, :default => false)
+        self.formatter = Yell.__fetch__(options, :format, :formatter)
+        self.sync = Yell.__fetch__(options, :sync, :default => true)
+
+        super
+      end
+
+      # @overload write!( event )
+      def write!( event )
+        message = formatter.call(event)
+
+        # colorize if applicable
+        if colors and color = TTYColors[event.level]
+          message = color + message + TTYColors[-1]
+        end
+
+        stream.syswrite(message)
+
+        super
+      end
+
+      # @overload open!
+      def open!
+        @stream.sync = self.sync if @stream.respond_to?(:sync)
+        @stream.flush if @stream.respond_to?(:flush)
+
+        super
+      end
+
+      # @overload close!
+      def close!
+        @stream.close if @stream.respond_to?(:close)
+        @stream = nil
+
+        super
+      end
+
+      # The IO stream
+      #
+      # Adapter classes should provide their own implementation 
+      # of this method.
+      def stream
+        synchronize { open! if @stream.nil?; @stream }
+      end
+
+      # @overload inspectables
+      def inspectables
+        super.concat [:formatter, :colors, :sync]
+      end
+
+    end
+
+  end
+end
+
diff --git a/lib/yell/adapters/streams.rb b/lib/yell/adapters/streams.rb
new file mode 100644
index 0000000..4532f83
--- /dev/null
+++ b/lib/yell/adapters/streams.rb
@@ -0,0 +1,32 @@
+# encoding: utf-8
+
+module Yell #:nodoc:
+  module Adapters #:nodoc:
+
+    class Stdout < Yell::Adapters::Io
+
+      private
+
+      # @overload open!
+      def open!
+        @stream = $stdout.clone
+        super
+      end
+
+    end
+
+    class Stderr < Yell::Adapters::Io
+
+      private
+
+      # @overload open!
+      def open!
+        @stream = $stderr.clone
+        super
+      end
+
+    end
+
+  end
+end
+
diff --git a/lib/yell/configuration.rb b/lib/yell/configuration.rb
new file mode 100644
index 0000000..44a810a
--- /dev/null
+++ b/lib/yell/configuration.rb
@@ -0,0 +1,25 @@
+# encoding: utf-8
+
+require 'erb'
+require 'yaml'
+
+module Yell #:nodoc:
+
+  # The Configuration can be used to setup Yell before
+  # initializing an instance.
+  class Configuration
+
+    def self.load!( file )
+      yaml = YAML.load( ERB.new(File.read(file)).result )
+
+      # in case we have ActiveSupport
+      if defined?(ActiveSupport::HashWithIndifferentAccess)
+        yaml = ActiveSupport::HashWithIndifferentAccess.new(yaml)
+      end
+
+      yaml[Yell.env] || {}
+    end
+
+  end
+end
+
diff --git a/lib/yell/event.rb b/lib/yell/event.rb
new file mode 100644
index 0000000..48c6f26
--- /dev/null
+++ b/lib/yell/event.rb
@@ -0,0 +1,130 @@
+# encoding: utf-8
+
+require 'time'
+require 'socket'
+
+module Yell #:nodoc:
+
+  # Yell::Event.new( :info, 'Hello World', { :scope => 'Application' } )
+  # #=> Hello World scope: Application
+  class Event
+    # regex to fetch caller attributes
+    CallerRegexp = /^(.+?):(\d+)(?::in `(.+)')?/
+
+    # jruby and rubinius seem to have a different caller
+    CallerIndex = defined?(RUBY_ENGINE) && ["rbx", "jruby"].include?(RUBY_ENGINE) ? 1 : 2
+
+
+    class Options
+      attr_reader :severity
+      attr_reader :caller_offset
+
+      def initialize( severity, caller_offset )
+        @severity = severity
+        @caller_offset = caller_offset
+      end
+
+      def <=>( other )
+        @severity <=> other
+      end
+
+      alias :to_i :severity
+      alias :to_int :severity
+    end
+
+    # Prefetch those values (no need to do that on every new instance)
+    @@hostname  = Socket.gethostname rescue nil
+    @@progname  = $0
+
+    # Accessor to the log level
+    attr_reader :level
+
+    # Accessor to the log message
+    attr_reader :messages
+
+    # Accessor to the time the log event occured
+    attr_reader :time
+
+    # Accessor to the logger's name
+    attr_reader :name
+
+
+    def initialize( logger, options, *messages)
+      @time = Time.now
+      @name = logger.name
+
+      extract!(options)
+
+      @messages = messages
+
+      @caller = logger.trace.at?(level) ? caller[caller_index].to_s : ''
+      @file = nil
+      @line = nil
+      @method = nil
+
+      @pid = nil
+    end
+
+    # Accessor to the hostname
+    def hostname
+      @@hostname
+    end
+
+    # Accessor to the progname
+    def progname
+      @@progname
+    end
+
+    # Accessor to the PID
+    def pid
+      Process.pid
+    end
+
+    # Accessor to the thread's id
+    def thread_id
+      Thread.current.object_id
+    end
+
+    # Accessor to filename the log event occured
+    def file
+      @file || (backtrace!; @file)
+    end
+
+    # Accessor to the line the log event occured
+    def line
+      @line || (backtrace!; @line)
+    end
+
+    # Accessor to the method the log event occured
+    def method
+      @method || (backtrace!; @method)
+    end
+
+
+    private
+
+    def extract!( options )
+      if options.is_a?(Yell::Event::Options)
+        @level = options.severity
+        @caller_offset = options.caller_offset
+      else
+        @level = options
+        @caller_offset = 0
+      end
+    end
+
+    def caller_index
+      CallerIndex + @caller_offset
+    end
+
+    def backtrace!
+      if m = CallerRegexp.match(@caller)
+        @file, @line, @method = m[1..-1]
+      else
+        @file, @line, @method = ['', '', '']
+      end
+    end
+
+  end
+end
+
diff --git a/lib/yell/formatter.rb b/lib/yell/formatter.rb
new file mode 100644
index 0000000..e98edd0
--- /dev/null
+++ b/lib/yell/formatter.rb
@@ -0,0 +1,242 @@
+# encoding: utf-8
+require 'time'
+
+# TODO: Register custom formats
+#
+# @example The Yell default fomat
+#   Yell::Formatter.register(:default)
+#
+# @example The Ruby standard logger format
+#   Yell::Formatter.register(:stdlogger, "%l, [%d #%p] %5L -- : %m", "%Y-%m-%dT%H:%M:%S.%6N")
+#
+module Yell #:nodoc:
+
+  # No format on the log message
+  #
+  # @example
+  #   logger = Yell.new STDOUT, :format => false
+  #   logger.info "Hello World!"
+  #   #=> "Hello World!"
+  NoFormat = "%m"
+
+  # Default Format
+  #
+  # @example
+  #   logger = Yell.new STDOUT, :format => Yell::DefaultFormat
+  #   logger.info "Hello World!"
+  #   #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World!"
+  #   #    ^                         ^       ^       ^
+  #   #    ISO8601 Timestamp         Level   Pid     Message
+  DefaultFormat = "%d [%5L] %p : %m"
+
+  # Basic Format
+  #
+  # @example
+  #   logger = Yell.new STDOUT, :format => Yell::BasicFormat
+  #   logger.info "Hello World!"
+  #   #=> "I, 2012-02-29T09:30:00+01:00 : Hello World!"
+  #   #    ^  ^                          ^
+  #   #    ^  ISO8601 Timestamp          Message
+  #   #    Level (short)
+  BasicFormat = "%l, %d : %m"
+
+  # Extended Format
+  #
+  # @example
+  #   logger = Yell.new STDOUT, :format => Yell::ExtendedFormat
+  #   logger.info "Hello World!"
+  #   #=> "2012-02-29T09:30:00+01:00 [ INFO] 65784 localhost : Hello World!"
+  #   #    ^                          ^      ^     ^           ^
+  #   #    ISO8601 Timestamp          Level  Pid   Hostname    Message
+  ExtendedFormat  = "%d [%5L] %p %h : %m"
+
+
+  # The +Formatter+ provides a handle to configure your log message style.
+  class Formatter
+
+    Table = {
+      "m" => "message(event.messages)",    # Message
+      "l" => "level(event.level, 1)",      # Level (short), e.g.'I', 'W'
+      "L" => "level(event.level)",         # Level, e.g. 'INFO', 'WARN'
+      "d" => "date(event.time)",           # ISO8601 Timestamp
+      "h" => "event.hostname",             # Hostname
+      "p" => "event.pid",                  # PID
+      "P" => "event.progname",             # Progname
+      "t" => "event.thread_id",            # Thread ID
+      "F" => "event.file",                 # Path with filename where the logger was called
+      "f" => "File.basename(event.file)",  # Filename where the loger was called
+      "M" => "event.method",               # Method name where the logger was called
+      "n" => "event.line",                 # Line where the logger was called
+      "N" => "event.name"                  # Name of the logger
+    }
+
+    # For standard formatted backwards compatibility
+    LegacyTable = Hash[ Table.keys.map { |k| [k, 'noop'] } ].merge(
+      'm' => 'message(msg)',
+      'l' => 'level(event, 1)',
+      'L' => 'level(event)',
+      'd' => 'date(time)',
+      "p" => "$$",
+      'P' => 'progname'
+    )
+
+    PatternMatcher = /([^%]*)(%\d*)?(#{Table.keys.join('|')})?(.*)/m
+
+
+    attr_reader :pattern, :date_pattern
+
+
+    # Initializes a new +Yell::Formatter+.
+    #
+    # Upon initialization it defines a format method. `format` takes
+    # a {Yell::Event} instance as agument in order to apply for desired log
+    # message formatting.
+    #
+    # @example Blank formatter
+    #   Formatter.new
+    #
+    # @example Formatter with a message pattern
+    #   Formatter.new("%d [%5L] %p : %m")
+    #
+    # @example Formatter with a message and date pattern
+    #   Formatter.new("%d [%5L] %p : %m", "%D %H:%M:%S.%L")
+    #
+    # @example Formatter with a message modifier
+    #   Formatter.new do |f|
+    #     f.modify(Hash) { |h| "Hash: #{h.inspect}" }
+    #   end
+    def initialize( *args, &block )
+      builder = Builder.new(*args, &block)
+
+      @pattern = builder.pattern
+      @date_pattern = builder.date_pattern
+      @modifier = builder.modifier
+
+      define_date_method!
+      define_call_method!
+    end
+
+    # Get a pretty string
+    def inspect
+      "#<#{self.class.name} pattern: #{@pattern.inspect}, date_pattern: #{@date_pattern.inspect}>"
+    end
+
+
+    private
+
+    # Message modifier class to allow different modifiers for different requirements.
+    class Modifier
+      def initialize
+        @repository = {}
+      end
+
+      def set( key, &block )
+        @repository.merge!(key => block)
+      end
+
+      def call( message )
+        case
+        when mod = @repository[message.class] || @repository[message.class.to_s]
+          mod.call(message)
+        when message.is_a?(Array)
+          message.map { |m| call(m) }.join(" ")
+        when message.is_a?(Hash)
+          message.map { |k, v| "#{k}: #{v}" }.join(", ")
+        when message.is_a?(Exception)
+          backtrace = message.backtrace ? "\n\t#{message.backtrace.join("\n\t")}" : ""
+          sprintf("%s: %s%s", message.class, message.message, backtrace)
+        else
+          message
+        end
+      end
+    end
+
+    # Builder class to allow setters that won't be accessible once
+    # transferred to the Formatter
+    class Builder
+      attr_accessor :pattern, :date_pattern
+      attr_reader :modifier
+
+      def initialize( pattern = nil, date_pattern = nil, &block )
+        @modifier = Modifier.new
+
+        @pattern = case pattern
+        when false then Yell::NoFormat
+        when nil then Yell::DefaultFormat
+        else pattern
+        end
+
+        @pattern << "\n" unless @pattern[-1] == ?\n # add newline if not present
+        @date_pattern = date_pattern || :iso8601
+
+        block.call(self) if block
+      end
+
+      def modify( key, &block )
+        modifier.set(key, &block)
+      end
+    end
+
+    def define_date_method!
+      buf = case @date_pattern
+      when String then "t.strftime(@date_pattern)"
+      when Symbol then respond_to?(@date_pattern, true) ? "#{@date_pattern}(t)" : "t.#{@date_pattern}"
+      else t.iso8601
+      end
+
+      # define the method
+      instance_eval <<-METHOD, __FILE__, __LINE__
+        def date(t = Time.now)
+          #{buf}
+        end
+       METHOD
+    end
+
+    # define a standard +Logger+ backwards compatible #call method for the formatter
+    def define_call_method!
+      instance_eval <<-METHOD, __FILE__, __LINE__
+        def call(event, time = nil, progname = nil, msg = nil)
+          event.is_a?(Yell::Event) ? #{to_sprintf(Table)} : #{to_sprintf(LegacyTable)}
+        end
+      METHOD
+    end
+
+    def to_sprintf( table )
+      buff, args, _pattern = "", [], @pattern.dup
+
+      while true
+        match = PatternMatcher.match(_pattern)
+
+        buff << match[1] unless match[1].empty?
+        break if match[2].nil?
+
+        buff << match[2] + 's'
+        args << table[ match[3] ]
+
+        _pattern = match[4]
+      end
+
+      %Q{sprintf("#{buff.gsub(/"/, '\"')}", #{args.join(', ')})}
+    end
+
+    def level( sev, length = nil )
+      severity = case sev
+      when Integer then Yell::Severities[sev] || 'ANY'
+      else sev
+      end
+
+      length.nil? ? severity : severity[0, length]
+    end
+
+    def message( messages )
+      @modifier.call(messages.is_a?(Array) && messages.size == 1 ? messages.first : messages)
+    end
+
+    # do nothing
+    def noop
+      ''
+    end
+
+  end
+end
+
diff --git a/lib/yell/helpers/adapter.rb b/lib/yell/helpers/adapter.rb
new file mode 100644
index 0000000..8fbe01c
--- /dev/null
+++ b/lib/yell/helpers/adapter.rb
@@ -0,0 +1,46 @@
+# encoding: utf-8
+module Yell #:nodoc:
+  module Helpers #:nodoc:
+    module Adapter #:nodoc:
+
+      # Define an adapter to be used for logging.
+      #
+      # @example Standard adapter
+      #   adapter :file
+      #
+      # @example Standard adapter with filename
+      #   adapter :file, 'development.log'
+      #
+      #   # Alternative notation for filename in options
+      #   adapter :file, :filename => 'developent.log'
+      #
+      # @example Standard adapter with filename and additional options
+      #   adapter :file, 'development.log', :level => :warn
+      #
+      # @example Set the adapter directly from an adapter instance
+      #   adapter Yell::Adapter::File.new
+      #
+      # @param [Symbol] type The type of the adapter, may be `:file` or `:datefile` (default `:file`)
+      # @return [Yell::Adapter] The instance
+      # @raise [Yell::NoSuchAdapter] Will be thrown when the adapter is not defined
+      def adapter( type = :file, *args, &block )
+        adapters.add(type, *args, &block)
+      end
+
+      def adapters
+        @__adapters__
+      end
+
+
+      private
+
+      def reset!
+        @__adapters__ = Yell::Adapters::Collection.new(@options)
+
+        super
+      end
+
+    end
+  end
+end
+
diff --git a/lib/yell/helpers/base.rb b/lib/yell/helpers/base.rb
new file mode 100644
index 0000000..d483c47
--- /dev/null
+++ b/lib/yell/helpers/base.rb
@@ -0,0 +1,19 @@
+# encoding: utf-8
+module Yell #:nodoc:
+  module Helpers #:nodoc:
+    module Base #:nodoc:
+
+      private
+
+      # stub
+      def reset!
+      end
+
+      def inspectables
+        []
+      end
+
+    end
+  end
+end
+
diff --git a/lib/yell/helpers/formatter.rb b/lib/yell/helpers/formatter.rb
new file mode 100644
index 0000000..c1c830d
--- /dev/null
+++ b/lib/yell/helpers/formatter.rb
@@ -0,0 +1,32 @@
+# encoding: utf-8
+module Yell #:nodoc:
+  module Helpers #:nodoc:
+    module Formatter #:nodoc:
+
+      # Set the format for your message.
+      def formatter=( pattern )
+        @__formatter__ = case pattern
+        when Yell::Formatter then pattern
+        else Yell::Formatter.new(*pattern)
+        end
+      end
+      alias :format= :formatter=
+
+      def formatter
+        @__formatter__
+      end
+      alias :format :formatter
+
+
+      private
+
+      def reset!
+        @__formatter__ = Yell::Formatter.new
+
+        super
+      end
+
+    end
+  end
+end
+
diff --git a/lib/yell/helpers/level.rb b/lib/yell/helpers/level.rb
new file mode 100644
index 0000000..9f63a65
--- /dev/null
+++ b/lib/yell/helpers/level.rb
@@ -0,0 +1,40 @@
+# encoding: utf-8
+module Yell #:nodoc:
+  module Helpers #:nodoc:
+    module Level
+
+      # Set the minimum log level.
+      #
+      # @example Set the level to :warn
+      #   level = :warn
+      #
+      # @param [String, Symbol, Integer] severity The minimum log level
+      def level=( severity )
+        @__level__ = case severity
+        when Yell::Level then severity
+        else Yell::Level.new(severity)
+        end
+      end
+
+      # @private
+      def level
+        @__level__
+      end
+
+
+      private
+
+      def reset!
+        @__level__ = Yell::Level.new
+
+        super
+      end
+
+      def inspectables
+        [:level] | super
+      end
+
+    end
+  end
+end
+
diff --git a/lib/yell/helpers/silencer.rb b/lib/yell/helpers/silencer.rb
new file mode 100644
index 0000000..669ec84
--- /dev/null
+++ b/lib/yell/helpers/silencer.rb
@@ -0,0 +1,31 @@
+# encoding: utf-8
+module Yell #:nodoc:
+  module Helpers #:nodoc:
+    module Silencer
+
+      # Set the silence pattern
+      def silence( *patterns )
+        silencer.add(*patterns)
+      end
+
+      def silencer
+        @__silencer__
+      end
+
+
+      private
+
+      def reset!
+        @__silencer__ = Yell::Silencer.new
+
+        super
+      end
+
+      def silence!( *messages )
+        @__silencer__.silence!(*messages) if silencer.silence?
+      end
+
+    end
+  end
+end
+
diff --git a/lib/yell/helpers/tracer.rb b/lib/yell/helpers/tracer.rb
new file mode 100644
index 0000000..d1fad15
--- /dev/null
+++ b/lib/yell/helpers/tracer.rb
@@ -0,0 +1,48 @@
+# encoding: utf-8
+module Yell #:nodoc:
+  module Helpers #:nodoc:
+    module Tracer #:nodoc:
+
+      # Set whether the logger should allow tracing or not. The trace option
+      # will tell the logger when to provider caller information.
+      #
+      # @example No tracing at all
+      #   trace = false
+      #
+      # @example Trace every time
+      #   race = true
+      #
+      # @example Trace from the error level onwards
+      #   trace = :error
+      #   trace = 'gte.error'
+      #
+      # @return [Yell::Level] a level representation of the tracer
+      def trace=( severity )
+        @__trace__ = case severity
+        when Yell::Level then severity
+        when false then Yell::Level.new("gt.#{Yell::Severities.last}")
+        else Yell::Level.new(severity)
+        end
+      end
+
+      def trace
+        @__trace__
+      end
+
+
+      private
+
+      def reset!
+        @__trace__ = Yell::Level.new('gte.error')
+
+        super
+      end
+
+      def inspectables
+        [:trace] | super
+      end
+
+    end
+  end
+end
+
diff --git a/lib/yell/level.rb b/lib/yell/level.rb
new file mode 100644
index 0000000..e47c283
--- /dev/null
+++ b/lib/yell/level.rb
@@ -0,0 +1,214 @@
+# encoding: utf-8
+
+module Yell #:nodoc:
+
+  # The +Level+ class handles the severities for you in order to determine 
+  # if an adapter should log or not.
+  #
+  # In order to setup your level, you have certain modifiers available:
+  #   at :warn    # will be set to :warn level only
+  #   gt :warn    # Will set from :error level onwards
+  #   gte :warn   # Will set from :warn level onwards
+  #   lt :warn    # Will set from :info level an below
+  #   lte :warn   # Will set from :warn level and below
+  #
+  # You are able to combine those modifiers to your convenience.
+  #
+  # @example Set from :info to :error (including)
+  #   Yell::Level.new(:info).lte(:error)
+  #
+  # @example Set from :info to :error (excluding)
+  #   Yell::Level.new(:info).lt(:error)
+  #
+  # @example Set at :info only
+  #   Yell::Level.new.at(:info)
+  class Level
+    include Comparable
+
+    InterpretRegexp = /(at|gt|gte|lt|lte)?\.?(#{Yell::Severities.join('|')})/i
+
+    # Create a new level instance.
+    #
+    # @example Enable all severities
+    #   Yell::Level.new
+    #
+    # @example Pass the minimum possible severity
+    #   Yell::Level.new :warn
+    #
+    # @example Pass an array to exactly set the level at the given severities
+    #   Yell::Level.new [:info, :error]
+    #
+    # @example Pass a range to set the level within the severities
+    #   Yell::Level.new (:info..:error)
+    #
+    # @param [Integer,String,Symbol,Array,Range,nil] severity The severity for the level.
+    def initialize( *severities )
+      set(*severities)
+    end
+
+    # Set the severity to the given format
+    def set( *severities )
+      @severities = Yell::Severities.map { true }
+      severity = severities.length > 1 ? severities : severities.first
+
+      case severity
+      when Array then at(*severity)
+      when Range then gte(severity.first).lte(severity.last)
+      when String then interpret(severity)
+      when Integer, Symbol then gte(severity)
+      when Yell::Level then @severities = severity.severities
+      end
+    end
+
+    # Returns whether the level is allowed at the given severity
+    #
+    # @example
+    #   at? :warn
+    #   at? 0       # debug
+    #
+    # @return [Boolean] tru or false
+    def at?( severity )
+      index = index_from(severity)
+
+      index.nil? ? false : @severities[index]
+    end
+
+    # Set the level at specific severities
+    #
+    # @example Set at :debug and :error only
+    #   at :debug, :error
+    #
+    # @return [Yell::Level] the instance
+    def at( *severities )
+      severities.each { |severity| calculate! :==, severity }
+      self
+    end
+
+    # Set the level to greater than the given severity
+    #
+    # @example Set to :error and above
+    #   gt :warn
+    #
+    # @return [Yell::Level] the instance
+    def gt( severity )
+      calculate! :>, severity
+      self
+    end
+
+    # Set the level greater or equal to the given severity
+    #
+    # @example Set to :warn and above
+    #   gte :warn
+    #
+    # @return [Yell::Level] the instance
+    def gte( severity )
+      calculate! :>=, severity
+      self
+    end
+
+    # Set the level lower than given severity
+    #
+    # @example Set to lower than :warn
+    #   lt :warn
+    #
+    # @return [Yell::Level] the instance
+    def lt( severity )
+      calculate! :<, severity
+      self
+    end
+
+    # Set the level lower or equal than given severity
+    #
+    # @example Set to lower or equal than :warn
+    #   lte :warn
+    #
+    # @return [Yell::Level] the instance
+    def lte( severity )
+      calculate! :<=, severity
+      self
+    end
+
+    # to_i implements backwards compatibility
+    def to_i
+      @severities.each_with_index { |s,i| return i if s == true }
+    end
+    alias :to_int :to_i
+
+    # Get a pretty string representation of the level, including the severities.
+    def inspect
+      inspectables = Yell::Severities.select.with_index { |l, i| !!@severities[i] }
+      "#<#{self.class.name} severities: #{inspectables * ', '}>"
+    end
+
+    # @private
+    def severities
+      @severities
+    end
+
+    # @private
+    def ==(other)
+      other.respond_to?(:severities) ? severities == other.severities : super
+    end
+
+    # @private
+    def <=>( other )
+      other.is_a?(Numeric) ? to_i <=> other : super
+    end
+
+
+    private
+
+    def interpret( severities )
+      severities.split( ' ' ).each do |severity|
+        if m = InterpretRegexp.match(severity)
+          m[1].nil? ? __send__( :gte, m[2] ) : __send__( m[1], m[2] )
+        end
+      end
+    end
+
+    def calculate!( modifier, severity )
+      index = index_from(severity)
+      return if index.nil?
+
+      case modifier
+      when :>   then ascending!( index+1 )
+      when :>=  then ascending!( index )
+      when :<   then descending!( index-1 )
+      when :<=  then descending!( index )
+      else set!( index ) # :==
+      end
+
+      taint unless tainted?
+    end
+
+    def index_from( severity )
+      case severity
+      when String, Symbol then Yell::Severities.index(severity.to_s.upcase)
+      else Integer(severity)
+      end
+    end
+
+    def ascending!( index )
+      each { |s, i| @severities[i] = i < index ? false : true }
+    end
+
+    def descending!( index )
+      each { |s, i| @severities[i] = index < i ? false : true }
+    end
+
+    def each
+      @severities.each_with_index do |s, i|
+        next if s == false # skip
+
+        yield(s, i)
+      end
+    end
+
+    def set!( index, val = true )
+      @severities.map! { false } unless tainted?
+
+      @severities[index] = val
+    end
+
+  end
+end
diff --git a/lib/yell/loggable.rb b/lib/yell/loggable.rb
new file mode 100644
index 0000000..05ae0bf
--- /dev/null
+++ b/lib/yell/loggable.rb
@@ -0,0 +1,37 @@
+# encoding: utf-8
+
+module Yell #:nodoc:
+
+  # Include this module to add a logger to any class.
+  #
+  # When including this module, your class will have a :logger instance method 
+  # available. Before you can use it, you will need to define a Yell logger and 
+  # provide it with the name of your class.
+  #
+  # @example
+  #   Yell.new :stdout, :name => 'Foo'
+  #
+  #   class Foo
+  #     include Yell::Loggable
+  #   end
+  #
+  #   Foo.new.logger.info "Hello World"
+  module Loggable
+
+    def self.included(base)
+      base.extend(ClassMethods)
+    end
+
+    module ClassMethods
+      def logger
+        Yell[self]
+      end
+    end
+
+    def logger
+      self.class.logger
+    end
+
+  end
+end
+
diff --git a/lib/yell/logger.rb b/lib/yell/logger.rb
new file mode 100644
index 0000000..30bb7ee
--- /dev/null
+++ b/lib/yell/logger.rb
@@ -0,0 +1,163 @@
+# encoding: utf-8
+
+require 'pathname'
+
+module Yell #:nodoc:
+
+  # The +Yell::Logger+ is your entrypoint. Anything onwards is derived from here.
+  #
+  # A +Yell::Logger+ instance holds all your adapters and sends the log events
+  # to them if applicable. There are multiple ways of how to create a new logger.
+  class Logger
+    include Yell::Helpers::Base
+    include Yell::Helpers::Level
+    include Yell::Helpers::Formatter
+    include Yell::Helpers::Adapter
+    include Yell::Helpers::Tracer
+    include Yell::Helpers::Silencer
+
+    # The name of the logger instance
+    attr_reader :name
+
+    # Initialize a new Logger
+    #
+    # @example A standard file logger
+    #   Yell::Logger.new 'development.log'
+    #
+    # @example A standard datefile logger
+    #   Yell::Logger.new :datefile
+    #   Yell::Logger.new :datefile, 'development.log'
+    #
+    # @example Setting the log level
+    #   Yell::Logger.new :level => :warn
+    #
+    #   Yell::Logger.new do |l|
+    #     l.level = :warn
+    #   end
+    #
+    # @example Combined settings
+    #   Yell::Logger.new 'development.log', :level => :warn
+    #
+    #   Yell::Logger.new :datefile, 'development.log' do |l|
+    #     l.level = :info
+    #   end
+    def initialize( *args, &block )
+      # extract options
+      @options = args.last.is_a?(Hash) ? args.pop : {}
+
+      # check if filename was given as argument and put it into the @options
+      if [String, Pathname].include?(args.last.class)
+        @options[:filename] = args.pop unless @options[:filename]
+      end
+
+      reset!
+
+      # FIXME: :format is deprecated in future versions --R
+      self.formatter = Yell.__fetch__(@options, :format, :formatter)
+      self.level = Yell.__fetch__(@options, :level, :default => 0)
+      self.name = Yell.__fetch__(@options, :name)
+      self.trace = Yell.__fetch__(@options, :trace, :default => :error)
+
+      # silencer
+      self.silence(*Yell.__fetch__(@options, :silence, :default => []))
+
+      # adapters may be passed in the options
+      extract!(*Yell.__fetch__(@options, :adapters, :default => []))
+
+      # extract adapter
+      self.adapter(args.pop) if args.any?
+
+      # eval the given block
+      block.arity > 0 ? block.call(self) : instance_eval(&block) if block_given?
+
+      # default adapter when none defined
+      self.adapter(:file) if adapters.empty?
+    end
+
+
+    # Set the name of a logger. When providing a name, the logger will
+    # automatically be added to the Yell::Repository.
+    #
+    # @return [String] The logger's name
+    def name=( val )
+      Yell::Repository[val] = self if val
+      @name = val.nil? ? "<#{self.class.name}##{object_id}>": val
+
+      @name
+    end
+
+    # Somewhat backwards compatible method (not fully though)
+    def add( options, *messages, &block )
+      return false unless level.at?(options)
+
+      messages = messages
+      messages << block.call unless block.nil?
+      messages = silencer.call(*messages)
+      return false if messages.empty?
+
+      event = Yell::Event.new(self, options, *messages)
+      write(event)
+    end
+
+    # Creates instance methods for every log level:
+    #   `debug` and `debug?`
+    #   `info` and `info?`
+    #   `warn` and `warn?`
+    #   `error` and `error?`
+    #   `unknown` and `unknown?`
+    Yell::Severities.each_with_index do |s, index|
+      name = s.downcase
+
+      class_eval <<-EOS, __FILE__, __LINE__ + index
+        def #{name}?; level.at?(#{index}); end            # def info?; level.at?(1); end
+                                                          #
+        def #{name}( *m, &b )                             # def info( *m, &b )
+          options = Yell::Event::Options.new(#{index}, 1)
+          add(options, *m, &b)                            #   add(Yell::Event::Options.new(1, 1), *m, &b)
+        end                                               # end
+      EOS
+    end
+
+    # Get a pretty string representation of the logger.
+    def inspect
+      inspection = inspectables.map { |m| "#{m}: #{send(m).inspect}" }
+      "#<#{self.class.name} #{inspection * ', '}>"
+    end
+
+    # @private
+    def close
+      adapters.close
+    end
+
+    # @private
+    def write( event )
+      adapters.write(event)
+    end
+
+    private
+
+    # The :adapters key may be passed to the options hash. It may appear in
+    # multiple variations:
+    #
+    # @example
+    #   extract!(:stdout, :stderr)
+    #
+    # @example
+    #   extract!(:stdout => {:level => :info}, :stderr => {:level => :error})
+    def extract!( *adapters )
+      adapters.each do |a|
+        case a
+        when Hash then a.each { |t, o| adapter(t, o) }
+        else adapter(a)
+        end
+      end
+    end
+
+    # Get an array of inspected attributes for the adapter.
+    def inspectables
+      [:name] | super
+    end
+
+  end
+end
+
diff --git a/lib/yell/repository.rb b/lib/yell/repository.rb
new file mode 100644
index 0000000..5461e2a
--- /dev/null
+++ b/lib/yell/repository.rb
@@ -0,0 +1,72 @@
+# encoding: utf-8
+
+require 'monitor'
+require "singleton"
+
+module Yell #:nodoc:
+
+  class LoggerNotFound < StandardError
+    def message; "Could not find a Yell::Logger instance with the name '#{super}'"; end
+  end
+
+  class Repository
+    extend MonitorMixin
+    include Singleton
+
+    def initialize
+      @loggers = {}
+    end
+
+    # Set loggers in the repository
+    #
+    # @example Set a logger
+    #   Yell::Repository[ 'development' ] = Yell::Logger.new :stdout
+    #
+    # @return [Yell::Logger] The logger instance
+    def self.[]=( name, logger )
+      synchronize { instance.loggers[name] = logger }
+    end
+
+    # Get loggers from the repository
+    #
+    # @example Get the logger
+    #   Yell::Repository[ 'development' ]
+    #
+    # @raise [Yell::LoggerNotFound] Raised when repository does not have that key
+    # @return [Yell::Logger] The logger instance
+    def self.[]( name )
+      synchronize { instance.__fetch__(name) or raise Yell::LoggerNotFound.new(name) }
+    end
+
+    # Get the list of all loggers in the repository
+    #
+    # @return [Hash] The map of loggers
+    def self.loggers
+      synchronize { instance.loggers }
+    end
+
+    # @private
+    def loggers
+      @loggers
+    end
+
+    # @private
+    #
+    # Fetch the logger by the given name.
+    #
+    # If the logger could not be found and has a superclass, it 
+    # will attempt to look there. This is important for the 
+    # Yell::Loggable module.
+    def __fetch__( name )
+      logger = loggers[name] || loggers[name.to_s]
+
+      if logger.nil? && name.respond_to?(:superclass)
+        return __fetch__(name.superclass)
+      end
+
+      logger
+    end
+
+  end
+end
+
diff --git a/lib/yell/silencer.rb b/lib/yell/silencer.rb
new file mode 100644
index 0000000..e371bbd
--- /dev/null
+++ b/lib/yell/silencer.rb
@@ -0,0 +1,86 @@
+# encoding: utf-8
+module Yell #:nodoc:
+
+  # The +Yell::Silencer+ is your handly helper for stiping out unwanted log messages.
+  class Silencer
+
+    class PresetNotFound < StandardError
+      def message; "Could not find a preset for #{super.inspect}"; end
+    end
+
+    Presets = {
+      :assets => [/\AStarted GET "\/assets/, /\AServed asset/, /\A\s*\z/] # for Rails
+    }
+
+
+    def initialize( *patterns )
+      @patterns = patterns.dup
+    end
+
+    # Add one or more patterns to the silencer
+    #
+    # @example
+    #   add( 'password' )
+    #   add( 'username', 'password' )
+    #
+    # @example Add regular expressions
+    #   add( /password/ )
+    #
+    # @return [self] The silencer instance
+    def add( *patterns )
+      patterns.each { |pattern| add!(pattern) }
+
+      self
+    end
+
+    # Clears out all the messages that would match any defined pattern
+    #
+    # @example
+    #   call(['username', 'password'])
+    #   #=> ['username]
+    #
+    # @return [Array] The remaining messages
+    def call( *messages )
+      return messages if @patterns.empty?
+
+      messages.reject { |m| matches?(m) }
+    end
+
+    # Get a pretty string
+    def inspect
+      "#<#{self.class.name} patterns: #{@patterns.inspect}>"
+    end
+
+    # @private
+    def patterns
+      @patterns
+    end
+
+
+    private
+
+    def add!( pattern )
+      @patterns = @patterns | fetch(pattern)
+    end
+
+    def fetch( pattern )
+      case pattern
+      when Symbol then Presets[pattern] or raise PresetNotFound.new(pattern)
+      else [pattern]
+      end
+    end
+
+    # Check if the provided message matches any of the defined patterns.
+    #
+    # @example
+    #   matches?('password')
+    #   #=> true
+    #
+    # @return [Boolean] true or false
+    def matches?( message )
+      @patterns.any? { |pattern| message.respond_to?(:match) && message.match(pattern) }
+    end
+
+  end
+end
+
diff --git a/lib/yell/version.rb b/lib/yell/version.rb
new file mode 100644
index 0000000..3bdbd3d
--- /dev/null
+++ b/lib/yell/version.rb
@@ -0,0 +1,7 @@
+# encoding: utf-8
+
+module Yell #:nodoc:
+  VERSION = "2.0.5"
+
+end
+
diff --git a/metadata.yml b/metadata.yml
new file mode 100644
index 0000000..cffbf32
--- /dev/null
+++ b/metadata.yml
@@ -0,0 +1,130 @@
+--- !ruby/object:Gem::Specification
+name: yell
+version: !ruby/object:Gem::Version
+  version: 2.0.5
+platform: ruby
+authors:
+- Rudolf Schmidt
+autorequire: 
+bindir: bin
+cert_chain: []
+date: 2014-10-14 00:00:00.000000000 Z
+dependencies: []
+description: Yell - Your Extensible Logging Library. Define multiple adapters, various
+  log level combinations or message formatting options like you've never done before
+email: 
+executables: []
+extensions: []
+extra_rdoc_files: []
+files:
+- ".gitignore"
+- ".travis.yml"
+- Gemfile
+- LICENSE.txt
+- README.md
+- Rakefile
+- examples/001-basic-usage.rb
+- examples/002.1-log-level-basics.rb
+- examples/002.2-log-level-on-certain-severities-only.rb
+- examples/002.3-log-level-within-range.rb
+- examples/003.1-formatting-DefaultFormat.rb
+- examples/003.2-formatting-BasicFormat.rb
+- examples/003.3-formatting-ExtendedFormat.rb
+- examples/003.4-formatting-on-your-own.rb
+- examples/004.1-colorizing-the-log-output.rb
+- examples/005.1-repository.rb
+- examples/006.1-the-loggable-module.rb
+- examples/006.2-the-loggable-module-with-inheritance.rb
+- lib/core_ext/logger.rb
+- lib/yell.rb
+- lib/yell/adapters.rb
+- lib/yell/adapters/base.rb
+- lib/yell/adapters/datefile.rb
+- lib/yell/adapters/file.rb
+- lib/yell/adapters/io.rb
+- lib/yell/adapters/streams.rb
+- lib/yell/configuration.rb
+- lib/yell/event.rb
+- lib/yell/formatter.rb
+- lib/yell/helpers/adapter.rb
+- lib/yell/helpers/base.rb
+- lib/yell/helpers/formatter.rb
+- lib/yell/helpers/level.rb
+- lib/yell/helpers/silencer.rb
+- lib/yell/helpers/tracer.rb
+- lib/yell/level.rb
+- lib/yell/loggable.rb
+- lib/yell/logger.rb
+- lib/yell/repository.rb
+- lib/yell/silencer.rb
+- lib/yell/version.rb
+- spec/compatibility/activesupport_logger_spec.rb
+- spec/compatibility/formatter_spec.rb
+- spec/compatibility/level_spec.rb
+- spec/fixtures/yell.yml
+- spec/spec_helper.rb
+- spec/threaded/yell_spec.rb
+- spec/yell/adapters/base_spec.rb
+- spec/yell/adapters/datefile_spec.rb
+- spec/yell/adapters/file_spec.rb
+- spec/yell/adapters/io_spec.rb
+- spec/yell/adapters/streams_spec.rb
+- spec/yell/adapters_spec.rb
+- spec/yell/configuration_spec.rb
+- spec/yell/dsl_spec.rb
+- spec/yell/event_spec.rb
+- spec/yell/formatter_spec.rb
+- spec/yell/level_spec.rb
+- spec/yell/loggable_spec.rb
+- spec/yell/logger_spec.rb
+- spec/yell/repository_spec.rb
+- spec/yell/silencer_spec.rb
+- spec/yell_spec.rb
+- yell.gemspec
+homepage: http://rudionrailspec.github.com/yell
+licenses:
+- MIT
+metadata: {}
+post_install_message: 
+rdoc_options: []
+require_paths:
+- lib
+required_ruby_version: !ruby/object:Gem::Requirement
+  requirements:
+  - - ">="
+    - !ruby/object:Gem::Version
+      version: '0'
+required_rubygems_version: !ruby/object:Gem::Requirement
+  requirements:
+  - - ">="
+    - !ruby/object:Gem::Version
+      version: '0'
+requirements: []
+rubyforge_project: yell
+rubygems_version: 2.2.2
+signing_key: 
+specification_version: 4
+summary: Yell - Your Extensible Logging Library
+test_files:
+- spec/compatibility/activesupport_logger_spec.rb
+- spec/compatibility/formatter_spec.rb
+- spec/compatibility/level_spec.rb
+- spec/fixtures/yell.yml
+- spec/spec_helper.rb
+- spec/threaded/yell_spec.rb
+- spec/yell/adapters/base_spec.rb
+- spec/yell/adapters/datefile_spec.rb
+- spec/yell/adapters/file_spec.rb
+- spec/yell/adapters/io_spec.rb
+- spec/yell/adapters/streams_spec.rb
+- spec/yell/adapters_spec.rb
+- spec/yell/configuration_spec.rb
+- spec/yell/dsl_spec.rb
+- spec/yell/event_spec.rb
+- spec/yell/formatter_spec.rb
+- spec/yell/level_spec.rb
+- spec/yell/loggable_spec.rb
+- spec/yell/logger_spec.rb
+- spec/yell/repository_spec.rb
+- spec/yell/silencer_spec.rb
+- spec/yell_spec.rb
diff --git a/spec/compatibility/activesupport_logger_spec.rb b/spec/compatibility/activesupport_logger_spec.rb
new file mode 100644
index 0000000..7ff24ae
--- /dev/null
+++ b/spec/compatibility/activesupport_logger_spec.rb
@@ -0,0 +1,35 @@
+# encoding: utf-8
+require 'spec_helper'
+
+begin
+  require 'active_support'
+rescue LoadError
+end
+
+# make a setup just like in railties ~> 4.0.0
+#
+# We simulate the case when Rails 4 starts up its server
+# and wants to append the log output.
+describe "Compatibility to ActiveSupport::Logger", :pending => (!defined?(ActiveSupport) || ActiveSupport::VERSION::MAJOR < 4) do
+
+  let!(:yell) { Yell.new($stdout, :format => "%m") }
+
+  let!(:logger) do
+    console = ActiveSupport::Logger.new($stdout)
+    console.formatter = yell.formatter
+    console.level = yell.level
+
+    yell.extend(ActiveSupport::Logger.broadcast(console))
+
+    console
+  end
+
+  it "should behave correctly" do
+    mock($stdout).syswrite("Hello World\n") # yell
+    mock($stdout).write("Hello World\n") # logger
+
+    yell.info "Hello World"
+  end
+
+end
+
diff --git a/spec/compatibility/formatter_spec.rb b/spec/compatibility/formatter_spec.rb
new file mode 100644
index 0000000..00a4484
--- /dev/null
+++ b/spec/compatibility/formatter_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+require 'logger'
+
+describe "backwards compatible formatter" do
+
+  let(:time) { Time.now }
+  let(:formatter) { Yell::Formatter.new(Yell::DefaultFormat) }
+  let(:logger) { Logger.new($stdout) }
+
+  before do
+    Timecop.freeze(time)
+
+    logger.formatter = formatter
+  end
+
+  it "should format out the message correctly" do
+    mock($stdout).write("#{time.iso8601} [ INFO] #{$$} : Hello World!\n")
+
+    logger.info "Hello World!"
+  end
+
+end
+
diff --git a/spec/compatibility/level_spec.rb b/spec/compatibility/level_spec.rb
new file mode 100644
index 0000000..42aebff
--- /dev/null
+++ b/spec/compatibility/level_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+require 'logger'
+
+describe "backwards compatible level" do
+
+  let(:level) { Yell::Level.new(:error) }
+  let(:logger) { Logger.new($stdout) }
+
+  before do
+    logger.level = level
+  end
+
+  it "should format out the level correctly" do
+    expect(logger.level).to eq(level.to_i)
+  end
+
+end
+
diff --git a/spec/fixtures/yell.yml b/spec/fixtures/yell.yml
new file mode 100644
index 0000000..7de4ee9
--- /dev/null
+++ b/spec/fixtures/yell.yml
@@ -0,0 +1,7 @@
+test:
+  :level: info
+
+  :adapters:
+    - :stdout
+    - :stderr:
+        :level: "gte.error"
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..7681f88
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,56 @@
+$:.unshift File.expand_path('..', __FILE__)
+$:.unshift File.expand_path('../../lib', __FILE__)
+
+ENV['YELL_ENV'] = 'test'
+
+require 'rspec/core'
+require 'rspec/expectations'
+require 'rr'
+require 'timecop'
+
+begin
+  require 'pry'
+rescue LoadError
+end
+
+begin
+  require 'coveralls'
+  require 'simplecov'
+
+  STDERR.puts "Running coverage..."
+  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
+    SimpleCov::Formatter::HTMLFormatter,
+    Coveralls::SimpleCov::Formatter
+  ]
+
+  SimpleCov.start do
+    add_filter 'spec'
+  end
+rescue LoadError
+  # do nothing
+end
+
+require 'yell'
+
+RSpec.configure do |config|
+  config.mock_framework = :rr
+
+  config.before :each do
+    Yell::Repository.loggers.clear
+
+    Dir[ fixture_path + "/*.log" ].each { |f| File.delete f }
+  end
+
+  config.after :each do
+    Timecop.return # release time after each test
+  end
+
+
+  private
+
+  def fixture_path
+    File.expand_path( "fixtures", File.dirname(__FILE__) )
+  end
+
+end
+
diff --git a/spec/threaded/yell_spec.rb b/spec/threaded/yell_spec.rb
new file mode 100644
index 0000000..1e1d6d8
--- /dev/null
+++ b/spec/threaded/yell_spec.rb
@@ -0,0 +1,101 @@
+require 'spec_helper'
+
+describe "running Yell multi-threaded" do
+  let( :threads ) { 100 }
+  let( :range ) { (1..threads) }
+
+  let( :filename ) { fixture_path + '/threaded.log' }
+  let( :lines ) { `wc -l #{filename}`.to_i }
+
+  context "one instance" do
+    before do
+      logger = Yell.new filename
+
+      range.map do |count|
+        Thread.new { 10.times { logger.info count } }
+      end.each(&:join)
+
+      sleep 0.5
+    end
+
+    it "should write all messages" do
+      lines.should == 10*threads
+    end
+  end
+
+  # context "one instance per thread" do
+  #   before do
+  #     range.map do |count|
+  #       Thread.new do
+  #         logger = Yell.new( filename )
+
+  #         10.times { logger.info count }
+  #       end
+  #     end.each(&:join)
+
+  #     sleep 0.5
+  #   end
+
+  #   it "should write all messages" do
+  #     lines.should == 10*threads
+  #   end
+  # end
+
+  context "one instance in the repository" do
+    before do
+      Yell[ 'threaded' ] = Yell.new( filename )
+    end
+
+    it "should write all messages" do
+      range.map do |count|
+        Thread.new { 10.times { Yell['threaded'].info count } }
+      end.each(&:join)
+
+      lines.should == 10*threads
+    end
+  end
+
+  context "multiple datefile instances" do
+    let( :threadlist ) { [] }
+    let( :date ) { Time.now }
+
+    before do
+      Timecop.freeze( date - 86400 )
+
+      range.each do |count|
+        threadlist << Thread.new do
+          logger = Yell.new :datefile, :filename => filename, :keep => 2
+          loop { logger.info :info; sleep 0.1 }
+        end
+      end
+
+      sleep 0.3 # sleep to get some messages into the file
+    end
+
+    after do
+      threadlist.each(&:kill)
+    end
+
+    it "should safely rollover" do
+      # now cycle the days
+      7.times do |count|
+        Timecop.freeze( date + 86400*count )
+        sleep 0.3
+
+        files = Dir[ fixture_path + '/*.*.log' ]
+        files.size.should == 2
+
+        # files.last.should match( datefile_pattern_for(Time.now) ) # today
+        # files.first.should match( datefile_pattern_for(Time.now-86400) ) # yesterday
+      end
+    end
+  end
+
+  private
+
+  def datefile_pattern_for( time )
+    time.strftime(Yell::Adapters::Datefile::DefaultDatePattern)
+  end
+
+end
+
diff --git a/spec/yell/adapters/base_spec.rb b/spec/yell/adapters/base_spec.rb
new file mode 100644
index 0000000..d0e62c0
--- /dev/null
+++ b/spec/yell/adapters/base_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe Yell::Adapters::Base do
+
+  context "initialize" do
+    context ":level" do
+      let(:level) { Yell::Level.new(:warn) }
+
+      it "should set the level" do
+        adapter = Yell::Adapters::Base.new(:level => level)
+
+        expect(adapter.level).to eq(level)
+      end
+
+      it "should set the level when block was given" do
+        adapter = Yell::Adapters::Base.new { |a| a.level = level }
+
+        expect(adapter.level).to eq(level)
+      end
+    end
+  end
+
+  context "#write" do
+    let(:logger) { Yell::Logger.new }
+    subject { Yell::Adapters::Base.new(:level => 1) }
+
+    it "should delegate :event to :write!" do
+      event = Yell::Event.new(logger, 1, "Hello World!")
+      mock(subject).write!(event)
+
+      subject.write(event)
+    end
+
+    it "should not write when event does not have the right level" do
+      event = Yell::Event.new(logger, 0, "Hello World!")
+      dont_allow(subject).write!(event)
+
+      subject.write(event)
+    end
+  end
+
+end
+
diff --git a/spec/yell/adapters/datefile_spec.rb b/spec/yell/adapters/datefile_spec.rb
new file mode 100644
index 0000000..e1d30d7
--- /dev/null
+++ b/spec/yell/adapters/datefile_spec.rb
@@ -0,0 +1,168 @@
+require 'spec_helper'
+
+describe Yell::Adapters::Datefile do
+  let(:logger) { Yell::Logger.new }
+  let(:message) { "Hello World" }
+  let(:event) { Yell::Event.new(logger, 1, message) }
+
+  let(:today) { Time.now }
+  let(:tomorrow) { Time.now + 86400 }
+
+  let(:filename) { fixture_path + '/test.log' }
+  let(:today_filename) { fixture_path + "/test.#{today.strftime(Yell::Adapters::Datefile::DefaultDatePattern)}.log" }
+  let(:tomorrow_filename) { fixture_path + "/test.#{tomorrow.strftime(Yell::Adapters::Datefile::DefaultDatePattern)}.log" }
+
+  let(:adapter) { Yell::Adapters::Datefile.new(:filename => filename, :format => "%m") }
+
+  before do
+    Timecop.freeze(today)
+  end
+
+  it { should be_kind_of Yell::Adapters::File }
+
+  describe "#write" do
+    let(:today_lines) { File.readlines(today_filename) }
+
+    before do
+      adapter.write(event)
+    end
+
+    it "should be output to filename with date pattern" do
+      expect(File.exist?(today_filename)).to be_true
+
+      expect(today_lines.size).to eq(2) # includes header line
+      expect(today_lines.last).to match(message)
+    end
+
+    it "should output to the same file" do
+      adapter.write(event)
+
+      expect(File.exist?(today_filename)).to be_true
+      expect(today_lines.size).to eq(3) # includes header line
+    end
+
+    it "should not open file handle again" do
+      dont_allow(File).open(anything, anything)
+
+      adapter.write(event)
+    end
+
+    context "on rollover" do
+      let(:tomorrow_lines) { File.readlines(tomorrow_filename) }
+
+      before do
+        Timecop.freeze(tomorrow) { adapter.write(event) }
+      end
+
+      it "should rotate file" do
+        expect(File.exist?(tomorrow_filename)).to be_true
+
+        expect(tomorrow_lines.size).to eq(2) # includes header line
+        expect(tomorrow_lines.last).to match(message)
+      end
+    end
+  end
+
+  describe "#keep" do
+    before do
+      adapter.symlink = false # to not taint the Dir
+      adapter.keep = 2
+
+      adapter.write(event)
+    end
+
+    it "should keep the specified number or files upon rollover" do
+      expect(Dir[fixture_path + '/*.log'].size).to eq(1)
+
+      Timecop.freeze(tomorrow) { adapter.write(event) }
+      expect(Dir[fixture_path + '/*.log'].size).to eq(2)
+
+      Timecop.freeze(tomorrow + 86400 ) { adapter.write(event) }
+      expect(Dir[fixture_path + '/*.log'].size).to eq(2)
+    end
+  end
+
+  describe "#symlink" do
+    context "when true (default)" do
+      before do
+        adapter.write(event)
+      end
+
+      it "should be created on the original filename" do
+        expect(File.symlink?(filename)).to be_true
+        expect(File.readlink(filename)).to eq(today_filename)
+      end
+
+      it "should be recreated upon rollover" do
+        Timecop.freeze(tomorrow) { adapter.write(event) }
+
+        expect(File.symlink?(filename)).to be_true
+        expect(File.readlink(filename)).to eq(tomorrow_filename)
+      end
+    end
+
+    context "when false" do
+      before do
+        adapter.symlink = false
+      end
+
+      it "should not create the sylink the original filename" do
+        adapter.write( event )
+
+        expect(File.symlink?(filename)).to be_false
+      end
+    end
+  end
+
+  describe "#header" do
+    let(:header) { File.open(today_filename, &:readline) }
+
+    context "when true (default)" do
+      before do
+        adapter.write(event)
+      end
+
+      it "should be written" do
+        expect(header).to match(Yell::Adapters::Datefile::HeaderRegexp)
+      end
+
+      it "should be rewritten upon rollover" do
+        Timecop.freeze(tomorrow) { adapter.write(event) }
+
+        expect(File.symlink?(filename)).to be_true
+        expect(File.readlink(filename)).to eq(tomorrow_filename)
+      end
+    end
+
+    context "when false" do
+      before do
+        adapter.header = false
+      end
+
+      it "should not be written" do
+        adapter.write(event)
+
+        expect(header).to eq("Hello World\n")
+      end
+    end
+  end
+
+  context "another adapter with the same :filename" do
+    let(:another_adapter) { Yell::Adapters::Datefile.new(:filename => filename) }
+
+    before do
+      adapter.write(event)
+    end
+
+    it "should not write the header again" do
+      another_adapter.write(event)
+
+      # 1: header
+      # 2: adapter write
+      # 3: another_adapter: write
+      expect(File.readlines(today_filename).size).to eq(3)
+    end
+  end
+
+end
+
diff --git a/spec/yell/adapters/file_spec.rb b/spec/yell/adapters/file_spec.rb
new file mode 100644
index 0000000..785cb80
--- /dev/null
+++ b/spec/yell/adapters/file_spec.rb
@@ -0,0 +1,75 @@
+require 'spec_helper'
+
+describe Yell::Adapters::File do
+  let(:devnull) { File.new('/dev/null', 'w') }
+
+  before do
+    stub(File).open(anything, anything) { devnull }
+  end
+
+  it { should be_kind_of(Yell::Adapters::Io) }
+
+  context "#stream" do
+    subject { Yell::Adapters::File.new.send(:stream) }
+
+    it { should be_kind_of(File) }
+  end
+
+  context "#write" do
+    let(:logger) { Yell::Logger.new }
+    let(:event) { Yell::Event.new(logger, 1, "Hello World") }
+
+    context "default filename" do
+      let(:filename) { File.expand_path "#{Yell.env}.log" }
+      let(:adapter) { Yell::Adapters::File.new }
+
+      it "should print to file" do
+        mock(File).open(filename, File::WRONLY|File::APPEND|File::CREAT) { devnull }
+
+        adapter.write(event)
+      end
+    end
+
+    context "with given :filename" do
+      let(:filename) { fixture_path + '/filename.log' }
+      let(:adapter) { Yell::Adapters::File.new(:filename => filename) }
+
+      it "should print to file" do
+        mock(File).open(filename, File::WRONLY|File::APPEND|File::CREAT) { devnull }
+
+        adapter.write(event)
+      end
+    end
+
+    context "with given :pathname" do
+      let(:pathname) { Pathname.new(fixture_path).join('filename.log') }
+      let(:adapter) { Yell::Adapters::File.new( :filename => pathname ) }
+
+      it "should accept pathanme as filename" do
+        mock(File).open(pathname.to_s, File::WRONLY|File::APPEND|File::CREAT) { devnull }
+
+        adapter.write(event)
+      end
+    end
+
+    context "#sync" do
+      let(:adapter) { Yell::Adapters::File.new }
+
+      it "should sync by default" do
+        mock(devnull).sync=(true)
+
+        adapter.write(event)
+      end
+
+      it "pass the option to File" do
+        adapter.sync = false
+
+        mock(devnull).sync=(false)
+
+        adapter.write(event)
+      end
+    end
+  end
+
+end
+
diff --git a/spec/yell/adapters/io_spec.rb b/spec/yell/adapters/io_spec.rb
new file mode 100644
index 0000000..5f26642
--- /dev/null
+++ b/spec/yell/adapters/io_spec.rb
@@ -0,0 +1,72 @@
+require 'spec_helper'
+
+describe Yell::Adapters::Io do
+
+  it { should be_kind_of Yell::Adapters::Base }
+
+  context "initialize" do
+    it "should set default :format" do
+      adapter = Yell::Adapters::Io.new
+
+      expect(adapter.format).to be_kind_of(Yell::Formatter)
+    end
+
+    context ":level" do
+      let(:level) { Yell::Level.new(:warn) }
+
+      it "should set the level" do
+        adapter = Yell::Adapters::Io.new(:level => level)
+
+        expect(adapter.level).to eq(level)
+      end
+
+      it "should set the level when block was given" do
+        adapter = Yell::Adapters::Io.new { |a| a.level = level }
+
+        expect(adapter.level).to eq(level)
+      end
+    end
+
+    context ":format" do
+      let(:format) { Yell::Formatter.new }
+
+      it "should set the level" do
+        adapter = Yell::Adapters::Io.new(:format => format)
+
+        expect(adapter.format).to eq(format)
+      end
+
+      it "should set the level when block was given" do
+        adapter = Yell::Adapters::Io.new { |a| a.format = format }
+
+        expect(adapter.format).to eq(format)
+      end
+    end
+  end
+
+  context "#write" do
+    let(:logger) { Yell::Logger.new }
+    let(:event) { Yell::Event.new(logger, 1, "Hello World") }
+    let(:adapter) { Yell::Adapters::Io.new }
+    let(:stream) { File.new('/dev/null', 'w') }
+
+    before do
+      stub(adapter).stream { stream }
+    end
+
+    it "should format the message" do
+      mock.proxy(adapter.format).call( event )
+
+      adapter.write(event)
+    end
+
+    it "should print formatted message to stream" do
+      formatted = Yell::Formatter.new.call(event)
+      mock(stream).syswrite(formatted)
+
+      adapter.write(event)
+    end
+  end
+
+end
+
diff --git a/spec/yell/adapters/streams_spec.rb b/spec/yell/adapters/streams_spec.rb
new file mode 100644
index 0000000..1dd9095
--- /dev/null
+++ b/spec/yell/adapters/streams_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe Yell::Adapters::Stdout do
+
+  it { should be_kind_of(Yell::Adapters::Io) }
+
+  context "#stream" do
+    subject { Yell::Adapters::Stdout.new.send :stream }
+
+    it { should be_kind_of(IO) }
+  end
+
+end
+
+describe Yell::Adapters::Stderr do
+
+  it { should be_kind_of(Yell::Adapters::Io) }
+
+  context "#stream" do
+    subject { Yell::Adapters::Stderr.new.send(:stream) }
+
+    it { should be_kind_of(IO) }
+  end
+
+end
+
diff --git a/spec/yell/adapters_spec.rb b/spec/yell/adapters_spec.rb
new file mode 100644
index 0000000..bbb1495
--- /dev/null
+++ b/spec/yell/adapters_spec.rb
@@ -0,0 +1,45 @@
+require 'spec_helper'
+
+describe Yell::Adapters do
+
+  context ".new" do
+    it "should accept an adapter instance" do
+      stdout = Yell::Adapters::Stdout.new
+      adapter = Yell::Adapters.new(stdout)
+
+      expect(adapter).to eq(stdout)
+    end
+
+    it "should accept STDOUT" do
+      mock.proxy(Yell::Adapters::Stdout).new(anything)
+
+      Yell::Adapters.new(STDOUT)
+    end
+
+    it "should accept STDERR" do
+      mock.proxy(Yell::Adapters::Stderr).new(anything)
+
+      Yell::Adapters.new(STDERR)
+    end
+
+    it "should raise an unregistered adapter" do
+      expect {
+        Yell::Adapters.new :unknown
+      }.to raise_error(Yell::AdapterNotFound)
+    end
+  end
+
+  context ".register" do
+    let(:name) { :test }
+    let(:klass) { mock }
+
+    before { Yell::Adapters.register(name, klass) }
+
+    it "should allow to being called from :new" do
+      mock(klass).new(anything)
+
+      Yell::Adapters.new(name)
+    end
+  end
+
+end
diff --git a/spec/yell/configuration_spec.rb b/spec/yell/configuration_spec.rb
new file mode 100644
index 0000000..1010b89
--- /dev/null
+++ b/spec/yell/configuration_spec.rb
@@ -0,0 +1,36 @@
+require 'spec_helper'
+
+describe Yell::Configuration do
+
+  describe ".load!" do
+    let(:file) { fixture_path + '/yell.yml' }
+    let(:config) { Yell::Configuration.load!(file) }
+
+    subject { config }
+
+    it { should be_kind_of(Hash) }
+    it { should have_key(:level) }
+    it { should have_key(:adapters) }
+
+    context ":level" do
+      subject { config[:level] }
+
+      it { should eq("info") }
+    end
+
+    context ":adapters" do
+      subject { config[:adapters] }
+
+      it { should be_kind_of(Array) }
+
+      # stdout
+      it { expect(subject.first).to eq(:stdout) }
+
+      # stderr
+      it { expect(subject.last).to be_kind_of(Hash) }
+      it { expect(subject.last).to eq(:stderr => {:level => 'gte.error'}) }
+    end
+  end
+
+end
+
diff --git a/spec/yell/dsl_spec.rb b/spec/yell/dsl_spec.rb
new file mode 100644
index 0000000..44f3396
--- /dev/null
+++ b/spec/yell/dsl_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe "Yell Adapter DSL spec" do
+
+  class DSLAdapter < Yell::Adapters::Base
+
+    setup do |options|
+      @test_setup = true
+    end
+
+    write do |event|
+      @test_write = true
+    end
+
+    close do
+      @test_close = true
+    end
+
+    def test_setup?; !!@test_setup; end
+    def test_write?; !!@test_write; end
+    def test_close?; !!@test_close; end
+  end
+
+  it "should perform #setup" do
+    adapter = DSLAdapter.new
+    expect(adapter.test_setup?).to be_true
+  end
+
+  it "should perform #write" do
+    event = 'event'
+    stub(event).level { 0 }
+
+    adapter = DSLAdapter.new
+    expect(adapter.test_write?).to be_false
+
+    adapter.write(event)
+    expect(adapter.test_write?).to be_true
+  end
+
+  it "should perform #close" do
+    adapter = DSLAdapter.new
+    expect(adapter.test_close?).to be_false
+
+    adapter.close
+    expect(adapter.test_close?).to be_true
+  end
+
+end
+
diff --git a/spec/yell/event_spec.rb b/spec/yell/event_spec.rb
new file mode 100644
index 0000000..c4a322b
--- /dev/null
+++ b/spec/yell/event_spec.rb
@@ -0,0 +1,97 @@
+require 'spec_helper'
+
+# Since Yell::Event.new is not called directly, but through
+# the logger methods, we need to divert here in order to get 
+# the correct caller.
+class EventFactory
+  def self.event(logger, level, message)
+    self._event(logger, level, message)
+  end
+
+  private
+
+  def self._event(logger, level, message)
+    Yell::Event.new(logger, level, message)
+  end
+
+end
+
+describe Yell::Event do
+  let(:logger) { Yell::Logger.new(:trace => true) }
+  let(:event) { Yell::Event.new(logger, 1, 'Hello World!') }
+
+  context "#level" do
+    subject { event.level }
+    it { should eq(1) }
+  end
+
+  context "#messages" do
+    subject { event.messages }
+    it { should eq(['Hello World!']) }
+  end
+
+  context "#time" do
+    let(:time) { Time.now }
+    subject { event.time.to_s }
+
+    before { Timecop.freeze(time) }
+
+    it { should eq(time.to_s) }
+  end
+
+  context "#hostname" do
+    subject { event.hostname }
+    it { should eq(Socket.gethostname) }
+  end
+
+  context "#pid" do
+    subject { event.pid }
+    it { should eq(Process.pid) }
+  end
+
+  context "#id when forked", :pending => RUBY_PLATFORM == 'java' ? "No forking with jruby" : false do
+    subject { @pid }
+
+    before do
+      read, write = IO.pipe
+
+      @pid = Process.fork do
+        event = Yell::Event.new(logger, 1, 'Hello World!')
+        write.puts event.pid
+      end
+      Process.wait
+      write.close
+
+      @child_pid = read.read.to_i
+      read.close
+    end
+
+    it { should_not eq(Process.pid) }
+    it { should eq(@child_pid) }
+  end
+
+  context "#progname" do
+    subject { event.progname }
+    it { should eq($0) }
+  end
+
+  context ":caller" do
+    subject { EventFactory.event(logger, 1, "Hello World") }
+
+    context "with trace" do
+      its(:file) { should eq(__FILE__) }
+      its(:line) { should eq("8") }
+      its(:method) { should eq("event") }
+    end
+
+    context "without trace" do
+      before { logger.trace = false }
+
+      its(:file) { should eq("") }
+      its(:line) { should eq("") }
+      its(:method) { should eq("") }
+    end
+  end
+
+end
+
diff --git a/spec/yell/formatter_spec.rb b/spec/yell/formatter_spec.rb
new file mode 100644
index 0000000..ffac567
--- /dev/null
+++ b/spec/yell/formatter_spec.rb
@@ -0,0 +1,146 @@
+require 'spec_helper'
+
+describe Yell::Formatter do
+
+  let(:logger) { Yell::Logger.new(:stdout, :name => 'Yell') }
+  let(:message) { "Hello World!" }
+  let(:event) { Yell::Event.new(logger, 1, message) }
+
+  let(:pattern) { "%m" }
+  let(:formatter) { Yell::Formatter.new(pattern) }
+
+  let(:time) { Time.now }
+
+  subject { formatter.call(event) }
+
+  before do
+    Timecop.freeze(time)
+  end
+
+  describe "patterns" do
+    context "%m" do
+      let(:pattern) { "%m" }
+      it { should eq("#{event.messages.join(' ')}\n") }
+    end
+
+    context "%l" do
+      let(:pattern) { "%l" }
+      it { should eq("#{Yell::Severities[event.level][0,1]}\n") }
+    end
+
+    context "%L" do
+      let(:pattern) { "%L" }
+      it { should eq("#{Yell::Severities[event.level]}\n") }
+    end
+
+    context "%d" do
+      let(:pattern) { "%d" }
+      it { should eq("#{event.time.iso8601}\n") }
+    end
+
+    context "%p" do
+      let(:pattern) { "%p" }
+      it { should eq("#{event.pid}\n") }
+    end
+
+    context "%P" do
+      let(:pattern) { "%P" }
+      it { should eq("#{event.progname}\n") }
+    end
+
+    context "%t" do
+      let(:pattern) { "%t" }
+      it { should eq("#{event.thread_id}\n") }
+    end
+
+    context "%h" do
+      let(:pattern) { "%h" }
+      it { should eq("#{event.hostname}\n") }
+    end
+
+    context ":caller" do
+      let(:_caller) { [nil, nil, "/path/to/file.rb:123:in `test_method'"] }
+
+      before do
+        any_instance_of(Yell::Event) do |e|
+          stub(e).file { "/path/to/file.rb" }
+          stub(e).line { "123" }
+          stub(e).method { "test_method" }
+        end
+      end
+
+      context "%F" do
+        let(:pattern) { "%F" }
+        it { should eq("/path/to/file.rb\n") }
+      end
+
+      context "%f" do
+        let(:pattern) { "%f" }
+        it { should eq("file.rb\n") }
+      end
+
+      context "%M" do
+        let(:pattern) { "%M" }
+        it { should eq("test_method\n") }
+      end
+
+      context "%n" do
+        let(:pattern) { "%n" }
+        it { should eq("123\n") }
+      end
+    end
+
+    context "%N" do
+      let(:pattern) { "%N" }
+      it { should eq("Yell\n") }
+    end
+  end
+
+  describe "presets" do
+    context "NoFormat" do
+      let(:pattern) { Yell::NoFormat }
+      it { should eq("Hello World!\n") }
+    end
+
+    context "DefaultFormat" do
+      let(:pattern) { Yell::DefaultFormat }
+      it { should eq("#{time.iso8601} [ INFO] #{$$} : Hello World!\n")  }
+    end
+
+    context "BasicFormat" do
+      let(:pattern) { Yell::BasicFormat }
+      it { should eq("I, #{time.iso8601} : Hello World!\n") }
+    end
+
+    context "ExtendedFormat" do
+      let(:pattern) { Yell::ExtendedFormat }
+      it { should eq("#{time.iso8601} [ INFO] #{$$} #{Socket.gethostname} : Hello World!\n") }
+    end
+  end
+
+  describe "Exception" do
+    let(:message) { StandardError.new("This is an Exception") }
+
+    before do
+      stub(message).backtrace { ["backtrace"] }
+    end
+
+    it { should eq("StandardError: This is an Exception\n\tbacktrace\n") }
+  end
+
+  describe "Hash" do
+    let(:message) { {:test => 'message'} }
+
+    it { should eq("test: message\n") }
+  end
+
+  describe "custom message modifiers" do
+    let(:formatter) do
+      Yell::Formatter.new(pattern) { |f| f.modify(String) { |m| "Modified! #{m}" } }
+    end
+
+    it { should eq("Modified! #{message}\n") }
+  end
+
+end
+
diff --git a/spec/yell/level_spec.rb b/spec/yell/level_spec.rb
new file mode 100644
index 0000000..03f3a06
--- /dev/null
+++ b/spec/yell/level_spec.rb
@@ -0,0 +1,200 @@
+require 'spec_helper'
+
+describe Yell::Level do
+
+  context "default" do
+    let(:level) { Yell::Level.new }
+
+    it "should should return correctly" do
+      expect(level.at?(:debug)).to be_true
+      expect(level.at?(:info)).to be_true
+      expect(level.at?(:warn)).to be_true
+      expect(level.at?(:error)).to be_true
+      expect(level.at?(:fatal)).to be_true
+    end
+  end
+
+  context "given a Symbol" do
+    let(:level) { Yell::Level.new(severity) }
+
+    context ":debug" do
+      let(:severity) { :debug }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_true
+        expect(level.at?(:info)).to be_true
+        expect(level.at?(:warn)).to be_true
+        expect(level.at?(:error)).to be_true
+        expect(level.at?(:fatal)).to be_true
+      end
+    end
+
+    context ":info" do
+      let(:severity) { :info }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_false
+        expect(level.at?(:info)).to be_true
+        expect(level.at?(:warn)).to be_true
+        expect(level.at?(:error)).to be_true
+        expect(level.at?(:fatal)).to be_true
+      end
+    end
+
+    context ":warn" do
+      let(:severity) { :warn }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_false
+        expect(level.at?(:info)).to be_false
+        expect(level.at?(:warn)).to be_true
+        expect(level.at?(:error)).to be_true
+        expect(level.at?(:fatal)).to be_true
+      end
+    end
+
+    context ":error" do
+      let(:severity) { :error }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_false
+        expect(level.at?(:info)).to be_false
+        expect(level.at?(:warn)).to be_false
+        expect(level.at?(:error)).to be_true
+        expect(level.at?(:fatal)).to be_true
+      end
+    end
+
+    context ":fatal" do
+      let(:severity) { :fatal }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_false
+        expect(level.at?(:info)).to be_false
+        expect(level.at?(:warn)).to be_false
+        expect(level.at?(:error)).to be_false
+        expect(level.at?(:fatal)).to be_true
+      end
+    end
+  end
+
+  context "given a String" do
+    let(:level) { Yell::Level.new(severity) }
+
+    context "basic string" do
+      let(:severity) { 'error' }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_false
+        expect(level.at?(:info)).to be_false
+        expect(level.at?(:warn)).to be_false
+        expect(level.at?(:error)).to be_true
+        expect(level.at?(:fatal)).to be_true
+      end
+    end
+
+    context "complex string with outer boundaries" do
+      let(:severity) { 'gte.info lte.error' }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_false
+        expect(level.at?(:info)).to be_true
+        expect(level.at?(:warn)).to be_true
+        expect(level.at?(:error)).to be_true
+        expect(level.at?(:fatal)).to be_false
+      end
+    end
+
+    context "complex string with inner boundaries" do
+      let(:severity) { 'gt.info lt.error' }
+
+      it "should be valid" do
+        expect(level.at?(:debug)).to be_false
+        expect(level.at?(:info)).to be_false
+        expect(level.at?(:warn)).to be_true
+        expect(level.at?(:error)).to be_false
+        expect(level.at?(:fatal)).to be_false
+      end
+    end
+
+    context "complex string with precise boundaries" do
+      let(:severity) { 'at.info at.error' }
+
+      it "should be valid" do
+        expect(level.at?(:debug)).to be_false
+        expect(level.at?(:info)).to be_true
+        expect(level.at?(:warn)).to be_false
+        expect(level.at?(:error)).to be_true
+        expect(level.at?(:fatal)).to be_false
+      end
+    end
+
+    context "complex string with combined boundaries" do
+      let(:severity) { 'gte.error at.debug' }
+
+      it "should be valid" do
+        expect(level.at?(:debug)).to be_true
+        expect(level.at?(:info)).to be_false
+        expect(level.at?(:warn)).to be_false
+        expect(level.at?(:error)).to be_true
+        expect(level.at?(:fatal)).to be_true
+      end
+    end
+  end
+
+  context "given an Array" do
+    let(:level) { Yell::Level.new( [:debug, :warn, :fatal] ) }
+
+    it "should return correctly" do
+      expect(level.at?(:debug)).to be_true
+      expect(level.at?(:info)).to be_false
+      expect(level.at?(:warn)).to be_true
+      expect(level.at?(:error)).to be_false
+      expect(level.at?(:fatal)).to be_true
+    end
+  end
+
+  context "given a Range" do
+    let(:level) { Yell::Level.new( (1..3) ) }
+
+    it "should return correctly" do
+      expect(level.at?(:debug)).to be_false
+      expect(level.at?(:info)).to be_true
+      expect(level.at?(:warn)).to be_true
+      expect(level.at?(:error)).to be_true
+      expect(level.at?(:fatal)).to be_false
+    end
+  end
+
+  context "given a Yell::Level instance" do
+    let(:level) { Yell::Level.new(:warn) }
+
+    it "should return correctly" do
+      expect(level.at?(:debug)).to be_false
+      expect(level.at?(:info)).to be_false
+      expect(level.at?(:warn)).to be_true
+      expect(level.at?(:error)).to be_true
+      expect(level.at?(:fatal)).to be_true
+    end
+  end
+
+  context "backwards compatibility" do
+    let(:level) { Yell::Level.new :warn }
+
+    it "should return correctly to :to_i" do
+      expect(level.to_i).to eq(2)
+    end
+
+    it "should typecast with Integer correctly" do
+      expect(Integer(level)).to eq(2)
+    end
+
+    it "should be compatible when passing to array (https://github.com/rudionrails/yell/issues/1)" do
+      severities = %w(FINE INFO WARNING SEVERE SEVERE INFO)
+
+      expect(severities[level]).to eq("WARNING")
+    end
+  end
+
+end
+
diff --git a/spec/yell/loggable_spec.rb b/spec/yell/loggable_spec.rb
new file mode 100644
index 0000000..2c56dd4
--- /dev/null
+++ b/spec/yell/loggable_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+class LoggableFactory
+  include Yell::Loggable
+end
+
+describe Yell::Loggable do
+  let(:factory) { LoggableFactory.new }
+  subject { factory }
+
+  it { should respond_to(:logger) }
+
+  it "should make a lookup in the Yell::Repository" do
+    mock(Yell::Repository)[LoggableFactory]
+
+    factory.logger
+  end
+
+end
+
diff --git a/spec/yell/logger_spec.rb b/spec/yell/logger_spec.rb
new file mode 100644
index 0000000..8be5db9
--- /dev/null
+++ b/spec/yell/logger_spec.rb
@@ -0,0 +1,268 @@
+require 'spec_helper'
+
+class LoggerFactory
+  attr_accessor :logger
+
+  def info
+    logger.info :foo
+  end
+
+  def add
+    logger.add 1, :bar
+  end
+end
+
+describe Yell::Logger do
+  let(:filename) { fixture_path + '/logger.log' }
+
+  describe "a Logger instance" do
+    let(:logger) { Yell::Logger.new }
+    subject { logger }
+
+    context "log methods" do
+      it { should respond_to(:debug) }
+      it { should respond_to(:debug?) }
+
+      it { should respond_to(:info) }
+      it { should respond_to(:info?) }
+
+      it { should respond_to(:warn) }
+      it { should respond_to(:warn?) }
+
+      it { should respond_to(:error) }
+      it { should respond_to(:error?) }
+
+      it { should respond_to(:fatal) }
+      it { should respond_to(:fatal?) }
+
+      it { should respond_to(:unknown) }
+      it { should respond_to(:unknown?) }
+    end
+
+    context "default #name" do
+      its(:name) { should eq("<Yell::Logger##{logger.object_id}>") }
+
+      it "should not be added to the repository" do
+        expect { Yell::Repository[logger.name] }.to raise_error(Yell::LoggerNotFound)
+      end
+    end
+
+    context "default #adapter" do
+      subject { logger.adapters.instance_variable_get(:@collection) }
+
+      its(:size) { should == 1 }
+      its(:first) { should be_kind_of(Yell::Adapters::File) }
+    end
+
+    context "default #level" do
+      subject { logger.level }
+
+      it { should be_instance_of(Yell::Level) }
+      its(:severities) { should eq([true, true, true, true, true, true]) }
+    end
+
+    context "default #trace" do
+      subject { logger.trace }
+
+      it { should be_instance_of(Yell::Level) }
+      its(:severities) { should eq([false, false, false, true, true, true]) } # from error onwards
+    end
+  end
+
+  describe "initialize with #name" do
+    let(:name) { 'test' }
+    let!(:logger) { Yell.new(:name => name) }
+
+    it "should set the name correctly" do
+      expect(logger.name).to eq(name)
+    end
+
+    it "should be added to the repository" do
+      expect(Yell::Repository[name]).to eq(logger)
+    end
+  end
+
+  context "initialize with #level" do
+    let(:level) { :error }
+    let(:logger) { Yell.new(:level => level) }
+    subject { logger.level }
+
+    it { should be_instance_of(Yell::Level) }
+    its(:severities) { should eq([false, false, false, true, true, true]) }
+  end
+
+  context "initialize with #trace" do
+    let(:trace) { :info }
+    let(:logger) { Yell.new(:trace => trace) }
+    subject { logger.trace }
+
+    it { should be_instance_of(Yell::Level) }
+    its(:severities) { should eq([false, true, true, true, true, true]) }
+  end
+
+  context "initialize with #silence" do
+    let(:silence) { "test" }
+    let(:logger) { Yell.new(:silence => silence) }
+    subject { logger.silencer }
+
+    it { should be_instance_of(Yell::Silencer) }
+    its(:patterns) { should eq([silence]) }
+  end
+
+  context "initialize with a #filename" do
+    it "should call adapter with :file" do
+      mock.proxy(Yell::Adapters::File).new(:filename => filename)
+
+      Yell::Logger.new(filename)
+    end
+  end
+
+  context "initialize with a #filename of Pathname type" do
+    let(:pathname) { Pathname.new(filename) }
+
+    it "should call adapter with :file" do
+      mock.proxy(Yell::Adapters::File).new(:filename => pathname)
+
+      Yell::Logger.new(pathname)
+    end
+  end
+
+  context "initialize with a :stdout adapter" do
+    before { mock.proxy(Yell::Adapters::Stdout).new(anything) }
+
+    it "should call adapter with STDOUT" do
+      Yell::Logger.new(STDOUT)
+    end
+
+    it "should call adapter with :stdout" do
+      Yell::Logger.new(:stdout)
+    end
+  end
+
+  context "initialize with a :stderr adapter" do
+    before { mock.proxy(Yell::Adapters::Stderr).new(anything) }
+
+    it "should call adapter with STDERR" do
+      Yell::Logger.new(STDERR)
+    end
+
+    it "should call adapter with :stderr" do
+      Yell::Logger.new(:stderr)
+    end
+  end
+
+  context "initialize with a block" do
+    let(:level) { Yell::Level.new :error }
+    let(:adapters) { logger.adapters.instance_variable_get(:@collection) }
+
+    context "with arity" do
+      let(:logger) do
+        Yell::Logger.new(:level => level) { |l| l.adapter(:stdout) }
+      end
+
+      it "should pass the level correctly" do
+        expect(logger.level).to eq(level)
+      end
+
+      it "should pass the adapter correctly" do
+        expect(adapters.first).to be_instance_of(Yell::Adapters::Stdout)
+      end
+    end
+
+    context "without arity" do
+      let(:logger) do
+        Yell::Logger.new(:level => level) { adapter(:stdout) }
+      end
+
+      it "should pass the level correctly" do
+        expect(logger.level).to eq(level)
+      end
+
+      it "should pass the adapter correctly" do
+        expect(adapters.first).to be_instance_of(Yell::Adapters::Stdout)
+      end
+    end
+  end
+
+  context "initialize with #adapters option" do
+    it "should set adapters in logger correctly" do
+      any_instance_of(Yell::Logger) do |logger|
+        mock.proxy(logger).adapter(:stdout)
+        mock.proxy(logger).adapter(:stderr, :level => :error)
+      end
+
+      Yell::Logger.new(:adapters => [:stdout, {:stderr => {:level => :error}}])
+    end
+  end
+
+  context "caller's :file, :line and :method" do
+    let(:stdout) { Yell::Adapters::Stdout.new(:format => "%F, %n: %M") }
+    let(:logger) { Yell::Logger.new(:trace => true) { |l| l.adapter(stdout) } }
+
+    it "should write correctly" do
+      factory = LoggerFactory.new
+      factory.logger = logger
+
+      mock(stdout.send(:stream)).syswrite("#{__FILE__}, 7: info\n")
+      mock(stdout.send(:stream)).syswrite("#{__FILE__}, 11: add\n")
+
+      factory.info
+      factory.add
+    end
+  end
+
+  context "logging in general" do
+    let(:logger) { Yell::Logger.new(filename, :format => "%m") }
+    let(:line) { File.open(filename, &:readline) }
+
+    it "should output a single message" do
+      logger.info "Hello World"
+
+      expect(line).to eq("Hello World\n")
+    end
+
+    it "should output multiple messages" do
+      logger.info ["Hello", "W", "o", "r", "l", "d"]
+
+      expect(line).to eq("Hello W o r l d\n")
+    end
+
+    it "should output a hash and message" do
+      logger.info ["Hello World", {:test => :message}]
+
+      expect(line).to eq("Hello World test: message\n")
+    end
+
+    it "should output a hash and message" do
+      logger.info [{:test => :message}, "Hello World"]
+
+      expect(line).to eq("test: message Hello World\n")
+    end
+
+    it "should output a hash and block" do
+      logger.info(:test => :message) { "Hello World" }
+
+      expect(line).to eq("test: message Hello World\n")
+    end
+  end
+
+  context "logging with a silencer" do
+    let(:silence) { "this" }
+    let(:stdout) { Yell::Adapters::Stdout.new }
+    let(:logger) { Yell::Logger.new(stdout, :silence => silence) }
+
+    it "should not pass a matching message to any adapter" do
+      dont_allow(stdout).write
+
+      logger.info "this should not be logged"
+    end
+
+    it "should pass a non-matching message to any adapter" do
+      mock(stdout).write(is_a(Yell::Event))
+
+      logger.info "that should be logged"
+    end
+  end
+
+end
+
diff --git a/spec/yell/repository_spec.rb b/spec/yell/repository_spec.rb
new file mode 100644
index 0000000..818524b
--- /dev/null
+++ b/spec/yell/repository_spec.rb
@@ -0,0 +1,70 @@
+require 'spec_helper'
+
+describe Yell::Repository do
+  let(:name) { 'test' }
+  let(:logger) { Yell.new(:stdout) }
+
+  subject { Yell::Repository[name] }
+
+  context ".[]" do
+    it "should raise when not set" do
+      expect { subject }.to raise_error(Yell::LoggerNotFound)
+    end
+
+    context "when logger with :name exists" do
+      let!(:logger) { Yell.new(:stdout, :name => name) }
+
+      it { should eq(logger) }
+    end
+
+    context "given a Class" do
+      let!(:logger) { Yell.new(:stdout, :name => "Numeric") }
+
+      it "should raise with the correct :name when logger not found" do
+        mock.proxy(Yell::LoggerNotFound).new(String)
+        lambda { Yell::Repository[String] }.should raise_error(Yell::LoggerNotFound)
+      end
+
+      it "should return the logger" do
+        Yell::Repository[Numeric].should eq(logger)
+      end
+
+      it "should return the logger when superclass has it defined" do
+        Yell::Repository[Integer].should eq(logger)
+      end
+    end
+  end
+
+  context ".[]=" do
+    before { Yell::Repository[name] = logger }
+    it { should eq(logger) }
+  end
+
+  context ".[]= with a named logger" do
+    let!(:logger) { Yell.new(:stdout, :name => name) }
+    before { Yell::Repository[name] = logger }
+
+    it { should eq(logger) }
+  end
+
+  context ".[]= with a named logger of a different name" do
+    let(:other) { 'other' }
+    let(:logger) { Yell.new(:stdout, :name => other) }
+    before { Yell::Repository[name] = logger }
+
+    it "should add logger to both repositories" do
+      Yell::Repository[name].should eq(logger)
+      Yell::Repository[other].should eq(logger)
+    end
+  end
+
+  context "loggers" do
+    let(:loggers) { { name => logger } }
+    subject { Yell::Repository.loggers }
+    before { Yell::Repository[name] = logger }
+
+    it { should eq(loggers) }
+  end
+
+end
+
diff --git a/spec/yell/silencer_spec.rb b/spec/yell/silencer_spec.rb
new file mode 100644
index 0000000..5d81e9e
--- /dev/null
+++ b/spec/yell/silencer_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe Yell::Silencer do
+
+  context "initialize with #patterns" do
+    subject { Yell::Silencer.new(/this/) }
+
+    its(:patterns) { should eq([/this/]) }
+  end
+
+  context "#add" do
+    let(:silencer) { Yell::Silencer.new }
+
+    it "should add patterns" do
+      silencer.add /this/, /that/
+
+      expect(silencer.patterns).to eq([/this/, /that/])
+    end
+
+    it "should ignore duplicate patterns" do
+      silencer.add /this/, /that/, /this/
+
+      expect(silencer.patterns).to eq([/this/, /that/])
+    end
+  end
+
+  context "#call" do
+    let(:silencer) { Yell::Silencer.new(/this/) }
+
+    it "should reject messages that match any pattern" do
+      expect(silencer.call("this")).to eq([])
+      expect(silencer.call("that")).to eq(["that"])
+      expect(silencer.call("this", "that")).to eq(["that"])
+    end
+  end
+
+end
+
diff --git a/spec/yell_spec.rb b/spec/yell_spec.rb
new file mode 100644
index 0000000..370ebf3
--- /dev/null
+++ b/spec/yell_spec.rb
@@ -0,0 +1,102 @@
+require 'spec_helper'
+
+describe Yell do
+  let( :logger ) { Yell.new }
+
+  subject { logger }
+
+  it { should be_kind_of Yell::Logger }
+
+  it "should raise AdapterNotFound when adapter cant be loaded" do
+    expect {
+      Yell.new :unknownadapter
+    }.to raise_error(Yell::AdapterNotFound)
+  end
+
+  context ".level" do
+    subject { Yell.level }
+    it { should be_kind_of Yell::Level }
+  end
+
+  context ".format" do
+    subject { Yell.format( "%m" ) }
+    it { should be_kind_of Yell::Formatter }
+  end
+
+  context ".load!" do
+    subject { Yell.load!('yell.yml') }
+
+    before do
+      mock(Yell::Configuration).load!('yell.yml') { {} }
+    end
+
+    it { should be_kind_of Yell::Logger }
+  end
+
+  context ".[]" do
+    let(:name) { 'test' }
+
+    it "should delegate to the repository" do
+      mock(Yell::Repository)[name]
+
+      Yell[name]
+    end
+  end
+
+  context ".[]=" do
+    let(:name) { 'test' }
+
+    it "should delegate to the repository" do
+      mock.proxy(Yell::Repository)[name] = logger
+
+      Yell[name] = logger
+    end
+  end
+
+  context ".env" do
+    subject { Yell.env }
+
+    it "should default to YELL_ENV" do
+      subject.should == 'test'
+    end
+
+    context "fallback to RACK_ENV" do
+      before do
+        stub(ENV).key?('YELL_ENV') { false }
+        mock(ENV).key?('RACK_ENV') { true }
+
+        ENV['RACK_ENV'] = 'rack'
+      end
+
+      after { ENV.delete 'RACK_ENV' }
+
+      it { should == 'rack' }
+    end
+
+    context "fallback to RAILS_ENV" do
+      before do
+        stub(ENV).key?('YELL_ENV') { false }
+        stub(ENV).key?('RACK_ENV') { false }
+        mock(ENV).key?('RAILS_ENV') { true }
+
+        ENV['RAILS_ENV'] = 'rails'
+      end
+
+      after { ENV.delete 'RAILS_ENV' }
+
+      it { should == 'rails' }
+    end
+
+    context "fallback to development" do
+      before do
+        stub(ENV).key?('YELL_ENV') { false }
+        stub(ENV).key?('RACK_ENV') { false }
+        stub(ENV).key?('RAILS_ENV') { false }
+      end
+
+      it { should == 'development' }
+    end
+  end
+
+end
+
diff --git a/yell.gemspec b/yell.gemspec
new file mode 100644
index 0000000..1624bd9
--- /dev/null
+++ b/yell.gemspec
@@ -0,0 +1,23 @@
+# coding: utf-8
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'yell/version'
+
+Gem::Specification.new do |spec|
+  spec.name        = "yell"
+  spec.version     = Yell::VERSION
+  spec.authors     = ["Rudolf Schmidt"]
+  spec.license     = 'MIT'
+
+  spec.homepage    = "http://rudionrailspec.github.com/yell"
+  spec.summary     = %q{Yell - Your Extensible Logging Library}
+  spec.description = %q{Yell - Your Extensible Logging Library. Define multiple adapters, various log level combinations or message formatting options like you've never done before}
+
+  spec.rubyforge_project = "yell"
+
+  spec.files         = `git ls-files -z`.split("\x0")
+  spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
+  spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
+  spec.require_paths = ["lib"]
+end
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-yell.git



More information about the Pkg-ruby-extras-commits mailing list