xail 0.0.1 → 0.0.2

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.md CHANGED
@@ -38,10 +38,10 @@ and performs some action, potentially altering the stream, or terminating the fl
38
38
  Compound filters take a stream and also a set of subfilters. These generally implement
39
39
  flow control.
40
40
 
41
- Stdout is the ultimate consumer of the strings, unless they've been filtered.
41
+ Stdout is the ultimate consumer of the strings, unless they've been redirected using `rest`.
42
42
 
43
43
  ### Compound Filters
44
- * `cascade` -- stream the result of first subfilter that streams
44
+ * `cascade` -- stream the result of first subfilter that streams, a cascade filter is the container for your xail script
45
45
  * `composition` -- applies each subfilter on the stream of the preceding subfilter, streaming the final result
46
46
 
47
47
  * `and` -- streams the original if all subfilters stream
@@ -65,7 +65,52 @@ Stdout is the ultimate consumer of the strings, unless they've been filtered.
65
65
  * `sample` -- samples the stream, only printing at the rate requested
66
66
  * `stop` -- stops processing of this stream and continues with the next
67
67
  * `count` -- [todo] computes the rate of the stream for display (need UI aspect)
68
+ * `rest` -- a special compound filter that is applied to any unmatched streams
68
69
 
69
70
  ### Custom Filters
70
71
 
71
72
  You can easily develop your own filters. Either as an anonymous block:
73
+
74
+ filter do |stream|
75
+ if stream.includes? 'awesome'
76
+ nil # stop the stream
77
+ else
78
+ stream # keep it going
79
+ end
80
+ end
81
+
82
+ Or, if you need to preserve state, as a filter within the xail file:
83
+
84
+ class LineNumbersFilter < AbstractFilter
85
+ def initialize
86
+ @lineno = 0
87
+ end
88
+
89
+ def streamLine(line)
90
+ @lineno += 1
91
+ return "%5d %s" % [@lineno, line]
92
+ end
93
+ end
94
+
95
+ linenumbers
96
+ group('fatal') {
97
+ contains 'fatal'
98
+ red
99
+ }
100
+
101
+
102
+ ### Hide unfiltered lines
103
+ By default xail will print any unfiltered lines as this is a more typical case.
104
+ You can hide unfiltered lines using a rest block. For example, to only show
105
+ exceptions:
106
+
107
+ group('error') {
108
+ contains 'exception'
109
+ red
110
+ }
111
+
112
+ stop
113
+
114
+ ### Fine-grained stream control
115
+ You can preform finer grained stream control using the `OR`, `AND`, and `NOT`
116
+ combinators.
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env xail
2
+
3
+ class ExecuteFilter < AbstractFilter
4
+ def initialize(command)
5
+ @command = command
6
+ end
7
+
8
+ def streamLine(line)
9
+ puts "WOULD EXECUTE: #{@command} #{line}"
10
+ return line
11
+ end
12
+ end
13
+
14
+ group('exec') {
15
+ contains 'exec'
16
+ execute 'echo'
17
+ stop
18
+ }
19
+
20
+ rest {
21
+ stop
22
+ }
@@ -3,22 +3,11 @@
3
3
  # a simple log error and warning highlighter
4
4
  #
5
5
 
6
- class ExecuteFilter < AbstractFilter
7
- def initialize(command)
8
- @command = command
9
- end
10
-
11
- def streamLine(line)
12
- puts "EXECUTING #{@command} #{line}"
13
- return line
14
- end
15
- end
16
-
17
-
6
+ #!/usr/bin/env xail
18
7
  group('fatal') {
19
8
  contains 'fatal'
20
9
  red
21
- onblue
10
+ underscore
22
11
  bell
23
12
  }
24
13
 
@@ -31,4 +20,4 @@ group('error') {
31
20
  group('warning') {
32
21
  contains 'warn'
33
22
  yellow
34
- }
23
+ }
@@ -28,16 +28,22 @@ A Ruby utility for performing basic stream processing, directly focused on incre
28
28
  end
29
29
  end
30
30
 
31
-
32
31
  stream = $stdin
33
32
  stream.each() do |line|
