class RuboCop::Cop::Style::ArgumentsForwarding
end
bar(**kwargs)
def foo(**kwargs)
end
bar(*args)
def foo(*args)
# but it will change the behavior. Because ‘…` forwards block also.
# The following code can replace the arguments with `…`,
# bad
@example AllowOnlyRestArgument: false
end
bar(**kwargs)
def foo(**kwargs)
end
bar(*args)
def foo(*args)
# good
@example AllowOnlyRestArgument: true (default)
end
bar(…)
def foo(…)
# good
end
bar(*args, **kwargs, &block)
def foo(*args, **kwargs, &block)
# bad
end
bar(*args, &block)
def foo(*args, &block)
# bad
@example
can be replaced by `do_something(…)`.
This cop identifies places where `do_something(*args, &block)`
In Ruby 2.7, arguments forwarding has been added.
def all_lvars_as_forwarding_method_arguments?(def_node, forwarding_method)
def all_lvars_as_forwarding_method_arguments?(def_node, forwarding_method) lvars = def_node.body.each_descendant(:lvar, :lvasgn) begin_pos = forwarding_method.source_range.begin_pos end_pos = forwarding_method.source_range.end_pos lvars.all? { |lvar| lvar.source_range.begin_pos.between?(begin_pos, end_pos) } end
def allow_only_rest_arguments?
def allow_only_rest_arguments? cop_config.fetch('AllowOnlyRestArgument', true) end
def arguments_range(node)
def arguments_range(node) arguments = node.arguments range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos) end
def extract_argument_names_from(args)
def extract_argument_names_from(args) kwargs_name = args.first.source.delete('**') if args.first&.kwrestarg_type? block_arg_name = args.last.source.delete('&') if args.last&.blockarg_type? [kwargs_name, block_arg_name].map { |name| name&.to_sym } end
def forwarding_method?(node, rest_arg, kwargs, block_arg)
def forwarding_method?(node, rest_arg, kwargs, block_arg) return only_rest_arguments?(node, rest_arg) unless allow_only_rest_arguments? forwarding_method_arguments?(node, rest_arg, block_arg, kwargs) end
def on_def(node)
def on_def(node) return unless node.body return unless (rest_args_name, args = use_rest_arguments?(node.arguments)) return if args.any?(&:default?) node.each_descendant(:send) do |send_node| kwargs_name, block_name = extract_argument_names_from(args) next unless forwarding_method?(send_node, rest_args_name, kwargs_name, block_name) && all_lvars_as_forwarding_method_arguments?(node, send_node) register_offense_to_forwarding_method_arguments(send_node) register_offense_to_method_definition_arguments(node) end end
def register_offense_to_forwarding_method_arguments(forwarding_method)
def register_offense_to_forwarding_method_arguments(forwarding_method) add_offense(arguments_range(forwarding_method)) do |corrector| begin_pos = forwarding_method.loc.selector&.end_pos || forwarding_method.loc.dot.end_pos range = range_between(begin_pos, forwarding_method.source_range.end_pos) corrector.replace(range, '(...)') end end
def register_offense_to_method_definition_arguments(method_definition)
def register_offense_to_method_definition_arguments(method_definition) add_offense(arguments_range(method_definition)) do |corrector| arguments_range = range_with_surrounding_space( method_definition.arguments.source_range, side: :left ) corrector.replace(arguments_range, '(...)') end end