chirp 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/History.txt +10 -3
- data/Manifest.txt +49 -1
- data/README.txt +4 -4
- data/Rakefile +3 -3
- data/bin/chirp +42 -0
- data/lib/chirp.rb +5 -223
- data/lib/chirp/application.rb +252 -0
- data/lib/chirp/statement.rb +91 -0
- data/test/account.dir/input +7 -0
- data/test/account.dir/output +1 -0
- data/test/account.dir/program.chirp +20 -0
- data/test/action.dir/input +7 -0
- data/test/action.dir/output +1 -0
- data/test/action.dir/program.chirp +3 -0
- data/test/beforeafter.dir/input +7 -0
- data/test/beforeafter.dir/output +11 -0
- data/test/beforeafter.dir/program.chirp +7 -0
- data/test/fields.dir/input +3 -0
- data/test/fields.dir/output +3 -0
- data/test/fields.dir/program.chirp +5 -0
- data/test/fields_sep.dir/input +7 -0
- data/test/fields_sep.dir/output +7 -0
- data/test/fields_sep.dir/program.chirp +6 -0
- data/test/files.dir/a.ignore +1 -0
- data/test/files.dir/a.txt +1 -0
- data/test/files.dir/b.txt +1 -0
- data/test/files.dir/c.stuff +1 -0
- data/test/files.dir/input +7 -0
- data/test/files.dir/output +2 -0
- data/test/files.dir/program.chirp +6 -0
- data/test/inplace.dir/a.txt +1 -0
- data/test/inplace.dir/b.txt +1 -0
- data/test/inplace.dir/input +7 -0
- data/test/inplace.dir/output +3 -0
- data/test/inplace.dir/program.chirp +9 -0
- data/test/line_no.dir/input +7 -0
- data/test/line_no.dir/output +1 -0
- data/test/line_no.dir/program.chirp +1 -0
- data/test/match.dir/input +14 -0
- data/test/match.dir/output +6 -0
- data/test/match.dir/program.chirp +1 -0
- data/test/proc.dir/input +8 -0
- data/test/proc.dir/output +3 -0
- data/test/proc.dir/program.chirp +3 -0
- data/test/span.dir/input +13 -0
- data/test/span.dir/output +7 -0
- data/test/span.dir/program.chirp +1 -0
- data/test/span2.dir/input +7 -0
- data/test/span2.dir/output +5 -0
- data/test/span2.dir/program.chirp +1 -0
- data/test/string.dir/input +14 -0
- data/test/string.dir/output +6 -0
- data/test/string.dir/program.chirp +1 -0
- data/test/test_application.rb +42 -0
- data/test/test_statement.rb +118 -0
- metadata +60 -7
- data/test/test_chirp.rb +0 -0
data/History.txt
CHANGED
@@ -1,5 +1,12 @@
|
|
1
|
-
== 1.0
|
1
|
+
== 0.1.0 / 2007-11-09
|
2
2
|
|
3
|
-
*
|
4
|
-
|
3
|
+
* Revive the project
|
4
|
+
* Initial update, very basic features
|
5
|
+
|
6
|
+
=== 0.2.0 / 2007-11-21:
|
7
|
+
|
8
|
+
* Added in ability to process multiple files
|
9
|
+
* Redid the event model
|
10
|
+
* Added tests
|
11
|
+
* Added examples
|
5
12
|
|
data/Manifest.txt
CHANGED
@@ -4,4 +4,52 @@ README.txt
|
|
4
4
|
Rakefile
|
5
5
|
bin/chirp
|
6
6
|
lib/chirp.rb
|
7
|
-
|
7
|
+
lib/chirp/application.rb
|
8
|
+
lib/chirp/statement.rb
|
9
|
+
test/test_statement.rb
|
10
|
+
test/test_application.rb
|
11
|
+
test/span.dir/output
|
12
|
+
test/span.dir/input
|
13
|
+
test/span.dir/program.chirp
|
14
|
+
test/match.dir/output
|
15
|
+
test/match.dir/program.chirp
|
16
|
+
test/match.dir/input
|
17
|
+
test/span2.dir/output
|
18
|
+
test/span2.dir/input
|
19
|
+
test/span2.dir/program.chirp
|
20
|
+
test/line_no.dir/output
|
21
|
+
test/line_no.dir/input
|
22
|
+
test/line_no.dir/program.chirp
|
23
|
+
test/inplace.dir/output
|
24
|
+
test/inplace.dir/input
|
25
|
+
test/inplace.dir/program.chirp
|
26
|
+
test/inplace.dir/a.txt
|
27
|
+
test/inplace.dir/b.txt
|
28
|
+
test/beforeafter.dir/output
|
29
|
+
test/beforeafter.dir/input
|
30
|
+
test/beforeafter.dir/program.chirp
|
31
|
+
test/action.dir/output
|
32
|
+
test/action.dir/input
|
33
|
+
test/action.dir/program.chirp
|
34
|
+
test/fields.dir/output
|
35
|
+
test/fields.dir/input
|
36
|
+
test/fields.dir/program.chirp
|
37
|
+
test/fields_sep.dir/output
|
38
|
+
test/fields_sep.dir/input
|
39
|
+
test/fields_sep.dir/program.chirp
|
40
|
+
test/string.dir/output
|
41
|
+
test/string.dir/input
|
42
|
+
test/string.dir/program.chirp
|
43
|
+
test/files.dir/output
|
44
|
+
test/files.dir/input
|
45
|
+
test/files.dir/program.chirp
|
46
|
+
test/files.dir/b.txt
|
47
|
+
test/files.dir/a.txt
|
48
|
+
test/files.dir/c.stuff
|
49
|
+
test/files.dir/a.ignore
|
50
|
+
test/proc.dir/output
|
51
|
+
test/proc.dir/input
|
52
|
+
test/proc.dir/program.chirp
|
53
|
+
test/account.dir/program.chirp
|
54
|
+
test/account.dir/output
|
55
|
+
test/account.dir/input
|
data/README.txt
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
chirp
|
2
|
-
by
|
3
|
-
|
2
|
+
by Russ Olsen
|
3
|
+
http://chirp.rubyforge.org
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
|
7
|
+
Chirp is a Ruby based DSL inspiried by awk.
|
8
8
|
|
9
9
|
== FEATURES/PROBLEMS:
|
10
10
|
|
11
|
-
*
|
11
|
+
* Need to add documentation
|
12
12
|
|
13
13
|
== SYNOPSIS:
|
14
14
|
|
data/Rakefile
CHANGED
@@ -6,9 +6,9 @@ require './lib/chirp.rb'
|
|
6
6
|
|
7
7
|
Hoe.new('chirp', Chirp::VERSION) do |p|
|
8
8
|
p.rubyforge_name = 'chirp'
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
p.author = 'Russ Olsen'
|
10
|
+
p.email = 'russ@russolsen.com'
|
11
|
+
p.summary = 'Chirp is a Ruby based text processing DSL similar to awk'
|
12
12
|
# p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
13
13
|
# p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
14
14
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
data/bin/chirp
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'chirp'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'chirp'
|
9
|
+
end
|
10
|
+
|
11
|
+
program_text=nil
|
12
|
+
verbose=false
|
13
|
+
|
14
|
+
option_parser = OptionParser.new do |op|
|
15
|
+
op.banner = "Usage: $0 [-v] [-e chirp_program_text] [chirp_program_file] [input_file ...]"
|
16
|
+
|
17
|
+
op.on('-p', '--program [chirp-program-text]',
|
18
|
+
'Execute this Chirp program') do |string|
|
19
|
+
program_text = string
|
20
|
+
end
|
21
|
+
|
22
|
+
op.on('-v', '--verbose',
|
23
|
+
'Produce lots out debugging output') do
|
24
|
+
verbose=true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
files=option_parser.parse(ARGV)
|
29
|
+
|
30
|
+
if files.empty? and program_text.nil?
|
31
|
+
STDERR.puts option_parser.banner
|
32
|
+
Kernel.exit(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
program_text = File.read(files.shift) unless program_text
|
36
|
+
|
37
|
+
app = Chirp::Application.new(program_text, verbose)
|
38
|
+
app.files(files)
|
39
|
+
app.evaluate
|
40
|
+
|
41
|
+
|
42
|
+
|
data/lib/chirp.rb
CHANGED
@@ -4,229 +4,11 @@
|
|
4
4
|
# Chirp is distributed under the same license as Ruby itself.
|
5
5
|
#
|
6
6
|
|
7
|
-
|
8
|
-
require 'pp'
|
9
|
-
require 'ftools'
|
10
|
-
require 'tempfile'
|
11
|
-
require 'forwardable'
|
7
|
+
ChirpLibDir=File.dirname(__FILE__)
|
12
8
|
|
13
|
-
|
14
|
-
|
15
|
-
VERSION = '0.1.0'
|
16
|
-
|
17
|
-
def Chirp.application
|
18
|
-
@application ||= Chirp::Application.new
|
19
|
-
end
|
20
|
-
|
21
|
-
class PatternAction
|
22
|
-
attr_reader :block
|
23
|
-
|
24
|
-
def initialize(re, block)
|
25
|
-
@re = re
|
26
|
-
@block = block
|
27
|
-
end
|
28
|
-
|
29
|
-
def matches(file, line, line_no)
|
30
|
-
@re =~ line
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class LineNumberAction
|
35
|
-
attr_reader :block
|
36
|
-
|
37
|
-
def initialize(number, block)
|
38
|
-
@number = number
|
39
|
-
@block = block
|
40
|
-
end
|
41
|
-
|
42
|
-
def matches(file, line, line_no)
|
43
|
-
line_no == @number
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
def Chirp.field_separator=(value)
|
49
|
-
application.field_separator=value
|
50
|
-
end
|
51
|
-
|
52
|
-
def Chirp.field_separator
|
53
|
-
application.field_separator
|
54
|
-
end
|
55
|
-
|
56
|
-
def Chirp.line
|
57
|
-
application.line
|
58
|
-
end
|
59
|
-
|
60
|
-
def Chirp.fields
|
61
|
-
application.fields
|
62
|
-
end
|
63
|
-
|
64
|
-
def Chirp.line_no
|
65
|
-
application.line_no
|
66
|
-
end
|
67
|
-
|
68
|
-
def Chirp.file
|
69
|
-
application.file
|
70
|
-
end
|
71
|
-
|
72
|
-
def Chirp.edit_in_place=(value)
|
73
|
-
application.edit_in_place = value
|
74
|
-
end
|
75
|
-
|
76
|
-
def Chirp.files=(value)
|
77
|
-
application.files=value
|
78
|
-
end
|
79
|
-
|
80
|
-
def Chirp.pattern( re, &block )
|
81
|
-
application.pattern(re, block)
|
82
|
-
end
|
9
|
+
require "#{ChirpLibDir}/chirp/statement"
|
10
|
+
require "#{ChirpLibDir}/chirp/application"
|
83
11
|
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
def Chirp.before &block
|
89
|
-
application.before(block)
|
90
|
-
end
|
91
|
-
|
92
|
-
def Chirp.before_file &block
|
93
|
-
application.before_file(block)
|
94
|
-
end
|
95
|
-
|
96
|
-
def Chirp.after_file &block
|
97
|
-
application.after_file(block)
|
98
|
-
end
|
99
|
-
|
100
|
-
def Chirp.after &block
|
101
|
-
application.after(block)
|
102
|
-
end
|
103
|
-
|
104
|
-
class Application
|
105
|
-
|
106
|
-
attr_accessor :field_separator
|
107
|
-
attr_reader :fields, :line, :line_no, :file
|
108
|
-
|
109
|
-
def initialize
|
110
|
-
@before_actions=[]
|
111
|
-
@before_file_actions=[]
|
112
|
-
@pattern_actions=[]
|
113
|
-
@after_file_actions=[]
|
114
|
-
@after_actions=[]
|
115
|
-
end
|
116
|
-
|
117
|
-
def files=(glob)
|
118
|
-
if glob.respond_to? :[]
|
119
|
-
@glob=glob
|
120
|
-
else
|
121
|
-
@glob = [ glob ]
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def edit_in_place=(value)
|
126
|
-
@edit_in_place=value
|
127
|
-
end
|
128
|
-
|
129
|
-
def has_run?
|
130
|
-
@has_run
|
131
|
-
end
|
132
|
-
|
133
|
-
def run
|
134
|
-
@has_run = true
|
135
|
-
@before_actions.each do |action|
|
136
|
-
action.call
|
137
|
-
end
|
138
|
-
|
139
|
-
if not @glob
|
140
|
-
process_stream
|
141
|
-
elsif @edit_in_place
|
142
|
-
process_edits(@glob)
|
143
|
-
else
|
144
|
-
process_streams(@glob)
|
145
|
-
end
|
146
|
-
|
147
|
-
@after_actions.each do |action|
|
148
|
-
action.call
|
149
|
-
end
|
150
|
-
|
151
|
-
end
|
152
|
-
|
153
|
-
def process_edits(glob)
|
154
|
-
glob.each do |path_pattern|
|
155
|
-
Dir.glob(path_pattern) do |path|
|
156
|
-
puts path
|
157
|
-
next if not Pathname.new(path).file?
|
158
|
-
backup_path = path + ".bak"
|
159
|
-
File.copy(path, backup_path)
|
160
|
-
open(backup_path,"r") do |in_stream|
|
161
|
-
open(path, "w") { |out_stream| process_stream(in_stream, out_stream, path) }
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def process_streams(glob)
|
168
|
-
glob.each do |path_pattern|
|
169
|
-
Dir.glob(path_pattern) do |path|
|
170
|
-
open(path,"r") { |stream| process_stream(stream, STDOUT, path) }
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def process_stream(in_stream=STDIN, out_stream=STDOUT, name='')
|
176
|
-
@file=name
|
177
|
-
old_stdout, $stdout = $stdout, out_stream
|
178
|
-
run_before_file_actions(name)
|
179
|
-
@line_no = 1
|
180
|
-
while not in_stream.eof?
|
181
|
-
@line = in_stream.readline.chomp
|
182
|
-
@fields=line.split(@field_separator)
|
183
|
-
@pattern_actions.each do |pa|
|
184
|
-
if pa.matches(name, @line, @line_no)
|
185
|
-
Chirp.module_eval &pa.block
|
186
|
-
end
|
187
|
-
end
|
188
|
-
@line_no += 1
|
189
|
-
end
|
190
|
-
run_after_file_actions(name)
|
191
|
-
$stdout = old_stdout
|
192
|
-
end
|
193
|
-
|
194
|
-
def run_before_file_actions(name)
|
195
|
-
@before_file_actions.each { |a| a.call(name) }
|
196
|
-
end
|
197
|
-
|
198
|
-
def run_after_file_actions(name)
|
199
|
-
@after_file_actions.each { |a| a.call(name) }
|
200
|
-
end
|
201
|
-
|
202
|
-
def pattern(re, block)
|
203
|
-
@pattern_actions << PatternAction.new(re, block)
|
204
|
-
end
|
205
|
-
|
206
|
-
def line_number(n, block)
|
207
|
-
@pattern_actions << LineNumberAction.new(n, block)
|
208
|
-
end
|
209
|
-
|
210
|
-
def before(block)
|
211
|
-
@before_actions << block
|
212
|
-
end
|
213
|
-
|
214
|
-
def before_file(block)
|
215
|
-
@before_file_actions << block
|
216
|
-
end
|
217
|
-
|
218
|
-
def after_file(block)
|
219
|
-
@after_file_actions << block
|
220
|
-
end
|
221
|
-
|
222
|
-
def after(block)
|
223
|
-
@after_actions << block
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
at_exit do
|
229
|
-
Chirp::application.run if not Chirp::application.has_run?
|
12
|
+
module Chirp
|
13
|
+
VERSION = '0.2.0'
|
230
14
|
end
|
231
|
-
|
232
|
-
|
@@ -0,0 +1,252 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2006-2007 Russell Olsen
|
3
|
+
# Chirp is distributed under the same license as Ruby itself.
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
require 'ftools'
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
module Chirp
|
11
|
+
def self.redirect_io_and_run(input, output=$stdout, &block)
|
12
|
+
old_stdout, $stdout = $stdout, output
|
13
|
+
old_stdin, $stdin = $stdin, input
|
14
|
+
begin
|
15
|
+
block.call
|
16
|
+
ensure
|
17
|
+
$stdin, $stdout = old_stdin, old_stdout
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Context
|
22
|
+
include FileUtils
|
23
|
+
|
24
|
+
attr_accessor :field_separator, :line, :line_no, :path, :paths
|
25
|
+
attr_writer :fields, :contents
|
26
|
+
|
27
|
+
def initialize(field_separator)
|
28
|
+
@field_separator = field_separator
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute(action)
|
32
|
+
instance_eval(&action)
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_binding
|
36
|
+
binding
|
37
|
+
end
|
38
|
+
|
39
|
+
def fields
|
40
|
+
@fields || @fields = line.split(@field_separator)
|
41
|
+
end
|
42
|
+
|
43
|
+
def contents
|
44
|
+
@contents || @contents = File.read(@file)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Action
|
49
|
+
def initialize(context, &block)
|
50
|
+
@context = context
|
51
|
+
@block = block
|
52
|
+
end
|
53
|
+
|
54
|
+
def evaluate(path)
|
55
|
+
@context.path = path
|
56
|
+
@context.execute(@block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def evaluate_paths(paths)
|
60
|
+
@context.paths = paths
|
61
|
+
@context.execute(@block)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
class PathAction
|
67
|
+
DEFAULT_ACTION = lambda {puts line}
|
68
|
+
|
69
|
+
attr_accessor :verbose
|
70
|
+
|
71
|
+
def initialize(glob, context, &block)
|
72
|
+
@glob = glob
|
73
|
+
@context = context
|
74
|
+
@edit_in_place = false
|
75
|
+
@before_actions = []
|
76
|
+
@match_statements=[]
|
77
|
+
@after_actions = []
|
78
|
+
@field_separator = /[ \t]/
|
79
|
+
instance_eval(&block)
|
80
|
+
end
|
81
|
+
|
82
|
+
def field_separator(sep=nil)
|
83
|
+
@field_separator=sep
|
84
|
+
end
|
85
|
+
|
86
|
+
def edit_in_place(new_value=true)
|
87
|
+
@edit_in_place = new_value
|
88
|
+
end
|
89
|
+
|
90
|
+
def evaluate_paths(paths)
|
91
|
+
@context.paths = paths
|
92
|
+
paths.each do |path|
|
93
|
+
evaluate_path(path)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def line(arg1=nil, arg2=nil, &block)
|
98
|
+
action = block || DEFAULT_ACTION
|
99
|
+
|
100
|
+
if arg1.nil? and arg2.nil?
|
101
|
+
@match_statements << Statement.new( MatchPredicate.new(/.*/), action)
|
102
|
+
elsif arg2.nil?
|
103
|
+
@match_statements << Statement.new( predicate_for(arg1), action)
|
104
|
+
else
|
105
|
+
@match_statements << Statement.new(
|
106
|
+
SpanPredicate.new(predicate_for(arg1), predicate_for(arg2)), action)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def before(&block)
|
111
|
+
@before_actions << block
|
112
|
+
end
|
113
|
+
|
114
|
+
def after(&block)
|
115
|
+
@after_actions << block
|
116
|
+
end
|
117
|
+
|
118
|
+
def applies_to(path)
|
119
|
+
File.fnmatch(@glob, path)
|
120
|
+
end
|
121
|
+
|
122
|
+
def evaluate_path(path)
|
123
|
+
return nil unless applies_to(path)
|
124
|
+
unless @edit_in_place
|
125
|
+
File.open(path) do |in_stream|
|
126
|
+
Chirp::redirect_io_and_run(in_stream, $stdout) {evaluate(path)}
|
127
|
+
end
|
128
|
+
else
|
129
|
+
backup_path = path + ".bak"
|
130
|
+
File.copy(path, backup_path)
|
131
|
+
File.open(backup_path) do |in_stream|
|
132
|
+
File.open(path, 'w') do |out_stream|
|
133
|
+
Chirp::redirect_io_and_run(in_stream, out_stream) {evaluate(path)}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def evaluate(path)
|
140
|
+
@context.path = path
|
141
|
+
@context.field_separator = @field_separator
|
142
|
+
@before_actions.each {|a| @context.execute(a)}
|
143
|
+
unless @match_statements.empty?
|
144
|
+
@context.line_no = 1
|
145
|
+
while not $stdin.eof?
|
146
|
+
@context.fields=nil
|
147
|
+
@context.line = $stdin.readline.chomp
|
148
|
+
@match_statements.each do |statement|
|
149
|
+
statement.evaluate(@context)
|
150
|
+
end
|
151
|
+
@context.line_no += 1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
@context.contents = nil
|
155
|
+
@after_actions.each {|a| @context.execute(a)}
|
156
|
+
end
|
157
|
+
|
158
|
+
def predicate_for(arg)
|
159
|
+
return LineNumberPredicate.new(arg) if arg.kind_of?(Numeric)
|
160
|
+
return StringPredicate.new(arg) if arg.kind_of?(String)
|
161
|
+
return MatchPredicate.new(arg) if arg.kind_of?(Regexp)
|
162
|
+
return RangePredicate.new(arg) if arg.kind_of?(Range)
|
163
|
+
return LambdaPredicate.new(arg) if arg.kind_of?(Proc)
|
164
|
+
raise "Unknown argument: #{arg}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
|
170
|
+
class Application
|
171
|
+
|
172
|
+
DEFAULT_ACTION = lambda {puts line}
|
173
|
+
|
174
|
+
attr_accessor :verbose
|
175
|
+
|
176
|
+
def initialize(program_string, verbose=false)
|
177
|
+
@glob = nil
|
178
|
+
@actions=[]
|
179
|
+
@verbose=verbose
|
180
|
+
@context = Chirp::Context.new(/[ \t]/)
|
181
|
+
self.program=program_string if program_string
|
182
|
+
end
|
183
|
+
|
184
|
+
def setup(args)
|
185
|
+
self.program=File.read(args[0])
|
186
|
+
end
|
187
|
+
|
188
|
+
def program=(chirp_program_string)
|
189
|
+
instance_eval(chirp_program_string, 'user program')
|
190
|
+
end
|
191
|
+
|
192
|
+
def run(&block)
|
193
|
+
@actions << Action.new(@context, &block)
|
194
|
+
end
|
195
|
+
|
196
|
+
def file(glob='*', &block)
|
197
|
+
@actions << PathAction.new(glob, @context, &block)
|
198
|
+
end
|
199
|
+
|
200
|
+
def files(args)
|
201
|
+
@glob = args unless args.empty?
|
202
|
+
@glob
|
203
|
+
end
|
204
|
+
|
205
|
+
def evaluate(in_stream=$stdin, out_stream=$stdout)
|
206
|
+
log('Running Chirp program')
|
207
|
+
Chirp::redirect_io_and_run(in_stream, out_stream) do
|
208
|
+
log('Running before actions')
|
209
|
+
if not @glob
|
210
|
+
process_stream(in_stream, out_stream, '-')
|
211
|
+
else
|
212
|
+
process_files(@glob)
|
213
|
+
end
|
214
|
+
log('Running after actions')
|
215
|
+
end
|
216
|
+
log('Chirp program done')
|
217
|
+
end
|
218
|
+
|
219
|
+
def process_stream(in_stream, outstream, name)
|
220
|
+
@actions.each do |path_action|
|
221
|
+
Chirp::redirect_io_and_run(in_stream, outstream) do
|
222
|
+
path_action.evaluate(name)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def process_files(globs)
|
228
|
+
@actions.each do |action|
|
229
|
+
paths = expand_globs(globs)
|
230
|
+
action.evaluate_paths(paths)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def log(*args)
|
235
|
+
return unless @verbose
|
236
|
+
STDERR.puts args.join(' ')
|
237
|
+
end
|
238
|
+
|
239
|
+
def expand_globs(globs)
|
240
|
+
results = []
|
241
|
+
globs.each do |path_pattern|
|
242
|
+
this_glob_results = []
|
243
|
+
Dir.glob(path_pattern) do |path|
|
244
|
+
this_glob_results << path if Pathname.new(path).file?
|
245
|
+
end
|
246
|
+
this_glob_results.sort!
|
247
|
+
results << this_glob_results
|
248
|
+
end
|
249
|
+
results.flatten!
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|