leftovers 0.2.1 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +35 -49
  4. data/docs/Configuration.md +627 -0
  5. data/exe/leftovers +2 -2
  6. data/leftovers.gemspec +13 -7
  7. data/lib/config/attr_encrypted.yml +3 -4
  8. data/lib/config/audited.yml +9 -4
  9. data/lib/config/datagrid.yml +1 -1
  10. data/lib/config/flipper.yml +1 -3
  11. data/lib/config/graphql.yml +15 -13
  12. data/lib/config/okcomputer.yml +1 -3
  13. data/lib/config/parser.yml +89 -91
  14. data/lib/config/rails.yml +160 -97
  15. data/lib/config/redcarpet.yml +35 -38
  16. data/lib/config/rollbar.yml +1 -3
  17. data/lib/config/rspec.yml +18 -10
  18. data/lib/config/ruby.yml +42 -49
  19. data/lib/config/selenium-webdriver.yml +19 -0
  20. data/lib/config/sidekiq.yml +9 -0
  21. data/lib/config/will_paginate.yml +12 -14
  22. data/lib/leftovers.rb +61 -43
  23. data/lib/leftovers/ast.rb +8 -0
  24. data/lib/leftovers/ast/builder.rb +6 -3
  25. data/lib/leftovers/ast/node.rb +66 -107
  26. data/lib/leftovers/backports.rb +24 -40
  27. data/lib/leftovers/cli.rb +17 -14
  28. data/lib/leftovers/collector.rb +7 -11
  29. data/lib/leftovers/config.rb +38 -13
  30. data/lib/leftovers/config_validator.rb +60 -0
  31. data/lib/leftovers/config_validator/error_processor.rb +196 -0
  32. data/lib/leftovers/config_validator/schema_hash.rb +496 -0
  33. data/lib/leftovers/definition.rb +16 -41
  34. data/lib/leftovers/definition_node.rb +36 -0
  35. data/lib/leftovers/definition_set.rb +17 -24
  36. data/lib/leftovers/dynamic_processors.rb +11 -0
  37. data/lib/leftovers/dynamic_processors/call.rb +25 -0
  38. data/lib/leftovers/dynamic_processors/call_definition.rb +31 -0
  39. data/lib/leftovers/dynamic_processors/definition.rb +26 -0
  40. data/lib/leftovers/dynamic_processors/each.rb +19 -0
  41. data/lib/leftovers/dynamic_processors/null.rb +9 -0
  42. data/lib/leftovers/erb.rb +2 -2
  43. data/lib/leftovers/file.rb +3 -5
  44. data/lib/leftovers/file_collector.rb +82 -62
  45. data/lib/leftovers/file_list.rb +9 -12
  46. data/lib/leftovers/haml.rb +9 -12
  47. data/lib/leftovers/matcher_builders.rb +24 -0
  48. data/lib/leftovers/matcher_builders/and.rb +19 -0
  49. data/lib/leftovers/matcher_builders/and_not.rb +14 -0
  50. data/lib/leftovers/matcher_builders/argument_node_value.rb +21 -0
  51. data/lib/leftovers/matcher_builders/name.rb +29 -0
  52. data/lib/leftovers/matcher_builders/node.rb +40 -0
  53. data/lib/leftovers/matcher_builders/node_has_argument.rb +71 -0
  54. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +22 -0
  55. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +24 -0
  56. data/lib/leftovers/matcher_builders/node_name.rb +15 -0
  57. data/lib/leftovers/matcher_builders/node_pair_name.rb +18 -0
  58. data/lib/leftovers/matcher_builders/node_pair_value.rb +16 -0
  59. data/lib/leftovers/matcher_builders/node_path.rb +14 -0
  60. data/lib/leftovers/matcher_builders/node_type.rb +28 -0
  61. data/lib/leftovers/matcher_builders/or.rb +73 -0
  62. data/lib/leftovers/matcher_builders/path.rb +15 -0
  63. data/lib/leftovers/matcher_builders/string.rb +11 -0
  64. data/lib/leftovers/matcher_builders/string_pattern.rb +19 -0
  65. data/lib/leftovers/matcher_builders/unless.rb +13 -0
  66. data/lib/leftovers/matchers.rb +26 -0
  67. data/lib/leftovers/matchers/all.rb +25 -0
  68. data/lib/leftovers/matchers/and.rb +24 -0
  69. data/lib/leftovers/matchers/any.rb +27 -0
  70. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +28 -0
  71. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +25 -0
  72. data/lib/leftovers/matchers/node_has_positional_argument.rb +23 -0
  73. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +25 -0
  74. data/lib/leftovers/matchers/node_name.rb +23 -0
  75. data/lib/leftovers/matchers/node_pair_value.rb +23 -0
  76. data/lib/leftovers/matchers/node_path.rb +23 -0
  77. data/lib/leftovers/matchers/node_scalar_value.rb +25 -0
  78. data/lib/leftovers/matchers/node_type.rb +23 -0
  79. data/lib/leftovers/matchers/not.rb +23 -0
  80. data/lib/leftovers/matchers/or.rb +26 -0
  81. data/lib/leftovers/merged_config.rb +24 -14
  82. data/lib/leftovers/parser.rb +2 -5
  83. data/lib/leftovers/processor_builders.rb +22 -0
  84. data/lib/leftovers/processor_builders/action.rb +63 -0
  85. data/lib/leftovers/processor_builders/add_prefix.rb +20 -0
  86. data/lib/leftovers/processor_builders/add_suffix.rb +20 -0
  87. data/lib/leftovers/processor_builders/argument.rb +25 -0
  88. data/lib/leftovers/processor_builders/dynamic.rb +27 -0
  89. data/lib/leftovers/processor_builders/each.rb +36 -0
  90. data/lib/leftovers/processor_builders/each_action.rb +51 -0
  91. data/lib/leftovers/processor_builders/each_dynamic.rb +54 -0
  92. data/lib/leftovers/processor_builders/each_for_definition_set.rb +36 -0
  93. data/lib/leftovers/processor_builders/itself.rb +13 -0
  94. data/lib/leftovers/processor_builders/keyword.rb +24 -0
  95. data/lib/leftovers/processor_builders/keyword_argument.rb +14 -0
  96. data/lib/leftovers/processor_builders/transform.rb +55 -0
  97. data/lib/leftovers/processor_builders/transform_chain.rb +24 -0
  98. data/lib/leftovers/processor_builders/transform_set.rb +47 -0
  99. data/lib/leftovers/processor_builders/value.rb +13 -0
  100. data/lib/leftovers/rake_task.rb +4 -4
  101. data/lib/leftovers/reporter.rb +1 -1
  102. data/lib/leftovers/value_processors.rb +40 -0
  103. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +31 -0
  104. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +31 -0
  105. data/lib/leftovers/value_processors/add_prefix.rb +20 -0
  106. data/lib/leftovers/value_processors/add_suffix.rb +20 -0
  107. data/lib/leftovers/value_processors/camelize.rb +24 -0
  108. data/lib/leftovers/value_processors/capitalize.rb +19 -0
  109. data/lib/leftovers/value_processors/deconstantize.rb +24 -0
  110. data/lib/leftovers/value_processors/delete_after.rb +22 -0
  111. data/lib/leftovers/value_processors/delete_before.rb +22 -0
  112. data/lib/leftovers/value_processors/delete_prefix.rb +26 -0
  113. data/lib/leftovers/value_processors/delete_suffix.rb +26 -0
  114. data/lib/leftovers/value_processors/demodulize.rb +24 -0
  115. data/lib/leftovers/value_processors/downcase.rb +19 -0
  116. data/lib/leftovers/value_processors/each.rb +21 -0
  117. data/lib/leftovers/value_processors/each_for_definition_set.rb +29 -0
  118. data/lib/leftovers/value_processors/each_keyword.rb +27 -0
  119. data/lib/leftovers/value_processors/each_keyword_argument.rb +27 -0
  120. data/lib/leftovers/value_processors/each_positional_argument.rb +24 -0
  121. data/lib/leftovers/value_processors/itself.rb +17 -0
  122. data/lib/leftovers/value_processors/keyword.rb +36 -0
  123. data/lib/leftovers/value_processors/keyword_argument.rb +36 -0
  124. data/lib/leftovers/value_processors/parameterize.rb +24 -0
  125. data/lib/leftovers/value_processors/placeholder.rb +18 -0
  126. data/lib/leftovers/value_processors/pluralize.rb +24 -0
  127. data/lib/leftovers/value_processors/positional_argument.rb +26 -0
  128. data/lib/leftovers/value_processors/replace_value.rb +18 -0
  129. data/lib/leftovers/value_processors/return_definition.rb +26 -0
  130. data/lib/leftovers/value_processors/return_string.rb +14 -0
  131. data/lib/leftovers/value_processors/singularize.rb +24 -0
  132. data/lib/leftovers/value_processors/split.rb +22 -0
  133. data/lib/leftovers/value_processors/swapcase.rb +19 -0
  134. data/lib/leftovers/value_processors/titleize.rb +24 -0
  135. data/lib/leftovers/value_processors/underscore.rb +24 -0
  136. data/lib/leftovers/value_processors/upcase.rb +19 -0
  137. data/lib/leftovers/version.rb +1 -1
  138. metadata +190 -28
  139. data/lib/config/selenium.yml +0 -21
  140. data/lib/leftovers/argument_rule.rb +0 -219
  141. data/lib/leftovers/core_ext.rb +0 -13
  142. data/lib/leftovers/hash_rule.rb +0 -40
  143. data/lib/leftovers/name_rule.rb +0 -53
  144. data/lib/leftovers/rule.rb +0 -74
  145. data/lib/leftovers/transform_rule.rb +0 -171
  146. data/lib/leftovers/value_rule.rb +0 -56
