debian-mirror-gitlab/rubocop/cop/gettext/static_identifier.rb
2023-07-09 08:55:56 +05:30

84 lines
2.3 KiB
Ruby

# frozen_string_literal: true
module RuboCop
module Cop
module Gettext
# Ensure that gettext identifiers are statically defined and not
# interpolated, formatted, or concatenated.
#
# @example
#
# # bad
# _('Hi #{name}')
# _('Hi %{name}' % { name: 'Luki' })
# _(format('Hi %{name}', name: 'Luki'))
#
# # good
# _('Hi %{name}') % { name: 'Luki' }
# format(_('Hi %{name}', name: 'Luki'))
#
# # also good
# var = "Hi"
# _(var)
# _(some_method_call)
# _(CONST)
class StaticIdentifier < RuboCop::Cop::Base
MSG = 'Ensure to pass static strings to translation method `%{method_name}(...)`.'
# Number of parameters to check for translation methods.
PARAMETERS_TO_CHECK = {
_: 1,
s_: 1,
N_: 1,
n_: 2
}.freeze
# RuboCop-specific optimization for `on_send`.
RESTRICT_ON_SEND = PARAMETERS_TO_CHECK.keys.freeze
DENIED_METHOD_CALLS = %i[% format + concat].freeze
def on_send(node)
method_name = node.method_name
arguments = node.arguments
each_invalid_argument(method_name, arguments) do |argument_node|
message = format(MSG, method_name: method_name)
add_offense(argument_node || node, message: message)
end
end
private
def each_invalid_argument(method_name, argument_nodes)
number = PARAMETERS_TO_CHECK.fetch(method_name)
argument_nodes.take(number).each do |argument_node|
yield argument_node unless valid_argument?(argument_node)
end
end
def valid_argument?(node)
return false unless node
basic_type?(node) || multiline_string?(node) || allowed_method_call?(node)
end
def basic_type?(node)
node.str_type? || node.lvar_type? || node.const_type?
end
def multiline_string?(node)
node.dstr_type? && node.children.all?(&:str_type?)
end
def allowed_method_call?(node)
return false unless node.send_type?
!DENIED_METHOD_CALLS.include?(node.method_name) # rubocop:disable Rails/NegateInclude
end
end
end
end
end