file_editor 0.5
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.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: []
|