frag 0.0.1

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/.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