filter_rename 1.0.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/.gitignore +15 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE +674 -0
- data/README.md +82 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/filter_rename +5 -0
- data/filter_rename.gemspec +44 -0
- data/lib/filter_rename.rb +137 -0
- data/lib/filter_rename.yaml +165 -0
- data/lib/filter_rename/cli.rb +145 -0
- data/lib/filter_rename/config.rb +120 -0
- data/lib/filter_rename/filename.rb +142 -0
- data/lib/filter_rename/filename_factory.rb +36 -0
- data/lib/filter_rename/filetype/image_filename.rb +28 -0
- data/lib/filter_rename/filetype/mp3_filename.rb +82 -0
- data/lib/filter_rename/filetype/pdf_filename.rb +24 -0
- data/lib/filter_rename/filter_base.rb +191 -0
- data/lib/filter_rename/filter_pipe.rb +64 -0
- data/lib/filter_rename/filters.rb +660 -0
- data/lib/filter_rename/utils.rb +283 -0
- data/lib/filter_rename/version.rb +3 -0
- metadata +202 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'mp3info'
|
2
|
+
|
3
|
+
module FilterRename
|
4
|
+
|
5
|
+
class Mp3Filename < Filename
|
6
|
+
|
7
|
+
def self.has_writable_tags
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(fname, cfg)
|
12
|
+
super fname, cfg
|
13
|
+
|
14
|
+
load_mp3_data(fname)
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(dest)
|
18
|
+
super &&
|
19
|
+
([ @title, @artist, @album, @track, @comments, @year, @genre ] ==
|
20
|
+
[ dest.get_string(:title), dest.get_string(:artist), dest.get_string(:album), dest.get_string(:track),
|
21
|
+
dest.get_string(:comments), dest.get_string(:year), dest.get_string(:genre) ])
|
22
|
+
end
|
23
|
+
|
24
|
+
def rename!(dest)
|
25
|
+
old_data = super dest
|
26
|
+
|
27
|
+
Mp3Info.open(full_filename) do |mp3|
|
28
|
+
old_data.merge!({ title: mp3.tag.title, artist: mp3.tag.artist, album: mp3.tag.album,
|
29
|
+
tracknum: mp3.tag.tracknum, comments: mp3.tag.comments, year: mp3.tag.year,
|
30
|
+
genre_s: mp3.tag.genre_s })
|
31
|
+
|
32
|
+
mp3.tag.title = dest.get_string(:title)
|
33
|
+
mp3.tag.artist = dest.get_string(:artist)
|
34
|
+
mp3.tag.album = dest.get_string(:album)
|
35
|
+
mp3.tag.tracknum = dest.get_string(:track)
|
36
|
+
mp3.tag.comments = dest.get_string(:comments).to_s
|
37
|
+
mp3.tag.year = dest.get_string(:year)
|
38
|
+
mp3.tag.genre_s = dest.get_string(:genre)
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
load_mp3_data(full_filename)
|
43
|
+
|
44
|
+
old_data
|
45
|
+
end
|
46
|
+
|
47
|
+
def diff(dest)
|
48
|
+
super(dest) + "
|
49
|
+
Title: #{Differ.diff_by_word(dest.get_string(:title).to_s, @title.to_s)}
|
50
|
+
Artist: #{Differ.diff_by_word(dest.get_string(:artist).to_s, @artist.to_s)}
|
51
|
+
Album: #{Differ.diff_by_word(dest.get_string(:album).to_s, @album.to_s)}
|
52
|
+
Track: #{Differ.diff_by_word(dest.get_string(:track).to_s, @track.to_s)}
|
53
|
+
Comments: #{Differ.diff_by_word(dest.get_string(:comments).to_s, @comments.to_s)}
|
54
|
+
Year: #{Differ.diff_by_word(dest.get_string(:year).to_s, @year.to_s)}
|
55
|
+
Genre: #{Differ.diff_by_word(dest.get_string(:genre).to_s, @genre.to_s)}
|
56
|
+
"
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def load_mp3_data(fname)
|
63
|
+
mp3info = Mp3Info.new(fname)
|
64
|
+
@title = mp3info.tag.title.to_s
|
65
|
+
@artist = mp3info.tag.artist.to_s
|
66
|
+
@album = mp3info.tag.album.to_s
|
67
|
+
@track = mp3info.tag.tracknum.to_i
|
68
|
+
@comments = mp3info.tag.comments.to_s
|
69
|
+
@year = mp3info.tag.year.to_i
|
70
|
+
@genre = mp3info.tag.genre_s.to_s
|
71
|
+
|
72
|
+
# read only stuff
|
73
|
+
@vbr = (mp3info.tag.vbr ? 'vbr' : '')
|
74
|
+
@samplerate = mp3info.samplerate.to_s
|
75
|
+
@bitrate = mp3info.bitrate.to_s
|
76
|
+
|
77
|
+
[@vbr, @samplerate, @bitrate].map(&:readonly!)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'pdf-reader'
|
2
|
+
|
3
|
+
module FilterRename
|
4
|
+
|
5
|
+
class PdfFilename < Filename
|
6
|
+
|
7
|
+
def initialize(fname, cfg)
|
8
|
+
super fname, cfg
|
9
|
+
|
10
|
+
if cfg.pdf_metadata
|
11
|
+
|
12
|
+
pdfinfo = PDF::Reader.new(fname)
|
13
|
+
|
14
|
+
@page_count = pdfinfo.page_count.to_s
|
15
|
+
@page_count.readonly!
|
16
|
+
|
17
|
+
pdfinfo.info.each do |key, value|
|
18
|
+
metatag_to_var!(key.to_s.gsub(/([A-Z])([^A-Z]+)/, '\1\2 ').strip, value, true)
|
19
|
+
end unless pdfinfo.info.nil?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module FilterRename
|
4
|
+
|
5
|
+
# This is the class which handles the list
|
6
|
+
# of filters.
|
7
|
+
class FilterList
|
8
|
+
attr_reader :filters
|
9
|
+
|
10
|
+
def initialize(list)
|
11
|
+
@filters = list
|
12
|
+
end
|
13
|
+
|
14
|
+
def expand_macros!(macro)
|
15
|
+
|
16
|
+
@filters.each_with_index do |names , i|
|
17
|
+
|
18
|
+
if FilterRename::MacroConfig == names.keys[0]
|
19
|
+
z = 1
|
20
|
+
names.values.pop.each do |n|
|
21
|
+
macro.get_macro(n).each do |k, v|
|
22
|
+
if v.nil? # Array
|
23
|
+
@filters.insert(i + z, k.keys[0].to_s.to_filter => k[k.keys[0]])
|
24
|
+
else # Hash
|
25
|
+
@filters.insert(i + z, k.to_s.to_filter => v)
|
26
|
+
end
|
27
|
+
z += 1
|
28
|
+
end
|
29
|
+
@filters[i] = nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
@filters.delete_if(&:nil?)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
class FilterBase < SimpleDelegator
|
41
|
+
|
42
|
+
def initialize(obj, options)
|
43
|
+
super obj
|
44
|
+
@dest = obj # useful for macros
|
45
|
+
@cfg = options[:cfg]
|
46
|
+
@words = options[:words]
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_words(name, section, idx = nil)
|
50
|
+
@words.get_words name, section, idx
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_config(name, value)
|
54
|
+
raise InvalidFilterSetting, name unless @cfg.instance_variables.include?("@#{name}".to_sym)
|
55
|
+
|
56
|
+
@cfg.instance_variable_set ('@' + name.to_s), value
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_config(name)
|
60
|
+
raise InvalidFilterSetting, name unless @cfg.instance_variables.include?("@#{name}".to_sym)
|
61
|
+
|
62
|
+
@cfg.instance_variable_get '@' + name.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def filter(value)
|
66
|
+
set_string value
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_string(value, target = nil)
|
70
|
+
if target.nil?
|
71
|
+
super @cfg.target, value
|
72
|
+
else
|
73
|
+
super target, value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def get_string(target = nil)
|
78
|
+
if target.nil?
|
79
|
+
super @cfg.target
|
80
|
+
else
|
81
|
+
super target
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def match?(mask)
|
86
|
+
get_string =~ Regexp.new(mask)
|
87
|
+
end
|
88
|
+
|
89
|
+
def wrap_regex(str)
|
90
|
+
str = "(#{str})" unless str =~ /\(.*\)/
|
91
|
+
str
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
module IndexedParams
|
98
|
+
|
99
|
+
def get_indexes(params, callback)
|
100
|
+
indexes = []
|
101
|
+
params_length = (indexed_params == 0) ? params.length : indexed_params
|
102
|
+
|
103
|
+
params[0..params_length.pred].each do |x|
|
104
|
+
if x =~ /\.\./
|
105
|
+
indexes = indexes + Range.new(*(x.split('..').map {|y| send(callback, y, get_string) })).map { |i| i }
|
106
|
+
else
|
107
|
+
indexes << send(callback, x, get_string)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
indexes
|
113
|
+
end
|
114
|
+
|
115
|
+
def indexed_params
|
116
|
+
1
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
class FilterWord < FilterBase
|
122
|
+
include IndexedParams
|
123
|
+
|
124
|
+
def filter(params)
|
125
|
+
super loop_words(get_string, get_indexes(params, :word_idx), params)
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def ws
|
132
|
+
get_config(:word_separator)
|
133
|
+
end
|
134
|
+
|
135
|
+
def word_idx(idx, str)
|
136
|
+
if idx.to_i.positive?
|
137
|
+
idx = idx.to_i.pred
|
138
|
+
elsif idx.to_i.negative?
|
139
|
+
idx = idx.to_i + str.split(ws).length
|
140
|
+
end
|
141
|
+
idx.to_i
|
142
|
+
end
|
143
|
+
|
144
|
+
def loop_words(str, arr_index, params)
|
145
|
+
str = str.split(ws)
|
146
|
+
|
147
|
+
arr_index.each_with_index do |idx, param_num|
|
148
|
+
str[idx] = send :filtered_word, str[idx], params, param_num.next
|
149
|
+
end
|
150
|
+
|
151
|
+
str.delete_if(&:nil?).join(ws)
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
class FilterNumber < FilterBase
|
157
|
+
|
158
|
+
include IndexedParams
|
159
|
+
|
160
|
+
def filter(params)
|
161
|
+
super loop_numbers(get_string, get_indexes(params, :num_idx), params)
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def num_idx(idx, str)
|
168
|
+
if idx.to_i < 0
|
169
|
+
idx = str.scan(/\d+/).length + idx.to_i
|
170
|
+
elsif idx.to_i > 0
|
171
|
+
idx = idx.to_i.pred
|
172
|
+
end
|
173
|
+
idx.to_i
|
174
|
+
end
|
175
|
+
|
176
|
+
def loop_numbers(str, arr_index, params)
|
177
|
+
arr_index.each_with_index do |idx, param_idx|
|
178
|
+
str = str.map_number_with_index do |num, i|
|
179
|
+
if idx == i
|
180
|
+
num = self.send :filtered_number, num, params, param_idx.next
|
181
|
+
end
|
182
|
+
|
183
|
+
num
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
str
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module FilterRename
|
2
|
+
|
3
|
+
class FilterPipe
|
4
|
+
attr_reader :source, :dest
|
5
|
+
|
6
|
+
def initialize(fname, filters, cfg)
|
7
|
+
# Filter params have to be reset for each file
|
8
|
+
@cfg = cfg.filter.clone
|
9
|
+
@source = FilenameFactory.create(fname, cfg.global)
|
10
|
+
@dest = Marshal.load(Marshal.dump(@source))
|
11
|
+
@filters = (filters.class == Array) ? filters : filters.filters
|
12
|
+
@words = cfg.words
|
13
|
+
end
|
14
|
+
|
15
|
+
def changed?
|
16
|
+
! unchanged?
|
17
|
+
end
|
18
|
+
|
19
|
+
def unchanged?
|
20
|
+
@source == @dest
|
21
|
+
end
|
22
|
+
alias_method :identical?, :unchanged?
|
23
|
+
|
24
|
+
def diff
|
25
|
+
@source.diff(@dest)
|
26
|
+
end
|
27
|
+
|
28
|
+
def apply
|
29
|
+
|
30
|
+
@filters.each_with_index do |f, i|
|
31
|
+
|
32
|
+
filter = f.keys.pop
|
33
|
+
params = f.values.pop
|
34
|
+
|
35
|
+
if [FilterRename::Filters::Config, FilterRename::Filters::Select].include? filter
|
36
|
+
filter.new(@dest, cfg: @cfg, words: @words).filter(params)
|
37
|
+
else
|
38
|
+
filter.new(@dest, cfg: @cfg, words: @words).filter(params) unless skip?
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def rename!
|
47
|
+
@source.rename!(@dest)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def skip?
|
53
|
+
if [:full_filename, :full_path, :filename].include? @cfg.grep_target.to_sym
|
54
|
+
unmatched = instance_variable_get('@' + @cfg.grep_on.to_s).send(@cfg.grep_target.to_sym).match(Regexp.new(@cfg.grep)).nil?
|
55
|
+
else
|
56
|
+
unmatched = instance_variable_get('@' + @cfg.grep_on.to_s).get_string(@cfg.grep_target).match(Regexp.new(@cfg.grep)).nil?
|
57
|
+
end
|
58
|
+
|
59
|
+
@cfg.grep_exclude.to_s.to_boolean ? !unmatched : unmatched
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,660 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FilterRename
|
4
|
+
|
5
|
+
module Filters
|
6
|
+
|
7
|
+
class Select < FilterBase
|
8
|
+
def self.hint; 'Select the target where apply further transformations'; end
|
9
|
+
def self.params; 'name|ext|folder|...'; end
|
10
|
+
|
11
|
+
def filter(params)
|
12
|
+
raise InvalidTarget, params[0] unless has_target? params[0].to_sym
|
13
|
+
set_config :target, params[0].to_sym
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Config < FilterBase
|
18
|
+
def self.hint; 'Set config PARAM to VALUE'; end
|
19
|
+
def self.params; 'PARAM:VALUE[,PARAMS2:VALUE2,...]'; end
|
20
|
+
|
21
|
+
def filter(params)
|
22
|
+
params.each do |par|
|
23
|
+
set_config(par.split(':')[0], par.split(':')[1])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#------------------------
|
29
|
+
|
30
|
+
|
31
|
+
class AddNumber < FilterNumber
|
32
|
+
def self.hint; 'Add NUM to the NTH number'; end
|
33
|
+
def self.params; 'NTH,NUM'; end
|
34
|
+
|
35
|
+
def filtered_number(num, params, param_num)
|
36
|
+
num.to_i + params[1].to_i
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
class Append < FilterBase
|
42
|
+
def self.hint; 'Append the TEXT to the current target'; end
|
43
|
+
def self.params; 'TEXT'; end
|
44
|
+
|
45
|
+
def filter(params)
|
46
|
+
super "#{get_string}#{params[0]}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
class AppendFrom < FilterBase
|
52
|
+
def self.hint; 'Append the text from TARGET'; end
|
53
|
+
def self.params; 'TARGET'; end
|
54
|
+
|
55
|
+
def filter(params)
|
56
|
+
super "#{get_string}#{get_string(params[0])}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
class AppendAsWordTo < FilterBase
|
62
|
+
def self.hint; 'Append the TEXT to TARGET as a word'; end
|
63
|
+
def self.params; 'TEXT,TARGET'; end
|
64
|
+
|
65
|
+
def filter(params)
|
66
|
+
ws = get_config(:word_separator)
|
67
|
+
set_string(get_string(params[1]).to_s.split(ws).push(params[0]).join(ws), params[1])
|
68
|
+
super get_string
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
class AppendTo < FilterBase
|
74
|
+
def self.hint; 'Append the TEXT to TARGET'; end
|
75
|
+
def self.params; 'TEXT,TARGET'; end
|
76
|
+
|
77
|
+
def filter(params)
|
78
|
+
set_string(get_string(params[1]).to_s + params[0], params[1])
|
79
|
+
super get_string
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
class AppendNumberTo < FilterNumber
|
85
|
+
def self.hint; 'Append the NTH number to TARGET'; end
|
86
|
+
def self.params; 'NTH,TARGET'; end
|
87
|
+
|
88
|
+
def filtered_number(num, params, param_num)
|
89
|
+
str = get_string(params[1])
|
90
|
+
set_string("#{str}#{num}", params[1])
|
91
|
+
num
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
class AppendToNumber < FilterNumber
|
97
|
+
def self.hint; 'Append the TEXT to the NTH number'; end
|
98
|
+
def self.params; 'NTH,TEXT'; end
|
99
|
+
|
100
|
+
def filtered_number(num, params, param_num)
|
101
|
+
"#{num}#{params[1]}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
class AppendToWord < FilterWord
|
107
|
+
def self.hint; 'Append the TEXT to the NTH word'; end
|
108
|
+
def self.params; 'NTH,TEXT'; end
|
109
|
+
|
110
|
+
def filtered_word(word, params, param_num)
|
111
|
+
word + params[1]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
class AppendWordFrom < FilterWord
|
117
|
+
def self.hint; 'Append the NTH word from TARGET'; end
|
118
|
+
def self.params; 'NTH,TARGET'; end
|
119
|
+
|
120
|
+
def filter(params)
|
121
|
+
word = get_string(params[1]).split(ws)
|
122
|
+
idx = word_idx(params[0], word)
|
123
|
+
set_string [get_string, word[idx]].join(ws)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
class AppendWordTo < FilterWord
|
129
|
+
def self.hint; 'Append the NTH word to TARGET'; end
|
130
|
+
def self.params; 'NTH,TARGET'; end
|
131
|
+
|
132
|
+
def filtered_word(word, params, param_num)
|
133
|
+
set_string([get_string(params[1]), word].join(ws), params[1])
|
134
|
+
word
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
class Capitalize < FilterBase
|
140
|
+
def self.hint; 'Capitalize each word'; end
|
141
|
+
def self.params; nil; end
|
142
|
+
|
143
|
+
def filter(params)
|
144
|
+
ws = get_config(:word_separator)
|
145
|
+
super (get_string.split(ws).map(&:capitalize)).join(ws)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
class CopyFrom < FilterBase
|
151
|
+
def self.hint; 'Copy the text from TARGET'; end
|
152
|
+
def self.params; 'TARGET'; end
|
153
|
+
|
154
|
+
def filter(params)
|
155
|
+
super get_string(params[0]).to_s
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
class CopyNumberTo < FilterNumber
|
161
|
+
def self.hint; 'Move the NTH number to TARGET'; end
|
162
|
+
def self.params; 'NTH,TARGET'; end
|
163
|
+
|
164
|
+
def filtered_number(num, params, param_num)
|
165
|
+
set_string(num, params[1])
|
166
|
+
num
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
class CopyTo < FilterBase
|
172
|
+
def self.hint; 'Copy the text selected by REGEX to TARGET'; end
|
173
|
+
def self.params; 'REGEX,TARGET'; end
|
174
|
+
|
175
|
+
def filter(params)
|
176
|
+
set_string(get_string.scan(Regexp.new(wrap_regex(params[0]), get_config(:ignore_case).to_boolean)).pop.to_a.pop, params[1])
|
177
|
+
super get_string
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
class CopyWord < FilterWord
|
183
|
+
def self.hint; 'Copy the NTH1 word to the NTH2 place'; end
|
184
|
+
def self.params; 'NTH1,NTH2'; end
|
185
|
+
|
186
|
+
def indexed_params; 2; end
|
187
|
+
|
188
|
+
def filtered_word(word, params, param_num)
|
189
|
+
case param_num
|
190
|
+
when 1
|
191
|
+
@word = word
|
192
|
+
when 2
|
193
|
+
word = @word + ws + word
|
194
|
+
end
|
195
|
+
|
196
|
+
word
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
class Delete < FilterBase
|
202
|
+
def self.hint; 'Remove the text matching REGEX'; end
|
203
|
+
def self.params; 'REGEX1[,REGEX2,...]'; end
|
204
|
+
|
205
|
+
def filter(params)
|
206
|
+
params.each do |par|
|
207
|
+
super get_string.gsub(Regexp.new(par, get_config(:ignore_case).to_boolean), '')
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
class DeleteNumber < FilterNumber
|
214
|
+
def self.hint; 'Remove the NTH number'; end
|
215
|
+
def self.params; 'NTH'; end
|
216
|
+
|
217
|
+
def filtered_number(num, params, param_num)
|
218
|
+
''
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
class DeleteWord < FilterWord
|
224
|
+
def self.hint; 'Remove the NTH word'; end
|
225
|
+
def self.params; 'NTH'; end
|
226
|
+
|
227
|
+
def filtered_word(word, params, param_num)
|
228
|
+
nil
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
class FormatNumber < FilterNumber
|
234
|
+
def self.hint; 'Format the NTH number adding leading zeroes to have LENGTH'; end
|
235
|
+
def self.params; 'NTH,LENGTH'; end
|
236
|
+
|
237
|
+
def filtered_number(num, params, param_num)
|
238
|
+
num.to_i.to_s.rjust(params[1].to_i, '0')
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
class InsertAfterWord < FilterWord
|
244
|
+
def self.hint; 'Insert the WORD after the NTH word'; end
|
245
|
+
def self.params; 'NTH,WORD'; end
|
246
|
+
|
247
|
+
def filtered_word(word, params, param_num)
|
248
|
+
[word, params[1]].join(ws)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
class InsertBeforeWord < FilterWord
|
254
|
+
def self.hint; 'Insert the WORD after the NTH word'; end
|
255
|
+
def self.params; 'NTH,WORD'; end
|
256
|
+
|
257
|
+
def filtered_word(word, params, param_num)
|
258
|
+
[params[1], word].join(ws)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
class JoinWords < FilterWord
|
264
|
+
def self.hint; 'Join the words from NTH1 to NTH2'; end
|
265
|
+
def self.params; 'NTH1,NTH2'; end
|
266
|
+
|
267
|
+
def filter(params)
|
268
|
+
res = get_string.split(ws)
|
269
|
+
istart = word_idx(params[0], get_string)
|
270
|
+
iend = word_idx(params[1], get_string)
|
271
|
+
|
272
|
+
res = res.insert(istart, res[istart..iend].join)
|
273
|
+
set_string res.delete_if.with_index { |x, idx| ((istart.next)..(iend.next)).include?(idx) }.join(ws)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
|
278
|
+
class LeftJustify < FilterBase
|
279
|
+
def self.hint; 'Add enough CHAR(s) to the right side to have a N-length string'; end
|
280
|
+
def self.params; 'N,CHAR'; end
|
281
|
+
|
282
|
+
def filter(params)
|
283
|
+
super get_string.ljust(params[0].to_i, params[1])
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
class Lowercase < FilterBase
|
289
|
+
def self.hint; 'Lowercase each word'; end
|
290
|
+
def self.params; nil; end
|
291
|
+
|
292
|
+
def filter(params)
|
293
|
+
super get_string.downcase
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
|
298
|
+
class MoveTo < FilterBase
|
299
|
+
def self.hint; 'Move the text selected by REGEX to TARGET'; end
|
300
|
+
def self.params; 'REGEX,TARGET'; end
|
301
|
+
|
302
|
+
def filter(params)
|
303
|
+
regex = Regexp.new(wrap_regex(params[0]), get_config(:ignore_case).to_boolean)
|
304
|
+
set_string(get_string.scan(regex).pop.to_a.pop, params[1])
|
305
|
+
str = get_string.gsub(regex, '')
|
306
|
+
super str
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
class MoveNumberTo < FilterNumber
|
312
|
+
def self.hint; 'Move the NTH number to TARGET'; end
|
313
|
+
def self.params; 'NTH,TARGET'; end
|
314
|
+
|
315
|
+
def filtered_number(num, params, param_num)
|
316
|
+
set_string(num, params[1])
|
317
|
+
''
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
class MoveWord < FilterWord
|
323
|
+
def self.hint; 'Move the NTH1 word to the NTH2 place'; end
|
324
|
+
def self.params; 'NTH1,NTH2'; end
|
325
|
+
|
326
|
+
def indexed_params; 2; end
|
327
|
+
|
328
|
+
def filtered_word(word, params, param_num)
|
329
|
+
case param_num
|
330
|
+
when 1
|
331
|
+
@word = word
|
332
|
+
res = nil
|
333
|
+
when 2
|
334
|
+
res = [word, @word].join(ws)
|
335
|
+
end
|
336
|
+
|
337
|
+
res
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
class MoveWordTo < FilterWord
|
343
|
+
def self.hint; 'Move the NTH word to TARGET'; end
|
344
|
+
def self.params; 'NTH,TARGET'; end
|
345
|
+
|
346
|
+
def filtered_word(word, params, param_num)
|
347
|
+
set_string(word, params[1])
|
348
|
+
nil
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
|
353
|
+
class MultiplyNumber < FilterNumber
|
354
|
+
def self.hint; 'Multiply the NTH number with NUM'; end
|
355
|
+
def self.params; 'NTH,NUM'; end
|
356
|
+
|
357
|
+
def filtered_number(num, params, param_num)
|
358
|
+
num.to_i * params[1].to_i
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
|
363
|
+
class Prepend < FilterBase
|
364
|
+
def self.hint; 'Prepend the current target with TEXT'; end
|
365
|
+
def self.params; 'TEXT'; end
|
366
|
+
|
367
|
+
def filter(params)
|
368
|
+
super "#{params[0]}#{get_string}"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
|
373
|
+
class PrependFrom < FilterBase
|
374
|
+
def self.hint; 'Prepend the current target with the text from TARGET'; end
|
375
|
+
def self.params; 'TARGET'; end
|
376
|
+
|
377
|
+
def filter(params)
|
378
|
+
super "#{get_string(params[0])}#{get_string}"
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
|
383
|
+
class PrependToNumber < FilterNumber
|
384
|
+
def self.hint; 'Prepend the TEXT to the NTH number'; end
|
385
|
+
def self.params; 'NTH,TEXT'; end
|
386
|
+
|
387
|
+
def filtered_number(num, params, param_num)
|
388
|
+
"#{params[1]}#{num}"
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
|
393
|
+
class PrependToWord < FilterWord
|
394
|
+
def self.hint; 'Prepend the TEXT to the NTH word'; end
|
395
|
+
def self.params; 'NTH,TEXT'; end
|
396
|
+
|
397
|
+
def filtered_word(word, params, param_num)
|
398
|
+
params[1] + word
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
|
403
|
+
class Replace < FilterBase
|
404
|
+
def self.hint; 'Replace the text matching REGEX with REPLACE'; end
|
405
|
+
def self.params; 'REGEX,REPLACE'; end
|
406
|
+
|
407
|
+
def filter(params)
|
408
|
+
regexp = Regexp.new(params[0], get_config(:ignore_case).to_boolean)
|
409
|
+
super get_string.gsub(regexp, params[1])
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
|
414
|
+
class ReplaceFrom < FilterBase
|
415
|
+
def self.hint; 'Replace the REGEX matching text with the TARGET content'; end
|
416
|
+
def self.params; 'REGEX,TARGET'; end
|
417
|
+
|
418
|
+
def filter(params)
|
419
|
+
regexp = Regexp.new(params[0], get_config(:ignore_case).to_boolean)
|
420
|
+
super get_string.gsub(regexp, get_string(params[1]).to_s)
|
421
|
+
end
|
422
|
+
|
423
|
+
end
|
424
|
+
|
425
|
+
|
426
|
+
class ReplaceNumber < FilterNumber
|
427
|
+
def self.hint; 'Replace the NTH number with NUMBER'; end
|
428
|
+
def self.params; 'NTH,NUMBER'; end
|
429
|
+
|
430
|
+
def filtered_number(num, params, param_num)
|
431
|
+
params[1]
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
|
436
|
+
class ReplaceWord < FilterWord
|
437
|
+
def self.hint; 'Replace the NTH word with TEXT'; end
|
438
|
+
def self.params; 'NTH,TEXT'; end
|
439
|
+
|
440
|
+
def filtered_word(word, params, param_num)
|
441
|
+
params[1]
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
|
446
|
+
class ReplaceDate < FilterBase
|
447
|
+
def self.hint; 'Replace a date from FORMATSRC to FORMATDEST (placeholders: <m>, <B>, <b>, <Y>, <d>)'; end
|
448
|
+
def self.params; 'FORMATSRC,FORMATDEST[,LANG]'; end
|
449
|
+
|
450
|
+
def filter(params)
|
451
|
+
params[2] ||= get_config(:lang)
|
452
|
+
super get_string.change_date_format(format_src: params[0], format_dest: params[1],
|
453
|
+
long_months: get_words(:long_months , params[2]),
|
454
|
+
short_months: get_words(:short_months , params[2]),
|
455
|
+
long_days: get_words(:long_days, params[2]),
|
456
|
+
short_days: get_words(:short_days, params[2]))
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
|
461
|
+
class Reverse < FilterBase
|
462
|
+
def self.hint; 'Reverse the string'; end
|
463
|
+
def self.params; nil; end
|
464
|
+
|
465
|
+
def filter(params)
|
466
|
+
super get_string.reverse
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
|
471
|
+
class RightJustify < FilterBase
|
472
|
+
def self.hint; 'Apply enough CHAR(s) to the left side to have a N-length string'; end
|
473
|
+
def self.params; 'N,CHAR'; end
|
474
|
+
|
475
|
+
def filter(params)
|
476
|
+
super get_string.rjust(params[0].to_i, params[1])
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
|
481
|
+
class Set < FilterBase
|
482
|
+
def self.hint; 'Set the current or an optional TARGET with TEXT'; end
|
483
|
+
def self.params; 'TEXT[,TARGET]'; end
|
484
|
+
|
485
|
+
def filter(params)
|
486
|
+
if params[1].nil?
|
487
|
+
str = params[0]
|
488
|
+
else
|
489
|
+
set_string(params[0], params[1].delete(':<>'))
|
490
|
+
str = get_string
|
491
|
+
end
|
492
|
+
|
493
|
+
super str
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
|
498
|
+
class SetWhen < FilterBase
|
499
|
+
def self.hint; 'Set the current or given TARGET to TEXT when REGEX is matched'; end
|
500
|
+
def self.params; 'REGEX,TEXT[,TARGET]'; end
|
501
|
+
|
502
|
+
def filter(params)
|
503
|
+
target = params[-1] if params.length.odd?
|
504
|
+
set_string(params[1], target) if get_string =~ Regexp.new(params[0], get_config(:ignore_case).to_boolean)
|
505
|
+
super get_string
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
|
510
|
+
class Spacify < FilterBase
|
511
|
+
def self.hint; 'Replace CHAR with a space'; end
|
512
|
+
def self.params; 'CHAR1,CHAR2,...'; end
|
513
|
+
|
514
|
+
def filter(params)
|
515
|
+
regexp = Regexp.new(params.join('|'), get_config(:ignore_case).to_boolean)
|
516
|
+
super get_string.gsub(regexp, ' ')
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
|
521
|
+
class SplitWord < FilterWord
|
522
|
+
def self.hint; 'Split the NTH word using a REGEX with capturing groups'; end
|
523
|
+
def self.params; 'NTH,REGEX'; end
|
524
|
+
|
525
|
+
def filtered_word(word, params, param_num)
|
526
|
+
word.scan(Regexp.new(wrap_regex(params[1]), get_config(:ignore_case))).pop.to_a.join(ws)
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
|
531
|
+
class Squeeze < FilterBase
|
532
|
+
def self.hint; 'Squeeze consecutive CHARS in only one'; end
|
533
|
+
def self.params; 'CHAR'; end
|
534
|
+
|
535
|
+
def filter(params)
|
536
|
+
super get_string.gsub Regexp.new("#{params[0]}{2,}", get_config(:ignore_case).to_boolean), params[0]
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
|
541
|
+
class SwapNumber < FilterNumber
|
542
|
+
def self.hint; 'Swap the NTH1 number with the NTH2'; end
|
543
|
+
def self.params; 'NTH1,NTH2'; end
|
544
|
+
|
545
|
+
def indexed_params; 2; end
|
546
|
+
|
547
|
+
def filtered_number(num, params, param_num)
|
548
|
+
case param_num
|
549
|
+
when 1
|
550
|
+
@number = num.clone
|
551
|
+
num = get_string.get_number(params[1].to_i.pred)
|
552
|
+
when 2
|
553
|
+
num = @number
|
554
|
+
end
|
555
|
+
|
556
|
+
num
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
|
561
|
+
class SwapWord < FilterWord
|
562
|
+
def self.hint; 'Swap the NTH1 word with the NTH2'; end
|
563
|
+
def self.params; 'NTH1,NTH2'; end
|
564
|
+
|
565
|
+
def indexed_words; 2; end
|
566
|
+
|
567
|
+
def filtered_word(word, params, param_num)
|
568
|
+
case param_num
|
569
|
+
when 1
|
570
|
+
@word = word.clone
|
571
|
+
word = get_string.split(ws)[params[1].to_i.pred]
|
572
|
+
when 2
|
573
|
+
word = @word
|
574
|
+
end
|
575
|
+
|
576
|
+
word
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
|
581
|
+
class Template < FilterBase
|
582
|
+
def self.hint; 'Replace the <placeholders> in TEMPLATE with the relative targets'; end
|
583
|
+
def self.params; 'TEMPLATE'; end
|
584
|
+
|
585
|
+
def filter(params)
|
586
|
+
super params[0].gsub(/<([a-z0-9\_]+)>/) { get_string(Regexp.last_match[1]) }
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
|
591
|
+
class TranslateWords < FilterBase
|
592
|
+
def self.hint; 'Replace words in GROUP from SUBGRPS to SUBGRPD'; end
|
593
|
+
def self.params; 'GROUP,SUBGRPS,SUBGRPD'; end
|
594
|
+
|
595
|
+
def filter(params)
|
596
|
+
str = get_string
|
597
|
+
group = params[0].to_sym
|
598
|
+
lang_src = params[1] ? params[1].to_sym : :none
|
599
|
+
lang_dest = params[2] ? params[2].to_sym : :none
|
600
|
+
|
601
|
+
get_words(group, lang_src).each_with_index do |x, i|
|
602
|
+
str = str.gsub(Regexp.new(x, get_config(:ignore_case)), get_words(group, lang_dest, i))
|
603
|
+
end
|
604
|
+
|
605
|
+
super str
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
|
610
|
+
class Trim < FilterBase
|
611
|
+
def self.hint; 'Remove trailing spaces'; end
|
612
|
+
def self.params; nil; end
|
613
|
+
|
614
|
+
def filter(params)
|
615
|
+
super get_string.strip
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
|
620
|
+
class Uppercase < FilterBase
|
621
|
+
def self.hint; 'Uppercase each word'; end
|
622
|
+
def self.params; nil; end
|
623
|
+
|
624
|
+
def filter(params)
|
625
|
+
super get_string.upcase
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
|
630
|
+
class Wrap < FilterBase
|
631
|
+
def self.hint; 'Wrap the text matching REGEX with SEPARATOR1 and SEPARATOR2'; end
|
632
|
+
def self.params; 'REGEX,SEPARATOR1,SEPARATOR2'; end
|
633
|
+
|
634
|
+
def filter(params)
|
635
|
+
params[0] = "(#{params[0]})" unless params[0] =~ /[()]+/
|
636
|
+
regexp = Regexp.new("(#{params[0]})", get_config(:ignore_case).to_boolean)
|
637
|
+
super get_string.gsub(regexp, "#{params[1]}\\1#{params[2]}")
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
|
642
|
+
class WrapWords < FilterWord
|
643
|
+
def self.hint; 'Wrap the words between the NTH1 and the NTH2 with SEPARATOR1 and SEPARATOR2'; end
|
644
|
+
def self.params; 'NTH1,NTH2,SEPARATOR1,SEPARATOR2'; end
|
645
|
+
|
646
|
+
def indexed_words; 2; end
|
647
|
+
|
648
|
+
def filtered_word(word, params, param_num)
|
649
|
+
case param_num
|
650
|
+
when 1
|
651
|
+
word = "#{params[2]}#{word}"
|
652
|
+
when 2
|
653
|
+
word = "#{word}#{params[3]}"
|
654
|
+
end
|
655
|
+
word
|
656
|
+
end
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
end
|