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,82 +1,145 @@
1
- require 'optparse'
2
- require 'ostruct'
3
- require 'filter_rename'
4
- require 'filter_rename/version'
1
+ # frozen_string_literal: true
5
2
 
6
- module FilterRename
3
+ require "optparse"
4
+ require "ostruct"
5
+ require "filter_rename"
6
+ require "filter_rename/version"
7
7
 
8
+ module FilterRename
9
+ #
10
+ # Parsing the input data.
11
+ #
8
12
  class OptParseMain
9
-
10
- def self.parse(args)
11
- options = OpenStruct.new
13
+ def self.parse(_args)
14
+ options = Struct.new(:filters, :files, :global, :operation, :show_macro, :help_config).new
12
15
  options.filters = []
13
16
  options.files = []
14
17
  options.global = {}
15
- options.operation = :preview
16
- options.show_macro = ''
18
+ options.operation = :diff
19
+ options.show_macro = ""
20
+ options.help_config = ""
17
21
 
18
22
  opt_parser = OptionParser.new do |opt|
19
- opt.banner = 'Usage: filter_rename [-g OPTION1[,OPTION2...]] [FILTER1[,FILTER2...]] <file1>[ <file2>...] [OPERATION]'
23
+ opt.banner = "Usage: filter_rename [-g OPTION1[,OPTION2...]] [FILTER1[,FILTER2...]] <file1>" \
24
+ "[ <file2>...] OPERATION"
20
25
 
21
- opt.separator ''
22
- opt.separator 'Operations:'
26
+ opt.separator ""
27
+ opt.separator "Operations:"
23
28
 
24
- opt.on('--apply', 'Apply the changes.') do |c|
29
+ opt.on("--apply", "Apply the changes.") do |_c|
25
30
  options.operation = :apply
26
31
  end
27
32
 
28
- opt.on('-d', '--dry-run', 'Don\'t apply any change but check for errors') do |c|
33
+ opt.on("-d", "--dry-run", "Don't apply any change but check for errors") do |_c|
29
34
  options.operation = :dry_run
30
35
  end
31
36
 
32
- opt.on('-p', '--preview', 'Preview the filter chain applied [DEFAULT]') do |c|
33
- options.operation = :preview
37
+ opt.on("-D", "--diff", "View the changes in a diff format [DEFAULT]") do |_c|
38
+ options.operation = :diff
34
39
  end
35
40
 
36
- opt.on('-t', '--targets', 'List of targets for each file') do |c|
41
+ opt.on("-t", "--targets", "List of targets for each file") do |_c|
37
42
  options.operation = :targets
38
43
  end
39
44
 
40
- opt.on('-g', '--globals', 'List of global variables') do |c|
45
+ opt.on("-v", "--values", "List of targets values for each file") do |_c|
46
+ options.operation = :values
47
+ end
48
+
49
+ opt.on("-g", "--globals", "List of global variables") do |_c|
41
50
  options.operation = :globals
42
51
  end
43
52
 
44
- opt.on('-c', '--configs', 'List of filter variables') do |c|
53
+ opt.on("-c", "--configs", "List of filter variables") do |_c|
45
54
  options.operation = :configs
46
55
  end
47
56
 
48
- opt.on('-w', '--words', 'List of groups of words available for translation') do |c|
57
+ opt.on("-w", "--words", "List of groups of words available for translation") do |_c|
49
58
  options.operation = :words
50
59
  end
51
60
 
52
- opt.on('-m', '--macros', 'List of available macros') do |c|
61
+ opt.on("-m", "--macros", "List of available macros") do |_c|
53
62
  options.operation = :macros
54
63
  end
55
64
 
56
- opt.on('-s' , '--show-macro <MACRO>', 'List of commands used by MACRO') do |c|
65
+ opt.on("-s", "--show-macro <MACRO>", "List of commands used by MACRO") do |c|
57
66
  options.operation = :show_macro
58
67
  options.show_macro = c
59
68
  end
60
69
 