34
- streamed = filter.streamLine(line)
35
- if streamed and streamed.size > 0
36
- printf streamed
33
+ begin
34
+ streamed = filter.streamLine(line)
35
+ if streamed and streamed.size > 0
36
+ print streamed
37
+ end
38
+
39
+ rescue StreamLineStop
37
40
  end
38
41
  end
39
42
  end
40
43
 
41
44
  config = IO.read(ARGV[0])
42
45
  Xail.run(config)
46
+
47
+ rescue SignalException
48
+ exit
43
49
  end
@@ -16,10 +16,19 @@ module Xail
16
16
  @filter_stack.pop
17
17
  end
18
18
 
19
- def stream(name, source = null)
20
- source ||= name
19
+ def filter(&block)
20
+ filter_in_scope << Class.new(AbstractFilter) do
21
+ def streamLine(line)
22
+ block(line)
23
+ end
24
+ end
21
25
  end
22
26
 
27
+ # TODO add support for explicitly listing sources
28
+ #def stream(name, source = null)
29
+ # source ||= name
30
+ #end
31
+
23
32
  def group(name, &filters)
24
33
  # TODO intergrate with UX
25
34
  filter_scope(FilterComposition.new) {
@@ -27,10 +36,7 @@ module Xail
27
36
  }
28
37
  end
29
38
 
30
- def has_final
31
- @has_final
32
- end
33
-
39
+ attr :has_final
34
40
  def rest(&filters)
35
41
  if @has_final
36
42
  raise "rest may only be specified once"
@@ -48,10 +54,18 @@ module Xail
48
54
  end
49
55
 
50
56
  def method_missing(name, *args, &block)
57
+ abort "internal error #{name} #{args} #{block}" unless name
51
58
  filterClass = FilterRegistry::get_filter(name.downcase)
52
- filter = filterClass.new(*args)
59
+ filter_scope(filterClass.new(*args)) do
60
+ block.yield if block
61
+ end
53
62
  filter_in_scope << filter
54
63
 
64
+ # short circuit the stream line stop exception so we can catch it
65
+ # in xail main
66
+ rescue StreamLineStop => stop
67
+ raise stop
68
+
55
69
  rescue UnknownFilter => error
56
70
  abort error.to_s
57
71
 
@@ -102,7 +102,7 @@ module Xail
102
102
  if line != nil
103
103
  filter.streamLine(line)
104
104
  else
105
- nil
105
+ return nil
106
106
  end
107
107
  end
108
108
  end
@@ -127,26 +127,26 @@ module Xail
127
127
  class OrFilter < AbstractCompoundFilter
128
128
  def streamLine(line)
129
129
  @filters.each do |filter|
130
- if filter.streamLine line
130
+ if filter and filter.streamLine(line)
131
131
  return line
132
132
  end
133
133
  end
134
134
 
135
- nil
135
+ return nil
136
136
  end
137
137
  end
138
138
 
139
139
 
140
140
  # the not filter streams the original if none of the component filters stream
141
- class NotFilter < AndFilter
141
+ class NotFilter < AbstractCompoundFilter
142
142
  def streamLine(line)
143
- result = super.streamLine(line)
144
-
145
- if result != nil
146
- nil
147
- else
148
- line
143
+ @filters.each do |filter|
144
+ if filter.streamLine(line)
145
+ return
146
+ end
149
147
  end
148
+
149
+ return line
150
150
  end
151
151
  end
152
152
 
@@ -157,7 +157,9 @@ module Xail
157
157
 
158
158
  def streamLine(line)
159
159
  @keys.each do |key|
160
- if line.include?(key)
160
+ if key.instance_of? Regexp and line[key]
161
+ return line
162
+ elsif key.instance_of? String and line.downcase.include? key.downcase
161
163
  return line
162
164
  end
163
165
  end
@@ -182,13 +184,21 @@ module Xail
182
184
  end
183
185
 
184
186
 
185
- # the stop filter never streams
186
- class StopFilter < AbstractFilter
187
+ # the sink filter never streams
188
+ class SinkFilter < AbstractFilter
187
189
  def streamLine(line)
188
190
  nil
189
191
  end
190
192
  end
191
193
 
194
+ # the stop filter stops all processing of this stream-line
195
+ class StreamLineStop < Exception; end
196
+ class StopFilter < AbstractFilter
197
+ def streamLine(line)
198
+ raise StreamLineStop
199
+ end
200
+ end
201
+
192
202
  # the pass through filter always streams
