filter_rename 1.1.0 → 1.2.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 +4 -4
- data/.github/FUNDING.yml +5 -3
- data/.github/workflows/gem-push.yml +46 -0
- data/.github/workflows/main.yml +32 -0
- data/.rubocop.yml +84 -0
- data/Gemfile +15 -1
- data/README.md +83 -39
- data/Rakefile +7 -1
- data/exe/filter_rename +1 -1
- data/filter_rename.gemspec +23 -25
- data/lib/filter_rename/cli.rb +121 -61
- data/lib/filter_rename/config.rb +218 -49
- data/lib/filter_rename/filename.rb +50 -39
- data/lib/filter_rename/filename_factory.rb +22 -17
- data/lib/filter_rename/filetype/audio_filename.rb +86 -0
- data/lib/filter_rename/filetype/image_filename.rb +18 -12
- data/lib/filter_rename/filetype/mp3_filename.rb +18 -18
- data/lib/filter_rename/filetype/pdf_filename.rb +19 -12
- data/lib/filter_rename/filter_base.rb +89 -69
- data/lib/filter_rename/filter_pipe.rb +20 -15
- data/lib/filter_rename/filters.rb +570 -273
- data/lib/filter_rename/utils.rb +288 -117
- data/lib/filter_rename/version.rb +3 -1
- data/lib/filter_rename.rb +95 -32
- data/lib/filter_rename.yaml +20 -10
- metadata +28 -41
data/lib/filter_rename/utils.rb
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
require 'digest'
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
require "date"
|
|
4
|
+
require "digest"
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
#
|
|
7
|
+
# Util classes collection.
|
|
8
|
+
#
|
|
9
|
+
module FilterRename
|
|
10
|
+
FILE_SIZES = %w[B KB MB GB TB].freeze
|
|
7
11
|
|
|
8
|
-
class Boolean; end
|
|
12
|
+
class Boolean; end # rubocop:disable Lint/EmptyClass
|
|
9
13
|
|
|
14
|
+
#
|
|
15
|
+
# Transform a TrueClass to boolean.
|
|
16
|
+
#
|
|
10
17
|
class ::TrueClass
|
|
11
18
|
def to_boolean
|
|
12
|
-
|
|
19
|
+
to_s.to_boolean
|
|
13
20
|
end
|
|
14
21
|
end
|
|
15
22
|
|
|
23
|
+
#
|
|
24
|
+
# Transform a FalseClass to boolean.
|
|
25
|
+
#
|
|
16
26
|
class ::FalseClass
|
|
17
27
|
def to_boolean
|
|
18
|
-
|
|
28
|
+
to_s.to_boolean
|
|
19
29
|
end
|
|
20
30
|
end
|
|
21
31
|
|
|
32
|
+
#
|
|
33
|
+
# Mixin for readable variables.
|
|
34
|
+
#
|
|
22
35
|
module ReadableVariables
|
|
23
|
-
|
|
24
36
|
def basic!
|
|
25
37
|
@custom = false
|
|
26
38
|
self
|
|
27
39
|
end
|
|
28
40
|
|
|
29
41
|
def custom?
|
|
30
|
-
@custom == true || @custom
|
|
42
|
+
@custom == true || @custom.nil?
|
|
31
43
|
end
|
|
32
44
|
|
|
33
45
|
def readonly!
|
|
@@ -36,7 +48,7 @@ module FilterRename
|
|
|
36
48
|
end
|
|
37
49
|
|
|
38
50
|
def writable?
|
|
39
|
-
@writable || @writable
|
|
51
|
+
@writable || @writable.nil?
|
|
40
52
|
end
|
|
41
53
|
end
|
|
42
54
|
|
|
@@ -44,45 +56,112 @@ module FilterRename
|
|
|
44
56
|
include ReadableVariables
|
|
45
57
|
end
|
|
46
58
|
|
|
59
|
+
#
|
|
60
|
+
# String class patch.
|
|
61
|
+
#
|
|
47
62
|
class ::String
|
|
48
63
|
include ReadableVariables
|
|
49
64
|
|
|
50
|
-
def black
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def
|
|
65
|
+
def black
|
|
66
|
+
"\033[30m#{self}\033[0m"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def red
|
|
70
|
+
"\033[31m#{self}\033[0m"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def green
|
|
74
|
+
"\033[32m#{self}\033[0m"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def yellow
|
|
78
|
+
"\033[33m#{self}\033[0m"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def blue
|
|
82
|
+
"\033[34m#{self}\033[0m"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def magenta
|
|
86
|
+
"\033[35m#{self}\033[0m"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def cyan
|
|
90
|
+
"\033[36m#{self}\033[0m"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def gray
|
|
94
|
+
"\033[37m#{self}\033[0m"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def bg_black
|
|
98
|
+
"\033[40m#{self}\0330m"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def bg_red
|
|
102
|
+
"\033[41m#{self}\033[0m"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def bg_green
|
|
106
|
+
"\033[42m#{self}\033[0m"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def bg_brown
|
|
110
|
+
"\033[43m#{self}\033[0m"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def bg_blue
|
|
114
|
+
"\033[44m#{self}\033[0m"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def bg_magenta
|
|
118
|
+
"\033[45m#{self}\033[0m"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def bg_cyan
|
|
122
|
+
"\033[46m#{self}\033[0m"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def bg_gray
|
|
126
|
+
"\033[47m#{self}\033[0m"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def bold
|
|
130
|
+
"\033[1m#{self}\033[22m"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def reverse_color
|
|
134
|
+
"\033[7m#{self}\033[27m"
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def cr
|
|
138
|
+
"\r#{self}"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def clean
|
|
142
|
+
"\e[K#{self}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def new_line
|
|
146
|
+
"\n#{self}"
|
|
147
|
+
end
|
|
71
148
|
|
|
72
149
|
def parametrize
|
|
73
|
-
|
|
150
|
+
split(/(?<!\\),/).map { |x| x.gsub('\,', ",") }
|
|
74
151
|
end
|
|
75
152
|
|
|
153
|
+
# rubocop:disable Naming/PredicateMethod
|
|
76
154
|
def to_boolean
|
|
77
|
-
|
|
155
|
+
%w[1 true].include? downcase
|
|
78
156
|
end
|
|
157
|
+
# rubocop:enable Naming/PredicateMethod
|
|
79
158
|
|
|
80
159
|
def to_filter
|
|
81
|
-
Object.const_get("FilterRename::Filters::#{
|
|
160
|
+
Object.const_get("FilterRename::Filters::#{to_s.split(/_|-/).map(&:capitalize).join}")
|
|
82
161
|
end
|
|
83
162
|
|
|
84
163
|
def to_switch
|
|
85
|
-
|
|
164
|
+
scan(/[A-Z][a-z0-9]*/).map(&:downcase).join "-"
|
|
86
165
|
end
|
|
87
166
|
|
|
88
167
|
def change_date_format(args)
|
|
@@ -93,12 +172,12 @@ module FilterRename
|
|
|
93
172
|
long_days = args[:long_days]
|
|
94
173
|
short_days = args[:short_days]
|
|
95
174
|
|
|
96
|
-
str =
|
|
175
|
+
str = clone
|
|
97
176
|
|
|
98
|
-
regexp = format_src.gsub(
|
|
99
|
-
.gsub(
|
|
100
|
-
.gsub(
|
|
101
|
-
.gsub(
|
|
177
|
+
regexp = format_src.gsub("<B>", "(#{long_months.join("|")})").gsub("<b>", "(#{short_months.join("|")})")
|
|
178
|
+
.gsub("<A>", "(#{long_days.join("|")})").gsub("<a>", "(#{short_days.join("|")})")
|
|
179
|
+
.gsub("<Y>", "[0-9]{4,4}").gsub(/<(d|m|y|H|I|M|S|U)>/, "[0-9]{2,2}")
|
|
180
|
+
.gsub("<u>", "[0-9]{1,1}")
|
|
102
181
|
|
|
103
182
|
to_replace = str.scan(Regexp.new("(#{regexp})", true))
|
|
104
183
|
|
|
@@ -113,201 +192,293 @@ module FilterRename
|
|
|
113
192
|
str
|
|
114
193
|
end
|
|
115
194
|
|
|
116
|
-
def map_number_with_index
|
|
117
|
-
|
|
118
|
-
yield num, i
|
|
119
|
-
end
|
|
195
|
+
def map_number_with_index(&block)
|
|
196
|
+
gsub(/\d+/).with_index(&block)
|
|
120
197
|
end
|
|
121
198
|
|
|
122
199
|
def get_number(idx)
|
|
123
|
-
|
|
200
|
+
scan(/\d+/)[idx]
|
|
124
201
|
end
|
|
125
202
|
|
|
126
|
-
def
|
|
127
|
-
|
|
203
|
+
def numbers
|
|
204
|
+
scan(/\d+/)
|
|
128
205
|
end
|
|
129
206
|
end
|
|
130
207
|
|
|
131
|
-
|
|
208
|
+
#
|
|
209
|
+
# Format the error messages.
|
|
210
|
+
#
|
|
132
211
|
class Messages
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
puts '[E] '.bold.red + e
|
|
212
|
+
def self.error(err)
|
|
213
|
+
if err.instance_of?(String)
|
|
214
|
+
puts "[E] ".bold.red + err
|
|
137
215
|
else
|
|
138
|
-
|
|
216
|
+
warn "Error! ".bold.red + err.message
|
|
139
217
|
end
|
|
140
218
|
end
|
|
141
219
|
|
|
142
|
-
def self.warning(
|
|
143
|
-
puts
|
|
220
|
+
def self.warning(msg)
|
|
221
|
+
puts "[W] ".bold.yellow + msg
|
|
144
222
|
end
|
|
145
223
|
|
|
146
|
-
def self.ok(
|
|
147
|
-
puts
|
|
224
|
+
def self.ok(msg)
|
|
225
|
+
puts "[V] ".bold.green + msg
|
|
148
226
|
end
|
|
149
227
|
|
|
150
|
-
def self.multi(
|
|
151
|
-
puts
|
|
228
|
+
def self.multi(msg)
|
|
229
|
+
puts "[*] ".bold.magenta + msg
|
|
152
230
|
end
|
|
153
231
|
|
|
154
|
-
def self.diff(
|
|
155
|
-
puts
|
|
232
|
+
def self.diff(fpipe)
|
|
233
|
+
puts fpipe.diff
|
|
156
234
|
end
|
|
157
235
|
|
|
158
|
-
def self.renamed(
|
|
159
|
-
if
|
|
160
|
-
Messages.ok "#{
|
|
236
|
+
def self.renamed(fpipe)
|
|
237
|
+
if fpipe.source.full_path == fpipe.dest.full_path
|
|
238
|
+
Messages.ok "#{fpipe.source.filename} #{">".bold.green} #{fpipe.dest.filename}"
|
|
161
239
|
else
|
|
162
|
-
Messages.ok "#{
|
|
240
|
+
Messages.ok "#{fpipe.source.filename} #{">".bold.green} #{fpipe.dest.full_filename}"
|
|
163
241
|
end
|
|
164
242
|
end
|
|
165
243
|
|
|
166
244
|
def self.renamed!(old_data, renamed)
|
|
167
|
-
if old_data[:full_path]
|
|
168
|
-
Messages.ok "#{old_data[:filename]} #{
|
|
245
|
+
if old_data[:full_path] == renamed.full_path
|
|
246
|
+
Messages.ok "#{old_data[:filename]} #{">".bold.green} #{renamed.filename}"
|
|
169
247
|
else
|
|
170
|
-
Messages.ok "#{old_data[:filename]} #{
|
|
248
|
+
Messages.ok "#{old_data[:filename]} #{">".bold.green} #{renamed.full_filename}"
|
|
171
249
|
end
|
|
172
250
|
end
|
|
173
251
|
|
|
174
|
-
|
|
175
252
|
def self.label(text)
|
|
176
|
-
puts "#{
|
|
253
|
+
puts "#{"[/]".bold.blue} #{text}"
|
|
177
254
|
end
|
|
178
255
|
|
|
179
|
-
def self.skipping(
|
|
180
|
-
puts
|
|
256
|
+
def self.skipping(fpipe)
|
|
257
|
+
puts "[X] ".bold.yellow + "Skipping <#{fpipe.source.filename}>, no changes!"
|
|
181
258
|
end
|
|
182
259
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
260
|
+
# rubocop:disable Style/HashEachMethods
|
|
261
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
|
262
|
+
def self.changed_tags(fpipe, old_data = {}, header = true)
|
|
263
|
+
Messages.ok "<#{fpipe.source.filename}> tags changed:" if header
|
|
264
|
+
old_source = old_data.empty? ? fpipe.source.values : old_data
|
|
186
265
|
|
|
187
|
-
|
|
188
|
-
|
|
266
|
+
fpipe.dest.values.each do |k, v|
|
|
267
|
+
next unless (v.to_s != old_source[k].to_s) && fpipe.source.writable?(k) && fpipe.source.custom?(k)
|
|
268
|
+
|
|
269
|
+
puts " #{k}: ".rjust(15, " ")
|
|
270
|
+
.bold.green +
|
|
271
|
+
(if old_source[k].to_s.empty?
|
|
272
|
+
" ~ ".bold.red
|
|
273
|
+
else
|
|
274
|
+
old_source[k].to_s
|
|
275
|
+
end) + " => ".bold.green + v.to_s
|
|
189
276
|
end
|
|
190
277
|
end
|
|
278
|
+
# rubocop:enable Style/HashEachMethods
|
|
279
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
|
191
280
|
|
|
192
|
-
def self.file_exists(
|
|
193
|
-
Messages.error "<#{
|
|
281
|
+
def self.file_exists(fpipe)
|
|
282
|
+
Messages.error "<#{fpipe.source.filename}> can't be renamed in <#{fpipe.dest.filename}>, it exists!"
|
|
194
283
|
end
|
|
195
284
|
|
|
196
|
-
def self.file_hash(
|
|
197
|
-
raise UnknownHashCode, hash_type unless [
|
|
285
|
+
def self.file_hash(fpipe, hash_type, cached = nil)
|
|
286
|
+
raise UnknownHashCode, hash_type unless %i[sha1 sha2 md5].include?(hash_type.to_sym)
|
|
287
|
+
|
|
198
288
|
klass = Object.const_get("Digest::#{hash_type.to_s.upcase}")
|
|
199
|
-
hash_src = klass.file
|
|
200
|
-
hash_dest = cached ? klass.file(cached.original) : klass.file(
|
|
289
|
+
hash_src = klass.file fpipe.source.filename
|
|
290
|
+
hash_dest = cached ? klass.file(cached.original) : klass.file(fpipe.dest.filename)
|
|
201
291
|
|
|
202
|
-
puts " #{hash_src == hash_dest ?
|
|
203
|
-
|
|
292
|
+
puts " #{hash_src == hash_dest ? "[=]".green : "[>]".red} " \
|
|
293
|
+
"#{hash_type.to_s.upcase} source: " \
|
|
294
|
+
"#{hash_src.to_s.send(hash_src == hash_dest ? :green : :red)}"
|
|
295
|
+
puts " #{hash_src == hash_dest ? "[=]".green : "[<]".red} " \
|
|
296
|
+
"#{hash_type.to_s.upcase} dest: " \
|
|
297
|
+
"#{hash_dest.to_s.send(hash_src == hash_dest ? :green : :red)}"
|
|
204
298
|
end
|
|
205
299
|
|
|
206
|
-
def self.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
300
|
+
def self.renaming_summary(renamed, skipped, errors)
|
|
301
|
+
puts ""
|
|
302
|
+
puts "=" * 40
|
|
303
|
+
Messages.ok("Renamed: #{renamed}")
|
|
304
|
+
Messages.warning("Unchanged: #{skipped}")
|
|
305
|
+
Messages.error("Errors: #{errors}")
|
|
210
306
|
end
|
|
211
307
|
|
|
212
|
-
def self.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
puts
|
|
308
|
+
def self.inline_targets(ffilters)
|
|
309
|
+
list [ffilters.targets[:readonly].map { |s| "<#{s.to_s.delete("@")}>" }.join(", ")], :red, "-"
|
|
310
|
+
list [ffilters.targets[:writable].map { |s| "<#{s.to_s.delete("@")}>" }.join(", ")], :green, "+"
|
|
311
|
+
puts ""
|
|
216
312
|
end
|
|
217
313
|
|
|
218
|
-
def self.
|
|
219
|
-
|
|
314
|
+
def self.column_targets(ffilters)
|
|
315
|
+
list ffilters.targets[:readonly].map { |s| "<#{s.to_s.delete("@")}>" }, :red, "-"
|
|
316
|
+
list ffilters.targets[:writable].map { |s| "<#{s.to_s.delete("@")}>" }, :green, "+"
|
|
317
|
+
puts ""
|
|
220
318
|
end
|
|
221
319
|
|
|
222
|
-
def self.
|
|
223
|
-
|
|
320
|
+
def self.inline_target_values(ffilters)
|
|
321
|
+
values = ffilters.values
|
|
322
|
+
|
|
323
|
+
list [ffilters.targets[:readonly].map { |s| "#{s}: #{values[s]}" }.join(", ")], :red, "-"
|
|
324
|
+
list [ffilters.targets[:writable].map { |s| "#{s}: #{values[s]}" }.join(", ")], :green, "+"
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def self.column_target_values(ffilters)
|
|
328
|
+
values = ffilters.values
|
|
329
|
+
|
|
330
|
+
list ffilters.targets[:readonly].map { |s| "#{s}: #{values[s]}" }, :red, "-"
|
|
331
|
+
list ffilters.targets[:writable].map { |s| "#{s}: #{values[s]}" }, :green, "+"
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def self.item(idx, color = :green, char = ">")
|
|
335
|
+
puts "[#{char}] ".bold.send(color) + idx
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def self.list(items, color = :green, char = ">")
|
|
339
|
+
items.each { |x| Messages.item(x, color, char) }
|
|
224
340
|
end
|
|
225
341
|
|
|
226
|
-
def self.config_list(items, color = :green,
|
|
227
|
-
items.instance_variables.each
|
|
342
|
+
def self.config_list(items, color = :green, char = ">")
|
|
343
|
+
items.instance_variables.each do |k|
|
|
344
|
+
Messages.item("#{k.to_s.gsub(/@/, "")}: #{items.instance_variable_get(k)}", color, char)
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def self.config_multilist(items, color = :green, char = ">")
|
|
349
|
+
items.instance_variables.each do |k|
|
|
350
|
+
Messages.item("#{k.to_s.gsub(/@/, "")}: [#{items.instance_variable_get(k).keys.join(", ")}]", color, char)
|
|
351
|
+
end
|
|
228
352
|
end
|
|
229
353
|
|
|
230
|
-
def self.
|
|
231
|
-
|
|
354
|
+
def self.help_option(name, data)
|
|
355
|
+
puts "OPTION:\n #{name}"
|
|
356
|
+
puts "\nDEFAULT VALUE:\n #{data[:default] == " " ? "(SPACE)" : data[:default]}"
|
|
357
|
+
puts "\nDESCRIPTION:\n#{data[:long].split("\n").map { |l| " #{l}" }.join("\n")}"
|
|
358
|
+
puts ""
|
|
232
359
|
end
|
|
233
360
|
end
|
|
234
361
|
|
|
362
|
+
#
|
|
363
|
+
# Index out of range error.
|
|
364
|
+
#
|
|
235
365
|
class IndexOutOfRange < StandardError
|
|
236
366
|
def initialize(values)
|
|
237
|
-
super
|
|
367
|
+
super("Invalid index '#{values[0]}' out of the range 1..#{values[1]}, -#{values[1]}..-1")
|
|
238
368
|
end
|
|
239
369
|
end
|
|
240
370
|
|
|
371
|
+
#
|
|
372
|
+
# Unknown hash error.
|
|
373
|
+
#
|
|
241
374
|
class UnknownHashCode < StandardError
|
|
242
375
|
def initialize(hash_type)
|
|
243
|
-
super
|
|
376
|
+
super("Invalid hash type: #{hash_type}")
|
|
244
377
|
end
|
|
245
378
|
end
|
|
246
379
|
|
|
380
|
+
#
|
|
381
|
+
# Invalid option as argument.
|
|
382
|
+
#
|
|
383
|
+
class InvalidOption < StandardError
|
|
384
|
+
def initialize(option)
|
|
385
|
+
super("The option #{option} doesn't exist")
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
#
|
|
390
|
+
# Invalid macro error.
|
|
391
|
+
#
|
|
247
392
|
class InvalidMacro < StandardError
|
|
248
393
|
def initialize(macro)
|
|
249
|
-
super
|
|
394
|
+
super("Invalid macro: #{macro}")
|
|
250
395
|
end
|
|
251
396
|
end
|
|
252
397
|
|
|
398
|
+
#
|
|
399
|
+
# Invalid target error.
|
|
400
|
+
#
|
|
253
401
|
class InvalidTarget < StandardError
|
|
254
402
|
def initialize(target)
|
|
255
|
-
super
|
|
403
|
+
super("Invalid target: #{target}")
|
|
256
404
|
end
|
|
257
405
|
end
|
|
258
406
|
|
|
407
|
+
#
|
|
408
|
+
# Invalid filter setting error.
|
|
409
|
+
#
|
|
259
410
|
class InvalidFilterSetting < StandardError
|
|
260
411
|
def initialize(name)
|
|
261
|
-
super
|
|
412
|
+
super("Invalid configuration setting: #{name}")
|
|
262
413
|
end
|
|
263
414
|
end
|
|
264
415
|
|
|
416
|
+
#
|
|
417
|
+
# Invalid word's group.
|
|
418
|
+
#
|
|
265
419
|
class InvalidWordsGroup < StandardError
|
|
266
420
|
def initialize(group)
|
|
267
|
-
super
|
|
421
|
+
super("Invalid words group: #{group}")
|
|
268
422
|
end
|
|
269
423
|
end
|
|
270
424
|
|
|
425
|
+
#
|
|
426
|
+
# Invalid words section.
|
|
427
|
+
#
|
|
271
428
|
class InvalidWordsSection < StandardError
|
|
272
429
|
def initialize(group, section)
|
|
273
|
-
super
|
|
430
|
+
super("Invalid words section for #{group}: #{section}")
|
|
274
431
|
end
|
|
275
432
|
end
|
|
276
433
|
|
|
434
|
+
#
|
|
435
|
+
# Invalid words index.
|
|
436
|
+
#
|
|
277
437
|
class InvalidWordsIndex < StandardError
|
|
278
438
|
def initialize(group, section, idx)
|
|
279
|
-
super
|
|
439
|
+
super("Missing the item #{idx + 1} in #{group}/#{section} words section")
|
|
280
440
|
end
|
|
281
441
|
end
|
|
282
442
|
|
|
443
|
+
#
|
|
444
|
+
# File not found error.
|
|
445
|
+
#
|
|
283
446
|
class FileNotFound < StandardError
|
|
284
447
|
def initialize(filename)
|
|
285
|
-
super
|
|
448
|
+
super("File not found: #{filename}")
|
|
286
449
|
end
|
|
287
450
|
end
|
|
288
451
|
|
|
452
|
+
#
|
|
453
|
+
# Missing files error.
|
|
454
|
+
#
|
|
289
455
|
class MissingFiles < StandardError
|
|
290
456
|
def initialize
|
|
291
|
-
super
|
|
457
|
+
super("No filenames specified")
|
|
292
458
|
end
|
|
293
459
|
end
|
|
294
460
|
|
|
461
|
+
#
|
|
462
|
+
# Existing file error.
|
|
463
|
+
#
|
|
295
464
|
class ExistingFile < StandardError
|
|
296
465
|
def initialize(filename)
|
|
297
|
-
super
|
|
466
|
+
super("The file #{filename} already exists and won't be overwrite")
|
|
298
467
|
end
|
|
299
468
|
end
|
|
300
469
|
|
|
470
|
+
#
|
|
471
|
+
# Ctrl + C message error.
|
|
472
|
+
#
|
|
301
473
|
class Interruption < StandardError
|
|
302
474
|
def initialize
|
|
303
|
-
super
|
|
475
|
+
super("Ok ok... Exiting!")
|
|
304
476
|
end
|
|
305
477
|
end
|
|
306
478
|
|
|
479
|
+
Differ.format = :color
|
|
307
480
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
Signal.trap('INT') { raise Interruption }
|
|
481
|
+
Signal.trap("INT") { raise Interruption }
|
|
311
482
|
|
|
312
|
-
Signal.trap(
|
|
483
|
+
Signal.trap("TERM") { raise Interruption }
|
|
313
484
|
end
|