file_editor 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +57 -0
- data/Rakefile +7 -0
- data/file_editor.gemspec +15 -0
- data/lib/file_editor.rb +84 -0
- data/test/test_file_editor.rb +469 -0
- metadata +53 -0
data/README.txt
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
File Editor makes it easy to edit a file in place. Just send it a file name and a short block with some instructions, and it will perform string substitution as indicated in the block
|
2
|
+
|
3
|
+
===Using File Editor
|
4
|
+
|
5
|
+
Your program block can use File Editor in two modes, with or without an explicit receiver:
|
6
|
+
|
7
|
+
FileEditor.edit('test.txt') do |editor|
|
8
|
+
editor.regex = /java/i
|
9
|
+
editor.substitution_string = 'ruby'
|
10
|
+
editor.run
|
11
|
+
end
|
12
|
+
|
13
|
+
OR
|
14
|
+
|
15
|
+
FileEditor.edit('test.txt') do
|
16
|
+
@regex = /java/i
|
17
|
+
@substitution_string = 'ruby'
|
18
|
+
run
|
19
|
+
end
|
20
|
+
|
21
|
+
The first version does not use instance_eval internally and is therefore able to use variables in the program's local scope. The second version does use instance_eval internally.
|
22
|
+
|
23
|
+
Here are some examples, alternating between approaches:
|
24
|
+
|
25
|
+
====Standard substitution. File editor will do a line-by-line gsub on the given file
|
26
|
+
|
27
|
+
FileEditor.edit('test.txt') do |editor|
|
28
|
+
editor.regex = /java/i
|
29
|
+
editor.substitution_string = 'ruby'
|
30
|
+
editor.run
|
31
|
+
end
|
32
|
+
|
33
|
+
====Setting global to false triggers the use of sub instead of gsub (in effect replacing only the first match on each line)
|
34
|
+
|
35
|
+
FileEditor.edit('test.txt') do
|
36
|
+
@regex = /java/i
|
37
|
+
@substitution_string = 'ruby'
|
38
|
+
@global = false
|
39
|
+
run
|
40
|
+
end
|
41
|
+
|
42
|
+
====Setting keep_backup = true ensures that you'll have a backup of your original file
|
43
|
+
|
44
|
+
FileEditor.edit('test.txt') do |editor|
|
45
|
+
editor.regex = /java/i
|
46
|
+
editor.substitution_string = 'ruby'
|
47
|
+
editor.keep_backup = true
|
48
|
+
editor.run
|
49
|
+
end
|
50
|
+
|
51
|
+
====If you pass in a multiline regex, FileEditor will detect it, read the entire file into a string, and match across new lines
|
52
|
+
|
53
|
+
FileEditor.edit('test.txt') do
|
54
|
+
@regex = /ja.*?va/mi
|
55
|
+
@substitution_string = 'ruby'
|
56
|
+
run
|
57
|
+
end
|
data/Rakefile
ADDED
data/file_editor.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name="file_editor"
|
3
|
+
s.version="0.5"
|
4
|
+
s.platform=Gem::Platform::RUBY
|
5
|
+
s.date="2013-02-14"
|
6
|
+
s.summary="Edit a file in place"
|
7
|
+
s.description="File editor makes it easy to edit a file in place, with options for saving a backup"
|
8
|
+
s.author="Mark Buechler"
|
9
|
+
s.files=Dir["file_editor.gemspec", "Rakefile", "README.txt", "lib/**/*", "test/test*.rb"]
|
10
|
+
s.homepage="http://rubygems.org/sqlfinder"
|
11
|
+
s.require_paths=["lib"]
|
12
|
+
s.has_rdoc=true
|
13
|
+
s.extra_rdoc_files=["README.txt"]
|
14
|
+
s.rdoc_options=["--main", "README.txt"]
|
15
|
+
end
|
data/lib/file_editor.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
class FileEditor
|
2
|
+
|
3
|
+
attr_accessor :file_name, :regex, :substitution_string, :keep_backup, :global
|
4
|
+
|
5
|
+
def initialize(file_name)
|
6
|
+
@file_name = file_name
|
7
|
+
@keep_backup = false
|
8
|
+
@global = true #this will yield the equivalent of gsub instead of sub
|
9
|
+
end
|
10
|
+
|
11
|
+
#You can send an explicit receiver as an argument to this block
|
12
|
+
#and set variables on it (useful inside another object where you need to access its
|
13
|
+
#own methods inside the block), or simply set variables without an explicit receiver.
|
14
|
+
#Either way, the block must call the run method. See Ruby Best Practices by Gregory Brown, p. 63-64,
|
15
|
+
#for elaboration of this approach
|
16
|
+
def self.edit(file_name, &b)
|
17
|
+
editor = FileEditor.new(file_name)
|
18
|
+
b.arity == 0 ? editor.instance_eval(&b) : b.call(editor)
|
19
|
+
end
|
20
|
+
|
21
|
+
#runs file editor
|
22
|
+
def run
|
23
|
+
raise "You need to provide a regular expression to the editor" unless @regex
|
24
|
+
raise "You need to provide a substitution string" unless @substitution_string
|
25
|
+
raise "The file #{@file_name} does not exist" unless File.exist?(@file_name)
|
26
|
+
raise "The path #{@file_name} does not point to a file" unless File.file?(@file_name)
|
27
|
+
raise "You do not have permission to read #{@file_name}" unless File.readable?(@file_name)
|
28
|
+
raise "You do not have permission to edit #{@file_name}" unless File.writable?(@file_name)
|
29
|
+
begin
|
30
|
+
if @keep_backup
|
31
|
+
temp_file_name = @file_name + ".backup"
|
32
|
+
File.delete(temp_file_name) if File.exist?(temp_file_name)
|
33
|
+
else
|
34
|
+
temp_file_name = @file_name + "." + get_random_extension
|
35
|
+
end
|
36
|
+
File.rename(@file_name, temp_file_name)
|
37
|
+
read_handle = File.new(temp_file_name, "r")
|
38
|
+
write_handle = File.new(@file_name, "w")
|
39
|
+
write_to_file(read_handle, write_handle)
|
40
|
+
ensure
|
41
|
+
read_handle.close if read_handle
|
42
|
+
write_handle.close if write_handle
|
43
|
+
File.delete(temp_file_name) unless @keep_backup
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
#testable write method, using io handles as arguments
|
48
|
+
#to enable the use of String.IO in testing
|
49
|
+
def write_to_file(read_handle, write_handle)
|
50
|
+
if is_multiline(@regex.to_s)
|
51
|
+
file_string = read_handle.read #no sense doing a line-by-line multiline
|
52
|
+
if (@global)
|
53
|
+
write_handle.puts(file_string.gsub(@regex, @substitution_string))
|
54
|
+
else
|
55
|
+
write_handle.puts(file_string.sub(@regex, @substitution_string))
|
56
|
+
end
|
57
|
+
else
|
58
|
+
if (@global)
|
59
|
+
read_handle.each do |line|
|
60
|
+
write_handle.puts (line.gsub(@regex, @substitution_string))
|
61
|
+
end
|
62
|
+
else
|
63
|
+
read_handle.each do |line|
|
64
|
+
write_handle.puts (line.sub(@regex, @substitution_string))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#Determines if a string derived from regexp.to_s
|
71
|
+
#represents a regular expression with the multiline option turned on
|
72
|
+
def is_multiline(regex_string)
|
73
|
+
regex_string.match(/\?.*?m.*?-/) || regex_string.match(/\?[^-]+:/)
|
74
|
+
end
|
75
|
+
|
76
|
+
#returns a random 6-letter extension (e.g., 'kjeihl');
|
77
|
+
#this ensures that we don't inadvertantly delete a pre-existing
|
78
|
+
#backup file if we're not saving the backup
|
79
|
+
def get_random_extension
|
80
|
+
('a'..'z').to_a.shuffle.slice(0..5).join
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
@@ -0,0 +1,469 @@
|
|
1
|
+
#ruby -Ilib -I. test/test_file_editor.rb
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'file_editor'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
#NOTE: these tests are not examples of how to use FileEditor in code;
|
8
|
+
#the gem was designed with a separate method for the actual IO operations,
|
9
|
+
#precisely so it could be tested without recourse to external files,
|
10
|
+
#using StringIO
|
11
|
+
#See README.txt for actual code examples
|
12
|
+
|
13
|
+
class FileEditorTest < Test::Unit::TestCase
|
14
|
+
|
15
|
+
def setup
|
16
|
+
@original = %q[
|
17
|
+
I like java and java likes me.
|
18
|
+
Java is a great language
|
19
|
+
|
20
|
+
Vote for ja
|
21
|
+
va.
|
22
|
+
|
23
|
+
]
|
24
|
+
end
|
25
|
+
|
26
|
+
#NO OPTIONS
|
27
|
+
|
28
|
+
#defaults to global, don't ignore case
|
29
|
+
def test_no_options_without_explicit_receiver
|
30
|
+
expected = %q[
|
31
|
+
I like ruby and ruby likes me.
|
32
|
+
Java is a great language
|
33
|
+
|
34
|
+
Vote for ja
|
35
|
+
va.
|
36
|
+
|
37
|
+
]
|
38
|
+
read_handle = StringIO.new(@original)
|
39
|
+
write_handle = StringIO.new("")
|
40
|
+
FileEditor.edit("dummy.txt") do
|
41
|
+
@regex = /java/
|
42
|
+
@substitution_string = "ruby"
|
43
|
+
write_to_file(read_handle, write_handle)
|
44
|
+
end
|
45
|
+
read_handle.close()
|
46
|
+
write_handle.close()
|
47
|
+
assert_equal(expected, write_handle.string)
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_no_options_with_explicit_receiver
|
52
|
+
expected = %q[
|
53
|
+
I like ruby and ruby likes me.
|
54
|
+
Java is a great language
|
55
|
+
|
56
|
+
Vote for ja
|
57
|
+
va.
|
58
|
+
|
59
|
+
]
|
60
|
+
read_handle = StringIO.new(@original)
|
61
|
+
write_handle = StringIO.new("")
|
62
|
+
FileEditor.edit("dummy.txt") do |editor|
|
63
|
+
editor.regex = /java/
|
64
|
+
editor.substitution_string = "ruby"
|
65
|
+
editor.write_to_file(read_handle, write_handle)
|
66
|
+
end
|
67
|
+
read_handle.close()
|
68
|
+
write_handle.close()
|
69
|
+
assert_equal(expected, write_handle.string)
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
#IGNORE CASE
|
74
|
+
|
75
|
+
def test_ignore_case_without_explicit_receiver
|
76
|
+
expected = %q[
|
77
|
+
I like ruby and ruby likes me.
|
78
|
+
ruby is a great language
|
79
|
+
|
80
|
+
Vote for ja
|
81
|
+
va.
|
82
|
+
|
83
|
+
]
|
84
|
+
read_handle = StringIO.new(@original)
|
85
|
+
write_handle = StringIO.new("")
|
86
|
+
FileEditor.edit("dummy.txt") do
|
87
|
+
@regex = /java/i
|
88
|
+
@substitution_string = "ruby"
|
89
|
+
write_to_file(read_handle, write_handle)
|
90
|
+
end
|
91
|
+
read_handle.close()
|
92
|
+
write_handle.close()
|
93
|
+
assert_equal(expected, write_handle.string)
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_ignore_case_with_explicit_receiver
|
98
|
+
expected = %q[
|
99
|
+
I like ruby and ruby likes me.
|
100
|
+
ruby is a great language
|
101
|
+
|
102
|
+
Vote for ja
|
103
|
+
va.
|
104
|
+
|
105
|
+
]
|
106
|
+
read_handle = StringIO.new(@original)
|
107
|
+
write_handle = StringIO.new("")
|
108
|
+
FileEditor.edit("dummy.txt") do |editor|
|
109
|
+
editor.regex = /java/i
|
110
|
+
editor.substitution_string = "ruby"
|
111
|
+
editor.write_to_file(read_handle, write_handle)
|
112
|
+
end
|
113
|
+
read_handle.close()
|
114
|
+
write_handle.close()
|
115
|
+
assert_equal(expected, write_handle.string)
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
#IGNORE CASE AND GLOBAL SUBSTITUTION
|
120
|
+
|
121
|
+
def test_ignore_case_and_global_false_without_explicit_receiver
|
122
|
+
expected = %q[
|
123
|
+
I like ruby and java likes me.
|
124
|
+
ruby is a great language
|
125
|
+
|
126
|
+
Vote for ja
|
127
|
+
va.
|
128
|
+
|
129
|
+
]
|
130
|
+
read_handle = StringIO.new(@original)
|
131
|
+
write_handle = StringIO.new("")
|
132
|
+
FileEditor.edit("dummy.txt") do
|
133
|
+
@regex = /java/i
|
134
|
+
@substitution_string = "ruby"
|
135
|
+
@global = false
|
136
|
+
write_to_file(read_handle, write_handle)
|
137
|
+
end
|
138
|
+
read_handle.close()
|
139
|
+
write_handle.close()
|
140
|
+
assert_equal(expected, write_handle.string)
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_ignore_case_and_global_substitution_with_explicit_receiver
|
145
|
+
expected = %q[
|
146
|
+
I like ruby and java likes me.
|
147
|
+
ruby is a great language
|
148
|
+
|
149
|
+
Vote for ja
|
150
|
+
va.
|
151
|
+
|
152
|
+
]
|
153
|
+
read_handle = StringIO.new(@original)
|
154
|
+
write_handle = StringIO.new("")
|
155
|
+
FileEditor.edit("dummy.txt") do |editor|
|
156
|
+
editor.regex = /java/i
|
157
|
+
editor.substitution_string = "ruby"
|
158
|
+
editor.global = false
|
159
|
+
editor.write_to_file(read_handle, write_handle)
|
160
|
+
end
|
161
|
+
read_handle.close()
|
162
|
+
write_handle.close()
|
163
|
+
assert_equal(expected, write_handle.string)
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
#MULTILINE (can't imagine doing this with global set to false, but we test that option anyway)
|
168
|
+
|
169
|
+
def test_multiline_and_global_without_explicit_receiver
|
170
|
+
expected = %q[
|
171
|
+
I like ruby and ruby likes me.
|
172
|
+
ruby is a great language
|
173
|
+
|
174
|
+
Vote for ruby.
|
175
|
+
|
176
|
+
]
|
177
|
+
read_handle = StringIO.new(@original)
|
178
|
+
write_handle = StringIO.new("")
|
179
|
+
FileEditor.edit("dummy.txt") do
|
180
|
+
@regex = /ja.*?va/mi
|
181
|
+
@substitution_string = "ruby"
|
182
|
+
write_to_file(read_handle, write_handle)
|
183
|
+
end
|
184
|
+
read_handle.close()
|
185
|
+
write_handle.close()
|
186
|
+
assert_equal(expected, write_handle.string)
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_multiline_and_not_global_without_explicit_receiver
|
191
|
+
expected = %q[
|
192
|
+
I like ruby and java likes me.
|
193
|
+
Java is a great language
|
194
|
+
|
195
|
+
Vote for ja
|
196
|
+
va.
|
197
|
+
|
198
|
+
]
|
199
|
+
read_handle = StringIO.new(@original)
|
200
|
+
write_handle = StringIO.new("")
|
201
|
+
FileEditor.edit("dummy.txt") do
|
202
|
+
@regex = /ja.*?va/mi
|
203
|
+
@substitution_string = "ruby"
|
204
|
+
@global = false
|
205
|
+
write_to_file(read_handle, write_handle)
|
206
|
+
end
|
207
|
+
read_handle.close()
|
208
|
+
write_handle.close()
|
209
|
+
assert_equal(expected, write_handle.string)
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_multiline_global_with_explicit_receiver
|
214
|
+
expected = %q[
|
215
|
+
I like ruby and ruby likes me.
|
216
|
+
Java is a great language
|
217
|
+
|
218
|
+
Vote for ruby.
|
219
|
+
|
220
|
+
]
|
221
|
+
read_handle = StringIO.new(@original)
|
222
|
+
write_handle = StringIO.new("")
|
223
|
+
FileEditor.edit("dummy.txt") do |editor|
|
224
|
+
editor.regex = /ja.*?va/m
|
225
|
+
editor.substitution_string = "ruby"
|
226
|
+
editor.write_to_file(read_handle, write_handle)
|
227
|
+
end
|
228
|
+
read_handle.close()
|
229
|
+
write_handle.close()
|
230
|
+
assert_equal(expected, write_handle.string)
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_no_regex
|
235
|
+
non_existent_file = 'no_file.txt'
|
236
|
+
e = assert_raise(RuntimeError) do
|
237
|
+
FileEditor.edit("#{non_existent_file}") do
|
238
|
+
#@regex = /a/
|
239
|
+
@substitution_string = 'b'
|
240
|
+
run
|
241
|
+
end
|
242
|
+
end
|
243
|
+
assert_equal("You need to provide a regular expression to the editor", e.message)
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_no_substitution_string
|
247
|
+
non_existent_file = 'no_file.txt'
|
248
|
+
e = assert_raise(RuntimeError) do
|
249
|
+
FileEditor.edit("#{non_existent_file}") do
|
250
|
+
@regex = /a/
|
251
|
+
#@substitution_string = 'b'
|
252
|
+
run
|
253
|
+
end
|
254
|
+
end
|
255
|
+
assert_equal("You need to provide a substitution string", e.message)
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_file_not_found
|
259
|
+
non_existent_file = 'no_file.txt'
|
260
|
+
e = assert_raise(RuntimeError) do
|
261
|
+
FileEditor.edit("#{non_existent_file}") do
|
262
|
+
@regex = /a/
|
263
|
+
@substitution_string = 'b'
|
264
|
+
run
|
265
|
+
end
|
266
|
+
end
|
267
|
+
assert_equal("The file #{non_existent_file} does not exist", e.message)
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_not_a_file
|
271
|
+
path_to_dir = 'lib'
|
272
|
+
e = assert_raise(RuntimeError) do
|
273
|
+
FileEditor.edit("#{path_to_dir}") do
|
274
|
+
@regex = /a/
|
275
|
+
@substitution_string = 'b'
|
276
|
+
run
|
277
|
+
end
|
278
|
+
end
|
279
|
+
assert_equal("The path #{path_to_dir} does not point to a file", e.message)
|
280
|
+
end
|
281
|
+
|
282
|
+
#THE FOLLOWING TESTS DO NOT TEST THE APPLICATION;
|
283
|
+
#THEY WERE AD HOC TEST TO DETERMINE HOW MULTILINE REGEXES WORK, AMONG OTHER THINGS
|
284
|
+
|
285
|
+
def test_is_multiline
|
286
|
+
|
287
|
+
editor = FileEditor.new("dummy.txt")
|
288
|
+
|
289
|
+
#these should not match
|
290
|
+
ignore = /anything/i.to_s #(?i-mx:anything)
|
291
|
+
extended = /anything/x.to_s #(?x-mi:anything)
|
292
|
+
ignore_plus_extended = /anything/ix.to_s #(?ix-m:anything)
|
293
|
+
|
294
|
+
not_multi = [ignore, extended, ignore_plus_extended]
|
295
|
+
not_multi.each do |r|
|
296
|
+
assert(!editor.is_multiline(r))
|
297
|
+
end
|
298
|
+
|
299
|
+
#these should match
|
300
|
+
multi = /anything/m.to_s #(?m-ix:anything)
|
301
|
+
multi_plus_ignore = /anything/mi.to_s #(?mi-x:anything)
|
302
|
+
multi_plus_extended = /anything/mx.to_s #(?mx-i:anything)
|
303
|
+
|
304
|
+
#special case that should match
|
305
|
+
all = /anything/mix.to_s #(?mix:anything)
|
306
|
+
|
307
|
+
is_multi = [multi, multi_plus_ignore, multi_plus_extended, all]
|
308
|
+
is_multi.each do |r|
|
309
|
+
assert(editor.is_multiline(r))
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
#second test is for special case of all: if there's no hyphen, the we know all options are included
|
315
|
+
def is_multiline(regex_string)
|
316
|
+
regex_string.match(/\?.*?m.*?-/) || regex_string.match(/\?[^-]+:/)
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_regex_object_and_modifiers
|
320
|
+
r = Regexp.new("ell", Regexp::IGNORECASE)
|
321
|
+
#puts "ignore case: #{r.to_s}"
|
322
|
+
assert_equal(1, r.options)
|
323
|
+
|
324
|
+
r = Regexp.new("ell", Regexp::EXTENDED)
|
325
|
+
#puts "extended: #{r.to_s}"
|
326
|
+
assert_equal(2, r.options)
|
327
|
+
|
328
|
+
r = Regexp.new("ell", Regexp::MULTILINE)
|
329
|
+
#puts "MULTILINE: #{r.to_s}"
|
330
|
+
assert_equal(4, r.options)
|
331
|
+
|
332
|
+
r = Regexp.new("ell", (Regexp::EXTENDED | Regexp::IGNORECASE))
|
333
|
+
#puts "EXTENDED AND IGNORE: #{r.to_s}"
|
334
|
+
assert_equal(3, r.options)
|
335
|
+
|
336
|
+
r = Regexp.new("ell", (Regexp::MULTILINE | Regexp::IGNORECASE))
|
337
|
+
#puts "MULTILINE AND IGNORE: #{r.to_s}"
|
338
|
+
assert_equal(5, r.options)
|
339
|
+
|
340
|
+
r = Regexp.new("ell", (Regexp::MULTILINE | Regexp::EXTENDED))
|
341
|
+
#puts "MULTILINE AND EXTENDED: #{r.to_s}"
|
342
|
+
assert_equal(6, r.options)
|
343
|
+
|
344
|
+
r = Regexp.new("ell", (Regexp::EXTENDED | Regexp::IGNORECASE | Regexp::MULTILINE))
|
345
|
+
#puts "all three: #{r.to_s}"
|
346
|
+
assert_equal(7, r.options)
|
347
|
+
|
348
|
+
#puts
|
349
|
+
|
350
|
+
ops_orred = [Regexp::IGNORECASE, Regexp::EXTENDED].reduce{|a,b| a|b }
|
351
|
+
assert_equal(3, ops_orred) #0001 | 0010 => 0011
|
352
|
+
|
353
|
+
ops_orred = [Regexp::IGNORECASE, Regexp::MULTILINE].reduce{|a,b| a|b }
|
354
|
+
assert_equal(5, ops_orred) #0001 | 0100 => 0101
|
355
|
+
|
356
|
+
ops_orred = [Regexp::IGNORECASE, Regexp::EXTENDED, Regexp::MULTILINE].reduce{|a,b| a|b }
|
357
|
+
assert_equal(7, ops_orred) #0001 | 0010 | 0100 => 0111
|
358
|
+
end
|
359
|
+
|
360
|
+
def test_multiline
|
361
|
+
#note we have to use non-greedy quantifiers (probably always with multiline, or results could be way unexpected)
|
362
|
+
multiline_string = %q[
|
363
|
+
You are fine.
|
364
|
+
I like you.
|
365
|
+
Y
|
366
|
+
ou are weird.
|
367
|
+
]
|
368
|
+
expected_multiline_string = %q[
|
369
|
+
yous are fine.
|
370
|
+
I like yous.
|
371
|
+
yous are weird.
|
372
|
+
]
|
373
|
+
edited_multiline_string = multiline_string.gsub(/y.*?ou/im, 'yous');
|
374
|
+
assert_equal(expected_multiline_string, edited_multiline_string)
|
375
|
+
|
376
|
+
m = "you".match (/y.*ou/)
|
377
|
+
assert m
|
378
|
+
m = "you".match (/y.*ou/m)
|
379
|
+
assert m
|
380
|
+
m = "y\nou".match (/y.*ou/m)
|
381
|
+
assert m
|
382
|
+
s = %q[
|
383
|
+
y
|
384
|
+
ou
|
385
|
+
]
|
386
|
+
m = s.match (/y.*ou/m)
|
387
|
+
assert m
|
388
|
+
|
389
|
+
result = "you".gsub(/y.*ou/m, 'Z')
|
390
|
+
assert_equal('Z', result)
|
391
|
+
|
392
|
+
#shows one of the tricks that greedy interpretations will play on multiline searches
|
393
|
+
test = %q[
|
394
|
+
you
|
395
|
+
y
|
396
|
+
ou
|
397
|
+
]
|
398
|
+
expected =
|
399
|
+
%q[
|
400
|
+
Z
|
401
|
+
]
|
402
|
+
result = test.gsub(/y.*ou/m, 'Z')
|
403
|
+
assert_equal(expected, result)
|
404
|
+
#note that we end up with one replacement instead of two,
|
405
|
+
#because the greedy interpretation matches the first y and then the last ou
|
406
|
+
|
407
|
+
#here's what we probably intended
|
408
|
+
test = %q[
|
409
|
+
you
|
410
|
+
y
|
411
|
+
ou
|
412
|
+
]
|
413
|
+
expected =
|
414
|
+
%q[
|
415
|
+
Z
|
416
|
+
Z
|
417
|
+
]
|
418
|
+
result = test.gsub(/y.*?ou/m, 'Z')
|
419
|
+
assert_equal(expected, result)
|
420
|
+
|
421
|
+
|
422
|
+
end
|
423
|
+
|
424
|
+
end
|
425
|
+
|
426
|
+
|
427
|
+
=begin
|
428
|
+
|
429
|
+
#TEMP
|
430
|
+
def test_ell
|
431
|
+
FileEditor.new("test.txt") do |editor|
|
432
|
+
editor.regex = /ell/i
|
433
|
+
editor.substitution_string = "ojj"
|
434
|
+
editor.keep_backup = false
|
435
|
+
editor.run
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
def test_ojj
|
440
|
+
FileEditor.new("test.txt") do |editor|
|
441
|
+
editor.regex = /ojj/i
|
442
|
+
editor.substitution_string = "ell"
|
443
|
+
editor.keep_backup = false
|
444
|
+
editor.run
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
#this feels like proper course going forward,
|
449
|
+
#pending the problem with including it in another class
|
450
|
+
def test_ell_with_instance_eval
|
451
|
+
FileEditor.edit("test.txt") do
|
452
|
+
@regex = /ell/i
|
453
|
+
@substitution_string = "ojj"
|
454
|
+
@keep_backup = false
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
|
459
|
+
def test_regex
|
460
|
+
s = "heLlo"
|
461
|
+
r = Regexp.new("ell", Regexp::IGNORECASE)
|
462
|
+
#r = Regexp.new(/ell/ix)
|
463
|
+
puts "r.to_s: #{r.to_s}"
|
464
|
+
puts "r.options: #{r.options}"
|
465
|
+
result = s.sub(r, "ojj")
|
466
|
+
puts "result: #{result}"
|
467
|
+
end
|
468
|
+
|
469
|
+
=end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: file_editor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.5'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mark Buechler
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-14 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: File editor makes it easy to edit a file in place, with options for saving
|
15
|
+
a backup
|
16
|
+
email:
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files:
|
20
|
+
- README.txt
|
21
|
+
files:
|
22
|
+
- file_editor.gemspec
|
23
|
+
- Rakefile
|
24
|
+
- README.txt
|
25
|
+
- lib/file_editor.rb
|
26
|
+
- test/test_file_editor.rb
|
27
|
+
homepage: http://rubygems.org/sqlfinder
|
28
|
+
licenses: []
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options:
|
31
|
+
- --main
|
32
|
+
- README.txt
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 1.8.24
|
50
|
+
signing_key:
|
51
|
+
specification_version: 3
|
52
|
+
summary: Edit a file in place
|
53
|
+
test_files: []
|