From f8f1cd46816d38efc7e23d8cabd336c6ce5a79e2 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sun, 7 Feb 2021 03:00:53 +0900 Subject: [PATCH] Add new `Gemspec/DateAssignment` cop Follow https://github.com/rubocop-hq/rubocop-rails/issues/432. This PR adds new `Gemspec/DateAssignment` cop. This cop checks that `date =` is not used in gemspec file. It is set automatically when the gem is packaged. ```ruby # bad Gem::Specification.new do |spec| s.name = 'your_cool_gem' spec.date = Time.now.strftime('%Y-%m-%d') end # good Gem::Specification.new do |spec| s.name = 'your_cool_gem' end ``` RubyGems doesn't expect the value to be set. https://github.com/rubygems/rubygems/blob/be08d8307eda3b61f0ec0460fe7fbcf647b526e6/lib/rubygems/specification.rb#L1679-L1681 --- ...new_add_new_gemspec_date_assignment_cop.md | 1 + config/default.yml | 7 +++ lib/rubocop.rb | 1 + lib/rubocop/cop/gemspec/date_assignment.rb | 56 +++++++++++++++++++ spec/rubocop/cli/cli_options_spec.rb | 2 + .../cop/gemspec/date_assignment_spec.rb | 53 ++++++++++++++++++ 6 files changed, 120 insertions(+) create mode 100644 changelog/new_add_new_gemspec_date_assignment_cop.md create mode 100644 lib/rubocop/cop/gemspec/date_assignment.rb create mode 100644 spec/rubocop/cop/gemspec/date_assignment_spec.rb diff --git a/changelog/new_add_new_gemspec_date_assignment_cop.md b/changelog/new_add_new_gemspec_date_assignment_cop.md new file mode 100644 index 00000000000..bf90559e866 --- /dev/null +++ b/changelog/new_add_new_gemspec_date_assignment_cop.md @@ -0,0 +1 @@ +* [#9496](https://github.com/rubocop-hq/rubocop/pull/9496): Add new `Gemspec/DateAssignment` cop. ([@koic][]) diff --git a/config/default.yml b/config/default.yml index f84e91cf3c3..5549a982da0 100644 --- a/config/default.yml +++ b/config/default.yml @@ -203,6 +203,13 @@ Bundler/OrderedGems: #################### Gemspec ############################### +Gemspec/DateAssignment: + Description: 'Checks that `date =` is not used in gemspec file, it is set automatically when the gem is packaged.' + Enabled: pending + VersionAdded: '<>' + Include: + - '**/*.gemspec' + Gemspec/DuplicatedAssignment: Description: 'An attribute assignment method calls should be listed only once in a gemspec.' Enabled: true diff --git a/lib/rubocop.rb b/lib/rubocop.rb index d4ffffb882c..c1891b089a1 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -152,6 +152,7 @@ require_relative 'rubocop/cop/bundler/insecure_protocol_source' require_relative 'rubocop/cop/bundler/ordered_gems' +require_relative 'rubocop/cop/gemspec/date_assignment' require_relative 'rubocop/cop/gemspec/duplicated_assignment' require_relative 'rubocop/cop/gemspec/ordered_dependencies' require_relative 'rubocop/cop/gemspec/required_ruby_version' diff --git a/lib/rubocop/cop/gemspec/date_assignment.rb b/lib/rubocop/cop/gemspec/date_assignment.rb new file mode 100644 index 00000000000..73e98accf61 --- /dev/null +++ b/lib/rubocop/cop/gemspec/date_assignment.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Gemspec + # This cop checks that `date =` is not used in gemspec file. + # It is set automatically when the gem is packaged. + # + # @example + # + # # bad + # Gem::Specification.new do |spec| + # s.name = 'your_cool_gem_name' + # spec.date = Time.now.strftime('%Y-%m-%d') + # end + # + # # good + # Gem::Specification.new do |spec| + # s.name = 'your_cool_gem_name' + # end + # + class DateAssignment < Base + include RangeHelp + extend AutoCorrector + + MSG = 'Do not use `date =` in gemspec, it is set automatically when the gem is packaged.' + + def_node_matcher :gem_specification, <<~PATTERN + (block + (send + (const + (const {cbase nil?} :Gem) :Specification) :new) + ...) + PATTERN + + def on_block(block_node) + return unless gem_specification(block_node) + + block_parameter = block_node.arguments.first.source + + date_assignment = block_node.descendants.detect do |node| + node.send_type? && node.receiver&.source == block_parameter && node.method?(:date=) + end + + return unless date_assignment + + add_offense(date_assignment) do |corrector| + range = range_by_whole_lines(date_assignment.source_range, include_final_newline: true) + + corrector.remove(range) + end + end + end + end + end +end diff --git a/spec/rubocop/cli/cli_options_spec.rb b/spec/rubocop/cli/cli_options_spec.rb index de18c4b3dd2..14af43a1062 100644 --- a/spec/rubocop/cli/cli_options_spec.rb +++ b/spec/rubocop/cli/cli_options_spec.rb @@ -541,6 +541,8 @@ class SomeCop < Cop Enabled: false Layout: Enabled: false + Gemspec: + Enabled: false Style/SomeCop: Description: Something diff --git a/spec/rubocop/cop/gemspec/date_assignment_spec.rb b/spec/rubocop/cop/gemspec/date_assignment_spec.rb new file mode 100644 index 00000000000..ea3d6ef5075 --- /dev/null +++ b/spec/rubocop/cop/gemspec/date_assignment_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Gemspec::DateAssignment, :config do + it 'registers and corrects an offense when using `s.date =`' do + expect_offense(<<~RUBY) + Gem::Specification.new do |s| + s.name = 'your_cool_gem_name' + s.date = Time.now.strftime('%Y-%m-%d') + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `date =` in gemspec, it is set automatically when the gem is packaged. + s.bindir = 'exe' + end + RUBY + + expect_correction(<<~RUBY) + Gem::Specification.new do |s| + s.name = 'your_cool_gem_name' + s.bindir = 'exe' + end + RUBY + end + + it 'registers and corrects an offense when using `spec.date =`' do + expect_offense(<<~RUBY) + Gem::Specification.new do |spec| + spec.name = 'your_cool_gem_name' + spec.date = Time.now.strftime('%Y-%m-%d') + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `date =` in gemspec, it is set automatically when the gem is packaged. + spec.bindir = 'exe' + end + RUBY + + expect_correction(<<~RUBY) + Gem::Specification.new do |spec| + spec.name = 'your_cool_gem_name' + spec.bindir = 'exe' + end + RUBY + end + + it 'does not register an offense when using `s.date =` outside `Gem::Specification.new`' do + expect_no_offenses(<<~RUBY) + s.date = Time.now.strftime('%Y-%m-%d') + RUBY + end + + it 'does not register an offense when using `date =` and receiver is not `Gem::Specification.new` block variable' do + expect_no_offenses(<<~RUBY) + Gem::Specification.new do |spec| + s.date = Time.now.strftime('%Y-%m-%d') + end + RUBY + end +end