log2mail 0.0.1.pre3 → 0.0.1.pre4
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.
- checksums.yaml +4 -4
- data/{INSTALL → INSTALL.md} +2 -0
- data/README.md +1 -1
- data/features/log2mail_configurations/config_1 +1 -1
- data/lib/ext/string.rb +6 -0
- data/lib/ext/symbol.rb +7 -0
- data/lib/log2mail.rb +1 -1
- data/lib/log2mail/config.rb +9 -210
- data/lib/log2mail/config/attribute.rb +21 -0
- data/lib/log2mail/config/config.rb +45 -0
- data/lib/log2mail/config/config_file_handler.rb +142 -0
- data/lib/log2mail/config/config_file_snippet.rb +17 -0
- data/lib/log2mail/config/old_config_file_handler.rb +220 -0
- data/lib/log2mail/config/parser.rb +144 -0
- data/lib/log2mail/config/section.rb +70 -0
- data/lib/log2mail/console/commands.rb +1 -1
- data/lib/log2mail/main.rb +2 -2
- data/lib/log2mail/version.rb +1 -1
- data/lib/log2mail/watcher.rb +1 -1
- data/log2mail.gemspec +1 -0
- data/man/log2mail.1 +1 -1
- data/man/log2mail.1.ronn +1 -1
- data/spec/factories.rb +126 -29
- data/spec/log2mail/{config_spec.rb → config/config_file_handler_spec.rb} +49 -3
- data/spec/log2mail/config/parser_spec.rb +467 -0
- data/spec/spec_helper.rb +1 -0
- metadata +29 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdf651d2af53d14c8f36ea64233f8db4116c055d
|
4
|
+
data.tar.gz: 1c35a2f8dc2df19d6635b66d24c279029bcff909
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cba00ca0b65e5f87f434450f44bbef5e17e94fdfb8c144e4f73ce002648425e96ba39f5a2d63ba9c7eac0d82df28ba3e15be46576629a4053818ccfd12d60a13
|
7
|
+
data.tar.gz: 5e640a298954ebf3fae7745f86ea478f9f4ff8f56e0d71bd8284f5ddd8feef13c1e530d2735ef8b8395e9f2a21f99f2c6e417f143adcce5152dd132d396f2889
|
data/{INSTALL → INSTALL.md}
RENAMED
@@ -4,6 +4,7 @@ log2mail.rb Installation
|
|
4
4
|
Requirements
|
5
5
|
------------
|
6
6
|
|
7
|
+
* Linux
|
7
8
|
* Ruby 1.9.3
|
8
9
|
|
9
10
|
Debian 7 (and higher)
|
@@ -25,6 +26,7 @@ Create a configuration file, e.g. at `/usr/local/etc/log2mail.conf`:
|
|
25
26
|
|
26
27
|
cat > /usr/local/etc/log2mail.conf <<EOF
|
27
28
|
defaults
|
29
|
+
sendmail = /usr/sbin/sendmail
|
28
30
|
mailto = your@mail.address
|
29
31
|
file = /tmp/test.log
|
30
32
|
pattern = test
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ log2mail.rb(1) -- monitors (log) files for patterns and reports hits by mail
|
|
9
9
|
|
10
10
|
`log2mail.rb` helps having an eye on your systems' log files. It efficiently monitors multiple files and reports as soon as specified (regular expression) patterns match.
|
11
11
|
|
12
|
-
On startup, `log2mail.rb` opens all files on the 'watch list' and seeks to EOF. All new data are parsed about once a minute (see `--sleeptime`).
|
12
|
+
On startup, `log2mail.rb` opens all files on the 'watch list' and seeks to EOF. All new data are parsed about once a minute (see `--sleeptime`). Matched patterns are reported to the configured mail address(es) (see `mailto` configuration option).
|
13
13
|
|
14
14
|
Log files are reopened automatically when rotated.
|
15
15
|
|
data/lib/ext/string.rb
CHANGED
data/lib/ext/symbol.rb
ADDED
data/lib/log2mail.rb
CHANGED
data/lib/log2mail/config.rb
CHANGED
@@ -1,216 +1,15 @@
|
|
1
1
|
module Log2mail
|
2
|
-
|
3
|
-
|
4
|
-
class <<self
|
5
|
-
def parse_config(config_path)
|
6
|
-
Log2mail::Config.new(config_path)
|
7
|
-
# pp config.config
|
8
|
-
# config.files.each do |f|
|
9
|
-
# puts "File: #{f}"
|
10
|
-
# config.patterns_for_file(f).each do |pattern|
|
11
|
-
# puts " Pattern: #{pattern}; mailto: " + config.mailtos_for_pattern( f, pattern ).join(', ')
|
12
|
-
# end
|
13
|
-
# end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# attr_reader :config
|
18
|
-
|
2
|
+
module Config
|
19
3
|
INT_OPTIONS = [:sendtime, :resendtime, :maxlines]
|
20
4
|
STR_OPTIONS = [:fromaddr, :sendmail]
|
21
5
|
PATH_OPTIONS = [:template]
|
22
|
-
|
23
|
-
def initialize(config_paths)
|
24
|
-
$logger.debug "Reading configuration from #{config_paths}"
|
25
|
-
@config_paths = Array(config_paths)
|
26
|
-
expand_paths
|
27
|
-
read_configuration
|
28
|
-
validate_configuration
|
29
|
-
end
|
30
|
-
|
31
|
-
# returns all the paths of all files needed to be watched
|
32
|
-
def files
|
33
|
-
@config.keys - [:defaults]
|
34
|
-
end
|
35
|
-
|
36
|
-
def file_patterns
|
37
|
-
h = {}
|
38
|
-
files.each do |file|
|
39
|
-
h[file] = patterns_for_file(file)
|
40
|
-
end
|
41
|
-
h
|
42
|
-
end
|
43
|
-
|
44
|
-
def patterns_for_file( file )
|
45
|
-
Hash(@config[file][:patterns]).keys + \
|
46
|
-
Hash(defaults[:patterns]).keys
|
47
|
-
end
|
48
|
-
|
49
|
-
def mailtos_for_pattern( file, pattern )
|
50
|
-
m = []
|
51
|
-
m.concat Hash( config_file_pattern(file, pattern)[:mailtos] ).keys
|
52
|
-
m.concat Hash(Hash(Hash(defaults[:patterns])[pattern])[:mailtos]).keys
|
53
|
-
m.concat Array(defaults[:mailtos]) if m.empty?
|
54
|
-
m.uniq
|
55
|
-
end
|
56
|
-
|
57
|
-
def settings_for_mailto( file, pattern, mailto )
|
58
|
-
h = defaults.reject {|k,v| k==:mailtos}
|
59
|
-
h.merge config_file_mailto(file, pattern, mailto)
|
60
|
-
end
|
61
|
-
|
62
|
-
def defaults
|
63
|
-
Hash(@config[:defaults])
|
64
|
-
end
|
65
|
-
|
66
|
-
def formatted( show_effective )
|
67
|
-
Terminal::Table.new do |t|
|
68
|
-
settings_header = show_effective ? 'Effective Settings' : 'Settings'
|
69
|
-
t << ['File', 'Pattern', 'Recipient', settings_header]
|
70
|
-
t << :separator
|
71
|
-
files.each do |file|
|
72
|
-
patterns_for_file(file).each do |pattern|
|
73
|
-
mailtos_for_pattern(file, pattern).each do |mailto|
|
74
|
-
settings = []
|
75
|
-
if show_effective
|
76
|
-
settings_for_mailto(file, pattern, mailto).each_pair \
|
77
|
-
{ |k,v| settings << '%s=%s' % [k,v] }
|
78
|
-
else
|
79
|
-
config_file_mailto(file, pattern, mailto).each_pair \
|
80
|
-
{ |k,v| settings << '%s=%s' % [k,v] }
|
81
|
-
end
|
82
|
-
t.add_row [file, pattern, mailto, settings.join($/)]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def config_file(file)
|
92
|
-
Hash(@config[file])
|
93
|
-
end
|
94
|
-
|
95
|
-
def config_file_pattern(file, pattern)
|
96
|
-
Hash( Hash( config_file(file)[:patterns] )[pattern] )
|
97
|
-
end
|
98
|
-
|
99
|
-
def config_file_mailtos(file, pattern)
|
100
|
-
Hash( config_file_pattern(file, pattern)[:mailtos] )
|
101
|
-
end
|
102
|
-
|
103
|
-
def config_file_mailto(file, pattern, mailto)
|
104
|
-
Hash( config_file_mailtos(file, pattern)[mailto] )
|
105
|
-
end
|
106
|
-
|
107
|
-
def expand_paths
|
108
|
-
expanded_paths = []
|
109
|
-
@config_paths.each do |path|
|
110
|
-
if ::File.directory?(path)
|
111
|
-
expanded_paths.concat Dir.glob( ::File.join( path, '*[^~#]' ) )
|
112
|
-
else
|
113
|
-
expanded_paths << path
|
114
|
-
end
|
115
|
-
end
|
116
|
-
@config_paths = expanded_paths
|
117
|
-
end
|
118
|
-
|
119
|
-
# tries to follow original code at https://github.com/lordlamer/log2mail/blob/master/config.cc#L192
|
120
|
-
def read_configuration
|
121
|
-
@config = {}
|
122
|
-
@config_paths.each do |file|
|
123
|
-
@section = nil; @pattern = nil; @mailto = nil
|
124
|
-
# section, pattern, mailto are reset for every file (but not when included by 'include')
|
125
|
-
parse_file( file )
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def parse_file( filename )
|
130
|
-
IO.readlines(filename).each_with_index do |line, lineno|
|
131
|
-
parse(filename, line, lineno + 1)
|
132
|
-
end
|
133
|
-
rescue Errno::ENOENT
|
134
|
-
fail Error, "Configuration file or directory not found (or not readable): #{filename}"
|
135
|
-
end
|
136
|
-
|
137
|
-
def parse(file, line, lineno)
|
138
|
-
line.strip!
|
139
|
-
return if line =~ /^#/
|
140
|
-
return if line =~ /^$/
|
141
|
-
line =~ /^(\S+)\s*=?\s*"?(.*?)"?(\s*#.*)?$/ # drop double quotes on right hand side; drop comments
|
142
|
-
key, value = $1.to_sym, $2.strip
|
143
|
-
if key == :include # include shall work everywhere
|
144
|
-
parse_file( ::File.join(Pathname(file).parent, value) )
|
145
|
-
return
|
146
|
-
end
|
147
|
-
if key == :defaults and value.empty? # section: specifies top level; must be 'defaults' or 'file'
|
148
|
-
@section = key
|
149
|
-
@pattern = nil; @mailto = nil
|
150
|
-
fail Error, "Invalid section. Section 'defaults' already specified." if @config[@section]
|
151
|
-
@config[@section] = {}
|
152
|
-
elsif key == :file
|
153
|
-
@section = value
|
154
|
-
@pattern = nil; @mailto = nil
|
155
|
-
@config[@section] ||= {}
|
156
|
-
elsif key == :pattern # must come inside 'file' (or 'defaults')
|
157
|
-
# fail "Invalid section. All statements must appear after 'defaults' or 'file=...'" unless @section
|
158
|
-
@pattern = value; @mailto = nil
|
159
|
-
@config[@section][:patterns] ||= {}
|
160
|
-
warning { "Redefining pattern section '#{value}' which has been defined already for '#{@section}'." } \
|
161
|
-
if @config[@section][:patterns][value]
|
162
|
-
@config[@section][:patterns][value] = {}
|
163
|
-
elsif key == :mailto and @section != :defaults # must come inside 'pattern' (or 'defaults')
|
164
|
-
fail Error, "'mailto' statements only allowed inside 'pattern' or 'defaults'." unless @pattern
|
165
|
-
@mailto = value
|
166
|
-
@config[@section][:patterns][@pattern][:mailtos] ||= {}
|
167
|
-
warning { "Redefining mailto section '#{value}' which has been defined already for '#{@section}'." } \
|
168
|
-
if @config[@section][:patterns][@pattern][:mailtos][value]
|
169
|
-
@config[@section][:patterns][@pattern][:mailtos][value] = {}
|
170
|
-
else # everything else must come inside 'defaults' or 'mailto'
|
171
|
-
fail Error, "'#{key}' must be set within 'defaults' or 'mailto'." unless @section == :defaults or @mailto
|
172
|
-
if INT_OPTIONS.include?(key)
|
173
|
-
value = value.to_i
|
174
|
-
elsif STR_OPTIONS.include?(key)
|
175
|
-
elsif PATH_OPTIONS.include?(key)
|
176
|
-
value = ::File.expand_path( value, Pathname(file).parent ) unless Pathname(value).absolute?
|
177
|
-
elsif key == :mailto # special handling for 'mailto' in 'defaults' section
|
178
|
-
@config[:defaults][:mailtos] ||= []
|
179
|
-
@config[:defaults][:mailtos] << value
|
180
|
-
return # skip the 'mailto' entry itself
|
181
|
-
else
|
182
|
-
fail Error, "'#{key}' is an unknown configuration statement."
|
183
|
-
end
|
184
|
-
if @section == :defaults and !@pattern and !@mailto
|
185
|
-
warning { "Redefining value for '#{key}'." } if @config[@section][key]
|
186
|
-
@config[@section][key] = value
|
187
|
-
else
|
188
|
-
warning { "Redefining value for '#{key}'." } \
|
189
|
-
if @config[@section][:patterns][@pattern][:mailtos][@mailto][key]
|
190
|
-
@config[@section][:patterns][@pattern][:mailtos][@mailto][key] = value
|
191
|
-
end
|
192
|
-
end
|
193
|
-
rescue
|
194
|
-
fail Error, "#{file} (line #{lineno}): #{$!.message}#$/[#{$!.class} at #{$!.backtrace.first}]"
|
195
|
-
end
|
196
|
-
|
197
|
-
def validate_configuration
|
198
|
-
files.each do |file|
|
199
|
-
patterns_for_file(file).each do |pattern|
|
200
|
-
mailtos = mailtos_for_pattern(file, pattern)
|
201
|
-
$logger.warn "Pattern #{file}:#{pattern} has no recipients." if mailtos.empty?
|
202
|
-
end
|
203
|
-
end
|
204
|
-
# FIXME: empty configuration should cause FATAL error
|
205
|
-
# TODO: illegal regexp pattern should cause ERROR
|
206
|
-
end
|
207
|
-
|
208
|
-
def warning(&block)
|
209
|
-
file = block.binding.eval('file')
|
210
|
-
lineno = block.binding.eval('lineno')
|
211
|
-
message = block.call
|
212
|
-
$logger.warn "#{file} (line #{lineno}): #{message}#$/[at #{caller.first}]"
|
213
|
-
end
|
214
|
-
|
6
|
+
ATTRIBUTES = INT_OPTIONS + STR_OPTIONS + PATH_OPTIONS
|
215
7
|
end
|
216
8
|
end
|
9
|
+
|
10
|
+
require_relative 'config/config'
|
11
|
+
require_relative 'config/attribute'
|
12
|
+
require_relative 'config/section'
|
13
|
+
require_relative 'config/parser'
|
14
|
+
require_relative 'config/config_file_snippet'
|
15
|
+
require_relative 'config/config_file_handler'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Log2mail
|
2
|
+
module Config
|
3
|
+
class Attribute
|
4
|
+
attr_reader :name, :value
|
5
|
+
def initialize( name, value )
|
6
|
+
@name = name.to_sym
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
def ==(other)
|
10
|
+
self.name == other.name and self.value == other.value
|
11
|
+
end
|
12
|
+
def inspect
|
13
|
+
'Attribute %s = %s' % [@name.inspect, @value.inspect]
|
14
|
+
end
|
15
|
+
def tree
|
16
|
+
{self.name => self.value}
|
17
|
+
# self.value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Log2mail
|
2
|
+
module Config
|
3
|
+
class Config
|
4
|
+
attr_reader :sections
|
5
|
+
def initialize( sections = [] )
|
6
|
+
@sections = merge sections
|
7
|
+
end
|
8
|
+
def ==(other)
|
9
|
+
return false unless other.instance_of?(self.class)
|
10
|
+
self.sections == other.sections
|
11
|
+
end
|
12
|
+
def inspect
|
13
|
+
'Config: %s' % [@sections.inspect]
|
14
|
+
end
|
15
|
+
def tree
|
16
|
+
h = {}
|
17
|
+
@sections.inject(h) do |h, a|
|
18
|
+
if a.name==:defaults
|
19
|
+
h[:defaults] = a.tree
|
20
|
+
else
|
21
|
+
a.tree.each_pair {|k,v| ( h[a.name.pluralize.to_sym] ||= {} )[k] = v }
|
22
|
+
end
|
23
|
+
h
|
24
|
+
end
|
25
|
+
h
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# FIXME: needs specing
|
31
|
+
def merge( sections )
|
32
|
+
sections = sections.compact.find_all{ |s| s.respond_to?(:name) }
|
33
|
+
names = sections.map(&:name).uniq
|
34
|
+
names.map do |name|
|
35
|
+
secs_with_same_name = sections.find_all{ |sec| sec.name == name }
|
36
|
+
their_uniq_values = secs_with_same_name.map(&:value).uniq
|
37
|
+
their_uniq_values.map{ |val| secs_with_same_name.find_all{ |s| s.value == val }.reduce(:+) }
|
38
|
+
end.flatten(1)
|
39
|
+
rescue NoMethodError
|
40
|
+
fail "Invalid configuration: #{$!.inspect}"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Log2mail
|
2
|
+
module Config
|
3
|
+
class ConfigFileHandler
|
4
|
+
|
5
|
+
class <<self
|
6
|
+
def parse_config(config_path)
|
7
|
+
new(config_path)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(config_paths)
|
12
|
+
$logger.debug "Reading configuration from #{config_paths}"
|
13
|
+
@config_paths = Array(config_paths)
|
14
|
+
expand_paths
|
15
|
+
@config = Parser.new.parse_snippets( raw ).tree
|
16
|
+
validate_configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
def expand_paths
|
20
|
+
expanded_paths = []
|
21
|
+
@config_paths.each do |path|
|
22
|
+
if ::File.directory?(path)
|
23
|
+
expanded_paths.concat Dir.glob( ::File.join( path, '*[^~#]' ) )
|
24
|
+
else
|
25
|
+
expanded_paths << path
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@config_paths = expanded_paths
|
29
|
+
end
|
30
|
+
|
31
|
+
def raw
|
32
|
+
@config_paths.map do |file|
|
33
|
+
ConfigFileSnippet.new( IO.read(file), file )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# returns all the paths of all files needed to be watched
|
38
|
+
def files
|
39
|
+
Hash(@config[:files]).keys
|
40
|
+
end
|
41
|
+
|
42
|
+
# FIXME: specs
|
43
|
+
def file_patterns
|
44
|
+
h = {}
|
45
|
+
files.each do |file|
|
46
|
+
h[file] = patterns_for_file(file)
|
47
|
+
end
|
48
|
+
h
|
49
|
+
end
|
50
|
+
|
51
|
+
# returns the default settings
|
52
|
+
def defaults
|
53
|
+
Hash(@config[:defaults])
|
54
|
+
end
|
55
|
+
|
56
|
+
# returns all patterns for file
|
57
|
+
def patterns_for_file( file )
|
58
|
+
Hash(config_file(file)[:patterns]).keys + \
|
59
|
+
Hash(defaults[:patterns]).keys
|
60
|
+
end
|
61
|
+
|
62
|
+
def mailtos_for_pattern( file, pattern )
|
63
|
+
m = []
|
64
|
+
m.concat Hash( config_file_pattern(file, pattern)[:mailtos] ).keys
|
65
|
+
m.concat Hash(Hash(Hash(defaults[:patterns])[pattern])[:mailtos]).keys
|
66
|
+
m.concat Hash(defaults[:mailtos]).keys if m.empty?
|
67
|
+
m.uniq
|
68
|
+
end
|
69
|
+
|
70
|
+
def settings_for_mailto( file, pattern, mailto )
|
71
|
+
h = defaults.reject {|k,v| k==:mailtos}
|
72
|
+
h.merge config_file_mailto(file, pattern, mailto)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
def formatted( show_effective = false )
|
78
|
+
Terminal::Table.new do |t|
|
79
|
+
settings_header = show_effective ? 'Effective Settings' : 'Settings'
|
80
|
+
t << ['File', 'Pattern', 'Recipient', settings_header]
|
81
|
+
t << :separator
|
82
|
+
files.each do |file|
|
83
|
+
patterns_for_file(file).each do |pattern|
|
84
|
+
mailtos_for_pattern(file, pattern).each do |mailto|
|
85
|
+
settings = []
|
86
|
+
if show_effective
|
87
|
+
settings_for_mailto(file, pattern, mailto).each_pair \
|
88
|
+
{ |k,v| settings << '%s=%s' % [k,v] }
|
89
|
+
else
|
90
|
+
config_file_mailto(file, pattern, mailto).each_pair \
|
91
|
+
{ |k,v| settings << '%s=%s' % [k,v] }
|
92
|
+
end
|
93
|
+
t.add_row [file, pattern, mailto, settings.join($/)]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def config_file(file)
|
105
|
+
Hash(Hash(@config[:files])[file])
|
106
|
+
end
|
107
|
+
|
108
|
+
def config_file_pattern(file, pattern)
|
109
|
+
Hash( Hash( config_file(file)[:patterns] )[pattern] )
|
110
|
+
end
|
111
|
+
|
112
|
+
def config_file_mailtos(file, pattern)
|
113
|
+
config_file_pattern(file, pattern)[:mailtos] || {}
|
114
|
+
end
|
115
|
+
|
116
|
+
def config_file_mailto(file, pattern, mailto)
|
117
|
+
config_file_mailtos(file, pattern)[mailto] || {}
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def validate_configuration
|
122
|
+
files.each do |file|
|
123
|
+
patterns_for_file(file).each do |pattern|
|
124
|
+
mailtos = mailtos_for_pattern(file, pattern)
|
125
|
+
$logger.warn "Pattern #{file}:#{pattern} has no recipients." if mailtos.empty?
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
$logger.warn "Attributes for a global default recipient specified. This may or may not be what you want. Consult `gem man log2mail` if unsure." \
|
130
|
+
if !defaults[:mailtos].nil? and defaults[:mailtos].any?{|k,v| !v.empty? }
|
131
|
+
|
132
|
+
$logger.warn "Attributes for a global default pattern specified. This may or may not be what you want. Consult `gem man log2mail` if unsure." \
|
133
|
+
if !defaults[:patterns].nil? and defaults[:patterns].any?{|k,v| !v.empty? }
|
134
|
+
|
135
|
+
# FIXME: empty configuration should cause FATAL error
|
136
|
+
# TODO: illegal regexp pattern should cause ERROR
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|