yell 0.1.0 → 0.2.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/Gemfile +2 -2
- data/LICENSE.txt +21 -0
- data/README.md +64 -0
- data/lib/yell.rb +49 -10
- data/lib/yell/adapters.rb +50 -14
- data/lib/yell/adapters/.file.rb.swp +0 -0
- data/lib/yell/adapters/base.rb +47 -64
- data/lib/yell/adapters/datefile.rb +49 -24
- data/lib/yell/adapters/file.rb +17 -80
- data/lib/yell/adapters/io.rb +89 -0
- data/lib/yell/formatter.rb +26 -21
- data/lib/yell/level.rb +139 -0
- data/lib/yell/logger.rb +105 -42
- data/lib/yell/version.rb +1 -1
- data/spec/spec_helper.rb +0 -9
- data/spec/yell_spec.rb +1 -0
- data/yell.gemspec +3 -3
- metadata +16 -8
- data/lib/yell/config.rb +0 -53
data/Gemfile
CHANGED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2011-2012 Rudolf Schmidt
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
Yell - Your Extensible Logging Library
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
System wide:
|
6
|
+
|
7
|
+
```console
|
8
|
+
gem install yell
|
9
|
+
```
|
10
|
+
|
11
|
+
Or in your Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'yell'
|
15
|
+
```
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
On the basics, Yell works just like any other logging library. However, it
|
19
|
+
tries to make your log mesages more readable. By default, it will format the given
|
20
|
+
message as follows:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
logger = Yell.new STDOUT
|
24
|
+
|
25
|
+
logger.info "Hello World"
|
26
|
+
"2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World"
|
27
|
+
#^ ^ ^ ^
|
28
|
+
#ISO8601 Timestamp Level Pid message
|
29
|
+
```
|
30
|
+
|
31
|
+
You can alternate the formatting, or completely disable it altogether. See the
|
32
|
+
next examples for reference:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
# No formatting
|
36
|
+
logger = Yell.new STDOUT, :format => false
|
37
|
+
logger.info "No formatting"
|
38
|
+
"No formatting"
|
39
|
+
|
40
|
+
# Alternate formatting
|
41
|
+
logger = Yell.new STDOUT, :format => "'%m' at %d"
|
42
|
+
logger.info "Alternate formatting"
|
43
|
+
"'Alternate format' at 2012-02-29T09:30:00+01:00"
|
44
|
+
```
|
45
|
+
|
46
|
+
As you can see, it basically is just string interpolation with a few reserved
|
47
|
+
captures. You can see the list at #Yell::Formatter.
|
48
|
+
|
49
|
+
When no arguments are given, Yell will check for `ENV['RACK_ENV']` and
|
50
|
+
determine the filename from that.
|
51
|
+
|
52
|
+
Alternatively, you may define `ENV['YELL_ENV']` to set the filename. If neither
|
53
|
+
`YELL_ENV` or `RACK_ENV` is defined, `'development'` will be the default. Also, if a
|
54
|
+
`log` directory exists, Yell will place the file there (only if you have not passed
|
55
|
+
a filename explicitly.
|
56
|
+
|
57
|
+
Naturally, if you pass a `:filename` to Yell:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
logger = Yell.new 'custom.log'
|
61
|
+
```
|
62
|
+
|
63
|
+
Copyright © 2011-2012 Rudolf Schmidt, released under the MIT license
|
64
|
+
|
data/lib/yell.rb
CHANGED
@@ -1,19 +1,58 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
# Copyright (c) 2011-2012 Rudolf Schmidt
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
7
23
|
|
8
|
-
|
24
|
+
require 'time'
|
9
25
|
|
26
|
+
$: << File.dirname(__FILE__)
|
10
27
|
|
11
|
-
|
28
|
+
require 'yell/formatter'
|
29
|
+
require 'yell/adapters'
|
30
|
+
require 'yell/level'
|
31
|
+
require 'yell/logger'
|
32
|
+
|
33
|
+
module Yell #:nodoc:
|
34
|
+
# The possible log levels
|
35
|
+
Severities = [ 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'UNKNOWN' ]
|
36
|
+
|
37
|
+
extend self
|
38
|
+
|
39
|
+
# Creates a new logger instance.
|
40
|
+
#
|
41
|
+
# Refer to #Yell::Loggger for usage.
|
42
|
+
#
|
43
|
+
# @returns [Yell::Logger] The logger instance
|
44
|
+
def new( *args, &block )
|
12
45
|
Yell::Logger.new( *args, &block )
|
13
46
|
end
|
14
|
-
|
15
|
-
|
16
|
-
|
47
|
+
|
48
|
+
|
49
|
+
def env #:nodoc:
|
50
|
+
ENV['YELL_ENV'] || ENV['RACK_ENV'] || 'development'
|
51
|
+
end
|
52
|
+
|
53
|
+
def level( val = nil ) #:nodoc:
|
54
|
+
Yell::Level.new( val )
|
17
55
|
end
|
18
56
|
|
19
57
|
end
|
58
|
+
|
data/lib/yell/adapters.rb
CHANGED
@@ -1,21 +1,57 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yell/adapters/base'
|
4
|
+
require 'yell/adapters/io'
|
5
|
+
require 'yell/adapters/file'
|
6
|
+
require 'yell/adapters/datefile'
|
7
|
+
|
8
|
+
module Yell #:nodoc:
|
9
|
+
|
10
|
+
# NoSuchAdapter is raised whenever you want to instantiate an
|
11
|
+
# adapter that does not exist.
|
12
|
+
class NoSuchAdapter < StandardError; end
|
13
|
+
|
14
|
+
# This module provides the interface to attaching adapters to
|
15
|
+
# the logger. You should not have to call the corresponding classes
|
16
|
+
# directly.
|
2
17
|
module Adapters
|
18
|
+
extend self
|
3
19
|
|
4
|
-
|
5
|
-
|
6
|
-
|
20
|
+
# Returns an instance of the given processor type.
|
21
|
+
#
|
22
|
+
# @example A simple file adapter
|
23
|
+
# Yell::Adapters[ :file ]
|
24
|
+
def []( type, options = {}, &block )
|
25
|
+
# return type if type.instance_of?(Yell::Adapters::)
|
26
|
+
|
27
|
+
if type.instance_of?( ::IO )
|
28
|
+
# should apply to STDOUT, STDERR, File, etc
|
29
|
+
Yell::Adapters::Io.new( type, options, &block )
|
30
|
+
else
|
31
|
+
# any other type
|
32
|
+
adapter = case type
|
33
|
+
when String, Symbol then self.const_get( camelize(type.to_s) )
|
34
|
+
else type
|
35
|
+
end
|
7
36
|
|
8
|
-
|
9
|
-
def self.new( type, options = {}, &block )
|
10
|
-
klass = case type
|
11
|
-
when String, Symbol then const_get( type.to_s.capitalize )
|
12
|
-
else type
|
37
|
+
adapter.new( options, &block )
|
13
38
|
end
|
14
|
-
|
15
|
-
klass.new( options, &block )
|
16
|
-
rescue NameError => e
|
17
|
-
raise Yell::NoSuchAdapter, "no such adapter #{type.inspect}"
|
18
39
|
end
|
19
|
-
|
40
|
+
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Simple camelcase converter.
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# camelize("file")
|
48
|
+
# #=> "File"
|
49
|
+
#
|
50
|
+
# camelize("date_file")
|
51
|
+
# #=> "DateFile"
|
52
|
+
def camelize( str )
|
53
|
+
str.capitalize.gsub( /(_\w)/ ) { |match| match.reverse.chop.upcase }
|
54
|
+
end
|
55
|
+
|
20
56
|
end
|
21
57
|
end
|
Binary file
|
data/lib/yell/adapters/base.rb
CHANGED
@@ -1,72 +1,55 @@
|
|
1
|
-
|
2
|
-
class Base
|
1
|
+
# encoding: utf-8
|
3
2
|
|
4
|
-
|
3
|
+
module Yell #:nodoc:
|
4
|
+
module Adapters #:nodoc:
|
5
5
|
|
6
|
-
#
|
7
|
-
|
8
|
-
@block = block
|
9
|
-
|
10
|
-
@name = options[:name] || Yell.config.env
|
11
|
-
@level, @data = '', '' # default
|
12
|
-
end
|
13
|
-
|
14
|
-
def call ( level, msg )
|
15
|
-
reset!(true) if reset? # connect / get a file handle or whatever
|
16
|
-
|
17
|
-
@level, @message = level, msg
|
18
|
-
|
19
|
-
# self.instance_eval &@block if @block
|
20
|
-
@block.call( self ) if @block
|
21
|
-
end
|
22
|
-
|
23
|
-
def message
|
24
|
-
return @message if @message.is_a?( String )
|
25
|
-
|
26
|
-
@message.inspect
|
27
|
-
end
|
28
|
-
|
29
|
-
# Convenience method for resetting the processor.
|
6
|
+
# This class provides the basic interface for all allowed
|
7
|
+
# operations on any adapter implementation.
|
30
8
|
#
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
9
|
+
# Other adapters should include it for the base methods used
|
10
|
+
# by the {Yell::Logger}.
|
11
|
+
module Base
|
12
|
+
|
13
|
+
# The main method for calling the adapter.
|
14
|
+
#
|
15
|
+
# Adapter classes should provide their own implementation
|
16
|
+
# of this method.
|
17
|
+
def write( level, message )
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# Determine whether to write at the given severity.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# write? :error
|
25
|
+
#
|
26
|
+
# @param [String,Symbol,Integer] severity The severity to ask if to write or not.
|
27
|
+
#
|
28
|
+
# @return [Boolean] true or false
|
29
|
+
def write?( severity )
|
30
|
+
@level.nil? || @level.at?( severity )
|
31
|
+
end
|
32
|
+
|
33
|
+
# Close the adapter (stream, connection, etc).
|
34
|
+
#
|
35
|
+
# Adapter classes should provide their own implementation
|
36
|
+
# of this method.
|
37
|
+
def close
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Set the log level.
|
42
|
+
#
|
43
|
+
# @example Set minimum level to :info
|
44
|
+
# level :info
|
45
|
+
#
|
46
|
+
# For more examples, refer to {Yell::Level}.
|
47
|
+
def level( severity = nil )
|
48
|
+
@level = Yell::Level.new( severity )
|
49
|
+
end
|
41
50
|
|
42
|
-
# Closes the file handle or connection (in case of a database adapter)
|
43
|
-
def close
|
44
|
-
close! unless closed?
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def reset?; closed?; end
|
51
|
-
|
52
|
-
# stub
|
53
|
-
def open!
|
54
|
-
raise "Not implemented"
|
55
|
-
end
|
56
|
-
|
57
|
-
def opened?; false; end
|
58
|
-
|
59
|
-
# stub
|
60
|
-
def close!
|
61
|
-
raise "Not implemented"
|
62
|
-
end
|
63
|
-
|
64
|
-
def closed?; !opened?; end
|
65
|
-
|
66
|
-
# stub
|
67
|
-
def write
|
68
|
-
raise 'Not implemented'
|
69
51
|
end
|
70
52
|
|
71
53
|
end
|
72
54
|
end
|
55
|
+
|
@@ -1,38 +1,63 @@
|
|
1
|
-
|
2
|
-
class Datefile < Yell::Adapters::File
|
1
|
+
# encoding: utf-8
|
3
2
|
|
4
|
-
|
3
|
+
module Yell #:nodoc:
|
4
|
+
module Adapters #:nodoc:
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
# The +Datefile+ adapter is similar to the +File+ adapter. However, it
|
7
|
+
# rotates the file at midnight.
|
8
|
+
class Datefile < Yell::Adapters::File
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
# The default date pattern, e.g. "19820114" (14 Jan 1982)
|
11
|
+
DefaultDatePattern = "%Y%m%d"
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
def initialize( options = {}, &block )
|
14
|
+
@date_pattern = options[:date_pattern] || DefaultDatePattern
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
super( now )
|
19
|
-
end
|
16
|
+
@file_basename = options[:filename] || default_filename
|
17
|
+
options[:filename] = @file_basename
|
20
18
|
|
19
|
+
@date = nil # default; do not override --R
|
20
|
+
|
21
|
+
super( options, &block )
|
22
|
+
end
|
21
23
|
|
22
|
-
|
24
|
+
def write( level, message )
|
25
|
+
close if close?
|
23
26
|
|
24
|
-
|
25
|
-
_date = Time.now.strftime( @date_pattern )
|
26
|
-
unless opened? && _date == @date
|
27
|
-
@date = _date
|
28
|
-
return true
|
27
|
+
super( level, message )
|
29
28
|
end
|
30
29
|
|
31
|
-
|
32
|
-
|
30
|
+
# @override Reset the file handle
|
31
|
+
def close
|
32
|
+
@filename = new_filename
|
33
|
+
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Determines whether to close the file handle or not.
|
41
|
+
#
|
42
|
+
# It is based on the `:date_pattern` (can be passed as option upon initialize).
|
43
|
+
# If the current time hits the pattern, it closes the file stream.
|
44
|
+
#
|
45
|
+
# @return [Boolean] true or false
|
46
|
+
def close?
|
47
|
+
_date = Time.now.strftime( @date_pattern )
|
48
|
+
if !@stream or _date != @date
|
49
|
+
@date = _date
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sets the filename with the `:date_pattern` appended to it.
|
57
|
+
def new_filename
|
58
|
+
@file_basename.sub( /(\.\w+)?$/, ".#{@date}\\1" )
|
59
|
+
end
|
33
60
|
|
34
|
-
def new_filename
|
35
|
-
@file_basename.sub( /(\.\w+)?$/, ".#{@date}\\1" )
|
36
61
|
end
|
37
62
|
|
38
63
|
end
|
data/lib/yell/adapters/file.rb
CHANGED
@@ -1,95 +1,32 @@
|
|
1
|
-
|
2
|
-
class File < Yell::Adapters::Base
|
1
|
+
# encoding: utf-8
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
# 'INFO' => "\e[0m", # white
|
7
|
-
'WARN' => "\e[33;1m", # yello;bold
|
8
|
-
'ERROR' => "\e[31;1m", # red;bold
|
9
|
-
'FATAL' => "\e[35;1m", # magenta;bold
|
10
|
-
'UNKNOWN' => "\e[36m", # cyan
|
11
|
-
'DEFAULT' => "\e[0m" # NONE
|
12
|
-
}
|
3
|
+
module Yell #:nodoc:
|
4
|
+
module Adapters #:nodoc:
|
13
5
|
|
14
|
-
|
15
|
-
|
6
|
+
# The +File+ adapter is the most basic. As one would expect, it's used
|
7
|
+
# for logging into files.
|
8
|
+
class File < Yell::Adapters::Io
|
16
9
|
|
17
|
-
|
10
|
+
def initialize( options = {}, &block )
|
11
|
+
super( nil, options, &block )
|
18
12
|
|
19
|
-
|
20
|
-
@filename = options[:filename] || default_filename
|
21
|
-
|
22
|
-
@file_prefix, @file_suffix = options[:file_prefix], options[:file_suffix]
|
23
|
-
|
24
|
-
# validate the filename
|
25
|
-
unless @filename.is_a?( String )
|
26
|
-
raise( TypeError, "Argument :filename must be a string." )
|
13
|
+
@filename = options.fetch(:filename, default_filename)
|
27
14
|
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def call ( level, msg )
|
31
|
-
super # Base call
|
32
|
-
|
33
|
-
msg = @formatter.format( @level, message )
|
34
|
-
msg = colorize( @level, msg ) if @colorize
|
35
|
-
msg << "\n" unless msg[-1] == ?\n # add new line if there is none
|
36
15
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def write ( msg )
|
44
|
-
@file.print( msg )
|
45
|
-
@file.flush
|
46
|
-
rescue Exception => e
|
47
|
-
close # make sure the file gets closed
|
48
|
-
raise( e ) # re-raise the error
|
49
|
-
end
|
50
|
-
|
51
|
-
def close!
|
52
|
-
@file.close
|
53
|
-
@file = nil
|
54
|
-
end
|
55
|
-
|
56
|
-
def open!
|
57
|
-
# create directory if not exists
|
58
|
-
dirname = ::File.dirname( @filename )
|
59
|
-
FileUtils.mkdir_p( dirname ) unless ::File.directory?( dirname )
|
16
|
+
# @override Lazily open the file handle
|
17
|
+
def stream
|
18
|
+
@stream ||= ::File.open( @filename, ::File::WRONLY|::File::APPEND|::File::CREAT )
|
19
|
+
end
|
60
20
|
|
61
|
-
# open file for appending if exists, or create a new
|
62
|
-
filename = [ dirname, "#{@file_prefix}#{::File.basename(@filename)}#{@file_suffix}" ].join( '/' )
|
63
|
-
@file = ::File.open( filename, ::File::WRONLY|::File::APPEND|::File::CREAT )
|
64
|
-
end
|
65
21
|
|
66
|
-
|
22
|
+
private
|
67
23
|
|
68
|
-
|
69
|
-
|
70
|
-
if options.key?(:formatter)
|
71
|
-
# this is done, so we can set :formatter => false to just output the given message
|
72
|
-
options[:formatter] || Yell::Formatter.new( "%m" )
|
73
|
-
elsif options[:formatter]
|
74
|
-
# the options :formatter was given
|
75
|
-
Yell::Formatter.new(
|
76
|
-
options[:formatter][:pattern],
|
77
|
-
options[:formatter][:date_pattern]
|
78
|
-
)
|
79
|
-
else
|
80
|
-
# Standard formatter
|
81
|
-
Yell::Formatter.new
|
24
|
+
def default_filename
|
25
|
+
::File.directory?("log") ? "log/#{Yell.env}.log" : "#{Yell.env}.log"
|
82
26
|
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def colorize( level, msg )
|
86
|
-
return msg unless color = Colors[level.upcase]
|
87
|
-
color + msg + Colors['DEFAULT']
|
88
|
-
end
|
89
27
|
|
90
|
-
def default_filename
|
91
|
-
"#{Yell.config.env}.log"
|
92
28
|
end
|
93
29
|
|
94
30
|
end
|
95
31
|
end
|
32
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Yell
|
2
|
+
module Adapters
|
3
|
+
|
4
|
+
class Io
|
5
|
+
include Yell::Adapters::Base
|
6
|
+
|
7
|
+
# The possible unix log colors
|
8
|
+
Colors = {
|
9
|
+
'DEBUG' => "\e[32;1m", # green;bold
|
10
|
+
# 'INFO' => "\e[0m", # white
|
11
|
+
'WARN' => "\e[33;1m", # yello;bold
|
12
|
+
'ERROR' => "\e[31;1m", # red;bold
|
13
|
+
'FATAL' => "\e[35;1m", # magenta;bold
|
14
|
+
'UNKNOWN' => "\e[36m", # cyan
|
15
|
+
'DEFAULT' => "\e[0m" # NONE
|
16
|
+
}
|
17
|
+
|
18
|
+
# Accessor to the io stream
|
19
|
+
attr_reader :stream
|
20
|
+
|
21
|
+
|
22
|
+
def initialize( stream, options = {}, &block )
|
23
|
+
@stream = stream
|
24
|
+
@options = options
|
25
|
+
|
26
|
+
level options.fetch(:level, nil)
|
27
|
+
format options.fetch(:format, nil)
|
28
|
+
colorize! options.fetch(:colorize, false)
|
29
|
+
|
30
|
+
instance_eval &block if block
|
31
|
+
end
|
32
|
+
|
33
|
+
# Main method to calling the file adapter.
|
34
|
+
#
|
35
|
+
# The method formats the message and writes it to the file handle.
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# write( 'info', 'Hello World' )
|
39
|
+
def write( level, message )
|
40
|
+
msg = @formatter.format( level, message )
|
41
|
+
|
42
|
+
# colorize if applicable
|
43
|
+
if colorize? and color = Colors[level]
|
44
|
+
msg = color + msg + Colors['DEFAULT']
|
45
|
+
end
|
46
|
+
|
47
|
+
msg << "\n" unless msg[-1] == ?\n # add new line if there is none
|
48
|
+
|
49
|
+
write!( msg )
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set the format for your message.
|
53
|
+
def format( pattern, date_pattern = nil )
|
54
|
+
@formatter = case pattern
|
55
|
+
when Yell::Formatter then pattern
|
56
|
+
when false then Yell::Formatter.new( "%m" )
|
57
|
+
else Yell::Formatter.new( pattern, date_pattern )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Enable colorizing the log output.
|
62
|
+
def colorize!( color = true )
|
63
|
+
@colorize = color
|
64
|
+
end
|
65
|
+
|
66
|
+
# Determie whether to colorize the log output or nor
|
67
|
+
#
|
68
|
+
# @return [Boolean] true or false
|
69
|
+
def colorize?; !!@colorize; end
|
70
|
+
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# TODO: Implement Buffer to not flush immediately.
|
75
|
+
def write!( message )
|
76
|
+
stream.print( message )
|
77
|
+
stream.flush
|
78
|
+
rescue => e
|
79
|
+
close
|
80
|
+
|
81
|
+
# re-raise the exception
|
82
|
+
raise( e, caller )
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
data/lib/yell/formatter.rb
CHANGED
@@ -1,37 +1,39 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Yell #:nodoc:
|
4
|
+
|
5
|
+
# The +Formatter+ provides a handle to configure your log message style.
|
2
6
|
class Formatter
|
3
7
|
|
4
8
|
PatternTable = {
|
5
|
-
"m" => "message",
|
9
|
+
"m" => "message",
|
6
10
|
"d" => "date",
|
7
|
-
"l" => "level
|
11
|
+
"l" => "level[0]",
|
8
12
|
"L" => "level.upcase",
|
9
|
-
"p" => "$$",
|
13
|
+
"p" => "$$",
|
10
14
|
"h" => "hostname"
|
11
15
|
}
|
12
16
|
PatternRegexp = /([^%]*)(%\d*)?([dlLphm])?(.*)/
|
13
|
-
|
14
17
|
DefaultPattern = "%d [%5L] %p %h: %m"
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
-
define_format_method
|
18
|
+
|
19
|
+
|
20
|
+
def initialize( pattern = nil, date_pattern = nil )
|
21
|
+
@pattern = pattern || DefaultPattern
|
22
|
+
@date_pattern = date_pattern
|
23
|
+
|
24
|
+
define!
|
23
25
|
end
|
24
|
-
|
26
|
+
|
25
27
|
|
26
28
|
private
|
27
29
|
|
28
|
-
def
|
30
|
+
def define!
|
29
31
|
buff, args, _pattern = "", [], @pattern.dup
|
30
|
-
|
32
|
+
|
31
33
|
while true
|
32
34
|
match = PatternRegexp.match( _pattern )
|
33
35
|
|
34
|
-
buff << match[1] unless match[1].empty?
|
36
|
+
buff << match[1] unless match[1].empty?
|
35
37
|
break if match[2].nil?
|
36
38
|
|
37
39
|
buff << match[2] + 's' # '%s'
|
@@ -41,18 +43,21 @@ module Yell
|
|
41
43
|
end
|
42
44
|
|
43
45
|
instance_eval %-
|
44
|
-
def format
|
46
|
+
def format( level, message )
|
45
47
|
sprintf( "#{buff}", #{args.join(',')} )
|
46
48
|
end
|
47
49
|
-
|
48
50
|
end
|
49
51
|
|
50
|
-
def date
|
51
|
-
|
52
|
+
def date
|
53
|
+
@date_pattern ? Time.now.strftime( @date_pattern ) : Time.now.iso8601
|
54
|
+
end
|
55
|
+
|
52
56
|
def hostname
|
53
57
|
return @hostname if defined?( @hostname )
|
54
58
|
@hostname = Socket.gethostname rescue nil
|
55
59
|
end
|
56
60
|
|
57
61
|
end
|
58
|
-
end
|
62
|
+
end
|
63
|
+
|
data/lib/yell/level.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Yell #:nodoc:
|
4
|
+
|
5
|
+
# The +Level+ class handles the severities for you in order to determine
|
6
|
+
# if an adapter should log or not.
|
7
|
+
#
|
8
|
+
# In order to setup your level, you have certain modifiers available:
|
9
|
+
# at :warn # will be set to :warn level only
|
10
|
+
# gt :warn # Will set from :error level onwards
|
11
|
+
# gte :warn # Will set from :warn level onwards
|
12
|
+
# lt :warn # Will set from :info level an below
|
13
|
+
# lte :warn # Will set from :warn level and below
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# You are able to combine those modifiers to your convenience.
|
17
|
+
#
|
18
|
+
# @example Set from :info to :error (including)
|
19
|
+
# Yell::Level.new(:info).lte(:error)
|
20
|
+
#
|
21
|
+
# @example Set from :info to :error (excluding)
|
22
|
+
# Yell::Level.new(:info).lt(:error)
|
23
|
+
#
|
24
|
+
# @example Set at :info only
|
25
|
+
# Yell::Level.new.at(:info)
|
26
|
+
class Level
|
27
|
+
|
28
|
+
# Create a new level instance.
|
29
|
+
#
|
30
|
+
# @example Enable all severities
|
31
|
+
# Yell::Level.new
|
32
|
+
#
|
33
|
+
# @example Pass the minimum possible severity
|
34
|
+
# Yell::Level.new :warn
|
35
|
+
#
|
36
|
+
# @example Pass an array to exactly set the level at the given severities
|
37
|
+
# Yell::Level.new [:info, :error]
|
38
|
+
#
|
39
|
+
# @example Pass a range to set the level within the severities
|
40
|
+
# Yell::Level.new (:info..:error)
|
41
|
+
#
|
42
|
+
# @param [Integer,String,Symbol,Array,Range,nil] severity The severity for the level.
|
43
|
+
def initialize( severity = nil )
|
44
|
+
@severities = Yell::Severities.map { true } # all levels allowed by default
|
45
|
+
|
46
|
+
case severity
|
47
|
+
when Array then severity.each { |s| at(s) }
|
48
|
+
when Range then gte(severity.first).lte(severity.last)
|
49
|
+
when Integer, String, Symbol then gte(severity)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns whether the level is allowed at the given severity
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
# at? :warn
|
57
|
+
# at? 0 # debug
|
58
|
+
def at?( severity )
|
59
|
+
index = index_from( severity )
|
60
|
+
|
61
|
+
index.nil? ? false : @severities[index]
|
62
|
+
end
|
63
|
+
|
64
|
+
def at( severity ) #:nodoc:
|
65
|
+
calculate! :==, severity
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def gt( severity ) #:nodoc:
|
70
|
+
calculate! :>, severity
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
def gte( severity ) #:nodoc:
|
75
|
+
calculate! :>=, severity
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def lt( severity ) #:nodoc:
|
80
|
+
calculate! :<, severity
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def lte( severity ) #:nodoc:
|
85
|
+
calculate! :<=, severity
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def calculate!( modifier, severity )
|
93
|
+
index = index_from( severity )
|
94
|
+
return if index.nil?
|
95
|
+
|
96
|
+
case modifier
|
97
|
+
when :> then ascending!( index+1 )
|
98
|
+
when :>= then ascending!( index )
|
99
|
+
when :< then descending!( index-1 )
|
100
|
+
when :<= then descending!( index )
|
101
|
+
else set!( index ) # :==
|
102
|
+
end
|
103
|
+
|
104
|
+
taint unless tainted?
|
105
|
+
end
|
106
|
+
|
107
|
+
def index_from( severity )
|
108
|
+
case severity
|
109
|
+
when Integer then severity
|
110
|
+
when String, Symbol then Yell::Severities.index( severity.to_s.upcase )
|
111
|
+
else nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def ascending!( index )
|
116
|
+
@severities.each_with_index do |s, i|
|
117
|
+
next if s == false # skip
|
118
|
+
|
119
|
+
@severities[i] = i < index ? false : true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def descending!( index )
|
124
|
+
@severities.each_with_index do |s, i|
|
125
|
+
next if s == false # skip
|
126
|
+
|
127
|
+
@severities[i] = index < i ? false : true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def set!( index )
|
132
|
+
@severities.map! { false } unless tainted?
|
133
|
+
|
134
|
+
@severities[index] = true
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
data/lib/yell/logger.rb
CHANGED
@@ -1,82 +1,145 @@
|
|
1
|
-
|
2
|
-
class Logger
|
3
|
-
Levels = [ 'debug', 'info', 'warn', 'error', 'fatal', 'unknown' ]
|
1
|
+
# encoding: utf-8
|
4
2
|
|
3
|
+
module Yell #:nodoc:
|
5
4
|
|
5
|
+
# The +Logger+ is your entrypoint. Anything onwards is derived from here.
|
6
|
+
class Logger
|
7
|
+
# Creates a new Logger instance
|
8
|
+
#
|
9
|
+
# @example A standard file logger
|
10
|
+
# Yell::Logger.new
|
11
|
+
# Yell::Logger.new 'development.log'
|
12
|
+
#
|
13
|
+
# @example A standard datefile logger
|
14
|
+
# Yell::Logger.new :datefile
|
15
|
+
# Yell::Logger.new :datefile, 'development.log'
|
16
|
+
#
|
17
|
+
# @example Setting the log level
|
18
|
+
# Yell::Logger.new :level => :warn
|
19
|
+
#
|
20
|
+
# Yell::Logger.new do
|
21
|
+
# level :warn
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# @example Combined settings
|
25
|
+
# Yell::Logger.new 'development.log', :level => :warn
|
26
|
+
#
|
27
|
+
# Yell::Logger.new :datefile, 'development.log' do
|
28
|
+
# level :info
|
29
|
+
# end
|
6
30
|
def initialize( *args, &block )
|
7
31
|
@adapters = []
|
8
32
|
|
9
33
|
# extract options
|
10
34
|
@options = args.last.is_a?(Hash) ? args.pop : {}
|
11
35
|
|
36
|
+
# set the log level when given
|
37
|
+
# level @options[:level] if @options[:level]
|
38
|
+
level @options[:level] # default
|
39
|
+
|
12
40
|
# check if filename was given as argument and put it into the @options
|
13
41
|
if args.last.is_a?( String )
|
14
42
|
@options[:filename] = args.pop unless @options[:filename]
|
15
43
|
end
|
16
44
|
|
17
|
-
|
45
|
+
# extract adapter
|
46
|
+
adapter args.pop if args.any?
|
18
47
|
|
19
|
-
#
|
20
|
-
|
48
|
+
# set the log level when given
|
49
|
+
level @options[:level] if @options[:level]
|
21
50
|
|
22
|
-
|
23
|
-
|
51
|
+
# eval the given block
|
52
|
+
instance_eval &block if block
|
24
53
|
|
25
|
-
|
26
|
-
def adapter ( type, options = {}, &block )
|
27
|
-
@adapters << Yell::Adapters.new( type, @options.merge(options), &block )
|
28
|
-
rescue LoadError => e
|
29
|
-
raise Yell::NoSuchAdapter, e.message
|
54
|
+
define!
|
30
55
|
end
|
31
56
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
57
|
+
# Define an adapter to be used for logging.
|
58
|
+
#
|
59
|
+
# @example Standard adapter
|
60
|
+
# adapter :file
|
61
|
+
#
|
62
|
+
# @example Standard adapter with filename
|
63
|
+
# adapter :file, 'development.log'
|
64
|
+
#
|
65
|
+
# # Alternative notation for filename in options
|
66
|
+
# adapter :file, :filename => 'developent.log'
|
67
|
+
#
|
68
|
+
# @example Standard adapter with filename and additional options
|
69
|
+
# adapter :file, 'development.log', :level => :warn
|
70
|
+
#
|
71
|
+
# @example Set the adapter directly from an adapter instance
|
72
|
+
# adapter( Yell::Adapter::File.new )
|
73
|
+
#
|
74
|
+
# @param [Symbol] type The type of the adapter, may be `:file` or `:datefile` (default `:file`)
|
75
|
+
#
|
76
|
+
# @return A new +Yell::Adapter+ instance
|
77
|
+
#
|
78
|
+
# @raise [Yell::NoSuchAdapter] Will be thrown when the adapter is not defined
|
79
|
+
def adapter( type = :file, *args, &block )
|
80
|
+
options = [@options, *args].inject( Hash.new ) do |h,c|
|
81
|
+
h.merge( c.is_a?(String) ? {:filename => c} : c )
|
37
82
|
end
|
83
|
+
|
84
|
+
@adapters << Yell::Adapters[ type, options, &block ]
|
85
|
+
rescue NameError => e
|
86
|
+
raise Yell::NoSuchAdapter, type
|
87
|
+
end
|
88
|
+
|
89
|
+
# Set the minimum log level.
|
90
|
+
#
|
91
|
+
# @example Set the level to :warn
|
92
|
+
# level :warn
|
93
|
+
#
|
94
|
+
# @param [String, Symbol, Integer] val The minimum log level
|
95
|
+
def level( val = nil )
|
96
|
+
@level = Yell::Level.new( val )
|
38
97
|
end
|
39
98
|
|
40
99
|
# Convenience method for resetting all adapters of the Logger.
|
41
100
|
#
|
42
|
-
# @param [
|
43
|
-
def
|
44
|
-
close
|
45
|
-
open if now
|
101
|
+
# @param [Boolean] now Perform the reset immediately (default false)
|
102
|
+
def close( now = false )
|
103
|
+
@adapters.each(&:close)
|
46
104
|
end
|
47
105
|
|
48
|
-
def close; @adapters.each(&:close); end
|
49
|
-
def open; @adapters.each(&:open); end
|
50
106
|
|
51
|
-
|
52
107
|
private
|
53
108
|
|
54
|
-
|
55
|
-
|
109
|
+
# Sets a default adapter if none was given explicitly and defines the log methods on
|
110
|
+
# the logger instance.
|
111
|
+
def define!
|
112
|
+
adapter :file if @adapters.empty? # default adapter when none defined
|
56
113
|
|
57
|
-
define_log_methods
|
114
|
+
define_log_methods!
|
58
115
|
end
|
59
116
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
def #{name} ( data = '' )
|
66
|
-
return unless #{name}?
|
117
|
+
# Creates instance methods for every defined log level (debug, info, ...) depending
|
118
|
+
# on whether anything should be logged upon, for instance, #info.
|
119
|
+
def define_log_methods!
|
120
|
+
Yell::Severities.each do |l|
|
121
|
+
name = l.downcase
|
67
122
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
123
|
+
instance_eval %-
|
124
|
+
def #{name}?; #{@level.at?(name)}; end # def info?; true; end
|
125
|
+
#
|
126
|
+
def #{name}( message = nil ) # def info( message = nil )
|
127
|
+
return unless #{name}? # return unless info?
|
128
|
+
#
|
129
|
+
message = yield if block_given? # message = yield if block_given?
|
130
|
+
write( "#{l}", message ) # write( "INFO", message )
|
131
|
+
#
|
132
|
+
true # true
|
133
|
+
end # end
|
73
134
|
-
|
74
135
|
end
|
75
136
|
end
|
76
137
|
|
77
|
-
|
78
|
-
|
138
|
+
# Cycles all the adapters and writes the message
|
139
|
+
def write( level, message )
|
140
|
+
@adapters.each { |a| a.write(level, message) if a.write?(level) }
|
79
141
|
end
|
80
142
|
|
81
143
|
end
|
82
144
|
end
|
145
|
+
|
data/lib/yell/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -7,14 +7,5 @@ require 'rspec'
|
|
7
7
|
require 'timecop'
|
8
8
|
|
9
9
|
RSpec.configure do |config|
|
10
|
-
|
11
|
-
config.before do
|
12
|
-
Yell.config.stub!( :yaml_file ).and_return( File.dirname(__FILE__) + '/config/yell.yml' )
|
13
|
-
end
|
14
|
-
|
15
|
-
config.after do
|
16
|
-
Yell.config.reload! # to not run into caching problems during tests
|
17
|
-
end
|
18
|
-
|
19
10
|
end
|
20
11
|
|
data/spec/yell_spec.rb
CHANGED
data/yell.gemspec
CHANGED
@@ -9,10 +9,10 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ["Rudolf Schmidt"]
|
10
10
|
|
11
11
|
s.homepage = "http://rubygems.org/gems/yell"
|
12
|
-
s.summary = %q{
|
13
|
-
s.description = %q{
|
12
|
+
s.summary = %q{Yell - Your Extensible Logging Library }
|
13
|
+
s.description = %q{An easy to use logging library to log into files and any other self-defined adapters}
|
14
14
|
|
15
|
-
s.rubyforge_project = "
|
15
|
+
s.rubyforge_project = "yell"
|
16
16
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yell
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,9 +9,10 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-03-17 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description:
|
14
|
+
description: An easy to use logging library to log into files and any other self-defined
|
15
|
+
adapters
|
15
16
|
email:
|
16
17
|
executables: []
|
17
18
|
extensions: []
|
@@ -19,15 +20,19 @@ extra_rdoc_files: []
|
|
19
20
|
files:
|
20
21
|
- .gitignore
|
21
22
|
- Gemfile
|
23
|
+
- LICENSE.txt
|
24
|
+
- README.md
|
22
25
|
- Rakefile
|
23
26
|
- init.rb
|
24
27
|
- lib/yell.rb
|
25
28
|
- lib/yell/adapters.rb
|
29
|
+
- lib/yell/adapters/.file.rb.swp
|
26
30
|
- lib/yell/adapters/base.rb
|
27
31
|
- lib/yell/adapters/datefile.rb
|
28
32
|
- lib/yell/adapters/file.rb
|
29
|
-
- lib/yell/
|
33
|
+
- lib/yell/adapters/io.rb
|
30
34
|
- lib/yell/formatter.rb
|
35
|
+
- lib/yell/level.rb
|
31
36
|
- lib/yell/logger.rb
|
32
37
|
- lib/yell/version.rb
|
33
38
|
- spec/spec.opts
|
@@ -53,9 +58,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
58
|
- !ruby/object:Gem::Version
|
54
59
|
version: '0'
|
55
60
|
requirements: []
|
56
|
-
rubyforge_project:
|
57
|
-
rubygems_version: 1.8.
|
61
|
+
rubyforge_project: yell
|
62
|
+
rubygems_version: 1.8.17
|
58
63
|
signing_key:
|
59
64
|
specification_version: 3
|
60
|
-
summary:
|
61
|
-
test_files:
|
65
|
+
summary: Yell - Your Extensible Logging Library
|
66
|
+
test_files:
|
67
|
+
- spec/spec.opts
|
68
|
+
- spec/spec_helper.rb
|
69
|
+
- spec/yell_spec.rb
|
data/lib/yell/config.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
module Yell
|
2
|
-
class Config
|
3
|
-
|
4
|
-
def initialize( yaml_file = nil )
|
5
|
-
@yaml_file = yaml_file
|
6
|
-
|
7
|
-
reload!
|
8
|
-
end
|
9
|
-
|
10
|
-
def reload!; @options = nil; end
|
11
|
-
|
12
|
-
def []( key ); options[key]; end
|
13
|
-
|
14
|
-
def options
|
15
|
-
@options ||= begin
|
16
|
-
if yaml_file_defined?
|
17
|
-
require 'yaml'
|
18
|
-
require 'erb'
|
19
|
-
|
20
|
-
(YAML.load( ERB.new( File.read( yaml_file ) ).result ) || {})[ env ] || {}
|
21
|
-
else
|
22
|
-
{} # default
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def env
|
28
|
-
ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'default'
|
29
|
-
end
|
30
|
-
|
31
|
-
def root
|
32
|
-
return ENV['RAILS_ROOT'] if ENV['RAILS_ROOT']
|
33
|
-
return RAILS_ROOT if defined?( RAILS_ROOT )
|
34
|
-
|
35
|
-
'.'
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def yaml_file_defined?
|
42
|
-
yaml_file && File.exist?( yaml_file )
|
43
|
-
end
|
44
|
-
|
45
|
-
# Locates the yell.yml file. The file can end in .yml or .yaml,
|
46
|
-
# and be located in the current directory (eg. project root) or
|
47
|
-
# in a .config/ or config/ subdirectory of the current directory.
|
48
|
-
def yaml_file
|
49
|
-
@yaml_file || Dir.glob( "#{root}/{,.config/,config/}yell{.yml,.yaml}" ).first
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|