filter_rename 1.0.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 +16 -0
- 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 +219 -46
- data/lib/filter_rename/filename.rb +59 -35
- 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 +23 -21
- data/lib/filter_rename/filetype/pdf_filename.rb +19 -12
- data/lib/filter_rename/filter_base.rb +171 -70
- data/lib/filter_rename/filter_pipe.rb +20 -15
- data/lib/filter_rename/filters.rb +737 -269
- data/lib/filter_rename/utils.rb +306 -105
- data/lib/filter_rename/version.rb +3 -1
- data/lib/filter_rename.rb +100 -34
- data/lib/filter_rename.yaml +27 -13
- metadata +34 -44
data/lib/filter_rename/utils.rb
CHANGED
|
@@ -1,24 +1,46 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "date"
|
|
4
|
+
require "digest"
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
#
|
|
7
|
+
# Util classes collection.
|
|
8
|
+
#
|
|
9
|
+
module FilterRename
|
|
10
|
+
FILE_SIZES = %w[B KB MB GB TB].freeze
|
|
6
11
|
|
|
7
|
-
class Boolean; end
|
|
12
|
+
class Boolean; end # rubocop:disable Lint/EmptyClass
|
|
8
13
|
|
|
14
|
+
#
|
|
15
|
+
# Transform a TrueClass to boolean.
|
|
16
|
+
#
|
|
9
17
|
class ::TrueClass
|
|
10
18
|
def to_boolean
|
|
11
|
-
|
|
19
|
+
to_s.to_boolean
|
|
12
20
|
end
|
|
13
21
|
end
|
|
14
22
|
|
|
23
|
+
#
|
|
24
|
+
# Transform a FalseClass to boolean.
|
|
25
|
+
#
|
|
15
26
|
class ::FalseClass
|
|
16
27
|
def to_boolean
|
|
17
|
-
|
|
28
|
+
to_s.to_boolean
|
|
18
29
|
end
|
|
19
30
|
end
|
|
20
31
|
|
|
32
|
+
#
|
|
33
|
+
# Mixin for readable variables.
|
|
34
|
+
#
|
|
21
35
|
module ReadableVariables
|
|
36
|
+
def basic!
|
|
37
|
+
@custom = false
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def custom?
|
|
42
|
+
@custom == true || @custom.nil?
|
|
43
|
+
end
|
|
22
44
|
|
|
23
45
|
def readonly!
|
|
24
46
|
@writable = false
|
|
@@ -26,7 +48,7 @@ module FilterRename
|
|
|
26
48
|
end
|
|
27
49
|
|
|
28
50
|
def writable?
|
|
29
|
-
@writable || @writable
|
|
51
|
+
@writable || @writable.nil?
|
|
30
52
|
end
|
|
31
53
|
end
|
|
32
54
|
|
|
@@ -34,45 +56,112 @@ module FilterRename
|
|
|
34
56
|
include ReadableVariables
|
|
35
57
|
end
|
|
36
58
|
|
|
59
|
+
#
|
|
60
|
+
# String class patch.
|
|
61
|
+
#
|
|
37
62
|
class ::String
|
|
38
63
|
include ReadableVariables
|
|
39
64
|
|
|
40
|
-
def black
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
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
|
|
61
148
|
|
|
62
149
|
def parametrize
|
|
63
|
-
|
|
150
|
+
split(/(?<!\\),/).map { |x| x.gsub('\,', ",") }
|
|
64
151
|
end
|
|
65
152
|
|
|
153
|
+
# rubocop:disable Naming/PredicateMethod
|
|
66
154
|
def to_boolean
|
|
67
|
-
|
|
155
|
+
%w[1 true].include? downcase
|
|
68
156
|
end
|
|
157
|
+
# rubocop:enable Naming/PredicateMethod
|
|
69
158
|
|
|
70
159
|
def to_filter
|
|
71
|
-
Object.const_get("FilterRename::Filters::#{
|
|
160
|
+
Object.const_get("FilterRename::Filters::#{to_s.split(/_|-/).map(&:capitalize).join}")
|
|
72
161
|
end
|
|
73
162
|
|
|
74
163
|
def to_switch
|
|
75
|
-
|
|
164
|
+
scan(/[A-Z][a-z0-9]*/).map(&:downcase).join "-"
|
|
76
165
|
end
|
|
77
166
|
|
|
78
167
|
def change_date_format(args)
|
|
@@ -83,12 +172,12 @@ module FilterRename
|
|
|
83
172
|
long_days = args[:long_days]
|
|
84
173
|
short_days = args[:short_days]
|
|
85
174
|
|
|
86
|
-
str =
|
|
175
|
+
str = clone
|
|
87
176
|
|
|
88
|
-
regexp = format_src.gsub(
|
|
89
|
-
.gsub(
|
|
90
|
-
.gsub(
|
|
91
|
-
.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}")
|
|
92
181
|
|
|
93
182
|
to_replace = str.scan(Regexp.new("(#{regexp})", true))
|
|
94
183
|
|
|
@@ -103,181 +192,293 @@ module FilterRename
|
|
|
103
192
|
str
|
|
104
193
|
end
|
|
105
194
|
|
|
106
|
-
def map_number_with_index
|
|
107
|
-
|
|
108
|
-
yield num, i
|
|
109
|
-
end
|
|
195
|
+
def map_number_with_index(&block)
|
|
196
|
+
gsub(/\d+/).with_index(&block)
|
|
110
197
|
end
|
|
111
198
|
|
|
112
199
|
def get_number(idx)
|
|
113
|
-
|
|
200
|
+
scan(/\d+/)[idx]
|
|
114
201
|
end
|
|
115
|
-
end
|
|
116
202
|
|
|
203
|
+
def numbers
|
|
204
|
+
scan(/\d+/)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
117
207
|
|
|
208
|
+
#
|
|
209
|
+
# Format the error messages.
|
|
210
|
+
#
|
|
118
211
|
class Messages
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
puts '[E] '.bold.red + e
|
|
212
|
+
def self.error(err)
|
|
213
|
+
if err.instance_of?(String)
|
|
214
|
+
puts "[E] ".bold.red + err
|
|
123
215
|
else
|
|
124
|
-
|
|
216
|
+
warn "Error! ".bold.red + err.message
|
|
125
217
|
end
|
|
126
218
|
end
|
|
127
219
|
|
|
128
|
-
def self.warning(
|
|
129
|
-
puts
|
|
220
|
+
def self.warning(msg)
|
|
221
|
+
puts "[W] ".bold.yellow + msg
|
|
130
222
|
end
|
|
131
223
|
|
|
132
|
-
def self.ok(
|
|
133
|
-
puts
|
|
224
|
+
def self.ok(msg)
|
|
225
|
+
puts "[V] ".bold.green + msg
|
|
134
226
|
end
|
|
135
227
|
|
|
136
|
-
def self.multi(
|
|
137
|
-
puts
|
|
228
|
+
def self.multi(msg)
|
|
229
|
+
puts "[*] ".bold.magenta + msg
|
|
138
230
|
end
|
|
139
231
|
|
|
140
|
-
def self.diff(
|
|
141
|
-
puts
|
|
232
|
+
def self.diff(fpipe)
|
|
233
|
+
puts fpipe.diff
|
|
142
234
|
end
|
|
143
235
|
|
|
144
|
-
def self.renamed(
|
|
145
|
-
if
|
|
146
|
-
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}"
|
|
147
239
|
else
|
|
148
|
-
Messages.ok "#{
|
|
240
|
+
Messages.ok "#{fpipe.source.filename} #{">".bold.green} #{fpipe.dest.full_filename}"
|
|
149
241
|
end
|
|
150
242
|
end
|
|
151
243
|
|
|
152
244
|
def self.renamed!(old_data, renamed)
|
|
153
|
-
if old_data[:full_path]
|
|
154
|
-
Messages.ok "#{old_data[:filename]} #{
|
|
245
|
+
if old_data[:full_path] == renamed.full_path
|
|
246
|
+
Messages.ok "#{old_data[:filename]} #{">".bold.green} #{renamed.filename}"
|
|
155
247
|
else
|
|
156
|
-
Messages.ok "#{old_data[:filename]} #{
|
|
248
|
+
Messages.ok "#{old_data[:filename]} #{">".bold.green} #{renamed.full_filename}"
|
|
157
249
|
end
|
|
158
250
|
end
|
|
159
251
|
|
|
160
|
-
|
|
161
252
|
def self.label(text)
|
|
162
|
-
puts "#{
|
|
253
|
+
puts "#{"[/]".bold.blue} #{text}"
|
|
163
254
|
end
|
|
164
255
|
|
|
165
|
-
def self.skipping(
|
|
166
|
-
puts
|
|
256
|
+
def self.skipping(fpipe)
|
|
257
|
+
puts "[X] ".bold.yellow + "Skipping <#{fpipe.source.filename}>, no changes!"
|
|
167
258
|
end
|
|
168
259
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
|
265
|
+
|
|
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)
|
|
172
268
|
|
|
173
|
-
|
|
174
|
-
|
|
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
|
|
175
276
|
end
|
|
176
277
|
end
|
|
278
|
+
# rubocop:enable Style/HashEachMethods
|
|
279
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
|
280
|
+
|
|
281
|
+
def self.file_exists(fpipe)
|
|
282
|
+
Messages.error "<#{fpipe.source.filename}> can't be renamed in <#{fpipe.dest.filename}>, it exists!"
|
|
283
|
+
end
|
|
284
|
+
|
|
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
|
+
|
|
288
|
+
klass = Object.const_get("Digest::#{hash_type.to_s.upcase}")
|
|
289
|
+
hash_src = klass.file fpipe.source.filename
|
|
290
|
+
hash_dest = cached ? klass.file(cached.original) : klass.file(fpipe.dest.filename)
|
|
291
|
+
|
|
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)}"
|
|
298
|
+
end
|
|
299
|
+
|
|
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}")
|
|
306
|
+
end
|
|
307
|
+
|
|
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 ""
|
|
312
|
+
end
|
|
177
313
|
|
|
178
|
-
def self.
|
|
179
|
-
|
|
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 ""
|
|
180
318
|
end
|
|
181
319
|
|
|
182
|
-
def self.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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, "+"
|
|
186
325
|
end
|
|
187
326
|
|
|
188
|
-
def self.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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, "+"
|
|
192
332
|
end
|
|
193
333
|
|
|
194
|
-
def self.item(
|
|
195
|
-
puts "[#{
|
|
334
|
+
def self.item(idx, color = :green, char = ">")
|
|
335
|
+
puts "[#{char}] ".bold.send(color) + idx
|
|
196
336
|
end
|
|
197
337
|
|
|
198
|
-
def self.list(items, color = :green,
|
|
199
|
-
items.each { |x| Messages.item(x, color,
|
|
338
|
+
def self.list(items, color = :green, char = ">")
|
|
339
|
+
items.each { |x| Messages.item(x, color, char) }
|
|
200
340
|
end
|
|
201
341
|
|
|
202
|
-
def self.config_list(items, color = :green,
|
|
203
|
-
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
|
|
204
346
|
end
|
|
205
347
|
|
|
206
|
-
def self.config_multilist(items, color = :green,
|
|
207
|
-
items.instance_variables.each
|
|
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
|
|
352
|
+
end
|
|
353
|
+
|
|
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 ""
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
#
|
|
363
|
+
# Index out of range error.
|
|
364
|
+
#
|
|
365
|
+
class IndexOutOfRange < StandardError
|
|
366
|
+
def initialize(values)
|
|
367
|
+
super("Invalid index '#{values[0]}' out of the range 1..#{values[1]}, -#{values[1]}..-1")
|
|
208
368
|
end
|
|
209
369
|
end
|
|
210
370
|
|
|
371
|
+
#
|
|
372
|
+
# Unknown hash error.
|
|
373
|
+
#
|
|
211
374
|
class UnknownHashCode < StandardError
|
|
212
375
|
def initialize(hash_type)
|
|
213
|
-
super
|
|
376
|
+
super("Invalid hash type: #{hash_type}")
|
|
214
377
|
end
|
|
215
378
|
end
|
|
216
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
|
+
#
|
|
217
392
|
class InvalidMacro < StandardError
|
|
218
393
|
def initialize(macro)
|
|
219
|
-
super
|
|
394
|
+
super("Invalid macro: #{macro}")
|
|
220
395
|
end
|
|
221
396
|
end
|
|
222
397
|
|
|
398
|
+
#
|
|
399
|
+
# Invalid target error.
|
|
400
|
+
#
|
|
223
401
|
class InvalidTarget < StandardError
|
|
224
402
|
def initialize(target)
|
|
225
|
-
super
|
|
403
|
+
super("Invalid target: #{target}")
|
|
226
404
|
end
|
|
227
405
|
end
|
|
228
406
|
|
|
407
|
+
#
|
|
408
|
+
# Invalid filter setting error.
|
|
409
|
+
#
|
|
229
410
|
class InvalidFilterSetting < StandardError
|
|
230
411
|
def initialize(name)
|
|
231
|
-
super
|
|
412
|
+
super("Invalid configuration setting: #{name}")
|
|
232
413
|
end
|
|
233
414
|
end
|
|
234
415
|
|
|
416
|
+
#
|
|
417
|
+
# Invalid word's group.
|
|
418
|
+
#
|
|
235
419
|
class InvalidWordsGroup < StandardError
|
|
236
420
|
def initialize(group)
|
|
237
|
-
super
|
|
421
|
+
super("Invalid words group: #{group}")
|
|
238
422
|
end
|
|
239
423
|
end
|
|
240
424
|
|
|
425
|
+
#
|
|
426
|
+
# Invalid words section.
|
|
427
|
+
#
|
|
241
428
|
class InvalidWordsSection < StandardError
|
|
242
429
|
def initialize(group, section)
|
|
243
|
-
super
|
|
430
|
+
super("Invalid words section for #{group}: #{section}")
|
|
244
431
|
end
|
|
245
432
|
end
|
|
246
433
|
|
|
434
|
+
#
|
|
435
|
+
# Invalid words index.
|
|
436
|
+
#
|
|
247
437
|
class InvalidWordsIndex < StandardError
|
|
248
438
|
def initialize(group, section, idx)
|
|
249
|
-
super
|
|
439
|
+
super("Missing the item #{idx + 1} in #{group}/#{section} words section")
|
|
250
440
|
end
|
|
251
441
|
end
|
|
252
442
|
|
|
443
|
+
#
|
|
444
|
+
# File not found error.
|
|
445
|
+
#
|
|
253
446
|
class FileNotFound < StandardError
|
|
254
447
|
def initialize(filename)
|
|
255
|
-
super
|
|
448
|
+
super("File not found: #{filename}")
|
|
256
449
|
end
|
|
257
450
|
end
|
|
258
451
|
|
|
452
|
+
#
|
|
453
|
+
# Missing files error.
|
|
454
|
+
#
|
|
259
455
|
class MissingFiles < StandardError
|
|
260
456
|
def initialize
|
|
261
|
-
super
|
|
457
|
+
super("No filenames specified")
|
|
262
458
|
end
|
|
263
459
|
end
|
|
264
460
|
|
|
461
|
+
#
|
|
462
|
+
# Existing file error.
|
|
463
|
+
#
|
|
265
464
|
class ExistingFile < StandardError
|
|
266
465
|
def initialize(filename)
|
|
267
|
-
super
|
|
466
|
+
super("The file #{filename} already exists and won't be overwrite")
|
|
268
467
|
end
|
|
269
468
|
end
|
|
270
469
|
|
|
470
|
+
#
|
|
471
|
+
# Ctrl + C message error.
|
|
472
|
+
#
|
|
271
473
|
class Interruption < StandardError
|
|
272
474
|
def initialize
|
|
273
|
-
super
|
|
475
|
+
super("Ok ok... Exiting!")
|
|
274
476
|
end
|
|
275
477
|
end
|
|
276
478
|
|
|
479
|
+
Differ.format = :color
|
|
277
480
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
Signal.trap('INT') { raise Interruption }
|
|
481
|
+
Signal.trap("INT") { raise Interruption }
|
|
281
482
|
|
|
282
|
-
Signal.trap(
|
|
483
|
+
Signal.trap("TERM") { raise Interruption }
|
|
283
484
|
end
|