class RuboCop::Cop::Bundler::GemComment
gem ‘bar’, ‘< 2.1’
# Version 2.1 introduces breaking change baz
gem ‘foo’, github: ‘some_account/some_fork_of_foo’
# Using this fork because baz
# good
gem ‘bar’, ‘< 2.1’
gem ‘foo’, github: ‘some_account/some_fork_of_foo’
# bad
@example OnlyFor: [‘version_specifiers’, ‘github’]
gem ‘foo’, ‘< 2.1’
# Version 2.1 introduces breaking change baz
gem ‘foo’, ‘>= 1.0’
# good
gem ‘foo’, ‘< 2.1’
# bad
@example OnlyFor: [‘restrictive_version_specifiers’]
gem ‘foo’, ‘< 2.1’
# Version 2.1 introduces breaking change baz
# good
gem ‘foo’, ‘< 2.1’
# bad
@example OnlyFor: [‘version_specifiers’]
gem ‘foo’
# Helpers for the foo things.
# good
gem ‘foo’
# bad
@example OnlyFor: [] (default)
.
see bundler.io/man/gemfile.5.html<br>For a full list of options supported by bundler,
- ‘source`
- `github`
- `git`
- `gist`
- `bitbucket`
options that change the source of a gem:
A useful use case is to enforce a comment when using
a gem if an option by the same name is present.
For any other value in the array, a comment will be enforced for
holds back the version of the gem.
will be enforced if the gem has a version specifier that
When “restrictive_version_specifiers” is included, a comment
will be enforced if the gem has any version specifier.
When “version_specifiers” is included, a comment
use certain options or have version specifiers.
can be used to only register offenses when the gems
The optional “OnlyFor” configuration array
or source.
its purpose in the project, or the reason for its version
Each gem in the Gemfile should have a comment explaining
def checked_options_present?(node)
def checked_options_present?(node) (cop_config[CHECKED_OPTIONS_CONFIG].include?(VERSION_SPECIFIERS_OPTION) && version_specified_gem?(node)) || (cop_config[CHECKED_OPTIONS_CONFIG].include?(RESTRICTIVE_VERSION_SPECIFIERS_OPTION) && restrictive_version_specified_gem?(node)) || contains_checked_options?(node) end
def commented?(node)
def commented?(node) preceding_lines = preceding_lines(node) preceding_comment?(node, preceding_lines.last) end
def commented_any_descendant?(node)
def commented_any_descendant?(node) commented?(node) || node.each_descendant.any? { |n| commented?(n) } end
def contains_checked_options?(node)
def contains_checked_options?(node) (Array(cop_config[CHECKED_OPTIONS_CONFIG]) & gem_options(node).map(&:to_s)).any? end
def gem_options(node)
def gem_options(node) return [] unless node.arguments.last&.type == :hash node.arguments.last.keys.map(&:value) end
def ignored_gem?(node)
def ignored_gem?(node) ignored_gems = Array(cop_config['IgnoredGems']) ignored_gems.include?(node.first_argument.value) end
def on_send(node)
def on_send(node) return unless gem_declaration?(node) return if ignored_gem?(node) return if commented_any_descendant?(node) return if cop_config[CHECKED_OPTIONS_CONFIG].any? && !checked_options_present?(node) add_offense(node) end
def precede?(node1, node2)
The args node1 & node2 may represent a RuboCop::AST::Node
def precede?(node1, node2) node2.loc.line - node1.loc.line <= 1 end
def preceding_comment?(node1, node2)
def preceding_comment?(node1, node2) node1 && node2 && precede?(node2, node1) && comment_line?(node2.source) end
def preceding_lines(node)
def preceding_lines(node) processed_source.ast_with_comments[node].select do |line| line.loc.line <= node.loc.line end end
def restrictive_version_specified_gem?(node)
Version specifications that restrict all updates going forward. This excludes versions
def restrictive_version_specified_gem?(node) return false unless version_specified_gem?(node) node.arguments[1..] .any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.value) } end
def version_specified_gem?(node)
Besides the gem name, all other *positional* arguments to `gem` are version specifiers,
def version_specified_gem?(node) # arguments[0] is the gem name node.arguments[1]&.str_type? end