61
- opt.separator ''
62
- opt.separator 'Options:'
70
+ opt.separator ""
71
+ opt.separator "Global options:"
72
+ opt.separator ""
63
73
 
64
- opt.on('--global [OPTION:VALUE[,OPTION:VALUE]]', 'Override global options with: "option:value"') do |v|
65
- v.parametrize.each do |i|
66
- options.global.store(i.split(':')[0].to_sym, i.split(':')[1])
74
+ opt.on("-G", "--global OPTION:VALUE[,OPTION:VALUE]", String,
75
+ 'Override global options with: "option:value"') do |v|
76
+ v.parametrize.each do |idx|
77
+ options.global.store(idx.split(":")[0].to_sym, idx.split(":")[1])
67
78
  end
68
79
  end
69
80
 
70
- opt.separator ''
71
- opt.separator 'Filters:'
81
+ opt.separator ""
72
82
 
73
- opt.on('--macro MACRO1,[MACRO2,...]', Array, 'Apply the MACRO' ) do |v|
74
- options.filters << MacroConfig.create(v) # { FilterRename::MacroConfig => v }
75
- # options.filters.merge MacroConfig.expand_macros(v)
83
+ opt.on("-V", "--virtual", "Accept a list of file not present in the local drives") do |_c|
84
+ options.global.store(:mimemagic, false)
85
+ options.global.store(:essential_tags, true)
86
+ options.global.store(:check_source, false)
76
87
  end
77
88
 
78
- Filters.constants.sort.each do |c|
89
+ opt.separator ""
90
+
91
+ GlobalConfig::OPTIONS.each do |k, v|
92
+ if v[:args].nil?
93
+ opt.on("--[no-]g-#{k.to_s.gsub("_", "-")}", v[:desc]) do |c|
94
+ options.global.store(k, c)
95
+ end
96
+ else
97
+ opt.on("--g-#{k.to_s.gsub("_", "-")} #{v[:args]}", String, v[:desc]) do |c|
98
+ options.global.store(k, c)
99
+ end
100
+ end
101
+ end
102
+
103
+ opt.separator ""
104
+ opt.separator "Filter options:"
105
+ opt.separator ""
106
+
107
+ opt.on("-X", "--exclude-files PATTERN", String, "Exclude the files matching the PATTERN") do |c|
108
+ klass = Object.const_get("FilterRename::Filters::Config")
109
+ options.filters << { klass => ["grep:#{c}"] }
110
+ options.filters << { klass => ["grep_exclude:true"] }
111
+ end
112
+
113
+ opt.on("-O", "--only-files PATTERN", String, "Select only the files matching the PATTERN") do |c|
114
+ klass = Object.const_get("FilterRename::Filters::Config")
115
+ options.filters << { klass => ["grep:#{c}"] }
116
+ options.filters << { klass => ["grep_exclude:false"] }
117
+ end
118
+
119
+ opt.on("-M", "--macro MACRO1,[MACRO2,...]", Array, "Apply the MACRO") do |v|
120
+ options.filters << MacroConfig.create(v)
121
+ end
122
+
123
+ opt.separator ""
79
124
 
125
+ FilterConfig::OPTIONS.each do |k, v|
126
+ klass = Object.const_get("FilterRename::Filters::Config")
127
+
128
+ if v[:args].nil?
129
+ opt.on("--[no-]f-#{k.to_s.gsub("_", "-")}", v[:desc]) do |c|
130
+ options.filters << { klass => ["#{k}:#{c}"] }
131
+ end
132
+ else
133
+ opt.on("--f-#{k.to_s.gsub("_", "-")} #{v[:args]}", String, v[:desc]) do |c|
134
+ options.filters << { klass => ["#{k}:#{c}"] }
135
+ end
136
+ end
137
+ end
138
+
139
+ opt.separator ""
140
+ opt.separator "Filters:"
141
+
142
+ Filters.constants.sort.each do |c|
80
143
  switch = c.to_s.to_switch
81
144
  klass = Object.const_get("FilterRename::Filters::#{c}")
82
145
 
