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.
@@ -1,24 +1,46 @@
1
- require 'date'
1
+ # frozen_string_literal: true
2
2
 
3
- module FilterRename
3
+ require "date"
4
+ require "digest"
4
5
 
5
- FILE_SIZES = ['B', 'KB', 'MB', 'GB', 'TB']
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
- self.to_s.to_boolean
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
- self.to_s.to_boolean
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 == nil
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; "\033[30m#{self}\033[0m" end
41
- def red; "\033[31m#{self}\033[0m" end
42
- def green; "\033[32m#{self}\033[0m" end
43
- def yellow; "\033[33m#{self}\033[0m" end
44
- def blue; "\033[34m#{self}\033[0m" end
45
- def magenta; "\033[35m#{self}\033[0m" end
46
- def cyan; "\033[36m#{self}\033[0m" end
47
- def gray; "\033[37m#{self}\033[0m" end
48
- def bg_black; "\033[40m#{self}\0330m" end
49
- def bg_red; "\033[41m#{self}\033[0m" end
50
- def bg_green; "\033[42m#{self}\033[0m" end
51
- def bg_brown; "\033[43m#{self}\033[0m" end
52
- def bg_blue; "\033[44m#{self}\033[0m" end
53
- def bg_magenta; "\033[45m#{self}\033[0m" end
54
- def bg_cyan; "\033[46m#{self}\033[0m" end
55
- def bg_gray; "\033[47m#{self}\033[0m" end
56
- def bold; "\033[1m#{self}\033[22m" end
57
- def reverse_color; "\033[7m#{self}\033[27m" end
58
- def cr; "\r#{self}" end
59
- def clean; "\e[K#{self}" end
60
- def new_line; "\n#{self}" end
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
- self.split(/(?<!\\),/).map { |x| x.gsub('\,', ',') }
150
+ split(/(?<!\\),/).map { |x| x.gsub('\,', ",") }
64
151
  end
65
152
 
153
+ # rubocop:disable Naming/PredicateMethod
66
154
  def to_boolean
67
- self == 'true'
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::#{self.to_s.split(/_|-/).map(&:capitalize).join}")
160
+ Object.const_get("FilterRename::Filters::#{to_s.split(/_|-/).map(&:capitalize).join}")
72
161
  end
73
162
 
74
163
  def to_switch
75
- self.scan(/[A-Z][a-z0-9]*/).map(&:downcase).join '-'
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 = self.clone
175
+ str = clone
87
176
 
88
- regexp = format_src.gsub('<B>', "(#{long_months.join('|')})").gsub('<b>', "(#{short_months.join('|')})")
89
- .gsub('<A>', "(#{long_days.join('|')})").gsub('<a>', "(#{short_days.join('|')})")
90
- .gsub('<Y>', '[0-9]{4,4}').gsub(/<(d|m|y|H|I|M|S|U)>/, '[0-9]{2,2}')
91
- .gsub('<u>', '[0-9]{1,1}')
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
- self.gsub(/\d+/).with_index do |num, i|
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
- self.scan(/\d+/)[idx]
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
- def self.error(e)
121
- if e.class == String
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
- STDERR.puts 'Error! '.bold.red + e.message
216
+ warn "Error! ".bold.red + err.message
125
217
  end
126
218
  end
127
219
 
128
- def self.warning(m)
129
- puts '[W] '.bold.yellow + m
220
+ def self.warning(msg)
221
+ puts "[W] ".bold.yellow + msg
130
222
  end
131
223
 
132
- def self.ok(m)
133
- puts '[V] '.bold.green + m
224
+ def self.ok(msg)
225
+ puts "[V] ".bold.green + msg
134
226
  end
135
227
 
136
- def self.multi(m)
137
- puts '[*] '.bold.magenta + m
228
+ def self.multi(msg)
229
+ puts "[*] ".bold.magenta + msg
138
230
  end
139
231
 
