New Upstream Snapshot - ruby-yell

Ready changes

Summary

Merged new upstream version: 2.2.2+git20210825.1.1c5920b (was: 2.2.2).

Resulting package

Built on 2022-10-23T22:03 (took 14m51s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots ruby-yell

Lintian Result

Diff

diff --git a/.travis.yml b/.travis.yml
index 4971010..44c65ae 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,8 @@ language: ruby
 before_install: gem install bundler
 script: "bundle exec rspec"
 
+cache: bundler
+
 matrix:
   include:
     - rvm: ruby-head
diff --git a/debian/changelog b/debian/changelog
index a5603e6..5c1c80b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-ruby-yell (2.2.2-2) UNRELEASED; urgency=medium
+ruby-yell (2.2.2+git20210825.1.1c5920b-1) UNRELEASED; urgency=medium
 
   * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository,
     Repository-Browse.
@@ -8,8 +8,9 @@ ruby-yell (2.2.2-2) UNRELEASED; urgency=medium
   * Bump debhelper from old 12 to 13.
   * Update standards version to 4.5.1, no changes needed.
   * Update standards version to 4.6.1, no changes needed.
+  * New upstream snapshot.
 
- -- Debian Janitor <janitor@jelmer.uk>  Sat, 25 Apr 2020 01:58:24 +0000
+ -- Debian Janitor <janitor@jelmer.uk>  Sun, 23 Oct 2022 21:51:26 -0000
 
 ruby-yell (2.2.2-1) unstable; urgency=medium
 
diff --git a/spec/compatibility/activesupport_logger_spec.rb b/spec/compatibility/activesupport_logger_spec.rb
new file mode 100644
index 0000000..f00c008
--- /dev/null
+++ b/spec/compatibility/activesupport_logger_spec.rb
@@ -0,0 +1,36 @@
+# 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
+    expect($stdout).to receive(:syswrite).with("Hello World\n") # yell
+    expect($stdout).to receive(:write).with("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..d279233
--- /dev/null
+++ b/spec/compatibility/formatter_spec.rb
@@ -0,0 +1,21 @@
+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
+    expect($stdout).to(
+      receive(:write).with("#{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..edb11e4
--- /dev/null
+++ b/spec/compatibility/level_spec.rb
@@ -0,0 +1,36 @@
+require 'spec_helper'
+require 'logger'
+
+describe "backwards compatible level" do
+  let(:logger) { Logger.new($stdout) }
+
+  before do
+    logger.level = level
+  end
+
+  context "with a Yell::Level instance" do
+    let(:level) { Yell::Level.new(:error) }
+
+    it "should format out the level correctly" do
+      expect(logger.level).to eq(level.to_i)
+    end
+  end
+
+  context "with a symbol", :pending => (RUBY_VERSION < "2.3") do
+    let(:level) { :error }
+
+    it "should format out the level correctly" do
+      expect(logger.level).to eq(3)
+    end
+  end
+
+  context "with an integer" do
+    let(:level) { 2 }
+
+    it "should format out the level correctly" do
+      expect(logger.level).to eq(2)
+    end
+  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..5c9bfad
--- /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 'rspec/mocks'
+require 'rspec/its'
+require 'timecop'
+
+begin
+  require 'byebug'
+rescue LoadError
+  # do nothing
+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.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..bb886cc
--- /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
+      expect(lines).to eq(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)
+
+      expect(lines).to eq(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' ]
+        expect(files.size).to eq(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..f2ea412
--- /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 }
+    let(:adapter) { Yell::Adapters::Base.new(:level => 1) }
+
+    it "should delegate :event to :write!" do
+      event = Yell::Event.new(logger, 1, "Hello World!")
+      expect(adapter).to receive(:write!).with(event)
+
+      adapter.write(event)
+    end
+
+    it "should not write when event does not have the right level" do
+      event = Yell::Event.new(logger, 0, "Hello World!")
+      expect(adapter).to_not receive(:write!)
+
+      adapter.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..18b2188
--- /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_truthy
+
+      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_truthy
+      expect(today_lines.size).to eq(3) # includes header line
+    end
+
+    it "should not open file handle again" do
+      expect(File).to_not receive(:open)
+
+      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_truthy
+
+        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_truthy
+        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_truthy
+        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_falsey
+      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_truthy
+        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..6c33af8
--- /dev/null
+++ b/spec/yell/adapters/file_spec.rb
@@ -0,0 +1,84 @@
+require 'spec_helper'
+
+describe Yell::Adapters::File do
+  let(:devnull) { File.new('/dev/null', 'w') }
+
+  before do
+    allow(File).to receive(:open) { 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
+        expect(File).to(
+          receive(:open).
+            with(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
+        expect(File).to(
+          receive(:open).
+            with(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
+        expect(File).to(
+          receive(:open).
+            with(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
+        expect(devnull).to receive(:sync=).with(true)
+
+        adapter.write(event)
+      end
+
+      it "pass the option to File" do
+        adapter.sync = false
+
+        expect(devnull).to receive(:sync=).with(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..b7dab24
--- /dev/null
+++ b/spec/yell/adapters/io_spec.rb
@@ -0,0 +1,71 @@
+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
+      allow(adapter).to receive(:stream) { stream }
+    end
+
+    it "should format the message" do
+      expect(adapter.format).to(
+        receive(:call).with(event).and_call_original
+      )
+
+      adapter.write(event)
+    end
+
+    it "should print formatted message to stream" do
+      formatted = Yell::Formatter.new.call(event)
+      expect(stream).to receive(:syswrite).with(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..f009007
--- /dev/null
+++ b/spec/yell/adapters_spec.rb
@@ -0,0 +1,43 @@
+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
+      expect(Yell::Adapters::Stdout).to receive(:new).with(anything)
+
+      Yell::Adapters.new(STDOUT)
+    end
+
+    it "should accept STDERR" do
+      expect(Yell::Adapters::Stderr).to receive(:new).with(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(:type) { :test }
+    let(:klass) { double }
+
+    it "should allow to being called from :new" do
+      Yell::Adapters.register(type, klass)
+      expect(klass).to receive(:new).with(anything)
+
+      Yell::Adapters.new(type)
+    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..4d22386
--- /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_truthy
+  end
+
+  it "should perform #write" do
+    event = 'event'
+    allow(event).to receive(:level) { 0 }
+
+    adapter = DSLAdapter.new
+    expect(adapter.test_write?).to be_falsey
+
+    adapter.write(event)
+    expect(adapter.test_write?).to be_truthy
+  end
+
+  it "should perform #close" do
+    adapter = DSLAdapter.new
+    expect(adapter.test_close?).to be_falsey
+
+    adapter.close
+    expect(adapter.test_close?).to be_truthy
+  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..32edd51
--- /dev/null
+++ b/spec/yell/formatter_spec.rb
@@ -0,0 +1,199 @@
+# frozen_string_literal: true
+
+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(:time) { Time.now }
+
+  let(:pattern) { "%m" }
+  let(:formatter) { Yell::Formatter.new(pattern) }
+
+  let(:output) { formatter.call(event) }
+
+  before do
+    Timecop.freeze(time)
+  end
+
+  describe "patterns" do
+    context "%m" do
+      let(:pattern) { "%m" }
+
+      it "returns correctly" do
+        expect(output).to eq("#{event.messages.join(' ')}\n")
+      end
+    end
+
+    context "%l" do
+      let(:pattern) { "%l" }
+
+      it "returns correctly" do
+        expect(output).to eq("#{Yell::Severities[event.level][0,1]}\n")
+      end
+    end
+
+    context "%L" do
+      let(:pattern) { "%L" }
+
+      it "returns correctly" do
+        expect(output).to eq("#{Yell::Severities[event.level]}\n")
+      end
+    end
+
+    context "%d" do
+      let(:pattern) { "%d" }
+
+      it "returns correctly" do
+        expect(output).to eq("#{event.time.iso8601}\n")
+      end
+    end
+
+    context "%p" do
+      let(:pattern) { "%p" }
+
+      it "returns correctly" do
+        expect(output).to eq("#{event.pid}\n")
+      end
+    end
+
+    context "%P" do
+      let(:pattern) { "%P" }
+
+      it "returns correctly" do
+        expect(output).to eq("#{event.progname}\n")
+      end
+    end
+
+    context "%t" do
+      let(:pattern) { "%t" }
+
+      it "returns correctly" do
+        expect(output).to eq("#{event.thread_id}\n")
+      end
+    end
+
+    context "%h" do
+      let(:pattern) { "%h" }
+
+      it "returns correctly" do
+        expect(output).to eq("#{event.hostname}\n")
+      end
+    end
+
+    context ":caller" do
+      let(:_caller) { [nil, nil, "/path/to/file.rb:123:in `test_method'"] }
+
+      before do
+        allow(event).to receive(:file) { "/path/to/file.rb" }
+        allow(event).to receive(:line) { "123" }
+        allow(event).to receive(:method) { "test_method" }
+      end
+
+      context "%F" do
+        let(:pattern) { "%F" }
+
+        it "returns correctly" do
+          expect(output).to eq("/path/to/file.rb\n")
+        end
+      end
+
+      context "%f" do
+        let(:pattern) { "%f" }
+
+        it "returns correctly" do
+          expect(output).to eq("file.rb\n")
+        end
+      end
+
+      context "%M" do
+        let(:pattern) { "%M" }
+
+        it "returns correctly" do
+          expect(output).to eq("test_method\n")
+        end
+      end
+
+      context "%n" do
+        let(:pattern) { "%n" }
+
+        it "returns correctly" do
+          expect(output).to eq("123\n")
+        end
+      end
+    end
+
+    context "%N" do
+      let(:pattern) { "%N" }
+
+      it "returns correctly" do
+        expect(output).to eq("Yell\n")
+      end
+    end
+  end
+
+  describe "presets" do
+    context "NoFormat" do
+      let(:pattern) { Yell::NoFormat }
+
+      it "Retrns correctly" do
+        expect(output).to eq("Hello World!\n")
+      end
+    end
+
+    context "DefaultFormat" do
+      let(:pattern) { Yell::DefaultFormat }
+
+      it "returns correctly" do
+        expect(output).to eq("#{time.iso8601} [ INFO] #{$$} : Hello World!\n")
+      end
+    end
+
+    context "BasicFormat" do
+      let(:pattern) { Yell::BasicFormat }
+
+      it "returns correctly" do
+        expect(output).to eq("I, #{time.iso8601} : Hello World!\n")
+      end
+    end
+
+    context "ExtendedFormat" do
+      let(:pattern) { Yell::ExtendedFormat }
+
+      it "Returns correctly" do
+        expect(output).to eq("#{time.iso8601} [ INFO] #{$$} #{Socket.gethostname} : Hello World!\n")
+      end
+    end
+  end
+
+  describe "Exception" do
+    let(:message) { StandardError.new("This is an Exception") }
+
+    before do
+      allow(message).to receive(:backtrace) { ["backtrace"] }
+    end
+
+    it "returns correctly" do
+      expect(output).to eq("StandardError: This is an Exception\n\tbacktrace\n")
+    end
+  end
+
+  describe "Hash" do
+    let(:message) { {test: 'message'} }
+
+    it "Returns correctly" do
+      expect(output).to eq("test: message\n")
+    end
+  end
+
+  describe "custom message modifiers" do
+    let(:formatter) do
+      Yell::Formatter.new(pattern) { |f| f.modify(String) { |m| "Modified! #{m}" } }
+    end
+
+    it "Returns correctly" do
+      expect(output).to eq("Modified! #{message}\n")
+    end
+  end
+end
diff --git a/spec/yell/level_spec.rb b/spec/yell/level_spec.rb
new file mode 100644
index 0000000..12426b8
--- /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_truthy
+      expect(level.at?(:info)).to be_truthy
+      expect(level.at?(:warn)).to be_truthy
+      expect(level.at?(:error)).to be_truthy
+      expect(level.at?(:fatal)).to be_truthy
+    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_truthy
+        expect(level.at?(:info)).to be_truthy
+        expect(level.at?(:warn)).to be_truthy
+        expect(level.at?(:error)).to be_truthy
+        expect(level.at?(:fatal)).to be_truthy
+      end
+    end
+
+    context ":info" do
+      let(:severity) { :info }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_falsey
+        expect(level.at?(:info)).to be_truthy
+        expect(level.at?(:warn)).to be_truthy
+        expect(level.at?(:error)).to be_truthy
+        expect(level.at?(:fatal)).to be_truthy
+      end
+    end
+
+    context ":warn" do
+      let(:severity) { :warn }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_falsey
+        expect(level.at?(:info)).to be_falsey
+        expect(level.at?(:warn)).to be_truthy
+        expect(level.at?(:error)).to be_truthy
+        expect(level.at?(:fatal)).to be_truthy
+      end
+    end
+
+    context ":error" do
+      let(:severity) { :error }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_falsey
+        expect(level.at?(:info)).to be_falsey
+        expect(level.at?(:warn)).to be_falsey
+        expect(level.at?(:error)).to be_truthy
+        expect(level.at?(:fatal)).to be_truthy
+      end
+    end
+
+    context ":fatal" do
+      let(:severity) { :fatal }
+
+      it "should should return correctly" do
+        expect(level.at?(:debug)).to be_falsey
+        expect(level.at?(:info)).to be_falsey
+        expect(level.at?(:warn)).to be_falsey
+        expect(level.at?(:error)).to be_falsey
+        expect(level.at?(:fatal)).to be_truthy
+      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_falsey
+        expect(level.at?(:info)).to be_falsey
+        expect(level.at?(:warn)).to be_falsey
+        expect(level.at?(:error)).to be_truthy
+        expect(level.at?(:fatal)).to be_truthy
+      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_falsey
+        expect(level.at?(:info)).to be_truthy
+        expect(level.at?(:warn)).to be_truthy
+        expect(level.at?(:error)).to be_truthy
+        expect(level.at?(:fatal)).to be_falsey
+      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_falsey
+        expect(level.at?(:info)).to be_falsey
+        expect(level.at?(:warn)).to be_truthy
+        expect(level.at?(:error)).to be_falsey
+        expect(level.at?(:fatal)).to be_falsey
+      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_falsey
+        expect(level.at?(:info)).to be_truthy
+        expect(level.at?(:warn)).to be_falsey
+        expect(level.at?(:error)).to be_truthy
+        expect(level.at?(:fatal)).to be_falsey
+      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_truthy
+        expect(level.at?(:info)).to be_falsey
+        expect(level.at?(:warn)).to be_falsey
+        expect(level.at?(:error)).to be_truthy
+        expect(level.at?(:fatal)).to be_truthy
+      end
+    end
+  end
+
+  context "given an Array" do
+    let(:level) { Yell::Level.new( %i[debug warn fatal] ) }
+
+    it "should return correctly" do
+      expect(level.at?(:debug)).to be_truthy
+      expect(level.at?(:info)).to be_falsey
+      expect(level.at?(:warn)).to be_truthy
+      expect(level.at?(:error)).to be_falsey
+      expect(level.at?(:fatal)).to be_truthy
+    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_falsey
+      expect(level.at?(:info)).to be_truthy
+      expect(level.at?(:warn)).to be_truthy
+      expect(level.at?(:error)).to be_truthy
+      expect(level.at?(:fatal)).to be_falsey
+    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_falsey
+      expect(level.at?(:info)).to be_falsey
+      expect(level.at?(:warn)).to be_truthy
+      expect(level.at?(:error)).to be_truthy
+      expect(level.at?(:fatal)).to be_truthy
+    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..23b947b
--- /dev/null
+++ b/spec/yell/loggable_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+class LoggableFactory
+  include Yell::Loggable
+end
+
+describe Yell::Loggable do
+  let(:factory) { LoggableFactory.new }
+
+  it "responds with logger" do
+    expect(factory).to respond_to(:logger)
+  end
+
+  it "should make a lookup in the Yell::Repository" do
+    expect(Yell::Repository).to(
+      receive(:[]).with(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..c8b4dfc
--- /dev/null
+++ b/spec/yell/logger_spec.rb
@@ -0,0 +1,290 @@
+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
+      expect(Yell::Adapters::File).to(
+        receive(:new).with(filename: filename).and_call_original
+      )
+
+      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
+      expect(Yell::Adapters::File).to(
+        receive(:new).with(filename: pathname).and_call_original
+      )
+
+      Yell::Logger.new(pathname)
+    end
+  end
+
+  context "initialize with a :stdout adapter" do
+    before do
+      expect(Yell::Adapters::Stdout).to receive(:new)
+    end
+
+    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 do
+      expect(Yell::Adapters::Stderr).to receive(:new)
+    end
+
+    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
+      expect(Yell::Adapters::Stdout).to(
+        receive(:new).
+          and_call_original
+      )
+      expect(Yell::Adapters::Stderr).to(
+        receive(:new).
+          with(hash_including(level: :error)).
+          and_call_original
+      )
+
+      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
+
+      expect(stdout.send(:stream)).to(
+        receive(:syswrite).with("#{__FILE__}, 7: info\n")
+      )
+      expect(stdout.send(:stream)).to(
+        receive(:syswrite).with("#{__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"]
+      logger.info %w[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
+      expect(stdout).to_not receive(:write)
+
+      logger.info "this should not be logged"
+    end
+
+    it "should pass a non-matching message to any adapter" do
+      expect(stdout).to receive(:write).with(kind_of(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..84eed1c
--- /dev/null
+++ b/spec/yell/repository_spec.rb
@@ -0,0 +1,83 @@
+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)" do
+        expect(subject).to eq(logger)
+      end
+    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
+        expect(Yell::LoggerNotFound).to(
+          receive(:new).with(String).and_call_original
+        )
+
+        expect {
+          Yell::Repository[String]
+        }.to raise_error(Yell::LoggerNotFound)
+      end
+
+      it "should return the logger" do
+        expect(Yell::Repository[Numeric]).to eq(logger)
+      end
+
+      it "should return the logger when superclass has it defined" do
+        expect(Yell::Repository[Integer]).to eq(logger)
+      end
+    end
+  end
+
+  context ".[]=" do
+    before { Yell::Repository[name] = logger }
+    it "should eq(logger)" do
+      expect(subject).to eq(logger)
+    end
+  end
+
+  context ".[]= with a named logger" do
+    let!(:logger) { Yell.new(:stdout, name: name) }
+    before { Yell::Repository[name] = logger }
+
+    it "should eq(logger)" do
+      expect(subject).to eq(logger)
+    end
+  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
+      expect(Yell::Repository[name]).to eq(logger)
+      expect(Yell::Repository[other]).to eq(logger)
+    end
+  end
+
+  context "loggers" do
+    let(:loggers) { { name => logger } }
+    subject { Yell::Repository.loggers }
+    before { Yell::Repository[name] = logger }
+
+    it "should eq(loggers)" do
+      expect(subject).to eq(loggers)
+    end
+  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..367c6b1
--- /dev/null
+++ b/spec/yell_spec.rb
@@ -0,0 +1,120 @@
+require 'spec_helper'
+
+describe Yell do
+  let( :logger ) { Yell.new }
+
+  subject { logger }
+
+  it "should be_kind_of Yell::Logger" do
+    expect(subject).to be_a_kind_of(Yell::Logger)
+  end
+
+  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" do
+      expect(subject).to be_a_kind_of(Yell::Level)
+    end
+  end
+
+  context ".format" do
+    subject { Yell.format( "%m" ) }
+    it "should be_kind_of Yell::Formatter" do
+      expect(subject).to be_a_kind_of(Yell::Formatter)
+    end
+  end
+
+  context ".load!" do
+    subject { Yell.load!('yell.yml') }
+
+    before do
+      expect(Yell::Configuration).to(
+        receive(:load!).with('yell.yml') { {} }
+      )
+    end
+
+    it "should be_kind_of Yell::Logger" do
+      expect(subject).to be_a_kind_of(Yell::Logger)
+    end
+  end
+
+  context ".[]" do
+    let(:name) { 'test' }
+
+    it "should delegate to the repository" do
+      expect(Yell::Repository).to receive(:[]).with(name)
+
+      Yell[name]
+    end
+  end
+
+  context ".[]=" do
+    let(:name) { 'test' }
+
+    it "should delegate to the repository" do
+      expect(Yell::Repository).to(
+        receive(:[]=).with(name, logger).and_call_original
+      )
+
+      Yell[name] = logger
+    end
+  end
+
+  context ".env" do
+    subject { Yell.env }
+
+    it "should default to YELL_ENV" do
+      expect(subject).to eq('test')
+    end
+
+    context "fallback to RACK_ENV" do
+      before do
+        expect(ENV).to receive(:key?).with('YELL_ENV') { false }
+        expect(ENV).to receive(:key?).with('RACK_ENV') { true }
+
+        ENV['RACK_ENV'] = 'rack'
+      end
+
+      after { ENV.delete 'RACK_ENV' }
+
+      it "should == 'rack'" do
+        expect(subject).to eq('rack')
+      end
+    end
+
+    context "fallback to RAILS_ENV" do
+      before do
+        expect(ENV).to receive(:key?).with('YELL_ENV') { false }
+        expect(ENV).to receive(:key?).with('RACK_ENV') { false }
+        expect(ENV).to receive(:key?).with('RAILS_ENV') { true }
+
+        ENV['RAILS_ENV'] = 'rails'
+      end
+
+      after { ENV.delete 'RAILS_ENV' }
+
+      it "should == 'rails'" do
+        expect(subject).to eq('rails')
+      end
+    end
+
+    context "fallback to development" do
+      before do
+        expect(ENV).to receive(:key?).with('YELL_ENV') { false }
+        expect(ENV).to receive(:key?).with('RACK_ENV') { false }
+        expect(ENV).to receive(:key?).with('RAILS_ENV') { false }
+      end
+
+      it "should == 'development'" do
+        expect(subject).to eq('development')
+      end
+    end
+  end
+
+end
+

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details