AbsoluteRenamer 1.1.0 → 1.1.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/AbsoluteRenamer.gemspec +26 -87
- data/Gemfile +4 -0
- data/README.rdoc +3 -1
- data/Rakefile +2 -59
- data/bin/absrenamer +4 -6
- data/conf/absrenamer/absrenamer.conf +1 -1
- data/lib/absolute_renamer.rb +99 -103
- data/lib/absolute_renamer/config.rb +43 -34
- data/lib/absolute_renamer/core-packages/core-case/module.rb +23 -24
- data/lib/absolute_renamer/core-packages/core-general/module.rb +106 -128
- data/lib/absolute_renamer/core-packages/core-general/parser.rb +75 -64
- data/lib/absolute_renamer/core-packages/core-interactive/parser.rb +15 -15
- data/lib/absolute_renamer/core-packages/core-interactive/plugin.rb +29 -29
- data/lib/absolute_renamer/core-packages/core-listing/parser.rb +6 -6
- data/lib/absolute_renamer/core-packages/core-listing/plugin.rb +10 -10
- data/lib/absolute_renamer/external.rb +48 -48
- data/lib/absolute_renamer/file_info.rb +87 -88
- data/lib/absolute_renamer/imodule.rb +69 -72
- data/lib/absolute_renamer/iparser.rb +4 -4
- data/lib/absolute_renamer/iplugin.rb +6 -6
- data/lib/absolute_renamer/libs/file.rb +8 -8
- data/lib/absolute_renamer/libs/hash.rb +23 -23
- data/lib/absolute_renamer/libs/string.rb +21 -21
- data/lib/absolute_renamer/parser.rb +57 -58
- data/lib/absolute_renamer/use_config.rb +6 -6
- data/lib/absolute_renamer/version.rb +3 -0
- data/lib/absolute_renamer/with_children.rb +15 -15
- data/test/config_test.rb +1 -8
- data/test/file_info_test.rb +23 -22
- data/test/imodule_test.rb +1 -8
- metadata +54 -18
- data/VERSION +0 -1
@@ -1,35 +1,35 @@
|
|
1
1
|
module AbsoluteRenamer
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
-
print "Do you want to rename this files ? [y/N] "
|
9
|
-
begin
|
10
|
-
resp = STDIN.readline.chomp.downcase
|
11
|
-
rescue Exception => e
|
12
|
-
puts "\nExiting renamer"
|
13
|
-
exit(0)
|
14
|
-
end
|
15
|
-
return resp == "y"
|
16
|
-
end
|
17
|
-
true
|
2
|
+
class InteractivePlugin < AbsoluteRenamer::IPlugin
|
3
|
+
def before_batch_renaming
|
4
|
+
ask_for_confirmation(:once, 'Do you want to rename this files ?') do
|
5
|
+
conf[:files].each do |file|
|
6
|
+
file.display_change
|
18
7
|
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def before_file_renaming(params)
|
12
|
+
ask_for_confirmation(:always, 'Do you want to rename this file ?') do
|
13
|
+
params[:file].display_change
|
14
|
+
end
|
15
|
+
end
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
true
|
17
|
+
def ask_for_confirmation(interactivity, message, waited_answer = 'y')
|
18
|
+
if conf[:options][:interactive] == interactivity
|
19
|
+
yield
|
20
|
+
|
21
|
+
print "#{message} [y/N] "
|
22
|
+
|
23
|
+
begin
|
24
|
+
resp = STDIN.readline.chomp.downcase
|
25
|
+
rescue
|
26
|
+
puts "\nExiting renamer"
|
27
|
+
exit(0)
|
33
28
|
end
|
29
|
+
|
30
|
+
return resp == waited_answer
|
31
|
+
end
|
32
|
+
true
|
34
33
|
end
|
34
|
+
end
|
35
35
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module AbsoluteRenamer
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
2
|
+
class ListingParser < AbsoluteRenamer::IParser
|
3
|
+
def self.add_options(parser, options)
|
4
|
+
parser.on('-l', '--list', "Only display how files will be renamed") do
|
5
|
+
options[:listing] = true
|
6
|
+
end
|
8
7
|
end
|
8
|
+
end
|
9
9
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module AbsoluteRenamer
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
return false
|
10
|
-
end
|
11
|
-
true
|
2
|
+
class ListingPlugin < AbsoluteRenamer::IPlugin
|
3
|
+
def before_batch_renaming
|
4
|
+
listing = conf[:options][:listing] || false
|
5
|
+
if listing
|
6
|
+
conf[:files].each do |file|
|
7
|
+
file.display_change
|
12
8
|
end
|
9
|
+
return false
|
10
|
+
end
|
11
|
+
true
|
13
12
|
end
|
13
|
+
end
|
14
14
|
end
|
@@ -3,58 +3,58 @@ require 'absolute_renamer/iplugin'
|
|
3
3
|
require 'absolute_renamer/use_config'
|
4
4
|
|
5
5
|
begin
|
6
|
-
|
6
|
+
require 'rubygems'
|
7
7
|
rescue LoadError
|
8
8
|
end
|
9
9
|
|
10
10
|
module AbsoluteRenamer
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def find_gems
|
33
|
-
installed_gems = Gem.source_index.find_name(/.*AbsoluteRenamer-.*/).map(&:name).uniq || []
|
34
|
-
installed_gems.each do |gem_name|
|
35
|
-
@gems[gem_name] = { :lib => gem_name, :version => '>= 0' }
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def find_gems_from_conf
|
40
|
-
if conf[:gems]
|
41
|
-
conf[:gems].each do |gem_name, gem_infos|
|
42
|
-
@gems[gem_name] = gem_infos ||= {}
|
43
|
-
@gems[gem_name][:lib] ||= gem_name
|
44
|
-
@gems[gem_name][:version] ||= ">= 0"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def exclude_gems
|
50
|
-
if @conf[:exclude]
|
51
|
-
@gems.reject! { |gem_name, gem_infos| @conf[:exclude].include? gem_name }
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def load_core
|
56
|
-
require 'absolute_renamer/core-packages/core-packages'
|
57
|
-
end
|
11
|
+
# Class in charge of loading external modules.
|
12
|
+
class External
|
13
|
+
class << self
|
14
|
+
include AbsoluteRenamer::UseConfig
|
15
|
+
|
16
|
+
def load_gems
|
17
|
+
if defined?(Gem)
|
18
|
+
@gems = {}
|
19
|
+
|
20
|
+
find_gems
|
21
|
+
find_gems_from_conf
|
22
|
+
exclude_gems
|
23
|
+
|
24
|
+
@gems.each do |gem_name, gem_infos|
|
25
|
+
puts "Loading gem #{gem_name} (#{gem_infos[:version]}) : #{gem_infos[:lib]}" if conf[:debug]
|
26
|
+
gem gem_name, gem_infos[:version]
|
27
|
+
require gem_infos[:lib]
|
28
|
+
end
|
58
29
|
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_gems
|
33
|
+
installed_gems = Gem.source_index.find_name(/.*AbsoluteRenamer-.*/).map(&:name).uniq || []
|
34
|
+
installed_gems.each do |gem_name|
|
35
|
+
@gems[gem_name] = { :lib => gem_name, :version => '>= 0' }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def find_gems_from_conf
|
40
|
+
if conf[:gems]
|
41
|
+
conf[:gems].each do |gem_name, gem_infos|
|
42
|
+
@gems[gem_name] = gem_infos ||= {}
|
43
|
+
@gems[gem_name][:lib] ||= gem_name
|
44
|
+
@gems[gem_name][:version] ||= ">= 0"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def exclude_gems
|
50
|
+
if @conf[:exclude]
|
51
|
+
@gems.reject! { |gem_name, gem_infos| @conf[:exclude].include? gem_name }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_core
|
56
|
+
require 'absolute_renamer/core-packages/core-packages'
|
57
|
+
end
|
59
58
|
end
|
59
|
+
end
|
60
60
|
end
|
@@ -4,105 +4,104 @@ require 'absolute_renamer/use_config'
|
|
4
4
|
require 'absolute_renamer/libs/file'
|
5
5
|
|
6
6
|
module AbsoluteRenamer
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
# Class that represents each file to be renamed.
|
8
|
+
# It contains all informations about a file and, in the end,
|
9
|
+
# processes to its renaming.
|
10
|
+
class FileInfo
|
11
|
+
include AbsoluteRenamer::UseConfig
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
attr_accessor :name, :new_name,
|
14
|
+
:path, :real_path,
|
15
|
+
:ext, :dir, :dir_path,
|
16
|
+
:level
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
18
|
+
# Initializes a FileInfo.
|
19
|
+
# path: the relative or absolute path of the file.
|
20
|
+
def initialize(path)
|
21
|
+
@path = path
|
22
|
+
@real_path = File.expand_path(@path)
|
23
|
+
@dir_path = File.dirname(@real_path)
|
24
|
+
@dir = File.directory?(@real_path)
|
25
|
+
@name = File.basename(@real_path)
|
26
|
+
unless @dir
|
27
|
+
@ext = File.extname(@name, conf[:options][:dots])
|
28
|
+
@name.gsub!(Regexp.new('.' << @ext << '$'), '') unless @ext.empty?
|
29
|
+
@level = 0
|
30
|
+
else
|
31
|
+
@level = @real_path.split('/').size
|
32
|
+
end
|
33
|
+
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
# Returns a description of a FileInfo
|
36
|
+
# some_fileinfo.inspect # => "File: hello_world pdf"
|
37
|
+
def inspect
|
38
|
+
"File: #{@name} #{@ext}"
|
39
|
+
end
|
41
40
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
# Displays the action that will be done on the file.
|
42
|
+
# some_fileinfo.display_change # => "rename a_file.txt --> A_File.TXT"
|
43
|
+
def display_change
|
44
|
+
puts "#{color conf[:options][:mode]} #{@real_path.sub(Dir.pwd+'/', '')} #{color '-->'} #{new_path.sub(Dir.pwd+'/', '')}"
|
45
|
+
end
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
# Returns a text colorized in red.
|
48
|
+
# color('hello') #=> "\e[31mhello\e[0m"
|
49
|
+
def color(text)
|
50
|
+
"\e[31m#{text}\e[0m"
|
51
|
+
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
53
|
+
# Returns the new path of the file.
|
54
|
+
def new_path
|
55
|
+
if conf[:options][:dest].nil? or conf[:options][:dest].empty?
|
56
|
+
File.join(@dir_path, @new_name)
|
57
|
+
else
|
58
|
+
File.join(conf[:options][:dest], @new_name)
|
59
|
+
end
|
60
|
+
end
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
# Renames the file.
|
63
|
+
def rename
|
64
|
+
display_change
|
65
|
+
File.rename(@real_path, new_path)
|
66
|
+
end
|
68
67
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
78
|
-
else
|
79
|
-
File.copy(@real_path, new_path, false)
|
80
|
-
end
|
68
|
+
# Copies the file.
|
69
|
+
def copy
|
70
|
+
display_change
|
71
|
+
if @dir
|
72
|
+
if @real_path != conf[:options][:dest]
|
73
|
+
FileUtils.cp_r(@real_path, conf[:options][:dest])
|
74
|
+
else
|
75
|
+
puts "#{real_path} ignored"
|
81
76
|
end
|
77
|
+
else
|
78
|
+
File.copy(@real_path, new_path, false)
|
79
|
+
end
|
80
|
+
end
|
82
81
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
82
|
+
# Moves a file. Moving to the same directories is just like renaming.
|
83
|
+
def move
|
84
|
+
display_change
|
85
|
+
File.move(@real_path, new_path, false)
|
86
|
+
end
|
88
87
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
88
|
+
# Creates a symbolic link to the file.
|
89
|
+
def link
|
90
|
+
display_change
|
91
|
+
begin
|
92
|
+
File.symlink(@real_path, new_path)
|
93
|
+
rescue NotImplemented
|
94
|
+
puts "Error: cannot create symlinks"
|
95
|
+
end
|
96
|
+
end
|
99
97
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
98
|
+
# Overriding the comparison operator to sort paths
|
99
|
+
# based on their depth.
|
100
|
+
def <=>(file_info)
|
101
|
+
if (self.level == file_info.level)
|
102
|
+
return (file_info.name <=> self.name)
|
103
|
+
end
|
104
|
+
file_info.level <=> self.level
|
107
105
|
end
|
106
|
+
end
|
108
107
|
end
|
@@ -1,86 +1,83 @@
|
|
1
1
|
require 'absolute_renamer/with_children'
|
2
2
|
|
3
3
|
module AbsoluteRenamer
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
# Modules parent class.
|
5
|
+
# Modules must inherit of it.
|
6
|
+
class IModule < AbsoluteRenamer::WithChildren
|
7
|
+
def initialize
|
8
|
+
@filters = []
|
9
|
+
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
# Returns the classname symbol
|
12
|
+
def self.symbol
|
13
|
+
name.intern
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
# pattern('test') #=> '(\[(.)?test\])'
|
19
|
-
def pattern(pattern_string)
|
20
|
-
Regexp.new "(\\[(.)?#{pattern_string}\\])"
|
21
|
-
end
|
16
|
+
def self.process(file, name_format, ext_format)
|
17
|
+
@mods ||= {}
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
val = mod.call(val)
|
30
|
-
end
|
31
|
-
val
|
32
|
-
end
|
19
|
+
self.children.each do |mod|
|
20
|
+
mod_sym = mod.symbol
|
21
|
+
@mods[mod_sym] ||= mod.new
|
22
|
+
name_format = @mods[mod_sym].process(file, name_format)
|
23
|
+
ext_format = @mods[mod_sym].process(file, ext_format, :ext) unless file.dir
|
24
|
+
end
|
33
25
|
|
34
|
-
|
35
|
-
|
36
|
-
# The pattern is a regular expression obtained by concatening
|
37
|
-
# the +@filters+ variable with "|".
|
38
|
-
#
|
39
|
-
# file: a FileInfo instance
|
40
|
-
# format: the format string used to rename the file
|
41
|
-
# type: the type of the renaming format (:name or :ext)
|
42
|
-
def process(file, format, type = :name)
|
43
|
-
return format if @filters.empty?
|
26
|
+
[name_format, ext_format]
|
27
|
+
end
|
44
28
|
|
45
|
-
|
46
|
-
|
47
|
-
|
29
|
+
# Returns a format pattern generated from pattern_string that
|
30
|
+
# can be used to match strings like [*test] in the filename format
|
31
|
+
# pattern('test') #=> '(\[(.)?test\])'
|
32
|
+
def pattern(pattern_string)
|
33
|
+
Regexp.new "(\\[(.)?#{pattern_string}\\])"
|
34
|
+
end
|
48
35
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
36
|
+
# Returns a value modified using a modifier defined in the Case module
|
37
|
+
# modifiy('value', '&') #=> 'VALUE'
|
38
|
+
# modifiy('value', '*') #=> 'Value'
|
39
|
+
def modify(val, modifier)
|
40
|
+
modification = CaseModule.actions[modifier]
|
41
|
+
val = CaseModule.send(modification, val) unless modification.nil?
|
42
|
+
val
|
43
|
+
end
|
44
|
+
|
45
|
+
# Process a +file+ by searching for a known pattern in its name
|
46
|
+
# and replacing it by the corresponding value.
|
47
|
+
# The pattern is a regular expression obtained by concatening
|
48
|
+
# the +@filters+ variable with "|".
|
49
|
+
#
|
50
|
+
# file: a FileInfo instance
|
51
|
+
# format: the format string used to rename the file
|
52
|
+
# type: the type of the renaming format (:name or :ext)
|
53
|
+
def process(file, format, type = :name)
|
54
|
+
return format if @filters.empty?
|
63
55
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
#
|
68
|
-
# file: a FileInfo instance
|
69
|
-
# infos: the matched values depending of the pattern
|
70
|
-
# type: the type of the renaming format (:name or :ext)
|
71
|
-
def interpret(file, infos, type)
|
72
|
-
modifier = infos[2]
|
73
|
-
action = infos[3]
|
56
|
+
result = []
|
57
|
+
pattern = Regexp.union @filters
|
58
|
+
idx = format.index(pattern)
|
74
59
|
|
75
|
-
|
60
|
+
while idx
|
61
|
+
matched = pattern.match(format).to_a
|
62
|
+
part = format.partition(matched[0])
|
63
|
+
result.push(part[0])
|
64
|
+
result.push self.interpret(file, matched, type)
|
65
|
+
format = part[2]
|
66
|
+
idx = format.index(pattern)
|
67
|
+
end
|
68
|
+
result.push(format)
|
69
|
+
format.replace(result.join)
|
70
|
+
end
|
76
71
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
72
|
+
# Interprets a matched pattern.
|
73
|
+
# Searchs for the corresponding callback
|
74
|
+
# in the current module and call it.
|
75
|
+
#
|
76
|
+
# file: a FileInfo instance
|
77
|
+
# infos: the matched values depending of the pattern
|
78
|
+
# type: the type of the renaming format (:name or :ext)
|
79
|
+
def interpret(file, infos, type)
|
80
|
+
# This method has to be overriden in every module
|
85
81
|
end
|
82
|
+
end
|
86
83
|
end
|