@@ -89,57 +152,54 @@ module FilterRename
89
152
  options.filters << { klass => v }
90
153
  end
91
154
  else
92
- opt.on("--#{switch} #{klass.params}", "#{klass.hint}") do |v|
155
+ opt.on("--#{switch} #{klass.params}", klass.hint.to_s) do |v|
93
156
  options.filters << { klass => v.parametrize }
94
157
  end
95
158
  end
96
159
  end
97
160
 
98
- opt.separator ''
99
- opt.separator 'Other:'
161
+ opt.separator ""
162
+ opt.separator "Other:"
100
163
 
101
- opt.on_tail('-h', '--help', 'Show this message') do
164
+ opt.on_tail("-h", "--help", "Show this message") do
102
165
  puts opt
103
166
  exit
104
167
  end
105
- opt.on_tail('-v', '--version', 'Show version') do
168
+
169
+ opt.on_tail("-H", "--help-config [G-OPTION|F-OPTION]", String,
170
+ "Extended description for the available options") do |o|
171
+ options.operation = :help_config
172
+ options.help_config = o
173
+ end
174
+
175
+ opt.on_tail("-v", "--version", "Show version") do
106
176
  puts VERSION
107
177
  exit
108
178
  end
109
179
  end
110
180
 
111
- if (!STDIN.tty? && !STDIN.closed?) || !ARGV.empty?
112
-
181
+ if (!$stdin.tty? && !$stdin.closed?) || !ARGV.empty?
113
182
  opt_parser.parse!(ARGV)
114
-
115
- (ARGV.empty? ? ARGF : ARGV).each do |f|
116
- f = File.expand_path(f.strip)
117
-
118
- if File.exists?(f)
119
- options.files << f
120
- else
121
- raise FileNotFound, f
122
- end
123
- end if [:apply, :preview, :dry_run, :targets].include? options.operation
183
+ options.files = (ARGV.empty? ? ARGF : ARGV)
124
184
  else
125
- puts opt_parser; exit
185
+ puts opt_parser
186
+ exit
126
187
  end
127
188
 
128
189
  options
129
190
  end
130
-
131
191
  end
132
192
 
193
+ #
194
+ # Interface class to run the application.
195
+ #
133
196
  class CLI
134
197
  def self.start
135
- begin
136
- options = OptParseMain.parse(ARGV)
137
- Builder.new(options).send(options.operation)
138
- rescue => e
139
- Messages.error e
140
- exit 1
141
- end
198
+ options = OptParseMain.parse(ARGV)
199
+ Builder.new(options).send(options.operation)
200
+ rescue StandardError => e
201
+ Messages.error e
202
+ exit 1
142
203
  end
143
204
  end
144
-
145
205
  end
@@ -1,100 +1,276 @@
1
- require 'yaml'
1
+ # frozen_string_literal: true
2
2
 
3
- module FilterRename
3
+ require "yaml"
4
4
 
5
+ module FilterRename
6
+ #
7
+ # Macro configurations.
8
+ #
5
9
  class MacroConfig
6
-
7
10
  def initialize(cfg)
8
11
  cfg.each do |key, value|
9
- instance_variable_set('@' + key.to_s, value)
12
+ instance_variable_set("@#{key}", value)
10
13
  end
11
14
  end
12
15
 
13
16
  def get_macro(name)
14
- macro = instance_variable_get('@' + name.to_s.gsub(/[^a-zA-Z0-9,-_]/,''))
17
+ macro = instance_variable_get("@#{name.to_s.gsub(/[^a-zA-Z0-9,\-_]/, "")}")
15
18
  raise InvalidMacro, name if macro.nil? || macro.to_s.empty?
19
+
16
20
  macro
17
21
  end
18
22
 
19
- def get_macros
20
- instance_variables.map { |m| m.to_s.gsub(/^@/, '') }
23
+ def macros
24
+ instance_variables.map { |msg| msg.to_s.gsub(/^@/, "") }
21
25
  end
22
26
 
23
27
  def self.create(name)
