frag 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /Gemfile.lock
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ == 0.0.1 2012-08-05
2
+
3
+ * Hi.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ group :development do
5
+ gem 'debugger'
6
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) George Ogata
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.
data/README.markdown ADDED
@@ -0,0 +1,111 @@
1
+ ## Frag
2
+
3
+ Generate fragments of files from the output of shell commands.
4
+
5
+ ## Why? How?
6
+
7
+ Sometimes you want to generate just part of a file programatically. For example,
8
+ you might want to generate your `~/.ssh/config` from a list of hosts managed by
9
+ [Chef][chef]:
10
+
11
+ Host a
12
+ Hostname 123.123.123.1
13
+ User me
14
+
15
+ Host b
16
+ Hostname 123.123.123.2
17
+ User me
18
+
19
+ # GEN: knife sshgen
20
+ # ENDGEN
21
+
22
+ Now `frag` that file:
23
+
24
+ frag ~/.ssh/config
25
+
26
+ and the region delimited by the `GEN`..`ENDGEN` lines will be filled in with the
27
+ output from [knife sshgen][knife-sshgen]. The delimiter lines remain, so you can
28
+ re-`frag` anytime to bring it up to date.
29
+
30
+ Or maybe you want your `/etc/hosts` to set a list of local subdomains from a
31
+ database:
32
+
33
+ 127.0.0.1 localhost
34
+ 255.255.255.255 broadcasthost
35
+ ::1 localhost
36
+ fe80::1%lo0 localhost
37
+
38
+ # GEN: mysql myapp -Bre 'select subdomain from sites | sed -e 's/.*/127.0.0.1 &.myapp.local/'
39
+ # ENDGEN
40
+
41
+ Pipelines work - woo!
42
+
43
+ Or maybe you're authoring this README and want to show all the options `frag`
44
+ takes:
45
+
46
+ <!-- GEN: echo; ruby -Ilib bin/frag --help | sed -e 's/^/ /'; echo -->
47
+
48
+ USAGE: bin/frag [options] file ...
49
+ -b, --begin DELIMITER
50
+ -e, --end DELIMITER
51
+ -l, --leader STRING
52
+ -t, --trailer STRING
53
+ -p, --backup-prefix PREFIX
54
+ -s, --backup-suffix SUFFIX
55
+
56
+ <!-- ENDGEN -->
57
+
58
+ (Check the source... ;-)
59
+
60
+ [chef]: http://www.opscode.com/chef
61
+ [knife-sshgen]: https://github.com/harvesthq/knife-plugins/blob/master/.chef/plugins/knife/sshgen.rb
62
+
63
+ ## Too simple?
64
+
65
+ Make things complicated with these customizable options.
66
+
67
+ ### Comment Syntax
68
+
69
+ By default, frag assumes the beginning and ending lines for each fragment start
70
+ with a '#' (followed by optional whitespace). Change that with`-l` or
71
+ `--leader`:
72
+
73
+ frag -l '--' magic.hs
74
+
75
+ If your comments need trailing characters too, there's `-t` or `--trailer`:
76
+
77
+ frag -l '/*' -t '*/' magic.cc
78
+
79
+ ### Custom Delimiters
80
+
81
+ If you want to choose your own delimiters.
82
+
83
+ frag -b 'FRAGGED BY' -e 'FRAGGED' file.txt
84
+
85
+ Now your regions can look like:
86
+
87
+ # FRAGGED BY ...
88
+ ...
89
+ # FRAGGED
90
+
91
+ ### Backups
92
+
93
+ Back up the original file by providing a suffix:
94
+
95
+ frag -s '.backup' file.txt
96
+
97
+ Or dump all your backups into a directory with a prefix:
98
+
99
+ frag -p ~/.frag-backups file.txt
100
+
101
+ ## Note on Patches/Pull Requests
102
+
103
+ * Bug reports: http://github.com/oggy/frag/issues
104
+ * Source: http://github.com/oggy/frag
105
+ * Patches: Fork on Github, send pull request.
106
+ * Ensure patch includes tests.
107
+ * Leave the version alone, or bump it in a separate commit.
108
+
109
+ ## Copyright
110
+
111
+ Copyright (c) George Ogata. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'ritual'
data/bin/frag ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'frag'
4
+
5
+ exit Frag::App.new(ARGV).run
data/frag.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.unshift File.expand_path('lib', File.dirname(__FILE__))
3
+ require 'frag/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'frag'
7
+ gem.version = Frag::VERSION
8
+ gem.authors = ['George Ogata']
9
+ gem.email = ['george.ogata@gmail.com']
10
+ gem.license = 'MIT'
11
+ gem.summary = "Generate regions of files from the output of shell commands."
12
+ gem.homepage = 'http://github.com/oggy/frag'
13
+
14
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+
18
+ gem.add_development_dependency 'ritual', '~> 0.4.1'
19
+ end
data/lib/frag/app.rb ADDED
@@ -0,0 +1,123 @@
1
+ require 'tempfile'
2
+ require 'fileutils'
3
+ require 'optparse'
4
+
5
+ module Frag
6
+ class App
7
+ def initialize(args, input=STDIN, output=STDOUT, error=STDERR)
8
+ @input, @output, @error = input, output, error
9
+ @status = 0
10
+
11
+ beginning = 'GEN:'
12
+ ending = 'ENDGEN'
13
+ leader = '#'
14
+ trailer = ''
15
+ @backup_prefix = @backup_suffix = nil
16
+
17
+ parser = OptionParser.new do |parser|
18
+ parser.banner = "USAGE: #$0 [options] file ..."
19
+
20
+ parser.on '-b', '--begin DELIMITER' do |value|
21
+ beginning = Regexp.escape(value)
22
+ end
23
+ parser.on '-e', '--end DELIMITER' do |value|
24
+ ending = Regexp.escape(value)
25
+ end
26
+ parser.on '-l', '--leader STRING' do |value|
27
+ leader = Regexp.escape(value)
28
+ end
29
+ parser.on '-t', '--trailer STRING' do |value|
30
+ trailer = Regexp.escape(value)
31
+ end
32
+ parser.on '-p', '--backup-prefix PREFIX' do |value|
33
+ @backup_prefix = value
34
+ end
35
+ parser.on '-s', '--backup-suffix SUFFIX' do |value|
36
+ @backup_suffix = value
37
+ end
38
+ end
39
+
40
+ parser.parse!(args)
41
+ args.size > 0 or
42
+ return error "no files given"
43
+
44
+ @begin_line = Regexp.new(['^', leader, beginning, '(.*)', trailer, '$'].reject(&:empty?).join('\\s*'))
45
+ @end_line = Regexp.new(['^', leader, ending, trailer, '$'].reject(&:empty?).join('\\s*'))
46
+ @input_paths = args
47
+ end
48
+
49
+ def run
50
+ return @status if @status != 0
51
+ @input_paths.each do |input_path|
52
+ manage_files(input_path) do |input, output|
53
+ process(input, output)
54
+ end
55
+ end
56
+ @status
57
+ end
58
+
59
+ attr_reader :status
60
+
61
+ private
62
+
63
+ def error(message, status=1)
64
+ @error.puts "error: #{message}"
65
+ @status = status
66
+ false
67
+ end
68
+
69
+ def manage_files(input_path)
70
+ File.exist?(input_path) or
71
+ return error "file not found: #{input_path}"
72
+ File.file?(input_path) or
73
+ return error "not a file: #{input_path}"
74
+ File.readable?(input_path) or
75
+ return error "cannot open file: #{input_path}"
76
+ tempfile = nil
77
+ success = nil
78
+ open(input_path) do |input|
79
+ tempfile = Tempfile.open('frag') do |output|
80
+ yield input, output or
81
+ return
82
+ output
83
+ end
84
+ end
85
+ if @backup_prefix || @backup_suffix
86
+ backup_path = "#{@backup_prefix}#{File.expand_path(input_path)}#{@backup_suffix}"
87
+ FileUtils.mkdir_p File.dirname(backup_path)
88
+ FileUtils.cp input_path, backup_path
89
+ end
90
+ FileUtils.cp tempfile.path, input_path
91
+ end
92
+
93
+ def process(input, output)
94
+ region_start = nil
95
+ command = nil
96
+ while (line = input.gets)
97
+ unless region_start
98
+ output.puts line
99
+ end
100
+ case line
101
+ when @begin_line
102
+ region_start.nil? or
103
+ return error "#{input.lineno}: nested region"
104
+ command = $1
105
+ region_start = input.lineno
106
+ when @end_line
107
+ region_start or
108
+ return error "#{input.lineno}: unmatched begin delimiter"
109
+ output.puts `#{command}`
110
+ if !$?.success?
111
+ return error "#{region_start}: failed: (#{$?.exitstatus}) #{command}"
112
+ end
113
+ region_start = nil
114
+ output.puts line
115
+ end
116
+ end
117
+ if region_start
118
+ return error "#{region_start}: unmatched end delimiter"
119
+ end
120
+ true
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,11 @@
1
+ module Frag
2
+ VERSION = [0, 0, 1]
3
+
4
+ class << VERSION
5
+ include Comparable
6
+
7
+ def to_s
8
+ join('.')
9
+ end
10
+ end
11
+ end
data/lib/frag.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Frag
2
+ autoload :App, 'frag/app'
3
+ autoload :VERSION, 'frag/version'
4
+ end
@@ -0,0 +1,30 @@
1
+ require 'bundler'
2
+ require 'minitest/spec'
3
+ require 'debugger'
4
+
5
+ ROOT = File.expand_path('..', File.dirname(__FILE__))
6
+ $:.unshift "#{ROOT}/lib"
7
+ require 'frag'
8
+
9
+ String.class_eval do
10
+ def demargin
11
+ gsub(/^ *\|/, '')
12
+ end
13
+ end
14
+
15
+ MiniTest::Spec.class_eval do
16
+ before do
17
+ FileUtils.mkdir_p "#{ROOT}/test/tmp"
18
+ @original_pwd = Dir.pwd
19
+ FileUtils.chdir "#{ROOT}/test/tmp"
20
+ end
21
+
22
+ after do
23
+ FileUtils.chdir @original_pwd
24
+ FileUtils.rm_rf "#{ROOT}/test/tmp"
25
+ end
26
+
27
+ def write_file(path, input)
28
+ open(path, 'w') { |f| f.print input }
29
+ end
30
+ end
@@ -0,0 +1,49 @@
1
+ require_relative 'test_helper'
2
+ require 'open3'
3
+
4
+ describe Frag do
5
+ def frag(*args)
6
+ ruby = RbConfig::CONFIG.values_at('bindir', 'ruby_install_name').join('/')
7
+ command = [ruby, '-I', "#{ROOT}/lib", "#{ROOT}/bin/frag", *args]
8
+ @output, @error, status = Open3.capture3(*command)
9
+ status
10
+ end
11
+
12
+ describe "when a file is frag'd successfully" do
13
+ it "updates the file, and exits with zero status" do
14
+ write_file 'input', <<-EOS.demargin
15
+ |# GEN: echo new
16
+ |old
17
+ |# ENDGEN
18
+ EOS
19
+ frag('input').must_equal 0
20
+ File.read('input').must_equal <<-EOS.demargin
21
+ |# GEN: echo new
22
+ |new
23
+ |# ENDGEN
24
+ EOS
25
+ end
26
+ end
27
+
28
+ describe "when options are used succesfully" do
29
+ it "updates the file, and exits with zero status" do
30
+ write_file 'input', <<-EOS.demargin
31
+ |# GEN: echo new
32
+ |old
33
+ |# ENDGEN
34
+ |// GEN: echo new
35
+ |old
36
+ |// ENDGEN
37
+ EOS
38
+ frag('-l', '//', 'input').must_equal 0
39
+ File.read('input').must_equal <<-EOS.demargin
40
+ |# GEN: echo new
41
+ |old
42
+ |# ENDGEN
43
+ |// GEN: echo new
44
+ |new
45
+ |// ENDGEN
46
+ EOS
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,372 @@
1
+ require_relative '../test_helper'
2
+ require 'stringio'
3
+ require 'tempfile'
4
+
5
+ describe Frag::App do
6
+ let(:input) { StringIO.new }
7
+ let(:output) { StringIO.new }
8
+ let(:error) { StringIO.new }
9
+
10
+ def frag(*args)
11
+ Frag::App.new(args, input, output, error).run
12
+ end
13
+
14
+ describe "when no options are used" do
15
+ it "populates the delimited region if it's empty" do
16
+ write_file 'input', <<-EOS.demargin
17
+ |# GEN: echo hi
18
+ |# ENDGEN
19
+ EOS
20
+ frag('input').must_equal 0
21
+ (output.string + error.string).must_equal ''
22
+ File.read('input').must_equal <<-EOS.demargin
23
+ |# GEN: echo hi
24
+ |hi
25
+ |# ENDGEN
26
+ EOS
27
+ end
28
+
29
+ it "replaces the delimited region if there's already something there" do
30
+ write_file 'input', <<-EOS.demargin
31
+ |# GEN: echo new
32
+ |old
33
+ |# ENDGEN
34
+ EOS
35
+ frag('input').must_equal 0
36
+ (output.string + error.string).must_equal ''
37
+ File.read('input').must_equal <<-EOS.demargin
38
+ |# GEN: echo new
39
+ |new
40
+ |# ENDGEN
41
+ EOS
42
+ end
43
+
44
+ it "appends a newline if the command output doesn't end in one" do
45
+ write_file 'input', <<-EOS.demargin
46
+ |# GEN: echo -n hi
47
+ |# ENDGEN
48
+ EOS
49
+ frag('input').must_equal 0
50
+ (output.string + error.string).must_equal ''
51
+ File.read('input').must_equal <<-EOS.demargin
52
+ |# GEN: echo -n hi
53
+ |hi
54
+ |# ENDGEN
55
+ EOS
56
+ end
57
+
58
+ it "processes multiple regions, and leave surrounding content alone" do
59
+ write_file 'input', <<-EOS.demargin
60
+ |before
61
+ |# GEN: echo one
62
+ |# ENDGEN
63
+ |middle
64
+ |# GEN: echo two
65
+ |# ENDGEN
66
+ |after
67
+ EOS
68
+ frag('input').must_equal 0
69
+ (output.string + error.string).must_equal ''
70
+ File.read('input').must_equal <<-EOS.demargin
71
+ |before
72
+ |# GEN: echo one
73
+ |one
74
+ |# ENDGEN
75
+ |middle
76
+ |# GEN: echo two
77
+ |two
78
+ |# ENDGEN
79
+ |after
80
+ EOS
81
+ end
82
+
83
+ it "can process multiple files" do
84
+ write_file 'one', <<-EOS.demargin
85
+ |# GEN: echo one
86
+ |# ENDGEN
87
+ EOS
88
+ write_file 'two', <<-EOS.demargin
89
+ |# GEN: echo two
90
+ |# ENDGEN
91
+ EOS
92
+ frag('one', 'two').must_equal 0
93
+ (output.string + error.string).must_equal ''
94
+ File.read('one').must_equal <<-EOS.demargin
95
+ |# GEN: echo one
96
+ |one
97
+ |# ENDGEN
98
+ EOS
99
+ File.read('two').must_equal <<-EOS.demargin
100
+ |# GEN: echo two
101
+ |two
102
+ |# ENDGEN
103
+ EOS
104
+ end
105
+ end
106
+
107
+ describe "when the delimiter options are used" do
108
+ ['-b', '--begin'].each do |option|
109
+ it "uses the beginning delimiter given by #{option}" do
110
+ write_file 'input', <<-EOS.demargin
111
+ |# BEGIN echo one
112
+ |# ENDGEN
113
+ EOS
114
+ frag(option, 'BEGIN', 'input').must_equal 0
115
+ (output.string + error.string).must_equal ''
116
+ File.read('input').must_equal <<-EOS.demargin
117
+ |# BEGIN echo one
118
+ |one
119
+ |# ENDGEN
120
+ EOS
121
+ end
122
+ end
123
+
124
+ ['-e', '--end'].each do |option|
125
+ it "uses the ending delimiter given by #{option}" do
126
+ write_file 'input', <<-EOS.demargin
127
+ |# GEN: echo one
128
+ |# END
129
+ EOS
130
+ frag(option, 'END', 'input').must_equal 0
131
+ (output.string + error.string).must_equal ''
132
+ File.read('input').must_equal <<-EOS.demargin
133
+ |# GEN: echo one
134
+ |one
135
+ |# END
136
+ EOS
137
+ end
138
+ end
139
+
140
+ ['-l', '--leader'].each do |option|
141
+ it "uses the delimiter leader given by #{option}" do
142
+ write_file 'input', <<-EOS.demargin
143
+ |// GEN: echo one
144
+ |// ENDGEN
145
+ EOS
146
+ frag(option, '//', 'input').must_equal 0
147
+ (output.string + error.string).must_equal ''
148
+ File.read('input').must_equal <<-EOS.demargin
149
+ |// GEN: echo one
150
+ |one
151
+ |// ENDGEN
152
+ EOS
153
+ end
154
+ end
155
+
156
+ ['-t', '--trailer'].each do |option|
157
+ it "uses the delimiter trailer given by #{option}" do
158
+ write_file 'input', <<-EOS.demargin
159
+ |# GEN: echo one !!
160
+ |# ENDGEN !!
161
+ EOS
162
+ frag(option, '!!', 'input').must_equal 0
163
+ (output.string + error.string).must_equal ''
164
+ File.read('input').must_equal <<-EOS.demargin
165
+ |# GEN: echo one !!
166
+ |one
167
+ |# ENDGEN !!
168
+ EOS
169
+ end
170
+ end
171
+
172
+ it "supports using delimiter options together" do
173
+ write_file 'input', <<-EOS.demargin
174
+ |<!-- BEGIN echo one -->
175
+ |<!-- END -->
176
+ EOS
177
+ frag('-b', 'BEGIN', '-e', 'END', '-l', '<!--', '-t', '-->', 'input').must_equal 0
178
+ (output.string + error.string).must_equal ''
179
+ File.read('input').must_equal <<-EOS.demargin
180
+ |<!-- BEGIN echo one -->
181
+ |one
182
+ |<!-- END -->
183
+ EOS
184
+ end
185
+ end
186
+
187
+ describe "when the backup options are used" do
188
+ ['-p', '--backup-prefix'].each do |option|
189
+ it "backs up the input file with the prefix given by #{option}" do
190
+ write_file 'input', <<-EOS.demargin
191
+ |# GEN: echo new
192
+ |old
193
+ |# ENDGEN
194
+ EOS
195
+ frag(option, 'path/to/backups', 'input').must_equal 0
196
+ (output.string + error.string).must_equal ''
197
+ File.read('input').must_equal <<-EOS.demargin
198
+ |# GEN: echo new
199
+ |new
200
+ |# ENDGEN
201
+ EOS
202
+ File.read("path/to/backups/#{File.expand_path('input')}").must_equal <<-EOS.demargin
203
+ |# GEN: echo new
204
+ |old
205
+ |# ENDGEN
206
+ EOS
207
+ end
208
+ end
209
+
210
+ ['-s', '--backup-suffix'].each do |option|
211
+ it "backs up the input file with the suffix given by #{option}" do
212
+ write_file 'input', <<-EOS.demargin
213
+ |# GEN: echo new
214
+ |old
215
+ |# ENDGEN
216
+ EOS
217
+ frag(option, '.backup', 'input').must_equal 0
218
+ (output.string + error.string).must_equal ''
219
+ File.read('input').must_equal <<-EOS.demargin
220
+ |# GEN: echo new
221
+ |new
222
+ |# ENDGEN
223
+ EOS
224
+ File.read('input.backup').must_equal <<-EOS.demargin
225
+ |# GEN: echo new
226
+ |old
227
+ |# ENDGEN
228
+ EOS
229
+ end
230
+ end
231
+
232
+ it "supports using --backup-prefix and --backup-suffix together" do
233
+ write_file 'input', <<-EOS.demargin
234
+ |# GEN: echo new
235
+ |old
236
+ |# ENDGEN
237
+ EOS
238
+ frag('-p', 'path/to/backups', '-s', '.backup', 'input').must_equal 0
239
+ (output.string + error.string).must_equal ''
240
+ File.read('input').must_equal <<-EOS.demargin
241
+ |# GEN: echo new
242
+ |new
243
+ |# ENDGEN
244
+ EOS
245
+ File.read("path/to/backups/#{File.expand_path('input')}.backup").must_equal <<-EOS.demargin
246
+ |# GEN: echo new
247
+ |old
248
+ |# ENDGEN
249
+ EOS
250
+ end
251
+
252
+ it "does not back up files which produces errors" do
253
+ write_file 'a', <<-EOS.demargin
254
+ |# GEN: true
255
+ |# ENDGEN
256
+ EOS
257
+ write_file 'b', <<-EOS.demargin
258
+ |# GEN: false
259
+ |# ENDGEN
260
+ EOS
261
+ write_file 'c', <<-EOS.demargin
262
+ |# GEN: true
263
+ |# ENDGEN
264
+ EOS
265
+ frag('-s', '.backup', 'a', 'b', 'c').must_equal 1
266
+ File.exist?('a.backup').must_equal true
267
+ File.exist?('b.backup').must_equal false
268
+ File.exist?('c.backup').must_equal true
269
+ end
270
+ end
271
+
272
+ it "prints an error and leaves the input file unchanged if a command fails" do
273
+ write_file 'input', <<-EOS.demargin
274
+ |# GEN: echo new
275
+ |old
276
+ |# ENDGEN
277
+ |# GEN: false
278
+ |# ENDGEN
279
+ EOS
280
+ frag('input').must_equal 1
281
+ output.string.must_equal ''
282
+ error.string.must_match(/\b4:.*failed/)
283
+ File.read('input').must_equal <<-EOS.demargin
284
+ |# GEN: echo new
285
+ |old
286
+ |# ENDGEN
287
+ |# GEN: false
288
+ |# ENDGEN
289
+ EOS
290
+ end
291
+
292
+ it "prints an error if there's an unmatched beginning line" do
293
+ write_file 'input', <<-EOS.demargin
294
+ |# GEN: echo one
295
+ EOS
296
+ frag('input').must_equal 1
297
+ output.string.must_equal ''
298
+ error.string.must_match(/\b1:.*unmatched/)
299
+ end
300
+
301
+ it "prints an error if there's an unmatched ending line" do
302
+ write_file 'input', <<-EOS.demargin
303
+ |# ENDGEN
304
+ EOS
305
+ frag('input').must_equal 1
306
+ output.string.must_equal ''
307
+ error.string.must_match(/\b1:.*unmatched/)
308
+ end
309
+
310
+ it "continues processing other files if one of them produces an error" do
311
+ write_file 'a', <<-EOS.demargin
312
+ |# GEN: echo new
313
+ |old
314
+ |# ENDGEN
315
+ EOS
316
+ write_file 'b', <<-EOS.demargin
317
+ |# GEN: false
318
+ |old
319
+ |# ENDGEN
320
+ EOS
321
+ write_file 'c', <<-EOS.demargin
322
+ |# GEN: echo new
323
+ |old
324
+ |# ENDGEN
325
+ EOS
326
+ frag('a', 'b', 'c').must_equal 1
327
+ output.string.must_equal ''
328
+ File.read('a').must_equal <<-EOS.demargin
329
+ |# GEN: echo new
330
+ |new
331
+ |# ENDGEN
332
+ EOS
333
+ File.read('b').must_equal <<-EOS.demargin
334
+ |# GEN: false
335
+ |old
336
+ |# ENDGEN
337
+ EOS
338
+ File.read('c').must_equal <<-EOS.demargin
339
+ |# GEN: echo new
340
+ |new
341
+ |# ENDGEN
342
+ EOS
343
+ end
344
+
345
+ it "prints an error if an input file does not exist" do
346
+ frag('input').must_equal 1
347
+ output.string.must_equal ''
348
+ error.string.must_match /file not found.*input/
349
+ end
350
+
351
+ it "prints an error if an input file is not readable" do
352
+ write_file 'input', ''
353
+ File.chmod 0, 'input'
354
+ frag('input').must_equal 1
355
+ output.string.must_equal ''
356
+ error.string.must_match /cannot open file.*input/
357
+ end
358
+
359
+ it "prints an error if an input file is not a file" do
360
+ Dir.mkdir 'input'
361
+ frag('input').must_equal 1
362
+ output.string.must_equal ''
363
+ error.string.must_match /not a file.*input/
364
+ end
365
+
366
+ it "prints an error if an input file is a dangling symlink" do
367
+ File.symlink 'missing', 'input'
368
+ frag('input').must_equal 1
369
+ output.string.must_equal ''
370
+ error.string.must_match /file not found.*input/
371
+ end
372
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: frag
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - George Ogata
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ritual
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.4.1
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.4.1
30
+ description:
31
+ email:
32
+ - george.ogata@gmail.com
33
+ executables:
34
+ - frag
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - CHANGELOG
40
+ - Gemfile
41
+ - LICENSE
42
+ - README.markdown
43
+ - Rakefile
44
+ - bin/frag
45
+ - frag.gemspec
46
+ - lib/frag.rb
47
+ - lib/frag/app.rb
48
+ - lib/frag/version.rb
49
+ - test/test_helper.rb
50
+ - test/test_integration.rb
51
+ - test/unit/test_app.rb
52
+ homepage: http://github.com/oggy/frag
53
+ licenses:
54
+ - MIT
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ segments:
66
+ - 0
67
+ hash: 863246519076329498
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ segments:
75
+ - 0
76
+ hash: 863246519076329498
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 1.8.24
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Generate regions of files from the output of shell commands.
83
+ test_files:
84
+ - test/test_helper.rb
85
+ - test/test_integration.rb
86
+ - test/unit/test_app.rb