bracken 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +11 -0
- data/Rakefile +15 -0
- data/bin/bracken +9 -0
- data/examples/console.rb +6 -0
- data/features/step_definitions/bracken_steps.rb +15 -0
- data/features/support/env.rb +49 -0
- data/features/tailing.feature +33 -0
- data/lib/bracken.rb +3 -0
- data/lib/bracken/application.rb +30 -0
- data/lib/bracken/configuration.rb +26 -0
- data/lib/bracken/configuration/builder.rb +39 -0
- data/lib/bracken/configuration/options.rb +25 -0
- data/lib/bracken/logfile.rb +27 -0
- data/lib/bracken/logfile/filter.rb +24 -0
- data/lib/bracken/logfile/stream.rb +21 -0
- data/test/configuration_builder_test.rb +38 -0
- data/test/configuration_options_test.rb +22 -0
- data/test/configuration_test.rb +29 -0
- data/test/logfile_filter_test.rb +19 -0
- data/test/logfile_test.rb +21 -0
- data/test/test_helper.rb +15 -0
- metadata +148 -0
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'shoe'
|
3
|
+
rescue LoadError
|
4
|
+
abort 'Please `gem install shoe` to get started.'
|
5
|
+
end
|
6
|
+
|
7
|
+
Shoe.tie('bracken', '0.1.0', 'Bracken, at present, is a glorified logfile tailer.') do |spec|
|
8
|
+
spec.add_runtime_dependency 'open4'
|
9
|
+
|
10
|
+
spec.add_development_dependency 'cucumber'
|
11
|
+
spec.add_development_dependency 'fakefs'
|
12
|
+
spec.add_development_dependency 'jeremymcanally-matchy'
|
13
|
+
spec.add_development_dependency 'redgreen'
|
14
|
+
spec.add_development_dependency 'thoughtbot-shoulda'
|
15
|
+
end
|
data/bin/bracken
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Add our lib directory to the load path as necessary
|
4
|
+
lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
|
+
$:.unshift(lib) unless $:.include?(lib)
|
6
|
+
|
7
|
+
# And fire off the application
|
8
|
+
require 'bracken'
|
9
|
+
Bracken::Application.execute(ARGV)
|
data/examples/console.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Given /^these are the contents of "([^\"]*)":$/ do |path, contents|
|
2
|
+
write_to_file(path, contents)
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^another process appends "([^\"]*)" to "([^\"]*)"$/ do |contents, path|
|
6
|
+
write_to_file(path, contents, 'a')
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^I run (.*)$/ do |command|
|
10
|
+
run(command)
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^I should see "([^\"]*)" on standard out$/ do |expected|
|
14
|
+
standard_out.gets.chomp.should == expected
|
15
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'open4'
|
2
|
+
require 'pathname'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
class WorkingDirectory
|
6
|
+
PROJECT_ROOT = Pathname.new(File.expand_path(File.join(File.dirname(__FILE__), '..', '..')))
|
7
|
+
|
8
|
+
attr_reader :working_directory
|
9
|
+
attr_reader :standard_out
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@working_directory ||= Pathname.new(Dir.mktmpdir)
|
13
|
+
end
|
14
|
+
|
15
|
+
def write_to_file(path, contents, mode='w')
|
16
|
+
working_directory.join(path).open(mode) { |file| file.puts(contents) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def run(command)
|
20
|
+
Dir.chdir(working_directory) do
|
21
|
+
@pid, _, @standard_out, _ = Open4.popen4(rejigger_the_path(command))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def terminate_last_run
|
26
|
+
Process.kill('TERM', @pid) if @pid
|
27
|
+
@pid = nil
|
28
|
+
@standard_out = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def rejigger_the_path(command)
|
34
|
+
"/usr/bin/env -i PATH='#{PROJECT_ROOT.join('bin')}:#{ENV['PATH']}' RUBYLIB='#{PROJECT_ROOT.join('lib')}' RUBYOPT=rubygems #{command}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
World do
|
39
|
+
WorkingDirectory.new
|
40
|
+
end
|
41
|
+
|
42
|
+
Before do
|
43
|
+
working_directory.mkpath
|
44
|
+
end
|
45
|
+
|
46
|
+
After do
|
47
|
+
terminate_last_run
|
48
|
+
working_directory.rmtree
|
49
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Feature: Tailing
|
2
|
+
In order to keep track of what's going on with the system
|
3
|
+
As a system operator
|
4
|
+
I want to simultaneously tail (and filter) a set of logfiles
|
5
|
+
|
6
|
+
Scenario: Tailing an existing file with no filters or transformations
|
7
|
+
Given these are the contents of "config.rb":
|
8
|
+
"""
|
9
|
+
file 'syslog'
|
10
|
+
"""
|
11
|
+
And these are the contents of "syslog":
|
12
|
+
"""
|
13
|
+
Line One
|
14
|
+
"""
|
15
|
+
When I run bracken -c config.rb
|
16
|
+
Then I should see "Line One" on standard out
|
17
|
+
When another process appends "Line Two" to "syslog"
|
18
|
+
Then I should see "Line Two" on standard out
|
19
|
+
|
20
|
+
Scenario: Tailing and filtering an existing file
|
21
|
+
Given these are the contents of "config.rb":
|
22
|
+
"""
|
23
|
+
file 'syslog' do
|
24
|
+
on 'fetchmail', /reading message/
|
25
|
+
end
|
26
|
+
"""
|
27
|
+
And these are the contents of "syslog":
|
28
|
+
"""
|
29
|
+
Sep 30 13:11:39 frodo fetchmail[19159]: skipping message bob@example.org@pop.example.org:1 (51945 octets) (oversized) flushed
|
30
|
+
Sep 30 13:12:08 frodo fetchmail[19159]: reading message bob@example.org@pop.example.org:1 of 1 (4697 octets) flushed
|
31
|
+
"""
|
32
|
+
When I run bracken -c config.rb
|
33
|
+
Then I should see "Sep 30 13:12:08 frodo fetchmail[19159]: reading message bob@example.org@pop.example.org:1 of 1 (4697 octets) flushed" on standard out
|
data/lib/bracken.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Bracken
|
2
|
+
class Application
|
3
|
+
def self.execute(arguments)
|
4
|
+
new.execute(arguments)
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :configuration
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@configuration = Configuration.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(arguments)
|
14
|
+
configuration.parse(arguments)
|
15
|
+
|
16
|
+
while activity = IO.select(configuration.streams)
|
17
|
+
streams = activity.first
|
18
|
+
|
19
|
+
streams.each do |stream|
|
20
|
+
line = stream.filtered_gets
|
21
|
+
|
22
|
+
if line
|
23
|
+
STDOUT.puts line
|
24
|
+
STDOUT.flush
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'bracken/configuration/builder'
|
2
|
+
require 'bracken/configuration/options'
|
3
|
+
|
4
|
+
module Bracken
|
5
|
+
class Configuration
|
6
|
+
attr_reader :options
|
7
|
+
attr_reader :builder
|
8
|
+
attr_reader :files
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@options = Options.new
|
12
|
+
@builder = Builder.new(self)
|
13
|
+
@files = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse(arguments)
|
17
|
+
options.parse(arguments)
|
18
|
+
builder.parse(options.configuration_file)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def streams
|
23
|
+
files.map { |file| file.stream }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Bracken
|
4
|
+
class Configuration
|
5
|
+
|
6
|
+
class Builder
|
7
|
+
attr_reader :configuration
|
8
|
+
attr_reader :output_stream
|
9
|
+
attr_reader :error_stream
|
10
|
+
|
11
|
+
def initialize(configuration, output_stream = STDOUT, error_stream = STDERR)
|
12
|
+
@configuration = configuration
|
13
|
+
@output_stream = output_stream
|
14
|
+
@error_stream = error_stream
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse(pathname)
|
18
|
+
if File.exist?(pathname)
|
19
|
+
instance_eval(File.read(pathname), pathname)
|
20
|
+
else
|
21
|
+
error_stream.puts("WARNING file #{pathname} does not exist!")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def file(path, &block)
|
26
|
+
configuration.files << Logfile.new(path)
|
27
|
+
|
28
|
+
if block_given?
|
29
|
+
instance_eval(&block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def on(*args)
|
34
|
+
configuration.files.last.filters << Logfile::Filter.new(*args)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Bracken
|
4
|
+
class Configuration
|
5
|
+
|
6
|
+
class Options
|
7
|
+
attr_reader :configuration_file
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@configuration_file = '/etc/bracken.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(arguments)
|
14
|
+
arguments.extend(::OptionParser::Arguable)
|
15
|
+
|
16
|
+
arguments.options do |opts|
|
17
|
+
opts.on('-c', '--config-file PATH', 'Read configuration from PATH.', '[/etc/bracken.rb]') do |path|
|
18
|
+
@configuration_file = path
|
19
|
+
end
|
20
|
+
end.parse!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'bracken/logfile/filter'
|
2
|
+
require 'bracken/logfile/stream'
|
3
|
+
require 'open4'
|
4
|
+
|
5
|
+
module Bracken
|
6
|
+
class Logfile
|
7
|
+
attr_reader :filters
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
@filters = []
|
12
|
+
@path = path
|
13
|
+
end
|
14
|
+
|
15
|
+
def stream
|
16
|
+
@stream ||= begin
|
17
|
+
pid, _, out, _ = Open4.popen4("tail -f #{path}")
|
18
|
+
|
19
|
+
out.extend(Stream)
|
20
|
+
out.logfile = self
|
21
|
+
out.pid = pid
|
22
|
+
|
23
|
+
out
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bracken
|
2
|
+
class Logfile
|
3
|
+
|
4
|
+
class Filter < Struct.new(:service, :pattern)
|
5
|
+
# FIXME this is heinous
|
6
|
+
def match?(line)
|
7
|
+
if line.include?(service)
|
8
|
+
if pattern
|
9
|
+
if line.match(pattern)
|
10
|
+
true
|
11
|
+
else
|
12
|
+
false
|
13
|
+
end
|
14
|
+
else
|
15
|
+
true
|
16
|
+
end
|
17
|
+
else
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bracken
|
2
|
+
class Logfile
|
3
|
+
|
4
|
+
module Stream
|
5
|
+
attr_accessor :logfile
|
6
|
+
attr_accessor :pid
|
7
|
+
|
8
|
+
# FIXME this could use work
|
9
|
+
def filtered_gets
|
10
|
+
line = gets
|
11
|
+
line if logfile.filters.empty? || logfile.filters.any? { |filter| filter.match?(line) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def kill
|
15
|
+
Process.kill('TERM', pid)
|
16
|
+
Process.wait(pid)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class ConfigurationBuilderTest < Test::Unit::TestCase
|
4
|
+
context '#parse' do
|
5
|
+
should "warn on standard error when configuration file doesn't exist" do
|
6
|
+
error_stream = StringIO.new('')
|
7
|
+
|
8
|
+
builder = Configuration::Builder.new(nil, nil, error_stream)
|
9
|
+
builder.parse('/does/not/exist')
|
10
|
+
error_stream.rewind
|
11
|
+
error_stream.read.should == "WARNING file /does/not/exist does not exist!\n"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context '#file' do
|
16
|
+
should 'add a new file into the configuration' do
|
17
|
+
configuration = Configuration.new
|
18
|
+
|
19
|
+
builder = Configuration::Builder.new(configuration)
|
20
|
+
builder.file('/foo/bar')
|
21
|
+
|
22
|
+
configuration.files.map { |file| file.path }.should == ['/foo/bar']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context '#on' do
|
27
|
+
should 'add a filter to the current file' do
|
28
|
+
configuration = Configuration.new
|
29
|
+
|
30
|
+
builder = Configuration::Builder.new(configuration)
|
31
|
+
builder.file('/foo/bar') do
|
32
|
+
on 'foo'
|
33
|
+
end
|
34
|
+
|
35
|
+
configuration.files.map { |file| file.filters }.should == [[Logfile::Filter.new('foo')]]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class ConfigurationOptionsTest < Test::Unit::TestCase
|
4
|
+
context 'options' do
|
5
|
+
setup { @options = Configuration::Options.new }
|
6
|
+
|
7
|
+
should 'default the configuration file to /etc/bracken.rb' do
|
8
|
+
@options.parse(%w())
|
9
|
+
@options.configuration_file.should == '/etc/bracken.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'use the configuration file from -c' do
|
13
|
+
@options.parse(%w(-c config.rb))
|
14
|
+
@options.configuration_file.should == 'config.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'use the configuration file from --config-file' do
|
18
|
+
@options.parse(%w(--config-file config.rb))
|
19
|
+
@options.configuration_file.should == 'config.rb'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class ConfigurationTest < Test::Unit::TestCase
|
4
|
+
context 'faking the filesystem' do
|
5
|
+
setup { FakeFS.activate! }
|
6
|
+
teardown { FakeFS.deactivate! }
|
7
|
+
|
8
|
+
context '#files' do
|
9
|
+
should 'be empty when the configuration file specifies no files' do
|
10
|
+
File.open('/etc/bracken.rb', 'w') { |file| file.write('') }
|
11
|
+
Configuration.new.parse([]).files.should == []
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'have the files specified in the configuration file' do
|
15
|
+
File.open('/etc/bracken.rb', 'w') { |file| file.write('file "/var/log/syslog"') }
|
16
|
+
Configuration.new.parse([]).files.map { |file| file.path }.should == ['/var/log/syslog']
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context '#streams' do
|
21
|
+
should 'return the IO stream for each file' do
|
22
|
+
File.open('/etc/bracken.rb', 'w') { |file| file.write('file "/var/log/syslog"') }
|
23
|
+
|
24
|
+
configuration = Configuration.new.parse([])
|
25
|
+
configuration.streams.should == configuration.files.map { |file| file.stream }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class LogfileFilterTest < Test::Unit::TestCase
|
4
|
+
context '#match?' do
|
5
|
+
setup do
|
6
|
+
@line = 'Sep 30 13:11:39 frodo fetchmail[19159]: skipping message bob@example.org@pop.example.org:1 (51945 octets) (oversized) flushed'
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'match a syslog-style service name' do
|
10
|
+
Logfile::Filter.new('postfix').match?(@line).should == false
|
11
|
+
Logfile::Filter.new('fetchmail').match?(@line).should == true
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'match a syslog-style service name and filter by pattern' do
|
15
|
+
Logfile::Filter.new('fetchmail', /reading message/).match?(@line).should == false
|
16
|
+
Logfile::Filter.new('fetchmail', /skipping message/).match?(@line).should == true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class LogfileTest < Test::Unit::TestCase
|
4
|
+
context '#stream' do
|
5
|
+
setup do
|
6
|
+
@logfile = Logfile.new(__FILE__)
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'return a selectable, killable IO object tailing the file' do
|
10
|
+
reads, _, _ = IO.select([@logfile.stream], nil, nil, 0.2)
|
11
|
+
|
12
|
+
stream = reads.first
|
13
|
+
|
14
|
+
begin
|
15
|
+
stream.gets.should == File.readlines(__FILE__)[-10]
|
16
|
+
ensure
|
17
|
+
stream.kill
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'fakefs/safe'
|
5
|
+
require 'matchy'
|
6
|
+
require 'redgreen' if STDIN.tty?
|
7
|
+
require 'shoulda'
|
8
|
+
|
9
|
+
lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
10
|
+
$:.unshift(lib) unless $:.include?(lib)
|
11
|
+
require 'bracken'
|
12
|
+
|
13
|
+
class Test::Unit::TestCase
|
14
|
+
include Bracken
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bracken
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew Todd
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-28 00:00:00 +03:00
|
13
|
+
default_executable: bracken
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: shoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: open4
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: cucumber
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: fakefs
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: jeremymcanally-matchy
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: redgreen
|
67
|
+
type: :development
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: thoughtbot-shoulda
|
77
|
+
type: :development
|
78
|
+
version_requirement:
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
description:
|
86
|
+
email: matthew.todd@gmail.com
|
87
|
+
executables:
|
88
|
+
- bracken
|
89
|
+
extensions: []
|
90
|
+
|
91
|
+
extra_rdoc_files:
|
92
|
+
- README.rdoc
|
93
|
+
files:
|
94
|
+
- Rakefile
|
95
|
+
- README.rdoc
|
96
|
+
- bin/bracken
|
97
|
+
- examples/console.rb
|
98
|
+
- features/step_definitions/bracken_steps.rb
|
99
|
+
- features/support/env.rb
|
100
|
+
- features/tailing.feature
|
101
|
+
- lib/bracken/application.rb
|
102
|
+
- lib/bracken/configuration/builder.rb
|
103
|
+
- lib/bracken/configuration/options.rb
|
104
|
+
- lib/bracken/configuration.rb
|
105
|
+
- lib/bracken/logfile/filter.rb
|
106
|
+
- lib/bracken/logfile/stream.rb
|
107
|
+
- lib/bracken/logfile.rb
|
108
|
+
- lib/bracken.rb
|
109
|
+
- test/configuration_builder_test.rb
|
110
|
+
- test/configuration_options_test.rb
|
111
|
+
- test/configuration_test.rb
|
112
|
+
- test/logfile_filter_test.rb
|
113
|
+
- test/logfile_test.rb
|
114
|
+
- test/test_helper.rb
|
115
|
+
has_rdoc: true
|
116
|
+
homepage:
|
117
|
+
licenses: []
|
118
|
+
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options:
|
121
|
+
- --main
|
122
|
+
- README.rdoc
|
123
|
+
- --title
|
124
|
+
- bracken-0.1.0
|
125
|
+
- --inline-source
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: "0"
|
133
|
+
version:
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: "0"
|
139
|
+
version:
|
140
|
+
requirements: []
|
141
|
+
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 1.3.5
|
144
|
+
signing_key:
|
145
|
+
specification_version: 3
|
146
|
+
summary: Bracken, at present, is a glorified logfile tailer.
|
147
|
+
test_files: []
|
148
|
+
|