@@ -1,21 +0,0 @@
1
- rules:
2
- skip: true
3
- name:
4
- - before_navigate_to
5
- - before_navigate_back
6
- - after_navigate_back
7
- - before_navigate_forward
8
- - after_navigate_forward
9
- - before_find
10
- - after_find
11
- - before_click
12
- - before_change_value_of
13
- - after_change_value_of
14
- - before_execute_script
15
- - after_execute_script
16
- - before_quit
17
- - before_close
18
- - after_navigate_to
19
- - after_click
20
- - after_quit
21
- - after_close
@@ -1,219 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'definition'
4
- require_relative 'definition_set'
5
- require_relative 'name_rule'
6
- require_relative 'transform_rule'
7
- require_relative 'hash_rule'
8
-
9
- module Leftovers
10
- class ArgumentRule # rubocop:disable Metrics/ClassLength
11
- def self.wrap(rules, definer: false) # rubocop:disable Metrics/MethodLength
12
- case rules
13
- when Array
14
- rules.flat_map { |r| wrap(r, definer: definer) }
15
- when Hash
16
- [new(**rules, definer: definer)]
17
- else
18
- []
19
- end
20
- end
21
-
22
- ADDITIONAL_VALID_KEYS = Leftovers::TransformRule::VALID_TRANSFORMS + %i{if unless}
23
- def initialize( # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength, Metrics/CyclomaticComplexity
24
- argument: nil,
25
- arguments: nil,
26
- key: nil,
27
- keys: nil,
28
- itself: false,
29
- linked_transforms: nil,
30
- transforms: nil,
31
- definer: false,
32
- **options
33
- )
34
- assert_valid_keys(options, ADDITIONAL_VALID_KEYS)
35
- prepare_argument(argument, arguments)
36
- @key = prepare_key(key, keys)
37
- @itself = itself
38
-
39
- unless @positions || @keywords || @all_positions || @all_keywords || @key || @itself
40
- raise ArgumentError, "require at least one of 'argument(s)', 'key(s)', itself"
41
- end
42
-
43
- @if = prepare_condition(options.delete(:if))
44
- @unless = prepare_condition(options.delete(:unless))
45
- @transforms = prepare_transform(options, transforms, linked_transforms)
46
- @definer = definer
47
- end
48
-
49
- def prepare_transform(options, transforms, linked_transforms) # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
50
- if linked_transforms && transforms
51
- raise ArgumentError, 'Only use one of linked_transforms/transforms'
52
- end
53
- return if !linked_transforms && !transforms && options.empty?
54
-
55
- if !(linked_transforms || transforms)
56
- @transform = TransformRule.new(options)
57
- else
58
- @linked = !!linked_transforms
59
-
60
- transforms = (linked_transforms || transforms).map do |transform|
61
- transform = { transform.to_sym => true } if transform.is_a?(String)
62
- Leftovers::TransformRule.new(options.merge(transform))
63
- end
64
-
65
- if transforms.length <= 1
66
- @transform = transforms.first
67
- else
68
- @transforms = transforms
69
- end
70
- end
71
- end
72
-
73
- def prepare_condition(conditions)
74
- Leftovers.array_wrap(conditions).each do |cond|
75
- cond[:has_argument] = HashRule.new(cond[:has_argument]) if cond[:has_argument]
76
- end
77
- end
78
-
79
- def prepare_key(key, keys)
80
- raise ArgumentError, 'Only use one of key/keys' if key && keys
81
-
82
- key || keys
83
- end
84
-
85
- def prepare_argument(argument, arguments) # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
86
- raise ArgumentError, 'Only use one of argument/arguments' if argument && arguments
87
-
88
- positions = Set.new
89
- keywords = []
90
-
91
- Leftovers.each_or_self(argument || arguments) do |arg|
92
- case arg
93
- when '*'
94
- @all_positions = true
95
- when '**'
96
- @all_keywords = true
97
- when Integer
98
- positions << arg - 1
99
- when String, Symbol, Hash
100
- keywords << arg
101
- end
102
- end
103
-
104
- @positions = positions unless @all_positions || positions.empty? || @all_positions
105
- @keywords = NameRule.new(keywords) unless @all_keywords || keywords.empty?
106
- end
107
-
108
- def matches(method_node) # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
109
- return [].freeze unless all_conditions_match?(method_node)
110
-
111
- result = []
112
-
113
- if @all_positions
114
- result.leftovers_append values(method_node.positional_arguments, method_node)
115
- elsif @positions
116
- result.leftovers_append(
117
- values(method_node.positional_arguments_at(@positions).compact, method_node)
118
- )
119
- end
120
-
121
- if @keywords || @all_keywords || @key
122
- result.leftovers_append hash_values(method_node.kwargs, method_node)
123
- end
124
- result << method_value(method_node) if @itself
125
-
126
- result
127
- end
128
-
129
- def values(value_nodes, method_node)
130
- value_nodes.flat_map { |value_node| value(value_node, method_node) }.compact
131
- end
132
-
133
- def all_conditions_match?(method_node)
134
- @if.all? { |c| condition_match?(c, method_node) } &&
135
- @unless.all? { |c| !condition_match?(c, method_node) }
136
- end
137
-
138
- def condition_match?(condition, method_name)
139
- return unless condition[:has_argument]
140
-
141
- hash_node = method_name.kwargs
142
- return false unless hash_node
143
-
144
- hash_node.each_pair.any? { |key, value| condition[:has_argument].match_pair?(key, value) }
145
- end
146
-
147
- def hash_values(hash_node, method_node) # rubocop:disable Metrics/MethodLength
148
- return unless hash_node
149
-
150
- value_nodes = []
151
- value_nodes.concat hash_node.keys if @key
152
-
153
- if @all_keywords
154
- value_nodes.concat(hash_node.values)
155
- elsif @keywords
156
- value_nodes.concat(hash_node.values_at_match(@keywords))
157
- end
158
-
159
- values(value_nodes, method_node)
160
- end
161
-
162
- def value(value_node, method_node) # rubocop:disable Metrics/MethodLength
163
- return unless value_node
164
-
165
- value_node = value_node.unwrap_freeze
166
-
167
- case value_node.type
168
- when :array
169
- values(value_node.values, method_node)
170
- when :hash
171
- hash_values(value_node, method_node)
172
- when :str, :sym
173
- symbol_values(value_node, method_node)
174
- end
175
- end
176
-
177
- SPLIT = /[.:]+/.freeze
178
- def symbol_values(symbol_node, method_node) # rubocop:disable Metrics/MethodLength
179
- subnodes = Array(transform(symbol_node.to_s, method_node))
180
- .flat_map { |s| s.to_s.split(SPLIT).map(&:to_sym) }
181
-
182
- return subnodes unless @definer
183
-
184
- location = symbol_node.loc.expression
185
- if @linked
186
- Leftovers::DefinitionSet.new(subnodes, location: location, method_node: method_node)
187
- else
188
- subnodes.map do |subnode|
189
- Leftovers::Definition.new(subnode, location: location, method_node: method_node)
190
- end
191
- end
192
- end
193
-
194
- def method_value(method_node)
195
- value = transform(method_node.to_s, method_node)
196
-
197
- return value unless @definer
198
-
199
- Leftovers::Definition.new(value, method_node: method_node)
200
- end
201
-
202
- def transform(string, method_node)
203
- return string unless @transform || @transforms
204
- return @transform.transform(string, method_node) if @transform
205
-
206
- @transforms.map do |transform|
207
- transform.transform(string, method_node)
208
- end
209
- end
210
-
211
- def assert_valid_keys(options, keys)
212
- invalid = options.keys - keys
213
-
214
- return if invalid.empty?
215
-
216
- raise ArgumentError, "unknown keyword#{'s' if invalid.length > 1}: #{invalid.join(', ')}"
217
- end
218
- end
219
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'set'
4
-
5
- class Array
6
- def leftovers_append(other)
7
- case other
8
- when Array, Set then concat(other)
9
- when nil then self
10
- else self.<< other
11
- end
12
- end
13
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'set'
4
- require_relative 'value_rule'
5
- require_relative 'name_rule'
6
-
7
- module Leftovers
8
- class HashRule
9
- def initialize(patterns) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
10
- keys = []
11
- pairs = []
12
- Leftovers.each_or_self(patterns) do |pat|
13
- if pat.is_a?(Hash) && pat[:value]
14
- pairs << [
15
- (NameRule.new(pat[:keyword]) if pat[:keyword]),
16
- (ValueRule.new(pat[:value]) if pat[:value])
17
- ]
18
- else
19
- keys << NameRule.new(pat)
20
- end
21
- end
22
-
23
- @keys = (NameRule.new(keys) if keys)
24
-
25
- @pairs = (pairs unless pairs.empty?)
26
-
27
- freeze
28
- end
29
-
30
- def match_pair?(key_node, value_node)
31
- return true if @keys&.match?(key_node.to_sym, key_node.to_s)
32
-
33
- @pairs&.any? do |(key_rule, value_rule)|
34
- next unless !key_rule || key_rule.match?(key_node.to_sym, key_node.to_s)
35
-
36
- (!value_rule || value_rule.match?(value_node))
37
- end
38
- end
39
- end
40
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'set'
4
- module Leftovers
5
- class NameRule
6
- attr_reader :sym, :syms, :regexp
7
-
8
- def initialize(patterns) # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
9
- regexps = []
10
- syms = Set.new
11
- Leftovers.each_or_self(patterns) do |pat|
12
- case pat
13
- when Leftovers::NameRule
14
- syms.merge(pat.sym) if pat.sym
15
- syms.merge(pat.syms) if pat.syms
16
- regexps.concat(pat.regexp) if pat.regexp
17
- when String
18
- syms.merge(pat.split(/\s+/).map(&:to_sym))
19
- when Hash
20
- if pat[:match]
21
- regexps << /\A#{pattern[:match]}\z/
22
- elsif pat[:has_prefix] && pat[:has_suffix]
23
- regexps << /\A#{Regexp.escape(pat[:has_prefix])}.*#{Regexp.escape(pat[:has_suffix])}\z/
24
- elsif pat[:has_prefix]
25
- regexps << /\A#{Regexp.escape(pat[:has_prefix])}/
26
- elsif pat[:has_suffix]
27
- regexps << /#{Regexp.escape(pat[:has_suffix])}\z/
28
- end
29
- end
30
- end
31
-
32
- if syms.length <= 0
33
- @sym = syms.first
34
- @syms = nil
35
- else
36
- @sym = nil
37
- @syms = syms
38
- end
39
-
40
- @regexp = if regexps.empty?
41
- nil
42
- else
43
- Regexp.union(regexps)
44
- end
45
-
46
- freeze
47
- end
48
-
49
- def match?(sym, string)
50
- @sym&.==(sym) || @syms&.include?(sym) || @regexp&.match?(string)
51
- end
52
- end
53
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'name_rule'
4
- require_relative 'argument_rule'
5
- require 'fast_ignore'
6
-
7
- module Leftovers
8
- class Rule
9
- def self.wrap(rules)
10
- case rules
11
- when Array then rules.flat_map { |r| wrap(r) }
12
- when nil then [].freeze
13
- else new(**rules)
14
- end
15
- end
16
-
17
- attr_reader :skip
18
- alias_method :skip?, :skip
19
-
20
- def initialize( # rubocop:disable Metrics/ParameterLists, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
21
- name: nil,
22
- names: nil,
23
- calls: nil,
24
- call: nil,
25
- skip: false,
26
- defines: nil,
27
- define: nil,
28
- path: nil,
29
- paths: nil
30
- )
31
- raise ArgumentError, 'Only use one of name/names' if name && names
32
- raise ArgumentError, 'Only use one of path/paths' if path && paths
33
- raise ArgumentError, 'Only use one of call/calls' if call && calls
34
- raise ArgumentError, 'Only use one of define/defines' if define && defines
35
- if skip && (defines || calls)
36
- raise ArgumentError, "skip can't exist with defines or calls for #{name || names}"
37
- end
38
-
39
- @name_matcher = NameRule.new(name || names)
40
- @path = FastIgnore.new(include_rules: path || paths, gitignore: false) if path || paths
41
- @skip = skip
42
-
43
- begin
44
- @calls = ArgumentRule.wrap(calls)
45
- rescue ArgumentError => e
46
- raise e, "#{e.message} for calls for #{name}", e.backtrace
47
- end
48
-
49
- begin
50
- @defines = ArgumentRule.wrap(defines, definer: true)
51
- rescue ArgumentError => e
52
- raise e, "#{e.message} for defines for #{name}", e.backtrace
53
- end
54
- end
55
-
56
- def filename?(file)
57
- return true unless @path
58
-
59
- @path.allowed?(file)
60
- end
61
-
62
- def match?(name, name_s, file)
63
- @name_matcher.match?(name, name_s) && filename?(file)
64
- end
65
-
66
- def calls(node)
67
- @calls.flat_map { |m| m.matches(node) }
68
- end
69
-
70
- def definitions(node)
71
- @defines.flat_map { |m| m.matches(node) }
72
- end
73
- end
74
- end
@@ -1,171 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Leftovers
4
- class TransformRule # rubocop:disable Metrics/ClassLength
5
- # :nocov:
6
- using ::Leftovers::StringDeletePrefixSuffix if defined?(::Leftovers::StringDeletePrefixSuffix)
7
- # :nocov:
8
-
9
- RUBY_STRING_METHODS = %i{
10
- downcase
11
- upcase
12
- capitalize
13
- swapcase
14
- }.freeze
15
-
16
- ACTIVESUPPORT_STRING_METHODS = %i{
17
- pluralize
18
- singularize
19
- camelize
20
- camelcase
21
- underscore
22
- titleize
23
- titlecase
24
- demodulize
25
- deconstantize
26
- parameterize
27
- }.freeze
28
-
29
- CUSTOM_TRANSFORMS = %i{
30
- original
31
- delete_before
32
- delete_after
33
- add_prefix
34
- add_suffix
35
- delete_prefix
36
- delete_suffix
37
- replace_with
38
- }.freeze
39
-
40
- VALID_TRANSFORMS = RUBY_STRING_METHODS + ACTIVESUPPORT_STRING_METHODS + CUSTOM_TRANSFORMS
41
- # more possible transformations
42
- # gsub sub tr tr_s
43
- def initialize(transforms)
44
- @transforms = prepare_transforms(transforms)
45
-
46
- freeze
47
- end
48
-
49
- def transform(original_string, method_node)
50
- string = original_string
51
- @transforms.each { |proc| string = proc.call(string, method_node) }
52
-
53
- string.to_sym
54
- end
55
-
56
- private
57
-
58
- def prepare_transforms(transforms) # rubocop:disable Metrics/MethodLength
59
- transforms.map do |key, value|
60
- unless VALID_TRANSFORMS.include?(key)
61
- raise ArgumentError, <<~MESSAGE
62
- invalid transform key: (#{key}: #{value}).
63
- Valid transform keys are #{ALL_VALID_TRANSFORMS}"
64
- MESSAGE
65
- end
66
-
67
- key, value = prepare_hash_value(key, value) if value.is_a?(Hash)
68
-
69
- instance_variable_set(:"@#{key}", value.freeze)
70
- method(key)
71
- end
72
- end
73
-
74
- HASH_VALUE_TRANSFORMS = %i{add_prefix add_suffix}.freeze
75
- HASH_VALUE_KEYS = %i{from_argument joiner}.freeze
76
- def prepare_hash_value(method, hash) # rubocop:disable Metrics/MethodLength
77
- raise ArgumentError, <<~MESSAGE unless HASH_VALUE_TRANSFORMS.include?(method)
78
- invalid transform value (#{key}: #{value}).
79
- Hash values are only valid for #{HASH_VALUE_TRANSFORMS}
80
- MESSAGE
81
-
82
- hash = hash.map do |k, v|
83
- raise ArgumentError, <<~MESSAGE unless HASH_VALUE_KEYS.include?(k)
84
- invalid transform value argument (#{method}: { #{k}: #{v} }).
85
- Hash values are only valid for #{HASH_VALUE_TRANSFORMS}
86
- MESSAGE
87
-
88
- [k, v.to_sym]
89
- end.to_h
90
-
91
- ["#{method}_dynamic", hash]
92
- end
93
-
94
- RUBY_STRING_METHODS.each do |method|
95
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
96
- def #{method}(string, _method_node)
97
- string.#{method}
98
- end
99
- RUBY
100
- end
101
-
102
- # leftovers:call activesupport_available?
103
- ACTIVESUPPORT_STRING_METHODS.each do |method|
104
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
105
- def #{method}(string, _method_node)
106
- return string unless activesupport_available?(:#{method})
107
-
108
- string.#{method}
109
- end
110
- RUBY
111
- end
112
-
113
- def original(string, _method_node)
114
- string
115
- end
116
-
117
- def delete_prefix(string, _method_node)
118
- string.delete_prefix(@delete_prefix)
119
- end
120
-
121
- def delete_suffix(string, _method_node)
122
- string.delete_suffix(@delete_suffix)
123
- end
124
-
125
- def delete_before(string, _method_node)
126
- string.split(@delete_before, 2)[1] || string
127
- end
128
-
129
- def delete_after(string, _method_node)
130
- string.split(@delete_after, 2).first
131
- end
132
-
133
- def replace_with(_string, _method_node)
134
- @replace_with
135
- end
136
-
137
- def add_prefix(string, _method_node)
138
- "#{@add_prefix}#{string}"
139
- end
140
-
141
- def add_suffix(string, _method_node)
142
- "#{string}#{@add_suffix}"
143
- end
144
-
145
- def add_prefix_dynamic(string, method_node)
146
- "#{dynamic_value(@add_prefix_dynamic, method_node)}#{@add_prefix_dynamic[:joiner]}#{string}"
147
- end
148
-
149
- def add_suffix_dynamic(string, method_node)
150
- "#{string}#{@add_suffix_dynamic[:joiner]}#{dynamic_value(@add_suffix_dynamic, method_node)}"
151
- end
152
-
153
- def dynamic_value(value, method_node)
154
- method_node.kwargs[value[:from_argument]].to_s if value[:from_argument]
155
- end
156
-
157
- def activesupport_available?(method) # rubocop:disable Metrics/MethodLength
158
- Leftovers.try_require(
159
- 'active_support/core_ext/string', 'active_support/inflections',
160
- message: <<~MESSAGE
161
- Tried transforming a string using an activesupport method (#{method}), but the activesupport gem was not available
162
- `gem install activesupport`
163
- MESSAGE
164
- )
165
-
166
- Leftovers.try_require(::File.join(Leftovers.pwd, 'config', 'initializers', 'inflections.rb'))
167
-
168
- defined?(ActiveSupport)
169
- end
170
- end
171
- end