# encoding: utf-8 module RuboCop module Cop module Style # This cop looks for uses of Perl-style global variables. class SpecialGlobalVars < Cop MSG_BOTH = 'Prefer `%s` from the English library, or `%s` over `%s`.' MSG_ENGLISH = 'Prefer `%s` from the English library over `%s`.' MSG_REGULAR = 'Prefer `%s` over `%s`.' PREFERRED_VARS = { '$:' => ['$LOAD_PATH'], '$"' => ['$LOADED_FEATURES'], '$0' => ['$PROGRAM_NAME'], '$!' => ['$ERROR_INFO'], '$@' => ['$ERROR_POSITION'], '$;' => ['$FIELD_SEPARATOR', '$FS'], '$,' => ['$OUTPUT_FIELD_SEPARATOR', '$OFS'], '$/' => ['$INPUT_RECORD_SEPARATOR', '$RS'], '$\\' => ['$OUTPUT_RECORD_SEPARATOR', '$ORS'], '$.' => ['$INPUT_LINE_NUMBER', '$NR'], '$_' => ['$LAST_READ_LINE'], '$>' => ['$DEFAULT_OUTPUT'], '$<' => ['$DEFAULT_INPUT'], '$$' => ['$PROCESS_ID', '$PID'], '$?' => ['$CHILD_STATUS'], '$~' => ['$LAST_MATCH_INFO'], '$=' => ['$IGNORECASE'], '$*' => ['$ARGV', 'ARGV'], '$&' => ['$MATCH'], '$`' => ['$PREMATCH'], '$\'' => ['$POSTMATCH'], '$+' => ['$LAST_PAREN_MATCH'] }.symbolize_keys # Anything *not* in this set is provided by the English library. NON_ENGLISH_VARS = Set.new([ '$LOAD_PATH', '$LOADED_FEATURES', '$PROGRAM_NAME', 'ARGV' ]) def on_gvar(node) global_var, = *node add_offense(node, :expression) if PREFERRED_VARS[global_var] end def message(node) global_var, = *node regular, english = PREFERRED_VARS[global_var].partition do |var| NON_ENGLISH_VARS.include? var end # For now, we assume that lists are 2 items or less. Easy grammar! regular_msg = regular.join('` or `') english_msg = english.join('` or `') if regular.length > 0 && english.length > 0 format(MSG_BOTH, english_msg, regular_msg, global_var) elsif regular.length > 0 format(MSG_REGULAR, regular_msg, global_var) elsif english.length > 0 format(MSG_ENGLISH, english_msg, global_var) else fail 'Bug in SpecialGlobalVars - global var w/o preferred vars!' end end def autocorrect(node) @corrections << lambda do |corrector| global_var, = *node corrector.replace(node.loc.expression, PREFERRED_VARS[global_var].first) end end end end end end