140
- def self.diff(fp)
141
- puts fp.diff
232
+ def self.diff(fpipe)
233
+ puts fpipe.diff
142
234
  end
143
235
 
144
- def self.renamed(fp)
145
- if fp.source.full_path != fp.dest.full_path
146
- Messages.ok "#{fp.source.filename} #{'>'.bold.green} #{fp.dest.full_filename}"
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 "#{fp.source.filename} #{'>'.bold.green} #{fp.dest.filename}"
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] != renamed.full_path
154
- Messages.ok "#{old_data[:filename]} #{'>'.bold.green} #{renamed.full_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]} #{'>'.bold.green} #{renamed.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 "#{'[/]'.bold.blue} #{text}"
253
+ puts "#{"[/]".bold.blue} #{text}"
163
254
  end
164
255
 
165
- def self.skipping(fp)
166
- puts '[X] '.bold.yellow + "Skipping <#{fp.source.filename}>, no changes!"
256
+ def self.skipping(fpipe)
257
+ puts "[X] ".bold.yellow + "Skipping <#{fpipe.source.filename}>, no changes!"
167
258
  end
168
259
 
169
- def self.changed_tags(fp, old_data = {}, header = true)
170
- Messages.ok "<#{fp.source.filename}> tags changed:" if header
171
- old_source = old_data.empty? ? fp.source.values : old_data
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
- fp.dest.values.each do |k, v|
174
- puts " #{k}: ".bold.green + (old_source[k] || '-') + ' > '.bold.green + v if ((v != old_source[k]) && (!old_source[k].nil?))
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.file_exists(fp)
179
- Messages.error "<#{fp.source.filename}> can't be renamed in <#{fp.dest.filename}>, it exists!"
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.short_targets(ff)
183
- self.list [ff.targets[:readonly].map { |s| "<#{s.to_s.delete('@')}>"}.join(', ')], :red, '-'
184
- self.list [ff.targets[:writable].map { |s| "<#{s.to_s.delete('@')}>"}.join(', ')], :green, '+'
185
- puts ''
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.long_targets(ff)
189
- self.list ff.targets[:readonly].map { |s| "<#{s.to_s.delete('@')}>" }, :red, '-'
190
- self.list ff.targets[:writable].map { |s| "<#{s.to_s.delete('@')}>" }, :green, '+'
191
- puts ''
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(i, color = :green, ch = '>')
195
- puts "[#{ch}] ".bold.send(color) + i
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, ch = '>')
199
- items.each { |x| Messages.item(x, color, ch) }
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, ch = '>')
203
- items.instance_variables.each { |k| Messages.item("#{k.to_s.gsub(/@/, '')}: #{items.instance_variable_get(k)}", color, ch) }
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, ch = '>')
207
- items.instance_variables.each { |k| Messages.item("#{k.to_s.gsub(/@/, '')}: [#{items.instance_variable_get(k).keys.join(', ')}]", color, ch) }
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 "Invalid hash type: #{hash_type}"
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 "Invalid macro: #{macro}"
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 "Invalid target: #{target}"
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 "Invalid configuration setting: #{name}"
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 "Invalid words group: #{group}"
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 "Invalid words section for #{group}: #{section}"
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 "Missing the item #{idx + 1} in #{group}/#{section} words section"
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 "File not found: #{filename}"
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 'No filenames specified'
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 "The file #{filename} already exists and won't be overwrite"
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 'Ok ok... Exiting!'
475
+ super("Ok ok... Exiting!")
274
476
  end
275
477
  end
276
478
 
479
+ Differ.format = :color
277
480
 
278
- Differ.format = :color
279
-
280
- Signal.trap('INT') { raise Interruption }
481
+ Signal.trap("INT") { raise Interruption }
281
482
 
282
- Signal.trap('TERM') { raise Interruption }
483
+ Signal.trap("TERM") { raise Interruption }
283
484
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FilterRename
2
- VERSION = "1.0.0"
4
+ VERSION = "1.2.0"
3
5
  end