24
28
  { FilterRename::MacroConfig => name }
25
29
  end
26
-
27
30
  end
28
31
 
29
-
32
+ #
33
+ # Word filters configurations.
34
+ #
30
35
  class WordsConfig
31
-
32
36
  def initialize(cfg)
33
37
  cfg.each do |key, value|
34
- instance_variable_set('@' + key.to_s, value)
38
+ instance_variable_set("@#{key}", value)
35
39
  end
36
40
  end
37
41
 
38
42
  def get_words(name, section, idx = nil)
39
- w = instance_variable_get('@' + name.to_s)
43
+ w = instance_variable_get("@#{name}")
40
44
  raise InvalidWordsGroup, name if w.nil? || name.to_s.empty?
41
- raise InvalidWordsSection.new(name, section) unless w.has_key? section.to_sym
45
+ raise InvalidWordsSection.new(name, section) unless w.key? section.to_sym
42
46
 
43
47
  if idx.nil?
44
- return w[section]
45
- elsif w[section].class == Array
48
+ w[section]
49
+ elsif w[section].instance_of?(Array)
46
50
  raise InvalidWordsIndex.new(name, section, idx) unless idx < w[section].length
47
- return w[section][idx].to_s
51
+
52
+ w[section][idx].to_s
48
53
  else
49
- return w[section].to_s
54
+ w[section].to_s
50
55
  end
51
56
  end
52
57
  end
53
58
 
54
-
59
+ #
60
+ # Global configurations.
61
+ #
55
62
  class GlobalConfig