193
203
  class PassThroughFilter < AbstractFilter
194
204
  def streamLine(line)
@@ -1,3 +1,3 @@
1
1
  module Xail
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -24,10 +24,17 @@ describe PassThroughFilter do
24
24
  end
25
25
  end
26
26
 
27
+ describe SinkFilter do
28
+ it "should sink all streams" do
29
+ f = SinkFilter.new
30
+ f.streamLine("hi").should eq(nil)
31
+ end
32
+ end
33
+
27
34
  describe StopFilter do
28
- it "should stop all streams" do
35
+ it "should stop all processing of this stream-line" do
29
36
  f = StopFilter.new
30
- f.streamLine("hi").should eq(nil)
37
+ lambda { f.streamLine("hi") }.should raise_error(StreamLineStop)
31
38
  end
32
39
  end
33
40
 
@@ -61,10 +68,10 @@ end
61
68
  describe FilterCascade do
62
69
  it "should cascade through" do
63
70
  f = FilterCascade.new
64
- f << StopFilter.new
65
- f << StopFilter.new
71
+ f << SinkFilter.new
72
+ f << SinkFilter.new
66
73
  f << ContainsFilter.new("hi")
67
- f << StopFilter.new
74
+ f << SinkFilter.new
68
75
 
69
76
  f.streamLine("bye").should eq(nil)
70
77
  f.streamLine("hi").should eq("hi")
@@ -80,4 +87,48 @@ describe FilterComposition do
80
87
  f.streamLine('bye').should eq(nil)
81
88
  f.streamLine('hi there alice').should eq('hi there blice')
82
89
  end
90
+ end
91
+
92
+ describe OrFilter do
93
+ it "should act like logical or" do
94
+ f = OrFilter.new
95
+ f << ContainsFilter.new('a')
96
+ f << ContainsFilter.new('b')
97
+
98
+ f.streamLine('a').should eq('a')
99
+ f.streamLine('b').should eq('b')
100
+ f.streamLine('c').should eq(nil)
101
+ end
102
+ end
103
+
104
+ describe AndFilter do
105
+ it "should act like logical and" do
106
+ f = AndFilter.new
107
+ f << ContainsFilter.new('a')
108
+ f << ContainsFilter.new('b')
109
+
110
+ f.streamLine('a').should eq(nil)
111
+ f.streamLine('b').should eq(nil)
112
+ f.streamLine('ab').should eq('ab')
113
+ end
114
+ end
115
+
116
+ describe NotFilter do
117
+ it "should act like logical not" do
118
+ f = NotFilter.new
119
+ f << ContainsFilter.new('a')
120
+
121
+ f.streamLine('a').should eq(nil)
122
+ f.streamLine('b').should eq('b')
123
+ end
124
+
125
+ it "should take multiple subfilters" do
126
+ f = NotFilter.new
127
+ f << ContainsFilter.new('a')
128
+ f << ContainsFilter.new('b')
129
+
130
+ f.streamLine('a').should eq(nil)
131
+ f.streamLine('b').should eq(nil)
132
+ f.streamLine('c').should eq('c')
133
+ end
83
134
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-02-24 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70198967869060 !ruby/object:Gem::Requirement
16
+ requirement: &70300575161740 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70198967869060
24
+ version_requirements: *70300575161740
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: trollop
27
- requirement: &70198967868420 !ruby/object:Gem::Requirement
27
+ requirement: &70300575161280 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70198967868420
35
+ version_requirements: *70300575161280
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: term-ansicolor
38
- requirement: &70198967867800 !ruby/object:Gem::Requirement
38
+ requirement: &70300575160760 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70198967867800
46
+ version_requirements: *70300575160760
47
47
  description: A lightweight Ruby DSL for building text-stream filters
48
48
  email:
49
49
  - wiktor@tumblr.com
@@ -57,6 +57,7 @@ files:
57
57
  - README.md
58
58
  - Rakefile
59
59
  - bin/xail
60
+ - examples/customfilter.xail.rb
60
61
  - examples/logview.xail.rb
61
62
  - examples/logviewtest.txt
62
63
  - lib/xail.rb