lib/rubocop/cop/style/hash_syntax.rb in rubocop-0.29.1 vs lib/rubocop/cop/style/hash_syntax.rb in rubocop-0.30.0
- old
+ new
@@ -11,51 +11,96 @@
# A separate offense is registered for each problematic pair.
class HashSyntax < Cop
include ConfigurableEnforcedStyle
MSG_19 = 'Use the new Ruby 1.9 hash syntax.'
- MSG_HASH_ROCKETS = 'Always use hash rockets in hashes.'
+ MSG_RUBY19_NO_MIXED_KEYS = "Don't mix styles in the same hash."
+ MSG_HASH_ROCKETS = 'Use hash rockets syntax.'
+ @force_hash_rockets = false
+
def on_hash(node)
- style == :ruby19 ? ruby19_check(node) : hash_rockets_check(node)
+ if cop_config['UseHashRocketsWithSymbolValues']
+ pairs = *node
+ @force_hash_rockets = pairs.any? { |p| symbol_value?(p) }
+ end
+
+ if style == :hash_rockets || @force_hash_rockets
+ hash_rockets_check(node)
+ elsif style == :ruby19_no_mixed_keys
+ ruby19_no_mixed_keys_check(node)
+ else
+ ruby19_check(node)
+ end
end
def ruby19_check(node)
pairs = *node
- sym_indices = pairs.all? { |p| word_symbol_pair?(p) }
-
- check(pairs, '=>', MSG_19) if sym_indices
+ check(pairs, '=>', MSG_19) if sym_indices?(pairs)
end
def hash_rockets_check(node)
pairs = *node
check(pairs, ':', MSG_HASH_ROCKETS)
end
- def autocorrect(node)
- key = node.children.first.loc.expression
- op = node.loc.operator
+ def ruby19_no_mixed_keys_check(node)
+ pairs = *node
+ if @force_hash_rockets
+ check(pairs, ':', MSG_HASH_ROCKETS)
+ elsif sym_indices?(pairs)
+ check(pairs, '=>', MSG_19)
+ else
+ check(pairs, ':', MSG_RUBY19_NO_MIXED_KEYS)
+ end
+ end
+
+ def autocorrect(node)
@corrections << lambda do |corrector|
- if style == :ruby19
- range = Parser::Source::Range.new(key.source_buffer,
- key.begin_pos, op.end_pos)
- range = range_with_surrounding_space(range, :right)
- corrector.replace(range,
- range.source.sub(/^:(.*\S)\s*=>\s*$/, '\1: '))
+ if style == :hash_rockets || @force_hash_rockets
+ autocorrect_hash_rockets(corrector, node)
+ elsif style == :ruby19_no_mixed_keys
+ autocorrect_ruby19_no_mixed_keys(corrector, node)
else
- corrector.insert_after(key, ' => ')
- corrector.insert_before(key, ':')
- corrector.remove(range_with_surrounding_space(op))
+ autocorrect_ruby19(corrector, node)
end
end
end
+ def alternative_style
+ case style
+ when :hash_rockets then
+ :ruby19
+ when :ruby19, :ruby19_no_mixed_keys then
+ :hash_rockets
+ end
+ end
+
private
+ def symbol_value?(pair)
+ _key, value = *pair
+
+ value.sym_type?
+ end
+
+ def sym_indices?(pairs)
+ pairs.all? { |p| word_symbol_pair?(p) }
+ end
+
+ def word_symbol_pair?(pair)
+ key, _value = *pair
+
+ return false unless key.sym_type?
+
+ sym_name = key.loc.expression.source
+ sym_name !~ /\A:["']|=\z/
+ end
+
def check(pairs, delim, msg)
pairs.each do |pair|
if pair.loc.operator && pair.loc.operator.is?(delim)
add_offense(pair,
pair.loc.expression.begin.join(pair.loc.operator),
@@ -66,18 +111,36 @@
correct_style_detected
end
end
end
- def word_symbol_pair?(pair)
- key, _value = *pair
+ def autocorrect_ruby19(corrector, node)
+ key = node.children.first.loc.expression
+ op = node.loc.operator
- if key.type == :sym
- sym_name = key.to_a[0]
+ range = Parser::Source::Range.new(key.source_buffer,
+ key.begin_pos, op.end_pos)
+ range = range_with_surrounding_space(range, :right)
+ corrector.replace(range,
+ range.source.sub(/^:(.*\S)\s*=>\s*$/, '\1: '))
+ end
- sym_name =~ /\A[A-Za-z_]\w*\z/
+ def autocorrect_hash_rockets(corrector, node)
+ key = node.children.first.loc.expression
+ op = node.loc.operator
+
+ corrector.insert_after(key, ' => ')
+ corrector.insert_before(key, ':')
+ corrector.remove(range_with_surrounding_space(op))
+ end
+
+ def autocorrect_ruby19_no_mixed_keys(corrector, node)
+ op = node.loc.operator
+
+ if op.is?(':')
+ autocorrect_hash_rockets(corrector, node)
else
- false
+ autocorrect_ruby19(corrector, node)
end
end
end
end
end