56
- attr_reader :date_format, :hash_type, :counter_length, :counter_start, :targets,
57
- :pdf_metadata, :image_metadata, :mp3_metadata
63
+ OPTIONS = { date_format: { args: "FORMAT",
64
+ desc: "Describes the date FORMAT for <mtime> and <ctime> targets.",
65
+ long: "This is how the <mtime> and <ctime> targets will be formatted\n" \
66
+ "for each file read, unless the *essential_tags* option is on.\n" \
67
+ "The allowed placeholders are prefixed with a percentage % char\n" \
68
+ "and are the same used by the *date* command.\n" \
69
+ "Use the *date* man page to get more info.",
70
+ default: "%Y-%m-%d" },
71
+ hash_type: { args: "ALGORITHM",
72
+ desc: "Use one of the ALGORITHM among sha1, sha2, md5 to create the <hash> target.",
73
+ long: "It preloads the <hash> target with one of the allowed value\n" \
74
+ "sha1, sha2, or md5.\n" \
75
+ "Just as reminder, md5 is the less safe but the quicker to be\n" \
76
+ "executed, sha2 is the slowest but the safest.",
77
+ default: "md5" },
78
+ hash_on_tags: { args: nil,
79
+ desc: "Enable or not the hash calculation for each file.",
80
+ long: "Hash calculation can be expensive, that's why it is disabled\n" \
81
+ "by default and the <hash> target is not created.",
82
+ default: false },
83
+ hash_if_exists: { args: nil,
84
+ desc: "Prints the hash code in case the file exists.",
85
+ long: "This option shows the hash of the two files when the *dry* or\n" \
86
+ "*apply* operation is running and a conflict is raised.\n" \
87
+ "Looking at the hash code would be easier to understand wheter or\n" \
88
+ "not the renaming failure is caused by two clones or two totally\n" \
89
+ "different files that the chain of filters accidentally transformed\n" \
90
+ "in the same filename.",
91
+ default: true },
92
+ counter_length: { args: "NUMBER",
93
+ desc: "The minimum length of the counter padded by zeros.",
94
+ long: "This is the length of the counter in terms of total NUMBER of\n" \
95
+ "chars rendered.\n" \
96
+ "It means that, when the counter length is less than NUMBER, a certain\n" \
97
+ "number of '0' is prepended to the counter to cover the difference.",
98
+ default: "3" },
99
+ counter_start: { args: "NUMBER",
100
+ desc: "Start the <count> target from NUMBER+1.",
101
+ long: "This is the way to set the internal counter, that affect the <count>\n" \
102
+ "target, to a specific position.\n" \
103
+ "Be aware that, for technical reasons, it will start from NUMBER+1,\n" \
104
+ "so to have 0 for the first element just set NUMBER to -1",
105
+ default: "0" },
106
+ inline_targets: { args: nil,
107
+ desc: "Print the targets' list inline or in a column.",
108
+ long: "This option affects the way the target's list for each file is shown:\n" \
109
+ "a *short* list where the data is in the same line, one for RW targets\n" \
110
+ "and one for RO targets, or a *long* list where the data is in column.",
111
+ default: true },
112
+ pdf_metadata: { args: nil,
113
+ desc: "Create the targets from the PDF files metadata.",
114
+ long: "This option enable the generation of targets from the metadata\n" \
115
+ "embedded in the PDF files.",
116
+ default: true },
117
+ image_metadata: { args: nil,
118
+ desc: "Create the targets from the image files metadata.",
119
+ long: "This option enable the generation of targets from the metadata\n" \
120
+ "embedded in the supported image files.",
121
+ default: true },
122
+ audio_metadata: { args: nil,
123
+ desc: "Create the targets from the audio files metadata.",
124
+ long: "This option enable the generation of targets from the metadata\n" \
125
+ "embedded in the supported audio files.",
126
+ default: true },
127
+ mimemagic: { args: nil,
128
+ desc: "Create the extra targets depending from the file's mimetype.",
129
+ long: "Disabling it, disable all the extra targets' calculation\n" \
130
+ "based on the file's mimetype.",
131
+ default: true },
132
+ essential_tags: { args: nil,
133
+ desc: "Define whether or not to enable only essential targets.",
134
+ long: "Setting it to true the basic targets only which involve\n" \
135
+ "the file name, path, and extension, will be calculated.\n" \
136
+ "This is useful to use less memory or to skip\n" \
137
+ "those data that can't be calculated in case of a file list\n" \
138
+ "is served by the pipeline.",
139
+ default: false },
140
+ check_source: { args: nil,
141
+ desc: "Define whether or not to enable the source files checking.",
142
+ long: "Setting it to false the source files aren't checked out\n" \
143
+ "and a list of files not necessarily in the same machine\n" \
144
+ "could be provided using the pipeline as an input.\n" \
145
+ "Combined with essential_tags to true and mimemagic to false\n" \
146
+ "is useful to avoid errors in that last scenario.",
147
+ default: true } }.freeze
148
+
149
+ attr_reader(*OPTIONS.keys)
58
150
 
151
+ # rubocop:disable Style/RedundantCondition
59
152
  def initialize(cfg)
60
- @date_format = cfg[:date_format] || '%Y-%m-%d'
61
- @hash_type = cfg[:hash_type].to_sym || :none
62
- @counter_length = cfg[:counter_length] || 4
153
+ @date_format = cfg[:date_format] || "%Y-%m-%d"
154
+ @hash_type = cfg[:hash_type].nil? ? :md5 : cfg[:hash_type].to_sym
155
+ @hash_on_tags = cfg[:hash_on_tags] || false
156
+ @hash_if_exists = cfg[:hash_if_exists] || true
157
+ @counter_length = cfg[:counter_length] || 3
63
158
  @counter_start = cfg[:counter_start] || 0
64
- @targets = cfg[:targets].to_sym || :short
159
+ @inline_targets = cfg[:inline_targets].nil? ? true : cfg[:inline_targets].to_boolean
65
160
  @pdf_metadata = cfg[:pdf_metadata].nil? ? true : cfg[:pdf_metadata].to_boolean
66
161
  @image_metadata = cfg[:image_metadata].nil? ? true : cfg[:image_metadata].to_boolean
