rename_radically 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/rnr +193 -0
- data/lib/rename_radically.rb +497 -0
- metadata +67 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3230e483f124f396fe6faa8c4e6befb389de15f6
|
4
|
+
data.tar.gz: 88bd386e30263a94974c4fe50b7c57bdab6fcf66
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e08b91e8aa33451865b0ae1f47bea80dc56a2d8815b1ca8c54f7744acdd74a995c6844e1704d5f519439aff46904e9ea285ed52177d3ef1ee51269c821febbdd
|
7
|
+
data.tar.gz: 51bbd091e3d917247ebbb0a38fe3e4c0f8df8fe954ae77b918f5790d1bba8aeb8abcd2144aee16d46459561af53b95cdef4a6ece320ab88f46c127fbc72aeac8
|
data/bin/rnr
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rename_radically"
|
4
|
+
|
5
|
+
# Help reference function:
|
6
|
+
def help_reference()
|
7
|
+
lines = Array.new
|
8
|
+
name = "#{File.basename $0}"
|
9
|
+
|
10
|
+
# Help reference lines:
|
11
|
+
# Header:
|
12
|
+
lines.push "\e[33mReNameRadically: a simple file renamer who mostly " +
|
13
|
+
"hates spaces.\e[0m"
|
14
|
+
lines.push "\e[33mUsage:\e[0m"
|
15
|
+
# Compact mode:
|
16
|
+
lines.push "\e[34m#{name} <files>\e[0m: recursively renames the given " +
|
17
|
+
"files and folders to a CamelCase format."
|
18
|
+
# Widen mode:
|
19
|
+
lines.push "\e[34m#{name} -w/--widen <files>\e[0m: recursively renames " +
|
20
|
+
"the given files and folders adding spaces when needed."
|
21
|
+
# Regex mode:
|
22
|
+
lines.push "\e[34m#{name} -r/--regex <regex> <substitute> <files>\e[0m: " +
|
23
|
+
"recursively renames the given files and folders replacing " +
|
24
|
+
"any match of the given regex with the given substitute."
|
25
|
+
# Renaming script mode:
|
26
|
+
lines.push "\e[34m#{name} -s/--script <files>\e[0m: creates a bash script " +
|
27
|
+
"to quickly rename the given files and folders, for whenever " +
|
28
|
+
"the other modalities cannot yield the desired result."
|
29
|
+
# Help switch:
|
30
|
+
lines.push "\e[34m#{name} -h\e[0m: shows this help reference."
|
31
|
+
# Footer:
|
32
|
+
lines.push ""
|
33
|
+
lines.push "\e[33mNOTE\e[0m: if no files are specified to a command, it " +
|
34
|
+
"will process every file in the current folder."
|
35
|
+
lines.push ""
|
36
|
+
lines.push "See the configuration file located in \e[34m" +
|
37
|
+
"#{ENV['HOME']}/.rnr\e[0m to add your personal tweaks."
|
38
|
+
|
39
|
+
# Max 80 characters per line, but preserving words integrity! :3
|
40
|
+
lines.each do |entry|
|
41
|
+
# 80 characters line container:
|
42
|
+
composed = ""
|
43
|
+
|
44
|
+
# Split each message string on spaces:
|
45
|
+
entry.split( " " ).each do |word|
|
46
|
+
# If the current composed message plus the current word exceeds 80 is
|
47
|
+
# within 80 characters, keep composing:
|
48
|
+
if 80 >= "#{composed + " " + word}".length then
|
49
|
+
# Add a space when needed:
|
50
|
+
unless composed.empty? then
|
51
|
+
composed += " "
|
52
|
+
end
|
53
|
+
composed += "#{word}"
|
54
|
+
|
55
|
+
# If the current word would not fit in an 80 characters line, print the
|
56
|
+
# current composed message, and start composing the next one with an
|
57
|
+
# indentation of 2 spaces.
|
58
|
+
else
|
59
|
+
puts composed
|
60
|
+
composed = " #{word}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Finally, print the last line:
|
65
|
+
puts composed
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Here it is! The main protagonist! The Renamer object!
|
70
|
+
rnr = ReNameRadically.new "#{ENV['HOME']}/.rnr"
|
71
|
+
|
72
|
+
# Help reference:
|
73
|
+
if [ "-h", "--help" ].include? ARGV[0] and 1 == ARGV.size then
|
74
|
+
help_reference
|
75
|
+
exit 0
|
76
|
+
|
77
|
+
# Renaming script:
|
78
|
+
elsif [ "-s", "--script" ].include? ARGV[0] then
|
79
|
+
tmp = Array.new ARGV
|
80
|
+
tmp.shift
|
81
|
+
tmp.uniq!
|
82
|
+
|
83
|
+
# No other parameters: run this for every file in the current directory
|
84
|
+
# (except . and ..):
|
85
|
+
if tmp.empty? then
|
86
|
+
tmp = Dir.entries "."
|
87
|
+
|
88
|
+
# Always remove "." and "..".
|
89
|
+
tmp.delete "."
|
90
|
+
tmp.delete ".."
|
91
|
+
|
92
|
+
# This script is sort of harmless, so there is not going to be a check
|
93
|
+
# for user consent.
|
94
|
+
end
|
95
|
+
|
96
|
+
rnr.createScript *tmp
|
97
|
+
|
98
|
+
# Regex:
|
99
|
+
elsif [ "-r", "--regex" ].include? ARGV[0] then
|
100
|
+
tmp = Array.new ARGV
|
101
|
+
tmp.shift
|
102
|
+
regex = Regexp.new "#{tmp.shift}"
|
103
|
+
substitute_with = "#{tmp.shift}".gsub! "\\", "\\\\"
|
104
|
+
tmp.uniq!
|
105
|
+
|
106
|
+
# 3 Parameters: everything in the current folder.
|
107
|
+
if 3 == ARGV.size then
|
108
|
+
tmp = Dir.entries "."
|
109
|
+
|
110
|
+
# Always remove "." and "..".
|
111
|
+
tmp.delete "."
|
112
|
+
tmp.delete ".."
|
113
|
+
|
114
|
+
# This could be quite dangerous if erroneously invoked (eg. in the user's
|
115
|
+
# home directory). Better use a confirmation prompt:
|
116
|
+
print "Do you really want to rename every file and folder in the " +
|
117
|
+
"current directory (#{Dir.pwd})? [y/N] "
|
118
|
+
answer = STDIN.gets.chomp
|
119
|
+
|
120
|
+
# Abort from anything different than y/Y:
|
121
|
+
unless "Y" == Unicode::capitalize( answer ) then
|
122
|
+
puts "Operation aborted."
|
123
|
+
exit 0
|
124
|
+
end
|
125
|
+
|
126
|
+
# User is a moron.
|
127
|
+
elsif 3 > ARGV.size then
|
128
|
+
puts "Must specify at one regex and one substitute for this modality."
|
129
|
+
exit -1
|
130
|
+
end
|
131
|
+
|
132
|
+
rnr.regexRename *tmp, regex, substitute_with
|
133
|
+
|
134
|
+
# Widen:
|
135
|
+
elsif [ "-w", "--widen" ].include? ARGV[0] then
|
136
|
+
tmp = Array.new ARGV
|
137
|
+
tmp.shift
|
138
|
+
tmp.uniq!
|
139
|
+
|
140
|
+
# No other parameters: run this for every file in the current directory
|
141
|
+
# (except . and ..):
|
142
|
+
if tmp.empty? then
|
143
|
+
tmp = Dir.entries "."
|
144
|
+
|
145
|
+
# Always remove "." and "..".
|
146
|
+
tmp.delete "."
|
147
|
+
tmp.delete ".."
|
148
|
+
|
149
|
+
# This could be quite dangerous if erroneously invoked (eg. in the user's
|
150
|
+
# home directory). Better use a confirmation prompt:
|
151
|
+
print "Do you really want to rename every file and folder in the " +
|
152
|
+
"current directory (#{Dir.pwd})? [y/N] "
|
153
|
+
answer = STDIN.gets.chomp
|
154
|
+
|
155
|
+
# # Abort from anything different than y/Y:
|
156
|
+
unless "Y" == Unicode::capitalize( answer ) then
|
157
|
+
puts "Operation aborted."
|
158
|
+
exit 0
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
rnr.widen *tmp
|
163
|
+
|
164
|
+
# Compact:
|
165
|
+
else
|
166
|
+
tmp = Array.new ARGV
|
167
|
+
tmp.uniq!
|
168
|
+
|
169
|
+
# No other parameters: run this for every file in the current directory
|
170
|
+
# (except . and ..):
|
171
|
+
if tmp.empty? then
|
172
|
+
tmp = Dir.entries "."
|
173
|
+
|
174
|
+
# Always remove "." and "..".
|
175
|
+
tmp.delete "."
|
176
|
+
tmp.delete ".."
|
177
|
+
|
178
|
+
# This could be quite dangerous if erroneously invoked (eg. in the user's
|
179
|
+
# home directory). Better use a confirmation prompt:
|
180
|
+
print "Do you really want to rename every file and folder in the " +
|
181
|
+
"current directory (#{Dir.pwd})? [y/N] "
|
182
|
+
answer = STDIN.gets.chomp
|
183
|
+
|
184
|
+
# Abort from anything different than y/Y:
|
185
|
+
unless "Y" == Unicode::capitalize( answer ) then
|
186
|
+
puts "Operation aborted."
|
187
|
+
exit 0
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
rnr.compact *tmp
|
192
|
+
end
|
193
|
+
|
@@ -0,0 +1,497 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "unicode"
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
=begin
|
6
|
+
This is the ReNameRadically class.
|
7
|
+
|
8
|
+
It's supposed to help renaming files in different ways:
|
9
|
+
compact:: renames a file to a CamelCase format, removing spaces and using
|
10
|
+
capital letters to separate words. Other capital letters areconverted
|
11
|
+
to lower case.
|
12
|
+
widen:: renames a file adding spaces to separate words in CamelCase format,
|
13
|
+
and, depending on the case, before or after punctation.
|
14
|
+
regex:: replaces all occurrences of the given regex with the given
|
15
|
+
substitute string.
|
16
|
+
renaming script:: creates a bash script to rename files, for whenever the
|
17
|
+
other modalities cannot yield the desired result.
|
18
|
+
=end
|
19
|
+
|
20
|
+
class ReNameRadically
|
21
|
+
@config # Location of the user config file.
|
22
|
+
@as_spaces # Array of characters to be treated as spaces
|
23
|
+
@delimiters # Array of characters to used as word delimiters
|
24
|
+
@ex_after # Array of exceptions not to put a space after in widen mode.
|
25
|
+
@ex_before # Array of exceptions not to put a space before in widen mode.
|
26
|
+
@script # Script name for script renaming mode.
|
27
|
+
|
28
|
+
# Constructor: takes the path of the config file as a parameter, and ensures
|
29
|
+
# it contains the right info. If not, it gets created anew.
|
30
|
+
def initialize( config_file )
|
31
|
+
@config = Pathname.new config_file
|
32
|
+
|
33
|
+
# Attempt to read from the config file:
|
34
|
+
begin
|
35
|
+
loaded_config = YAML.load_file @config
|
36
|
+
@as_spaces = loaded_config["as_spaces"]
|
37
|
+
@delimiters = loaded_config["delimiters"]
|
38
|
+
@ex_after = loaded_config["ex_after"]
|
39
|
+
@ex_before = loaded_config["ex_before"]
|
40
|
+
@script = loaded_config["script"]
|
41
|
+
|
42
|
+
# Fastest way to check for data consistency:
|
43
|
+
@as_spaces[0]
|
44
|
+
@delimiters[0]
|
45
|
+
@ex_after[0]
|
46
|
+
@ex_before[0]
|
47
|
+
@script = loaded_config["script"][0]
|
48
|
+
|
49
|
+
# If it fails, create a new default config file:
|
50
|
+
rescue
|
51
|
+
# This is the best way I can think of to hardcode the default config file
|
52
|
+
# without breaking the formatting.
|
53
|
+
config = Array.new
|
54
|
+
config.push "# Characters treated as spaces, which get removed while " +
|
55
|
+
"renaming a file in"
|
56
|
+
config.push "# non-wide mode:"
|
57
|
+
config.push "as_spaces:"
|
58
|
+
config.push "- \"_\""
|
59
|
+
config.push " "
|
60
|
+
config.push "# Characters after which a word should be capitalized in" +
|
61
|
+
" non-wide mode:"
|
62
|
+
config.push "delimiters:"
|
63
|
+
config.push "- \"-\""
|
64
|
+
config.push "- \"+\""
|
65
|
+
config.push "- \"(\""
|
66
|
+
config.push "- \")\""
|
67
|
+
config.push "- \"[\""
|
68
|
+
config.push "- \"]\""
|
69
|
+
config.push "- \"{\""
|
70
|
+
config.push "- \"}\""
|
71
|
+
config.push "- \"'\""
|
72
|
+
config.push "- \"&\""
|
73
|
+
config.push "- \".\""
|
74
|
+
config.push "- \"!\""
|
75
|
+
config.push "- \"?\""
|
76
|
+
config.push " "
|
77
|
+
config.push "# Characters after which must not be added a space in " +
|
78
|
+
"wide mode:"
|
79
|
+
config.push "ex_after:"
|
80
|
+
config.push "- \"'\""
|
81
|
+
config.push "- \"(\""
|
82
|
+
config.push "- \"-\""
|
83
|
+
config.push "- \"<\""
|
84
|
+
config.push "- \"[\""
|
85
|
+
config.push "- \"{\""
|
86
|
+
config.push "- \".\""
|
87
|
+
config.push " "
|
88
|
+
config.push "# Characters before which must not be added a space in " +
|
89
|
+
"wide mode:"
|
90
|
+
config.push "ex_before:"
|
91
|
+
config.push "- \".\""
|
92
|
+
config.push "- \",\""
|
93
|
+
config.push "- \"?\""
|
94
|
+
config.push "- \"!\""
|
95
|
+
config.push "- \"'\""
|
96
|
+
config.push "- \")\""
|
97
|
+
config.push "- \"]\""
|
98
|
+
config.push "- \"}\""
|
99
|
+
config.push "- \">\""
|
100
|
+
config.push "- \"-\""
|
101
|
+
config.push "- \"_\""
|
102
|
+
config.push " "
|
103
|
+
config.push "# Name of the script file created by renaming script mode:"
|
104
|
+
config.push "script:"
|
105
|
+
config.push "- \"REN.bash\""
|
106
|
+
config.push " "
|
107
|
+
|
108
|
+
config = config.join "\n"
|
109
|
+
|
110
|
+
loaded_config = YAML.load config
|
111
|
+
|
112
|
+
# Attempt to create the file:
|
113
|
+
begin
|
114
|
+
File.open @config, "w" do |f|
|
115
|
+
f.puts config
|
116
|
+
end
|
117
|
+
puts "Created a new config file: #{@config}"
|
118
|
+
|
119
|
+
# ...And be sure that everything went right:
|
120
|
+
loaded_config = YAML.load_file @config
|
121
|
+
|
122
|
+
# Something went horribly wrong: maybe there's no home folder, or its
|
123
|
+
# permissions are all wrong... So, screw the config file and use default
|
124
|
+
# values for this ride.
|
125
|
+
rescue
|
126
|
+
puts "WARNING: could not read/write file #{@config}, you might want" +
|
127
|
+
" to check out why."
|
128
|
+
end
|
129
|
+
|
130
|
+
# Finally, valorize these:
|
131
|
+
@as_spaces = loaded_config["as_spaces"]
|
132
|
+
@delimiters = loaded_config["delimiters"]
|
133
|
+
@ex_after = loaded_config["ex_after"]
|
134
|
+
@ex_before = loaded_config["ex_before"]
|
135
|
+
@script = loaded_config["script"][0]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Public method: checks if the given files exist, then prints a list of the
|
140
|
+
# not found ones and returns an array containing the Pathname objects of the
|
141
|
+
# found ones.
|
142
|
+
public
|
143
|
+
def checkFiles( *files )
|
144
|
+
# This will contain the not found files:
|
145
|
+
not_found = Array.new
|
146
|
+
|
147
|
+
# This will contain files we do not have the permissions to move:
|
148
|
+
no_permissions = Array.new
|
149
|
+
|
150
|
+
# This will contain the valid files:
|
151
|
+
ok = Array.new
|
152
|
+
|
153
|
+
# Now, check each file:
|
154
|
+
files.each do |entry|
|
155
|
+
tmp = Pathname.new( entry )
|
156
|
+
|
157
|
+
# The file exists!
|
158
|
+
if tmp.exist? and "." != tmp.to_s and ".." != tmp.to_s then
|
159
|
+
|
160
|
+
# And we do have the permissions to move it!
|
161
|
+
if tmp.dirname.writable? then
|
162
|
+
ok.push tmp
|
163
|
+
|
164
|
+
# Apparently, we cannot rename it:
|
165
|
+
else
|
166
|
+
no_permissions.push tmp
|
167
|
+
end
|
168
|
+
|
169
|
+
# The file has not been found:
|
170
|
+
else
|
171
|
+
not_found.push entry
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Print a list of not found files:
|
176
|
+
not_found.each_with_index do |entry, idx|
|
177
|
+
if 0 == idx then
|
178
|
+
puts "The following files will be ignored (not found or invalid):"
|
179
|
+
end
|
180
|
+
|
181
|
+
puts "- #{entry}"
|
182
|
+
end
|
183
|
+
|
184
|
+
# Print a list of files we do not have permission to rename:
|
185
|
+
no_permissions.each_with_index do |entry, idx|
|
186
|
+
if 0 == idx then
|
187
|
+
puts "You lack the permissions to move the following files:"
|
188
|
+
end
|
189
|
+
|
190
|
+
puts "- #{entry}"
|
191
|
+
end
|
192
|
+
|
193
|
+
# Return the arraid containing the valid ones:
|
194
|
+
return ok
|
195
|
+
end
|
196
|
+
|
197
|
+
# Public method: will smartly rename a file (Pathname format) to
|
198
|
+
# new_name, preserving the original path and extension. If another file with
|
199
|
+
# the destination name already exists, the new one will have a number
|
200
|
+
# appended to its name. Returns the new name of the file.
|
201
|
+
public
|
202
|
+
def smartRename( file, new_name )
|
203
|
+
# Be sure to remove characters which are not allowed for file names:
|
204
|
+
new_name.gsub! "/" ""
|
205
|
+
new_name.gsub! "\0" ""
|
206
|
+
|
207
|
+
# Also, the max name length is 255, including the extension:
|
208
|
+
new_name.scan( /.{#{255 - "#{file.extname}".length}}/ )[0]
|
209
|
+
|
210
|
+
# Hopefully, this is already the name that will be used:
|
211
|
+
destination = Pathname.new "#{file.dirname}/#{new_name}#{file.extname}"
|
212
|
+
|
213
|
+
# Rename the file only if the destination is different than the origin and
|
214
|
+
# if the file name is not empty.
|
215
|
+
unless file.basename == destination.basename or "#{new_name}".empty? or
|
216
|
+
"." == new_name or ".." == new_name then
|
217
|
+
# Index variable for worst-case scenario:
|
218
|
+
index = 0
|
219
|
+
|
220
|
+
# To be honest... If this goes beyond 2, the user is really just messing
|
221
|
+
# with us.
|
222
|
+
while destination.exist? do
|
223
|
+
index += 1
|
224
|
+
destination = Pathname.new "#{file.dirname}/#{new_name}-#{index}" +
|
225
|
+
"#{file.extname}"
|
226
|
+
end
|
227
|
+
|
228
|
+
# Rename away!
|
229
|
+
file.rename destination
|
230
|
+
end
|
231
|
+
|
232
|
+
# In any case, return the destination (Pathname format):
|
233
|
+
return destination
|
234
|
+
end
|
235
|
+
|
236
|
+
# Private method, called through compact: renames a single file to a compact
|
237
|
+
# CamelCase version. This contains the main logic of renaming files in such
|
238
|
+
# way. Returns the new name of the renamed file.
|
239
|
+
private
|
240
|
+
def compactFile( file )
|
241
|
+
# Get the file's basename, without its extension:
|
242
|
+
file_name = file.basename( file.extname ).to_s
|
243
|
+
|
244
|
+
# Replace the characters contained in the "as_spaces" field in the config
|
245
|
+
# file with spaces:
|
246
|
+
@as_spaces.each do |rm|
|
247
|
+
file_name[0].gsub! rm, " "
|
248
|
+
end
|
249
|
+
|
250
|
+
# Add a space after each delimiter:
|
251
|
+
@delimiters.each do |delimiter|
|
252
|
+
file_name.gsub! delimiter, "#{delimiter} "
|
253
|
+
end
|
254
|
+
|
255
|
+
# Now split it into parts that should be capitalized!
|
256
|
+
file_name = file_name.split " "
|
257
|
+
|
258
|
+
# And actually capitalize them:
|
259
|
+
file_name.each_with_index do |entry, idx|
|
260
|
+
file_name[idx] = Unicode::capitalize entry
|
261
|
+
end
|
262
|
+
|
263
|
+
# Rename the file and return its new name:
|
264
|
+
return smartRename file, file_name.join
|
265
|
+
end
|
266
|
+
|
267
|
+
# Private method, called through compact: recursively renames a folder and
|
268
|
+
# its content to a compact CamelCase version.
|
269
|
+
private
|
270
|
+
def compactFolder( folder )
|
271
|
+
# Rename the folder:
|
272
|
+
new_folder_name = compactFile folder
|
273
|
+
|
274
|
+
# Then rename everything it contains, recursively:
|
275
|
+
new_folder_name.entries.each do |entry|
|
276
|
+
# Ignore "." and "..", though.
|
277
|
+
if "." != entry.to_s and ".." != entry.to_s then
|
278
|
+
compact Pathname.new "#{new_folder_name.realpath}/#{entry}"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# Public method: checks if the given files exist via checkFiles, then calls
|
284
|
+
# compactFile and compactFolder to process respectedly the given files and
|
285
|
+
# folders.
|
286
|
+
public
|
287
|
+
def compact( *files )
|
288
|
+
# First off: check if the files exist.
|
289
|
+
existing = checkFiles *files
|
290
|
+
|
291
|
+
# Behave differently for files and folders:
|
292
|
+
existing.each do |entry|
|
293
|
+
# Folders:
|
294
|
+
if entry.directory? then
|
295
|
+
compactFolder entry
|
296
|
+
|
297
|
+
# Files:
|
298
|
+
else
|
299
|
+
compactFile entry
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# Private method, called through widen: renames a single file to a wide
|
305
|
+
# version. This contains the main logic of renaming files in such way.
|
306
|
+
# Returns the new name of the renamed file.
|
307
|
+
private
|
308
|
+
def widenFile( file )
|
309
|
+
# Put the file's basename into an array, without its extension:
|
310
|
+
file_name = file.basename( file.extname ).to_s
|
311
|
+
|
312
|
+
# This will be the file's new name:
|
313
|
+
new_file_name = ""
|
314
|
+
|
315
|
+
# Read the file name character by character:
|
316
|
+
file_name.chars.each do |c|
|
317
|
+
# To avoid useless spaces, these rules must be respected to add a space
|
318
|
+
# before the current character:
|
319
|
+
# 1. c must not be a space.
|
320
|
+
# 2. new_file_name must not be empty
|
321
|
+
# 3. new_file_name[-1] must not be a space
|
322
|
+
# 4. c must not be included in @ex_before
|
323
|
+
# 5. new_file_name[-1] must not be included in @ex_after
|
324
|
+
# 6. c and new_file_name[-1] must not both be numbers
|
325
|
+
# 6. c must be equal to Unicode::capitalize c
|
326
|
+
if c != " " and false == new_file_name.empty? and
|
327
|
+
" " != new_file_name[-1] and false == ( @ex_before.include? c ) and
|
328
|
+
false == ( @ex_after.include? new_file_name[-1] ) and
|
329
|
+
( nil == ( c =~ /[0-9]/ ) or
|
330
|
+
nil == ( new_file_name[-1] =~ /[0-9]/ )
|
331
|
+
) and c == Unicode.capitalize( c ) then
|
332
|
+
new_file_name += " "
|
333
|
+
end
|
334
|
+
|
335
|
+
# Always add the old character:
|
336
|
+
new_file_name += c
|
337
|
+
end
|
338
|
+
|
339
|
+
# Rename the new file and return its new name:
|
340
|
+
return smartRename file, new_file_name
|
341
|
+
end
|
342
|
+
|
343
|
+
# Private method, called through widen: recursively renames a folder and
|
344
|
+
# its content to a wide name.
|
345
|
+
private
|
346
|
+
def widenFolder( folder )
|
347
|
+
# Rename the folder:
|
348
|
+
new_folder_name = widenFile folder
|
349
|
+
|
350
|
+
# Then rename everything it contains, recursively:
|
351
|
+
new_folder_name.entries.each do |entry|
|
352
|
+
# Ignore "." and "..", though.
|
353
|
+
if "." != entry.to_s and ".." != entry.to_s then
|
354
|
+
widen Pathname.new "#{new_folder_name.realpath}/#{entry}"
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Public method: checks if the given files exist via checkFiles, then calls
|
360
|
+
# widenFile and widenFolder to process respectedly the given files and
|
361
|
+
# folders.
|
362
|
+
public
|
363
|
+
def widen( *files )
|
364
|
+
# First off: check if the files exist.
|
365
|
+
existing = checkFiles *files
|
366
|
+
|
367
|
+
# Behave differently for files and folders:
|
368
|
+
existing.each do |entry|
|
369
|
+
# Folders:
|
370
|
+
if entry.directory? then
|
371
|
+
widenFolder entry
|
372
|
+
|
373
|
+
# Files:
|
374
|
+
else
|
375
|
+
widenFile entry
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Private method, called through regexRename: renames a single file using a
|
381
|
+
# given regex. This contains the main logic of renaming files in such way.
|
382
|
+
# Returns the new name of the renamed file.
|
383
|
+
private
|
384
|
+
def regexRenameFile( file, regex, with )
|
385
|
+
# Get the file's basename, without its extension:
|
386
|
+
file_name = file.basename( file.extname ).to_s
|
387
|
+
|
388
|
+
# Apply the regex!
|
389
|
+
file_name.gsub! regex, "#{with}"
|
390
|
+
|
391
|
+
# Rename the file and return its new name:
|
392
|
+
return smartRename file, file_name
|
393
|
+
end
|
394
|
+
|
395
|
+
# Private method, called through regexRename: recursively renames a folder
|
396
|
+
# and its content using a given regex.
|
397
|
+
private
|
398
|
+
def regexRenameFolder( folder, regex, with )
|
399
|
+
# Rename the folder:
|
400
|
+
new_folder_name = regexRenameFile folder, regex, "#{with}"
|
401
|
+
|
402
|
+
# Then rename everything it contains, recursively:
|
403
|
+
new_folder_name.entries.each do |entry|
|
404
|
+
# Ignore "." and "..", though.
|
405
|
+
if "." != entry.to_s and ".." != entry.to_s then
|
406
|
+
regexRename Pathname.new( "#{new_folder_name.realpath}/#{entry}" ),
|
407
|
+
regex, "#{with}"
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
# Public method: checks if the given files exist via checkFiles, then calls
|
413
|
+
# regexRenameFile and regexRenameFolder to process respectedly the given
|
414
|
+
# files and folders.
|
415
|
+
public
|
416
|
+
def regexRename( *files, regex, with )
|
417
|
+
# First off: check if the files exist.
|
418
|
+
existing = checkFiles *files
|
419
|
+
|
420
|
+
# Behave differently for files and folders:
|
421
|
+
existing.each do |entry|
|
422
|
+
# Folders:
|
423
|
+
if entry.directory? then
|
424
|
+
regexRenameFolder entry, regex, "#{with}"
|
425
|
+
|
426
|
+
# Files:
|
427
|
+
else
|
428
|
+
regexRenameFile entry, regex, "#{with}"
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
# Public method: checks if it's possible to create a file in the current
|
434
|
+
# directory. If successful, then checks if the given files exist via
|
435
|
+
# checkFiles, then creates a bash script to easily rename them.
|
436
|
+
public
|
437
|
+
def createScript( *files )
|
438
|
+
# Pointless to go any further if the current directory is not writable:
|
439
|
+
unless Pathname.new( "." ).dirname.writable? then
|
440
|
+
puts "You do not have the permissions to create a file in this folder."
|
441
|
+
exit -1
|
442
|
+
end
|
443
|
+
|
444
|
+
# Now check if the files exist.
|
445
|
+
existing = checkFiles *files
|
446
|
+
|
447
|
+
# Now, gotta be sure that @script is not in the list of the files that
|
448
|
+
# should be renamed:
|
449
|
+
existing.delete Pathname.new @script
|
450
|
+
|
451
|
+
# Just to be 100% sure:
|
452
|
+
begin
|
453
|
+
existing.each_with_index do |entry, idx|
|
454
|
+
# Only the first time: create the script.
|
455
|
+
if 0 == idx then
|
456
|
+
File.open @script, "w" do |f|
|
457
|
+
# Script header:
|
458
|
+
f.puts "#!/usr/bin/env bash"
|
459
|
+
f.puts ""
|
460
|
+
|
461
|
+
# Make it executable:
|
462
|
+
f.chmod 0700
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
# Append the line to rename the current file:
|
467
|
+
File.open @script, "a" do |f|
|
468
|
+
f.puts "mv \"#{entry}\" \\"
|
469
|
+
f.puts " \"#{entry}\""
|
470
|
+
f.puts ""
|
471
|
+
end
|
472
|
+
|
473
|
+
# Only the last time: add the last touches to the script.
|
474
|
+
if idx == existing.size - 1 then
|
475
|
+
File.open @script, "a" do |f|
|
476
|
+
# Self destruct line:
|
477
|
+
f.puts "# Self-destruction line, you may not want to edit this:"
|
478
|
+
f.puts "rm \"#{@script}\""
|
479
|
+
|
480
|
+
# And an empty line at the end, because I'm that kind of guy.
|
481
|
+
f.puts ""
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
# A little something for the user:
|
487
|
+
puts "Created script file: #{@script}"
|
488
|
+
|
489
|
+
# This should never happen... But, just in case...
|
490
|
+
rescue
|
491
|
+
puts "Something went wrong while writing the script file... " +
|
492
|
+
"Are you sure you weren't messing with it?"
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
end
|
497
|
+
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rename_radically
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Maurizio Oliveri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: unicode
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.4.4.2
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.4'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.4.4.2
|
33
|
+
description: A simple (and probably dirty) files mass-renamer.
|
34
|
+
email:
|
35
|
+
- 6tsukiyami9@gmail.com
|
36
|
+
executables:
|
37
|
+
- rnr
|
38
|
+
extensions: []
|
39
|
+
extra_rdoc_files: []
|
40
|
+
files:
|
41
|
+
- bin/rnr
|
42
|
+
- lib/rename_radically.rb
|
43
|
+
homepage: https://github.com/Soulsuke/ReNameR
|
44
|
+
licenses:
|
45
|
+
- GPL-3.0
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 2.5.1
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: ReNameRadically
|
67
|
+
test_files: []
|