67
- @mp3_metadata = cfg[:mp3_metadata].nil? ? true : cfg[:mp3_metadata].to_boolean
162
+ @audio_metadata = cfg[:audio_metadata].nil? ? true : cfg[:audio_metadata].to_boolean
163
+ @mimemagic = cfg[:mimemagic].nil? ? true : cfg[:mimemagic].to_boolean
164
+ @essential_tags = cfg[:essential_tags].nil? ? false : cfg[:essential_tags].to_boolean
165
+ @check_source = cfg[:check_source].nil? ? true : cfg[:check_source].to_boolean
68
166
  end
167
+ # rubocop:enable Style/RedundantCondition
69
168
  end
70
169
 
71
-
170
+ #
171
+ # Filter configurations.
172
+ #
72
173
  class FilterConfig
73
- attr_accessor :word_separator, :target, :ignore_case, :lang, :grep, :grep_on, :grep_exclude, :grep_target
174
+ OPTIONS = { word_separator: { args: "CHARACTER",
175
+ desc: "Define the CHARACTER that separates two words.",
176
+ long: "This options affects the way a string is split in words or how the\n" \
177
+ "words are joined together.\n" \
178
+ "All the filters that operate with words will use this CHARACTER\n" \
179
+ "to define the sequence of the word itself which can contain all\n" \
180
+ "characters except CHARACTER.",
181
+ default: " " },
182
+ number_separator: { args: "CHARACTER",
183
+ desc: "Define the CHARACTER to join two or more numbers.",
184
+ long: "This option configure the CHARACTER that will join two or more\n" \
185
+ "numbers in the swap-number filter when an interval is used as\n" \
186
+ "first parameter.",
187
+ default: "." },
188
+ # This one is unused
189
+ # occurrence_separator: { args: "CHARACTER"
190
+ # default: "-" },
191
+ target: { args: "TARGET",
192
+ desc: "This is the TARGET name where the filters are operating.",
193
+ long: "Switching to one of the available targets allows to alter their content\n" \
194
+ "directly using a chain of filters.\n" \
195
+ "Targets can be read-write or read-only: the former type reflects the data\n" \
196
+ "that will be write back to the file, the latter can be used to generate\n" \
197
+ "other values or be emedded in other targets using the *--template* filter.\n" \
198
+ "Also custom targets can be defined just to hold data that could be manipulated\n" \
199
+ "easier.\n" \
200
+ "This option is the same as using the *--select* filter",
201
+ default: "name" },
202
+ ignore_case: { args: nil,
203
+ desc: "Ignore or not the character case when searching for strings.",
204
+ long: "This option allows to ignore the case during the search and replace\n" \
205
+ "operations, doesn't matter which type of filter is involved.",
206
+ default: true },
207
+ lang: { args: "LANG",
208
+ desc: "Set the default LANG code for the *--replace-date* filter.",
209
+ long: "This option is used by the *--replace-date* filter to translate groups\n" \
210
+ "of words containing the months or day of weeks from a language to another\n" \
211
+ "where it's not specified.",
212
+ default: "en" },
213
+ grep: { args: "REGEXP",
214
+ desc: "Limit the file to be changed to only those matching the REGEXP pattern.",
215
+ long: "This options by default includes from the following filters only those files\n" \
216
+ "matching the REGEXP pattern.\n" \
217
+ "Depending on the *grep_exclude* option the logic can be inverted and the files\n" \
218
+ "matching the REGEXP excluded from the action of the following filters.",
219
+ default: ".*" },
220
+ grep_on_dest: { args: nil,
221
+ desc: "Execute the *grep* option on the destination filename.",
222
+ long: "To limit the files to be involved in the changes you can apply the\n" \
223
+ "grep option on the source or destination filename.\n" \
224
+ "By default it is executed on the source, while this option allows\n" \
225
+ "to select the destination.\n" \
226
+ "Be aware that the destination changes according to all the previous\n" \
227
+ "filters applied.",
228
+ default: false },
229
+ grep_exclude: { args: nil,
230
+ desc: "Invert the logic to exclude the files matching the regular expression.",
231
+ long: "With this option the *grep* options will be used to exclude the files\n" \
232
+ "matching the regular expression, from the following chain of filters.",
233
+ default: false },
234
+ grep_target: { args: "TARGET",
235
+ desc: "Use the specific TARGET to match files through the *grep* option.",
236
+ long: "With this option you can limit the *grep* option to one of the available\n" \
237
+ "TARGETs instead of considering the full filename.\n" \
238
+ "It comes in handy to focus on specific data contained within a TARGET\n" \
239
+ "and the file selection process is exclusively based on that data.",
240
+ default: "full_filename" } }.freeze
241
+
242
+ attr_accessor(*OPTIONS.keys)
74
243
 
244
+ # rubocop:disable Style/RedundantCondition
75
245
  def initialize(cfg)
76
- @word_separator = cfg[:word_separator] || ' '
77
- @target = cfg[:target].to_sym || :name
246
+ @word_separator = cfg[:word_separator] || " "
247
+ @number_separator = cfg[:number_separator] || "."
248
+ # Unused property
249
+ @occurrence_separator = cfg[:occurrence_separator] || "-"
250
+ @target = cfg[:target].nil? ? :name : cfg[:target].to_sym
78
251
  @ignore_case = cfg[:ignore_case].nil? ? true : cfg[:ignore_case].to_boolean
79
252
  @lang = (cfg[:lang] || :en).to_sym
80
253
  @macro = cfg[:macro] || {}
81
- @grep = cfg[:grep] || '.*'
82
- @grep_on = cfg[:grep_on].to_sym || :source
83
- @grep_exclude = cfg[:grep_exclude].to_boolean || false
84
- @grep_target = cfg[:grep_target].to_sym || :full_filename
254
+ @grep = cfg[:grep] || ".*"
255
+ @grep_on_dest = cfg[:grep_on_dest].nil? ? false : cfg[:grep_on_dest].to_boolean
256
+ @grep_exclude = cfg[:grep_exclude].nil? ? false : cfg[:grep_exclude].to_boolean
257
+ @grep_target = (cfg[:grep_target] || :full_filename).to_sym
85
258
  end
259
+ # rubocop:enable Style/RedundantCondition
86
260
  end
87
261
 
88
-
262
+ #
263
+ # Proxy class for all configurations.
264
+ #
89
265
  class Config
90
266
  attr_reader :filter, :global, :macro, :words
91
267
 
92
268
  def initialize(global = {})
93
- cfg = {filter: {}, global: {}, macro: {}, words: {}}
269
+ cfg = { filter: {}, global: {}, macro: {}, words: {} }
94
270
 
95
- load_file(File.expand_path(File.join(File.dirname(__FILE__), '..', 'filter_rename.yaml')), cfg)
96
- load_file(File.join(ENV['HOME'], '.filter_rename.yaml'), cfg)
97
- load_file(File.join(ENV['HOME'], '.filter_rename', 'config.yaml'), cfg)
271
+ load_file(File.expand_path(File.join(File.dirname(__FILE__), "..", "filter_rename.yaml")), cfg)
272
+ load_file(File.join(Dir.home, ".filter_rename.yaml"), cfg)
273
+ load_file(File.join(Dir.home, ".filter_rename", "config.yaml"), cfg)
98
274
 
99
275
  @filter = FilterConfig.new(cfg[:filter])
100
276
  @global = GlobalConfig.new(cfg[:global].merge(global))
@@ -105,16 +281,13 @@ module FilterRename
105
281
  private
106
282
 
107
283
  def load_file(filename, cfg = nil)
284
+ return unless File.exist?(filename)
108
285
 
109
- if File.exists?(filename)
110
- @filename = filename
111
- yaml = YAML.load_file(filename)
112
- [:filter, :global, :macro, :words].each do |s|
113
- cfg[s].merge!(yaml[s]) if yaml.has_key?(s)
114
- end
286
+ @filename = filename
287
+ yaml = YAML.load_file(filename)
288
+ %i[filter global macro words].each do |s|
289
+ cfg[s].merge!(yaml[s]) if yaml.key?(s)
115
290
  end
116
-
117
291
  end
118
292
  end
119
-
120
293
  end