From dae577ea21f5b21a69ccd73574d696415be71f85 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 10:56:40 +0100 Subject: [PATCH 01/14] chore: update gem dependencies to work with ruby 3.2.2 --- .gitignore | 2 - .ruby-version | 1 + Gemfile | 8 +- Gemfile.lock | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 239 insertions(+), 7 deletions(-) create mode 100644 .ruby-version create mode 100644 Gemfile.lock diff --git a/.gitignore b/.gitignore index bd5cc0e0b..a38a363d9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,12 +3,10 @@ .bundle .gems .rbenv-version -.ruby-* /.idea/ /.rbx /.rvmrc /.yardoc/* -/Gemfile.lock /coverage/* /dist /doc/* diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 000000000..acf9bf09d --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.2.2 \ No newline at end of file diff --git a/Gemfile b/Gemfile index 0998ee0d0..9519a924e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,5 @@ source 'https://rubygems.org' -ruby '>= 2.4.0' - gem 'activerecord', '>= 4.2.5', '< 6', require: false gem 'rake', require: false @@ -19,9 +17,10 @@ group :development, :test do gem 'guard-rspec', require: false gem 'rspec', require: false - gem 'rubocop', '~> 1.12.0', require: false + gem 'racc' + gem 'rubocop', require: false gem 'rubocop-rake', require: false - gem 'rubocop-rspec', '~> 2.2.0', require: false + gem 'rubocop-rspec', require: false gem 'simplecov', require: false gem 'terminal-notifier-guard', require: false @@ -29,7 +28,6 @@ group :development, :test do gem 'coveralls' gem 'overcommit' - gem 'ruby_dep', '1.5.0' platforms :mri, :mingw do gem 'pry', require: false diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..d875c162d --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,235 @@ +GEM + remote: https://rubygems.org/ + specs: + activemodel (5.2.8.1) + activesupport (= 5.2.8.1) + activerecord (5.2.8.1) + activemodel (= 5.2.8.1) + activesupport (= 5.2.8.1) + arel (>= 9.0) + activesupport (5.2.8.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + arel (9.0.0) + ast (2.4.3) + base64 (0.3.0) + bigdecimal (3.2.1) + bump (0.10.0) + byebug (12.0.0) + childprocess (5.1.0) + logger (~> 1.5) + codeclimate-test-reporter (1.0.7) + simplecov + coderay (1.1.3) + concurrent-ruby (1.3.5) + coveralls (0.8.23) + json (>= 1.8, < 3) + simplecov (~> 0.16.1) + term-ansicolor (~> 1.3) + thor (>= 0.19.4, < 2.0) + tins (~> 1.6) + diff-lcs (1.6.2) + docile (1.4.1) + faraday (2.7.12) + base64 + faraday-net_http (>= 2.0, < 3.1) + ruby2_keywords (>= 0.0.4) + faraday-net_http (3.0.2) + faraday-rack (2.1.2) + faraday (~> 2.0) + ffi (1.17.2) + ffi (1.17.2-aarch64-linux-gnu) + ffi (1.17.2-aarch64-linux-musl) + ffi (1.17.2-arm-linux-gnu) + ffi (1.17.2-arm-linux-musl) + ffi (1.17.2-arm64-darwin) + ffi (1.17.2-x86-linux-gnu) + ffi (1.17.2-x86-linux-musl) + ffi (1.17.2-x86_64-darwin) + ffi (1.17.2-x86_64-linux-gnu) + ffi (1.17.2-x86_64-linux-musl) + files (0.4.0) + formatador (1.1.0) + git (3.1.0) + activesupport (>= 5.0) + addressable (~> 2.8) + process_executer (~> 1.3) + rchardet (~> 1.9) + guard (2.19.1) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + logger (~> 1.6) + lumberjack (>= 1.0.12, < 2.0) + nenv (~> 0.1) + notiffany (~> 0.0) + ostruct (~> 0.6) + pry (>= 0.13.0) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) + guard-rspec (4.7.3) + guard (~> 2.1) + guard-compat (~> 1.1) + rspec (>= 2.99.0, < 4.0) + highline (2.1.0) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + iniparse (1.5.0) + json (2.12.2) + json_pure (2.6.3) + language_server-protocol (3.17.0.5) + launchy (2.5.2) + addressable (~> 2.8) + listen (3.9.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.7.0) + lumberjack (1.2.10) + method_source (1.1.0) + mg (0.0.8) + rake + minitest (5.25.5) + nenv (0.3.0) + notiffany (0.1.3) + nenv (~> 0.1) + shellany (~> 0.0) + ostruct (0.6.1) + overcommit (0.67.1) + childprocess (>= 0.6.3, < 6) + iniparse (~> 1.4) + rexml (>= 3.3.9) + parallel (1.27.0) + parser (3.3.8.0) + ast (~> 2.4.1) + racc + prism (1.4.0) + process_executer (1.3.0) + pry (0.15.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.11.0) + byebug (~> 12.0) + pry (>= 0.13, < 0.16) + public_suffix (6.0.2) + pusher-client (0.6.2) + json + websocket (~> 1.0) + racc (1.7.3) + rainbow (3.1.1) + rake (13.3.0) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) + rchardet (1.9.0) + regexp_parser (2.10.0) + rexml (3.4.1) + rspec (3.13.1) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.4) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.5) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.5) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.4) + rubocop (1.60.2) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.30.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.44.1) + parser (>= 3.3.7.2) + prism (~> 1.4) + rubocop-capybara (2.21.0) + rubocop (~> 1.41) + rubocop-factory_bot (2.26.0) + rubocop (~> 1.41) + rubocop-rake (0.6.0) + rubocop (~> 1.0) + rubocop-rspec (2.26.1) + rubocop (~> 1.40) + rubocop-capybara (~> 2.17) + rubocop-factory_bot (~> 2.22) + ruby-progressbar (1.13.0) + ruby2_keywords (0.0.5) + shellany (0.0.1) + simplecov (0.16.1) + docile (~> 1.1) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + sync (0.5.0) + term-ansicolor (1.11.2) + tins (~> 1.0) + terminal-notifier-guard (1.7.0) + thor (1.3.2) + thread_safe (0.3.6) + tins (1.38.0) + bigdecimal + sync + travis (1.13.1) + faraday (~> 2.7.10) + faraday-rack (~> 2) + highline (~> 2.1.0) + json_pure (~> 2.6.3) + launchy (~> 2.5.2) + pusher-client (~> 0.6.2) + tzinfo (1.2.11) + thread_safe (~> 0.1) + unicode-display_width (2.6.0) + websocket (1.2.11) + yard (0.9.37) + +PLATFORMS + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + x86-linux-gnu + x86-linux-musl + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + activerecord (>= 4.2.5, < 6) + bump + byebug + codeclimate-test-reporter + coveralls + files + git + guard-rspec + mg + overcommit + pry + pry-byebug + racc + rake + rspec + rubocop + rubocop-rake + rubocop-rspec + simplecov + terminal-notifier-guard + travis + yard + +BUNDLED WITH + 2.6.7 From 67a20043eb6ab140999d0b2ef144cdcf7b974119 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 10:59:07 +0100 Subject: [PATCH 02/14] chore: bump activerecord to rails 8 --- Gemfile | 2 +- Gemfile.lock | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Gemfile b/Gemfile index 9519a924e..e3ff4c028 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'activerecord', '>= 4.2.5', '< 6', require: false +gem 'activerecord', '>= 8.0.0', '< 9', require: false gem 'rake', require: false group :development do diff --git a/Gemfile.lock b/Gemfile.lock index d875c162d..1a69bd49d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,22 +1,30 @@ GEM remote: https://rubygems.org/ specs: - activemodel (5.2.8.1) - activesupport (= 5.2.8.1) - activerecord (5.2.8.1) - activemodel (= 5.2.8.1) - activesupport (= 5.2.8.1) - arel (>= 9.0) - activesupport (5.2.8.1) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) + activemodel (8.0.2) + activesupport (= 8.0.2) + activerecord (8.0.2) + activemodel (= 8.0.2) + activesupport (= 8.0.2) + timeout (>= 0.4.0) + activesupport (8.0.2) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) - arel (9.0.0) ast (2.4.3) base64 (0.3.0) + benchmark (0.4.1) bigdecimal (3.2.1) bump (0.10.0) byebug (12.0.0) @@ -26,6 +34,7 @@ GEM simplecov coderay (1.1.3) concurrent-ruby (1.3.5) + connection_pool (2.5.3) coveralls (0.8.23) json (>= 1.8, < 3) simplecov (~> 0.16.1) @@ -34,6 +43,7 @@ GEM tins (~> 1.6) diff-lcs (1.6.2) docile (1.4.1) + drb (2.2.3) faraday (2.7.12) base64 faraday-net_http (>= 2.0, < 3.1) @@ -166,6 +176,7 @@ GEM rubocop-factory_bot (~> 2.22) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) + securerandom (0.4.1) shellany (0.0.1) simplecov (0.16.1) docile (~> 1.1) @@ -177,7 +188,7 @@ GEM tins (~> 1.0) terminal-notifier-guard (1.7.0) thor (1.3.2) - thread_safe (0.3.6) + timeout (0.4.3) tins (1.38.0) bigdecimal sync @@ -188,9 +199,10 @@ GEM json_pure (~> 2.6.3) launchy (~> 2.5.2) pusher-client (~> 0.6.2) - tzinfo (1.2.11) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unicode-display_width (2.6.0) + uri (1.0.3) websocket (1.2.11) yard (0.9.37) @@ -208,7 +220,7 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES - activerecord (>= 4.2.5, < 6) + activerecord (>= 8.0.0, < 9) bump byebug codeclimate-test-reporter From 262feb7234fadad3c0c93cac4b4c6f431320cac5 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 12:23:58 +0100 Subject: [PATCH 03/14] chore: update gems, fix Rubocop --- .rubocop.yml | 7 ++++++- Gemfile | 4 ++++ Gemfile.lock | 49 ++++++++++++++++++++++++++++--------------------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 4d06aa989..3332cb79b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,7 @@ inherit_from: - .rubocop_todo.yml -require: +plugins: - rubocop-rake - rubocop-rspec @@ -16,3 +16,8 @@ AllCops: Metrics/BlockLength: Exclude: - 'spec/**/*.rb' + +Style/FrozenStringLiteralComment: + Enabled: true + # EnforcedStyle: always + SafeAutoCorrect: true \ No newline at end of file diff --git a/Gemfile b/Gemfile index e3ff4c028..039299ae1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,11 +1,15 @@ +# frozen_string_literal: true + source 'https://rubygems.org' gem 'activerecord', '>= 8.0.0', '< 9', require: false +gem 'json', '~> 2.7.0' gem 'rake', require: false group :development do gem 'bump' gem 'mg', require: false + gem 'ruby-lsp', require: false gem 'travis', require: false platforms :mri, :mingw do gem 'yard', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 1a69bd49d..0053108fb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -51,7 +51,6 @@ GEM faraday-net_http (3.0.2) faraday-rack (2.1.2) faraday (~> 2.0) - ffi (1.17.2) ffi (1.17.2-aarch64-linux-gnu) ffi (1.17.2-aarch64-linux-musl) ffi (1.17.2-arm-linux-gnu) @@ -89,11 +88,12 @@ GEM i18n (1.14.7) concurrent-ruby (~> 1.0) iniparse (1.5.0) - json (2.12.2) + json (2.7.6) json_pure (2.6.3) language_server-protocol (3.17.0.5) launchy (2.5.2) addressable (~> 2.8) + lint_roller (1.1.0) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -128,12 +128,14 @@ GEM pusher-client (0.6.2) json websocket (~> 1.0) - racc (1.7.3) + racc (1.8.1) rainbow (3.1.1) rake (13.3.0) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) + rbs (3.9.4) + logger rchardet (1.9.0) regexp_parser (2.10.0) rexml (3.4.1) @@ -150,30 +152,31 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-support (3.13.4) - rubocop (1.60.2) + rubocop (1.75.8) json (~> 2.3) - language_server-protocol (>= 3.17.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.30.0, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.44.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) + unicode-display_width (>= 2.4.0, < 4.0) rubocop-ast (1.44.1) parser (>= 3.3.7.2) prism (~> 1.4) - rubocop-capybara (2.21.0) - rubocop (~> 1.41) - rubocop-factory_bot (2.26.0) - rubocop (~> 1.41) - rubocop-rake (0.6.0) - rubocop (~> 1.0) - rubocop-rspec (2.26.1) - rubocop (~> 1.40) - rubocop-capybara (~> 2.17) - rubocop-factory_bot (~> 2.22) + rubocop-rake (0.7.1) + lint_roller (~> 1.1) + rubocop (>= 1.72.1) + rubocop-rspec (3.6.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + ruby-lsp (0.23.24) + language_server-protocol (~> 3.17.0) + prism (>= 1.2, < 2.0) + rbs (>= 3, < 5) + sorbet-runtime (>= 0.5.10782) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) securerandom (0.4.1) @@ -183,6 +186,7 @@ GEM json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.2) + sorbet-runtime (0.5.12149) sync (0.5.0) term-ansicolor (1.11.2) tins (~> 1.0) @@ -201,7 +205,9 @@ GEM pusher-client (~> 0.6.2) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (2.6.0) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) uri (1.0.3) websocket (1.2.11) yard (0.9.37) @@ -212,7 +218,6 @@ PLATFORMS arm-linux-gnu arm-linux-musl arm64-darwin - ruby x86-linux-gnu x86-linux-musl x86_64-darwin @@ -228,6 +233,7 @@ DEPENDENCIES files git guard-rspec + json (~> 2.7.0) mg overcommit pry @@ -238,6 +244,7 @@ DEPENDENCIES rubocop rubocop-rake rubocop-rspec + ruby-lsp simplecov terminal-notifier-guard travis From 9b8778af4f90d2acacc043115de553e7323211f7 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 12:25:33 +0100 Subject: [PATCH 04/14] fix: monkey patch file gem for rspec --- spec/spec_helper.rb | 4 ++++ spec/support/file_exists_patch.rb | 9 +++++++++ 2 files changed, 13 insertions(+) create mode 100644 spec/support/file_exists_patch.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e461e55bb..cb093fc35 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,7 @@ +# frozen_string_literal: true + +require_relative 'support/file_exists_patch' + if ENV['COVERAGE'] require 'coveralls' require 'codeclimate-test-reporter' diff --git a/spec/support/file_exists_patch.rb b/spec/support/file_exists_patch.rb new file mode 100644 index 000000000..e1ef211dc --- /dev/null +++ b/spec/support/file_exists_patch.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# Monkey patch to add back File.exists? for compatibility with the files gem +# This is needed because File.exists? was removed in Ruby 3.2 +class File + class << self + alias exists? exist? + end +end From 4383f9503daba72294a92c303608f623aacbc2f7 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 12:27:48 +0100 Subject: [PATCH 05/14] chore: auto-fix linting, fix frozen string literal violations, fix env access in specs --- Guardfile | 10 +- Rakefile | 31 ++- annotate.gemspec | 16 +- bin/annotate | 9 +- lib/annotate.rb | 20 +- lib/annotate/active_record_patch.rb | 2 + lib/annotate/annotate_models.rb | 255 ++++++++++-------- lib/annotate/annotate_models/file_patterns.rb | 2 + lib/annotate/annotate_routes.rb | 12 +- .../annotate_routes/header_generator.rb | 18 +- lib/annotate/annotate_routes/helpers.rb | 8 +- lib/annotate/constants.rb | 21 +- lib/annotate/helpers.rb | 9 +- lib/annotate/parser.rb | 27 +- lib/annotate/tasks.rb | 2 + lib/annotate/version.rb | 2 + lib/generators/annotate/install_generator.rb | 2 + .../templates/auto_annotate_models.rake | 96 +++---- lib/tasks/annotate_models.rake | 89 +++--- lib/tasks/annotate_models_migrate.rake | 32 +-- lib/tasks/annotate_routes.rake | 31 ++- .../annotate_models/file_patterns_spec.rb | 74 ++--- spec/lib/annotate/annotate_models_spec.rb | 231 +++++++++------- spec/lib/annotate/annotate_routes_spec.rb | 58 ++-- spec/lib/annotate/helpers_spec.rb | 24 +- spec/lib/annotate/parser_spec.rb | 37 ++- spec/lib/annotate_spec.rb | 2 + .../lib/tasks/annotate_models_migrate_spec.rb | 16 +- spec/lib/tasks/annotate_models_spec.rb | 4 +- 29 files changed, 637 insertions(+), 503 deletions(-) diff --git a/Guardfile b/Guardfile index f93bc135e..9c49ea77d 100644 --- a/Guardfile +++ b/Guardfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # NOTE: The cmd option is now required due to the increasing number of ways # rspec may be run, below are examples of the most common uses. # * bundler: 'bundle exec rspec' @@ -14,7 +16,9 @@ guard :rspec, cmd: 'bundle exec rspec' do # Rails example watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } - watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] } + watch(%r{^app/controllers/(.+)_(controller)\.rb$}) do |m| + ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] + end watch(%r{^spec/support/(.+)\.rb$}) { 'spec' } watch('config/routes.rb') { 'spec/routing' } watch('app/controllers/application_controller.rb') { 'spec/controllers' } @@ -25,5 +29,7 @@ guard :rspec, cmd: 'bundle exec rspec' do # Turnip features and steps watch(%r{^spec/acceptance/(.+)\.feature$}) - watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' } + watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m| + Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' + end end diff --git a/Rakefile b/Rakefile index 43944f2dc..5593781e9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,7 @@ +# frozen_string_literal: true + def exit_exception(e) - $stderr.puts e.message + warn e.message exit e.status_code end @@ -8,7 +10,7 @@ begin require 'bundler' Bundler.setup(:default, :development) rescue Bundler::BundlerError => e - $stderr.puts 'Run `bundle install` to install missing gems' + warn 'Run `bundle install` to install missing gems' exit_exception(e) end @@ -28,7 +30,7 @@ require 'mg' begin MG.new('annotate.gemspec') rescue Exception - $stderr.puts("WARNING: Couldn't read gemspec. As such, a number of tasks may be unavailable to you until you run 'rake gem:gemspec' to correct the issue.") + warn("WARNING: Couldn't read gemspec. As such, a number of tasks may be unavailable to you until you run 'rake gem:gemspec' to correct the issue.") # Gemspec is probably in a broken state, so let's give ourselves a chance to # build a new one... end @@ -54,9 +56,7 @@ namespace :gem do Bundler.load.dependencies_for(*RUNTIME_GROUPS).each do |dep| runtime_resolved = Bundler.definition.specs_for(RUNTIME_GROUPS).find { |spec| spec.name == dep.name } - unless runtime_resolved.nil? - gem.add_dependency(dep.name, dep.requirement) - end + gem.add_dependency(dep.name, dep.requirement) unless runtime_resolved.nil? end gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } @@ -73,7 +73,7 @@ namespace :gem do fn =~ /^pkg/ || fn =~ /^spec/ || fn =~ /^doc/ || - fn =~ /^vendor\/cache/ + fn =~ %r{^vendor/cache} end.sort end File.open('annotate.gemspec', 'wb') do |fh| @@ -135,6 +135,7 @@ namespace :integration do target_dir = File.expand_path(ENV['TARGET']) if ENV['TARGET'] raise 'Must specify TARGET=x, where x is an integration test scenario!' unless target_dir && Dir.exist?(target_dir) raise 'TARGET directory must be within spec/integration/!' unless target_dir.start_with?(integration_dir) + candidates = {} FileList[ "#{target_dir}/.rvmrc", @@ -142,14 +143,14 @@ namespace :integration do ].select { |fname| !(File.symlink?(fname) || File.directory?(fname)) } .map { |fname| fname.sub(integration_dir, '') } .reject do |fname| - fname =~ /\/\.gitkeep$/ || - fname =~ /\/app\/models\// || - fname =~ /\/routes\.rb$/ || - fname =~ /\/fixtures\// || - fname =~ /\/factories\// || + fname =~ %r{/\.gitkeep$} || + fname =~ %r{/app/models/} || + fname =~ %r{/routes\.rb$} || + fname =~ %r{/fixtures/} || + fname =~ %r{/factories/} || fname =~ /\.sqlite3$/ || - (fname =~ /\/test\// && fname !~ /_helper\.rb$/) || - (fname =~ /\/spec\// && fname !~ /_helper\.rb$/) + (fname =~ %r{/test/} && fname !~ /_helper\.rb$/) || + (fname =~ %r{/spec/} && fname !~ /_helper\.rb$/) end .map { |fname| "#{integration_dir}#{fname}" } .each do |fname| @@ -164,9 +165,11 @@ namespace :integration do candidates.each_key do |digest| next unless fixtures.key?(digest) + candidates[digest].each do |fname| # Double-check contents in case of hash collision... next unless FileUtils.identical?(fname, fixtures[digest]) + destination_dir = Pathname.new(File.dirname(fname)) relative_target = Pathname.new(fixtures[digest]).relative_path_from(destination_dir) Dir.chdir(destination_dir) do diff --git a/annotate.gemspec b/annotate.gemspec index 43b2ac990..b59bcebb5 100644 --- a/annotate.gemspec +++ b/annotate.gemspec @@ -1,5 +1,6 @@ -# -*- encoding: utf-8 -*- -lib = File.expand_path('../lib', __FILE__) +# frozen_string_literal: true + +lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'annotate/version' @@ -18,15 +19,14 @@ Gem::Specification.new do |s| s.homepage = 'https://github.com/ctran/annotate_models' s.licenses = ['Ruby'] s.require_paths = ['lib'] - s.rubygems_version = '2.1.11' s.summary = 'Annotates Rails Models, routes, fixtures, and others based on the database schema.' - s.specification_version = 4 if s.respond_to? :specification_version - s.add_runtime_dependency(%q, '>= 10.4', '< 14.0') - s.add_runtime_dependency(%q, ['>= 3.2', '< 8.0']) + s.add_dependency('activerecord', ['>= 8.0.0', '< 9']) + s.add_dependency('rake', '>= 10.4', '< 14.0') s.metadata = { - "bug_tracker_uri" => "https://github.com/ctran/annotate_models/issues/", - "source_code_uri" => "https://github.com/ctran/annotate_models.git" + 'bug_tracker_uri' => 'https://github.com/ctran/annotate_models/issues/', + 'source_code_uri' => 'https://github.com/ctran/annotate_models.git', + 'rubygems_mfa_required' => 'true' } end diff --git a/bin/annotate b/bin/annotate index feb0c0421..4a9b989aa 100755 --- a/bin/annotate +++ b/bin/annotate @@ -1,8 +1,7 @@ #!/usr/bin/env ruby +# frozen_string_literal: true -unless File.exist?('./Rakefile') || File.exist?('./Gemfile') - abort 'Please run annotate from the root of the project.' -end +abort 'Please run annotate from the root of the project.' unless File.exist?('./Rakefile') || File.exist?('./Gemfile') require 'rubygems' begin @@ -11,7 +10,7 @@ begin rescue StandardError end -here = File.expand_path(File.dirname __FILE__) +here = __dir__ $LOAD_PATH << "#{here}/../lib" require 'annotate' @@ -24,7 +23,7 @@ options_result = Annotate::Parser.parse(ARGV) exit if options_result[:exit] options = Annotate.setup_options( - is_rake: ENV['is_rake'] && !ENV['is_rake'].empty? + is_rake: ENV.fetch('is_rake', nil) && !ENV['is_rake'].empty? ) Annotate.eager_load(options) if Annotate::Helpers.include_models? diff --git a/lib/annotate.rb b/lib/annotate.rb index 7c54e9ea6..b722477c7 100644 --- a/lib/annotate.rb +++ b/lib/annotate.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'annotate/version' require 'annotate/annotate_models' @@ -21,6 +23,7 @@ module Annotate # def self.set_defaults(options = {}) return if @has_set_defaults + @has_set_defaults = true options = ActiveSupport::HashWithIndifferentAccess.new(options) @@ -44,20 +47,23 @@ def self.set_defaults(options = {}) # def self.setup_options(options = {}) Constants::POSITION_OPTIONS.each do |key| - options[key] = Annotate::Helpers.fallback(ENV[key.to_s], ENV['position'], 'before') + options[key] = Annotate::Helpers.fallback(ENV.fetch(key.to_s, nil), ENV.fetch('position', nil), 'before') end Constants::FLAG_OPTIONS.each do |key| - options[key] = Annotate::Helpers.true?(ENV[key.to_s]) + options[key] = Annotate::Helpers.true?(ENV.fetch(key.to_s, nil)) end Constants::OTHER_OPTIONS.each do |key| - options[key] = !ENV[key.to_s].blank? ? ENV[key.to_s] : nil + options[key] = ENV[key.to_s].blank? ? nil : ENV.fetch(key.to_s, nil) end Constants::PATH_OPTIONS.each do |key| - options[key] = !ENV[key.to_s].blank? ? ENV[key.to_s].split(',') : [] + options[key] = ENV[key.to_s].blank? ? [] : ENV[key.to_s].split(',') end options[:additional_file_patterns] ||= [] - options[:additional_file_patterns] = options[:additional_file_patterns].split(',') if options[:additional_file_patterns].is_a?(String) + if options[:additional_file_patterns].is_a?(String) + options[:additional_file_patterns] = + options[:additional_file_patterns].split(',') + end options[:model_dir] = ['app/models'] if options[:model_dir].empty? options[:wrapper_open] ||= options[:wrapper] @@ -111,7 +117,7 @@ def self.bootstrap_rake require 'rake/dsl_definition' rescue StandardError => e # We might just be on an old version of Rake... - $stderr.puts e.message + warn e.message exit e.status_code end require 'rake' @@ -119,7 +125,7 @@ def self.bootstrap_rake load './Rakefile' if File.exist?('./Rakefile') begin Rake::Task[:environment].invoke - rescue + rescue StandardError nil end unless defined?(Rails) diff --git a/lib/annotate/active_record_patch.rb b/lib/annotate/active_record_patch.rb index 8983b0465..b79690b05 100644 --- a/lib/annotate/active_record_patch.rb +++ b/lib/annotate/active_record_patch.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # monkey patches module ::ActiveRecord diff --git a/lib/annotate/annotate_models.rb b/lib/annotate/annotate_models.rb index dc2901a32..7079632cf 100644 --- a/lib/annotate/annotate_models.rb +++ b/lib/annotate/annotate_models.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # rubocop:disable Metrics/ModuleLength require 'bigdecimal' @@ -7,22 +9,22 @@ module AnnotateModels # Annotate Models plugin use this header - COMPAT_PREFIX = '== Schema Info'.freeze - COMPAT_PREFIX_MD = '## Schema Info'.freeze - PREFIX = '== Schema Information'.freeze - PREFIX_MD = '## Schema Information'.freeze - END_MARK = '== Schema Information End'.freeze + COMPAT_PREFIX = '== Schema Info' + COMPAT_PREFIX_MD = '## Schema Info' + PREFIX = '== Schema Information' + PREFIX_MD = '## Schema Information' + END_MARK = '== Schema Information End' - SKIP_ANNOTATION_PREFIX = '# -\*- SkipSchemaAnnotations'.freeze + SKIP_ANNOTATION_PREFIX = '# -\*- SkipSchemaAnnotations' - MATCHED_TYPES = %w(test fixture factory serializer scaffold controller helper).freeze + MATCHED_TYPES = %w[test fixture factory serializer scaffold controller helper].freeze # Don't show limit (#) on these column types # Example: show "integer" instead of "integer(4)" - NO_LIMIT_COL_TYPES = %w(integer bigint boolean).freeze + NO_LIMIT_COL_TYPES = %w[integer bigint boolean].freeze # Don't show default value for these column types - NO_DEFAULT_COL_TYPES = %w(json jsonb hstore).freeze + NO_DEFAULT_COL_TYPES = %w[json jsonb hstore].freeze INDEX_CLAUSES = { unique: { @@ -39,13 +41,14 @@ module AnnotateModels } }.freeze - MAGIC_COMMENT_MATCHER = Regexp.new(/(^#\s*encoding:.*(?:\n|r\n))|(^# coding:.*(?:\n|\r\n))|(^# -\*- coding:.*(?:\n|\r\n))|(^# -\*- encoding\s?:.*(?:\n|\r\n))|(^#\s*frozen_string_literal:.+(?:\n|\r\n))|(^# -\*- frozen_string_literal\s*:.+-\*-(?:\n|\r\n))/).freeze + MAGIC_COMMENT_MATCHER = /(^#\s*encoding:.*(?:\n|r\n))|(^# coding:.*(?:\n|\r\n))|(^# -\*- coding:.*(?:\n|\r\n))|(^# -\*- encoding\s?:.*(?:\n|\r\n))|(^#\s*frozen_string_literal:.+(?:\n|\r\n))|(^# -\*- frozen_string_literal\s*:.+-\*-(?:\n|\r\n))/ class << self def annotate_pattern(options = {}) if options[:wrapper_open] return /(?:^(\n|\r\n)?# (?:#{options[:wrapper_open]}).*(\n|\r\n)?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?(\n|\r\n)(#.*(\n|\r\n))*(\n|\r\n)*)|^(\n|\r\n)?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?(\n|\r\n)(#.*(\n|\r\n))*(\n|\r\n)*/ end + /^(\n|\r\n)?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?(\n|\r\n)(#.*(\n|\r\n))*(\n|\r\n)*/ end @@ -53,7 +56,7 @@ def model_dir @model_dir.is_a?(Array) ? @model_dir : [@model_dir || 'app/models'] end - attr_writer :model_dir + attr_writer :model_dir, :root_dir, :skip_subdirectory_model_load def root_dir if @root_dir.blank? @@ -65,8 +68,6 @@ def root_dir end end - attr_writer :root_dir - def skip_subdirectory_model_load # This option is set in options[:skip_subdirectory_model_load] # and stops the get_loaded_model method from loading a model from a subdir @@ -78,8 +79,6 @@ def skip_subdirectory_model_load end end - attr_writer :skip_subdirectory_model_load - def get_patterns(options, pattern_types = []) current_patterns = [] root_dir.each do |root_directory| @@ -89,7 +88,7 @@ def get_patterns(options, pattern_types = []) current_patterns += if pattern_type.to_sym == :additional_file_patterns patterns else - patterns.map { |p| p.sub(/^[\/]*/, '') } + patterns.map { |p| p.sub(%r{^[/]*}, '') } end end end @@ -136,7 +135,7 @@ def retrieve_indexes_from_table(klass) # each column. The line contains the column name, # the type (and length), and any optional attributes def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/MethodLength - info = "# #{header}\n" + info = String.new("# #{header}\n") info << get_schema_header_text(klass, options) max_size = max_schema_info_width(klass, options) @@ -145,9 +144,11 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho bare_type_allowance = 16 if options[:format_markdown] - info << sprintf( "# %-#{max_size + md_names_overhead}.#{max_size + md_names_overhead}s | %-#{md_type_allowance}.#{md_type_allowance}s | %s\n", 'Name', 'Type', 'Attributes' ) + info << format( + "# %-#{max_size + md_names_overhead}.#{max_size + md_names_overhead}s | %-#{md_type_allowance}.#{md_type_allowance}s | %s\n", 'Name', 'Type', 'Attributes' + ) - info << "# #{ '-' * ( max_size + md_names_overhead ) } | #{'-' * md_type_allowance} | #{ '-' * 27 }\n" + info << "# #{'-' * (max_size + md_names_overhead)} | #{'-' * md_type_allowance} | #{'-' * 27}\n" end cols = columns(klass, options) @@ -156,7 +157,7 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho # Precalculate Values cols_meta = cols.map do |col| - col_comment = with_comments || with_comments_column ? col.comment&.gsub(/\n/, "\\n") : nil + col_comment = with_comments || with_comments_column ? col.comment&.gsub("\n", '\\n') : nil col_type = get_col_type(col) attrs = get_attributes(col, col_type, klass, options) col_name = if with_comments && col_comment @@ -164,8 +165,13 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho else col.name end - simple_formatted_attrs = attrs.join(", ") - [col.name, { col_type: col_type, attrs: attrs, col_name: col_name, simple_formatted_attrs: simple_formatted_attrs, col_comment: col_comment }] + simple_formatted_attrs = attrs.join(', ') + [col.name, + { col_type: col_type, + attrs: attrs, + col_name: col_name, + simple_formatted_attrs: simple_formatted_attrs, + col_comment: col_comment }] end.to_h # Output annotation @@ -179,39 +185,37 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho col_comment = cols_meta[col.name][:col_comment] if options[:format_rdoc] - info << sprintf("# %-#{max_size}.#{max_size}s%s", "*#{col_name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n" + info << (format("# %-#{max_size}.#{max_size}s%s", "*#{col_name}*::", + attrs.unshift(col_type).join(', ')).rstrip + "\n") elsif options[:format_yard] - info << sprintf("# @!attribute #{col_name}") + "\n" - ruby_class = col.respond_to?(:array) && col.array ? "Array<#{map_col_type_to_ruby_classes(col_type)}>": map_col_type_to_ruby_classes(col_type) - info << sprintf("# @return [#{ruby_class}]") + "\n" + info << (sprintf("# @!attribute #{col_name}") + "\n") + ruby_class = col.respond_to?(:array) && col.array ? "Array<#{map_col_type_to_ruby_classes(col_type)}>" : map_col_type_to_ruby_classes(col_type) + info << (sprintf("# @return [#{ruby_class}]") + "\n") elsif options[:format_markdown] name_remainder = max_size - col_name.length - non_ascii_length(col_name) type_remainder = (md_type_allowance - 2) - col_type.length - info << (sprintf("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`", col_name, " ", col_type, " ", attrs.join(", ").rstrip)).gsub('``', ' ').rstrip + "\n" + info << (format("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`", col_name, ' ', col_type, ' ', attrs.join(', ').rstrip).gsub( + '``', ' ' + ).rstrip + "\n") elsif with_comments_column - info << format_default(col_name, max_size, col_type, bare_type_allowance, simple_formatted_attrs, bare_max_attrs_length, col_comment) + info << format_default(col_name, max_size, col_type, bare_type_allowance, simple_formatted_attrs, + bare_max_attrs_length, col_comment) else info << format_default(col_name, max_size, col_type, bare_type_allowance, simple_formatted_attrs) end end - if options[:show_indexes] && klass.table_exists? - info << get_index_info(klass, options) - end + info << get_index_info(klass, options) if options[:show_indexes] && klass.table_exists? - if options[:show_foreign_keys] && klass.table_exists? - info << get_foreign_key_info(klass, options) - end + info << get_foreign_key_info(klass, options) if options[:show_foreign_keys] && klass.table_exists? - if options[:show_check_constraints] && klass.table_exists? - info << get_check_constraint_info(klass, options) - end + info << get_check_constraint_info(klass, options) if options[:show_check_constraints] && klass.table_exists? info << get_schema_footer_text(klass, options) end def get_schema_header_text(klass, options = {}) - info = "#\n" + info = String.new("#\n") # Create a new mutable string if options[:format_markdown] info << "# Table name: `#{klass.table_name}`\n" info << "#\n" @@ -220,10 +224,11 @@ def get_schema_header_text(klass, options = {}) info << "# Table name: #{klass.table_name}\n" end info << "#\n" + info end def get_schema_footer_text(_klass, options = {}) - info = '' + info = String.new('') if options[:format_rdoc] info << "#--\n" info << "# #{END_MARK}\n" @@ -231,19 +236,20 @@ def get_schema_footer_text(_klass, options = {}) else info << "#\n" end + info end def get_index_info(klass, options = {}) index_info = if options[:format_markdown] - "#\n# ### Indexes\n#\n" + String.new("#\n# ### Indexes\n#\n") else - "#\n# Indexes\n#\n" + String.new("#\n# Indexes\n#\n") end indexes = retrieve_indexes_from_table(klass) return '' if indexes.empty? - max_size = indexes.collect{|index| index.name.size}.max + 1 + max_size = indexes.collect { |index| index.name.size }.max + 1 indexes.sort_by(&:name).each do |index| index_info << if options[:format_markdown] final_index_string_in_markdown(index) @@ -296,15 +302,15 @@ def index_using_info(index, format = :default) end def final_index_string_in_markdown(index) - details = sprintf( - "%s%s%s", + details = format( + '%s%s%s', index_unique_info(index, :markdown), index_where_info(index, :markdown), index_using_info(index, :markdown) ).strip details = " (#{details})" unless details.blank? - sprintf( + format( "# * `%s`%s:\n# * **`%s`**\n", index.name, details, @@ -313,7 +319,7 @@ def final_index_string_in_markdown(index) end def final_index_string(index, max_size) - sprintf( + format( "# %-#{max_size}.#{max_size}s %s%s%s%s", index.name, "(#{index_columns_info(index).join(',')})", @@ -347,34 +353,37 @@ def hide_default?(col_type, options) def get_foreign_key_info(klass, options = {}) fk_info = if options[:format_markdown] - "#\n# ### Foreign Keys\n#\n" + String.new("#\n# ### Foreign Keys\n#\n") else - "#\n# Foreign Keys\n#\n" + String.new("#\n# Foreign Keys\n#\n") end return '' unless klass.connection.respond_to?(:supports_foreign_keys?) && - klass.connection.supports_foreign_keys? && klass.connection.respond_to?(:foreign_keys) + klass.connection.supports_foreign_keys? && klass.connection.respond_to?(:foreign_keys) foreign_keys = klass.connection.foreign_keys(klass.table_name) return '' if foreign_keys.empty? format_name = lambda do |fk| return fk.options[:column] if fk.name.blank? + options[:show_complete_foreign_keys] ? fk.name : fk.name.gsub(/(?<=^fk_rails_)[0-9a-f]{10}$/, '...') end max_size = foreign_keys.map(&format_name).map(&:size).max + 1 - foreign_keys.sort_by {|fk| [format_name.call(fk), fk.column]}.each do |fk| + foreign_keys.sort_by { |fk| [format_name.call(fk), fk.column] }.each do |fk| ref_info = "#{fk.column} => #{fk.to_table}.#{fk.primary_key}" - constraints_info = '' + constraints_info = String.new('') constraints_info += "ON DELETE => #{fk.on_delete} " if fk.on_delete constraints_info += "ON UPDATE => #{fk.on_update} " if fk.on_update constraints_info.strip! fk_info << if options[:format_markdown] - sprintf("# * `%s`%s:\n# * **`%s`**\n", format_name.call(fk), constraints_info.blank? ? '' : " (_#{constraints_info}_)", ref_info) + format("# * `%s`%s:\n# * **`%s`**\n", format_name.call(fk), + constraints_info.blank? ? '' : " (_#{constraints_info}_)", ref_info) else - sprintf("# %-#{max_size}.#{max_size}s %s %s", format_name.call(fk), "(#{ref_info})", constraints_info).rstrip + "\n" + format("# %-#{max_size}.#{max_size}s %s %s", format_name.call(fk), "(#{ref_info})", + constraints_info).rstrip + "\n" end end @@ -383,13 +392,13 @@ def get_foreign_key_info(klass, options = {}) def get_check_constraint_info(klass, options = {}) cc_info = if options[:format_markdown] - "#\n# ### Check Constraints\n#\n" + String.new("#\n# ### Check Constraints\n#\n") else - "#\n# Check Constraints\n#\n" + String.new("#\n# Check Constraints\n#\n") end return '' unless klass.connection.respond_to?(:supports_check_constraints?) && - klass.connection.supports_check_constraints? && klass.connection.respond_to?(:check_constraints) + klass.connection.supports_check_constraints? && klass.connection.respond_to?(:check_constraints) check_constraints = klass.connection.check_constraints(klass.table_name) return '' if check_constraints.empty? @@ -399,11 +408,11 @@ def get_check_constraint_info(klass, options = {}) expression = check_constraint.expression ? "(#{check_constraint.expression.squish})" : nil cc_info << if options[:format_markdown] - cc_info_markdown = sprintf("# * `%s`", check_constraint.name) - cc_info_markdown << sprintf(": `%s`", expression) if expression + cc_info_markdown = format('# * `%s`', check_constraint.name) + cc_info_markdown << format(': `%s`', expression) if expression cc_info_markdown << "\n" else - sprintf("# %-#{max_size}.#{max_size}s %s", check_constraint.name, expression).rstrip + "\n" + format("# %-#{max_size}.#{max_size}s %s", check_constraint.name, expression).rstrip + "\n" end end @@ -425,6 +434,7 @@ def get_check_constraint_info(klass, options = {}) # def annotate_one_file(file_name, info_block, position, options = {}) return false unless File.exist?(file_name) + old_content = File.read(file_name) return false if old_content =~ /#{SKIP_ANNOTATION_PREFIX}.*\n/ @@ -439,11 +449,13 @@ def annotate_one_file(file_name, info_block, position, options = {}) return false if old_columns == new_columns && !options[:force] - abort "annotate error. #{file_name} needs to be updated, but annotate was run with `--frozen`." if options[:frozen] + if options[:frozen] + abort "annotate error. #{file_name} needs to be updated, but annotate was run with `--frozen`." + end # Replace inline the old schema info with the new schema info - wrapper_open = options[:wrapper_open] ? "# #{options[:wrapper_open]}\n" : "" - wrapper_close = options[:wrapper_close] ? "# #{options[:wrapper_close]}\n" : "" + wrapper_open = options[:wrapper_open] ? "# #{options[:wrapper_open]}\n" : '' + wrapper_close = options[:wrapper_close] ? "# #{options[:wrapper_close]}\n" : '' wrapped_info_block = "#{wrapper_open}#{info_block}#{wrapper_close}" old_annotation = old_content.match(annotate_pattern(options)).to_s @@ -455,7 +467,7 @@ def annotate_one_file(file_name, info_block, position, options = {}) old_content.gsub!(MAGIC_COMMENT_MATCHER, '') old_content.sub!(annotate_pattern(options), '') - new_content = if %w(after bottom).include?(options[position].to_s) + new_content = if %w[after bottom].include?(options[position].to_s) magic_comments_block + (old_content.rstrip + "\n\n" + wrapped_info_block) elsif magic_comments_block.empty? magic_comments_block + wrapped_info_block + old_content.lstrip @@ -542,18 +554,19 @@ def annotate(klass, file, header, options = {}) model_file_name = File.join(file) annotated = [] - if annotate_one_file(model_file_name, info, :position_in_class, options_with_position(options, :position_in_class)) + if annotate_one_file(model_file_name, info, :position_in_class, + options_with_position(options, :position_in_class)) annotated << model_file_name end matched_types(options).each do |key| - exclusion_key = "exclude_#{key.pluralize}".to_sym - position_key = "position_in_#{key}".to_sym + exclusion_key = :"exclude_#{key.pluralize}" + position_key = :"position_in_#{key}" # Same options for active_admin models if key == 'admin' - exclusion_key = 'exclude_class'.to_sym - position_key = 'position_in_class'.to_sym + exclusion_key = :exclude_class + position_key = :position_in_class end next if options[exclusion_key] @@ -563,14 +576,12 @@ def annotate(klass, file, header, options = {}) .map { |f| expand_glob_into_files(f) } .flatten .each do |f| - if annotate_one_file(f, info, position_key, options_with_position(options, position_key)) - annotated << f - end + annotated << f if annotate_one_file(f, info, position_key, options_with_position(options, position_key)) end end rescue StandardError => e - $stderr.puts "Unable to annotate #{file}: #{e.message}" - $stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace] + warn "Unable to annotate #{file}: #{e.message}" + warn "\t" + e.backtrace.join("\n\t") if options[:trace] end annotated @@ -578,7 +589,7 @@ def annotate(klass, file, header, options = {}) # position = :position_in_fixture or :position_in_class def options_with_position(options, position_in) - options.merge(position: (options[position_in] || options[:position])) + options.merge(position: options[position_in] || options[:position]) end # Return a list of the model files to annotate. @@ -595,9 +606,9 @@ def get_model_files(options) model_dir.each do |dir| Dir.chdir(dir) do list = if options[:ignore_model_sub_dir] - Dir["*.rb"].map { |f| [dir, f] } + Dir['*.rb'].map { |f| [dir, f] } else - Dir["**/*.rb"].reject { |f| f["concerns/"] }.map { |f| [dir, f] } + Dir['**/*.rb'].reject { |f| f['concerns/'] }.map { |f| [dir, f] } end model_files.concat(list) end @@ -605,9 +616,9 @@ def get_model_files(options) model_files rescue SystemCallError - $stderr.puts "No models found in directory '#{model_dir.join("', '")}'." - $stderr.puts "Either specify models on the command line, or use the --model-dir option." - $stderr.puts "Call 'annotate --help' for more info." + warn "No models found in directory '#{model_dir.join("', '")}'." + warn 'Either specify models on the command line, or use the --model-dir option.' + warn "Call 'annotate --help' for more info." exit 1 end @@ -638,15 +649,15 @@ def list_model_files_from_argument # in subdirectories without namespacing. def get_model_class(file) model_path = file.gsub(/\.rb$/, '') - model_dir.each { |dir| model_path = model_path.gsub(/^#{dir}/, '').gsub(/^\//, '') } + model_dir.each { |dir| model_path = model_path.gsub(/^#{dir}/, '').gsub(%r{^/}, '') } begin - get_loaded_model(model_path, file) || raise(BadModelFileError.new) + get_loaded_model(model_path, file) || raise(BadModelFileError) rescue LoadError # this is for non-rails projects, which don't get Rails auto-require magic file_path = File.expand_path(file) if File.file?(file_path) && Kernel.require(file_path) retry - elsif model_path =~ /\// + elsif model_path =~ %r{/} model_path = model_path.split('/')[1..-1].join('/').to_s retry else @@ -668,7 +679,7 @@ def get_loaded_model(model_path, file) model_paths = $LOAD_PATH.map(&:to_s) .select { |path| absolute_file.include?(path) } - .map { |path| absolute_file.sub(path, '').sub(/\.rb$/, '').sub(/^\//, '') } + .map { |path| absolute_file.sub(path, '').sub(/\.rb$/, '').sub(%r{^/}, '') } model_paths .map { |path| get_loaded_model_by_path(path) } .find { |loaded_model| !loaded_model.nil? } @@ -681,10 +692,10 @@ def get_loaded_model_by_path(model_path) # Revert to the old way but it is not really robust ObjectSpace.each_object(::Class) .select do |c| - Class === c && # note: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a? - c.ancestors.respond_to?(:include?) && # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82 - c.ancestors.include?(ActiveRecord::Base) - end.detect { |c| ActiveSupport::Inflector.underscore(c.to_s) == model_path } + c.is_a?(Class) && # NOTE: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a? + c.ancestors.respond_to?(:include?) && # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82 + c.ancestors.include?(ActiveRecord::Base) + end.detect { |c| ActiveSupport::Inflector.underscore(c.to_s) == model_path } end def parse_options(options = {}) @@ -694,7 +705,7 @@ def parse_options(options = {}) end def split_model_dir(option_value) - option_value = option_value.is_a?(Array) ? option_value : option_value.split(',') + option_value = option_value.split(',') unless option_value.is_a?(Array) option_value.map(&:strip).reject(&:empty?) end @@ -706,10 +717,12 @@ def do_annotations(options = {}) parse_options(options) header = options[:format_markdown] ? PREFIX_MD.dup : PREFIX.dup - version = ActiveRecord::Migrator.current_version rescue 0 - if options[:include_version] && version > 0 - header << "\n# Schema version: #{version}" + version = begin + ActiveRecord::Migrator.current_version + rescue StandardError + 0 end + header << "\n# Schema version: #{version}" if options[:include_version] && version > 0 annotated = [] get_model_files(options).each do |path, filename| @@ -728,25 +741,24 @@ def expand_glob_into_files(glob) end def annotate_model_file(annotated, file, header, options) - begin - return false if /#{SKIP_ANNOTATION_PREFIX}.*/ =~ (File.exist?(file) ? File.read(file) : '') - klass = get_model_class(file) - do_annotate = klass.is_a?(Class) && - klass < ActiveRecord::Base && - (!options[:exclude_sti_subclasses] || !(klass.superclass < ActiveRecord::Base && klass.table_name == klass.superclass.table_name)) && - !klass.abstract_class? && - klass.table_exists? - - annotated.concat(annotate(klass, file, header, options)) if do_annotate - rescue BadModelFileError => e - unless options[:ignore_unknown_models] - $stderr.puts "Unable to annotate #{file}: #{e.message}" - $stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace] - end - rescue StandardError => e - $stderr.puts "Unable to annotate #{file}: #{e.message}" - $stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace] + return false if /#{SKIP_ANNOTATION_PREFIX}.*/ =~ (File.exist?(file) ? File.read(file) : '') + + klass = get_model_class(file) + do_annotate = klass.is_a?(Class) && + klass < ActiveRecord::Base && + (!options[:exclude_sti_subclasses] || !(klass.superclass < ActiveRecord::Base && klass.table_name == klass.superclass.table_name)) && + !klass.abstract_class? && + klass.table_exists? + + annotated.concat(annotate(klass, file, header, options)) if do_annotate + rescue BadModelFileError => e + unless options[:ignore_unknown_models] + warn "Unable to annotate #{file}: #{e.message}" + warn "\t" + e.backtrace.join("\n\t") if options[:trace] end + rescue StandardError => e + warn "Unable to annotate #{file}: #{e.message}" + warn "\t" + e.backtrace.join("\n\t") if options[:trace] end def remove_annotations(options = {}) @@ -775,8 +787,8 @@ def remove_annotations(options = {}) end deannotated << klass if deannotated_klass rescue StandardError => e - $stderr.puts "Unable to deannotate #{File.join(file)}: #{e.message}" - $stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace] + warn "Unable to deannotate #{File.join(file)}: #{e.message}" + warn "\t" + e.backtrace.join("\n\t") if options[:trace] end end puts "Removed annotations from: #{deannotated.join(', ')}" @@ -842,9 +854,10 @@ def max_schema_info_width(klass, options) end # rubocop:disable Metrics/ParameterLists - def format_default(col_name, max_size, col_type, bare_type_allowance, simple_formatted_attrs, bare_max_attrs_length = 0, col_comment = nil) - sprintf( - "# %s:%s %s %s", + def format_default(col_name, max_size, col_type, bare_type_allowance, simple_formatted_attrs, + bare_max_attrs_length = 0, col_comment = nil) + format( + '# %s:%s %s %s', mb_chars_ljust(col_name, max_size), mb_chars_ljust(col_type, bare_type_allowance), mb_chars_ljust(simple_formatted_attrs, bare_max_attrs_length), @@ -862,7 +875,7 @@ def mb_chars_ljust(string, length) if padding > 0 string + (' ' * padding) else - string[0..length-1] + string[0..length - 1] end end @@ -935,10 +948,13 @@ def ignored_translation_table_colums(klass) # a given column. def get_attributes(column, column_type, klass, options) attrs = [] - attrs << "default(#{schema_default(klass, column)})" unless column.default.nil? || hide_default?(column_type, options) + attrs << "default(#{schema_default(klass, column)})" unless column.default.nil? || hide_default?(column_type, + options) attrs << 'unsigned' if column.respond_to?(:unsigned?) && column.unsigned? attrs << 'not null' unless column.null - attrs << 'primary key' if klass.primary_key && (klass.primary_key.is_a?(Array) ? klass.primary_key.collect(&:to_sym).include?(column.name.to_sym) : column.name.to_sym == klass.primary_key.to_sym) + if klass.primary_key && (klass.primary_key.is_a?(Array) ? klass.primary_key.collect(&:to_sym).include?(column.name.to_sym) : column.name.to_sym == klass.primary_key.to_sym) + attrs << 'primary key' + end if column_type == 'decimal' column_type << "(#{column.precision}, #{column.scale})" @@ -965,13 +981,14 @@ def get_attributes(column, column_type, klass, options) # Check if the column has indices and print "indexed" if true # If the index includes another column, print it too. - if options[:simple_indexes] && klass.table_exists?# Check out if this column is indexed + if options[:simple_indexes] && klass.table_exists? # Check out if this column is indexed indices = retrieve_indexes_from_table(klass) if indices = indices.select { |ind| ind.columns.include? column.name } indices.sort_by(&:name).each do |ind| next if ind.columns.is_a?(String) + ind = ind.columns.reject! { |i| i == column.name } - attrs << (ind.empty? ? "indexed" : "indexed => [#{ind.join(", ")}]") + attrs << (ind.empty? ? 'indexed' : "indexed => [#{ind.join(', ')}]") end end end diff --git a/lib/annotate/annotate_models/file_patterns.rb b/lib/annotate/annotate_models/file_patterns.rb index f6cf3c0e7..01e30d507 100644 --- a/lib/annotate/annotate_models/file_patterns.rb +++ b/lib/annotate/annotate_models/file_patterns.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AnnotateModels # This module provides module method to get file paths. module FilePatterns diff --git a/lib/annotate/annotate_routes.rb b/lib/annotate/annotate_routes.rb index c9a2218ac..78e3f2740 100644 --- a/lib/annotate/annotate_routes.rb +++ b/lib/annotate/annotate_routes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Annotate Routes # # Based on: @@ -18,8 +20,8 @@ # Released under the same license as Ruby. No Support. No Warranty. # -require_relative './annotate_routes/helpers' -require_relative './annotate_routes/header_generator' +require_relative 'annotate_routes/helpers' +require_relative 'annotate_routes/header_generator' module AnnotateRoutes class << self @@ -39,7 +41,7 @@ def do_annotations(options = {}) end end - def remove_annotations(options={}) + def remove_annotations(options = {}) if routes_file_exist? existing_text = File.read(routes_file) content, header_position = Helpers.strip_annotations(existing_text) @@ -94,8 +96,8 @@ def rewrite_contents(existing_text, new_text, frozen) def annotate_routes(header, content, header_position, options = {}) magic_comments_map, content = Helpers.extract_magic_comments_from_array(content) - if %w(before top).include?(options[:position_in_routes]) - header = header << '' if content.first != '' + if %w[before top].include?(options[:position_in_routes]) + header <<= '' if content.first != '' magic_comments_map << '' if magic_comments_map.any? new_content = magic_comments_map + header + content else diff --git a/lib/annotate/annotate_routes/header_generator.rb b/lib/annotate/annotate_routes/header_generator.rb index b1c93acf7..36852cc19 100644 --- a/lib/annotate/annotate_routes/header_generator.rb +++ b/lib/annotate/annotate_routes/header_generator.rb @@ -1,9 +1,11 @@ -require_relative './helpers' +# frozen_string_literal: true + +require_relative 'helpers' module AnnotateRoutes class HeaderGenerator - PREFIX = '== Route Map'.freeze - PREFIX_MD = '## Route Map'.freeze + PREFIX = '== Route Map' + PREFIX_MD = '## Route Map' HEADER_ROW = ['Prefix', 'Verb', 'URI Pattern', 'Controller#Action'].freeze class << self @@ -16,12 +18,12 @@ def generate(options = {}) private def routes_map(options) - result = `rake routes`.chomp("\n").split(/\n/, -1) + result = `rake routes`.chomp("\n").split("\n", -1) # In old versions of Rake, the first line of output was the cwd. Not so # much in newer ones. We ditch that line if it exists, and if not, we # keep the line around. - result.shift if result.first =~ %r{^\(in \/} + result.shift if result.first =~ %r{^\(in /} ignore_routes = options[:ignore_routes] regexp_for_ignoring_routes = ignore_routes ? /#{ignore_routes}/ : nil @@ -53,7 +55,7 @@ def generate out << comment(options[:wrapper_open]) if options[:wrapper_open] - out << comment(markdown? ? PREFIX_MD : PREFIX) + timestamp_if_required + out << (comment(markdown? ? PREFIX_MD : PREFIX) + timestamp_if_required) out << comment return out if contents_without_magic_comments.size.zero? @@ -68,7 +70,9 @@ def generate out << comment(content(contents_without_magic_comments[0], maxs)) end - out += contents_without_magic_comments[1..-1].map { |line| comment(content(markdown? ? line.split(' ') : line, maxs)) } + out += contents_without_magic_comments[1..-1].map do |line| + comment(content(markdown? ? line.split(' ') : line, maxs)) + end out << comment(options[:wrapper_close]) if options[:wrapper_close] out diff --git a/lib/annotate/annotate_routes/helpers.rb b/lib/annotate/annotate_routes/helpers.rb index 1dba65bbe..8ccb21a39 100644 --- a/lib/annotate/annotate_routes/helpers.rb +++ b/lib/annotate/annotate_routes/helpers.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + module AnnotateRoutes module Helpers - MAGIC_COMMENT_MATCHER = Regexp.new(/(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/).freeze + MAGIC_COMMENT_MATCHER = /(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/ class << self # TODO: write the method doc using ruby rdoc formats @@ -15,7 +17,7 @@ def strip_annotations(content) mode = :content header_position = 0 - content.split(/\n/, -1).each_with_index do |line, line_number| + content.split("\n", -1).each_with_index do |line, line_number| if mode == :header && line !~ /\s*#/ mode = :content real_content << line unless line.blank? @@ -62,7 +64,7 @@ def real_content_and_header_position(real_content, header_position) return real_content, :after if header_position >= real_content.count # and the default - return real_content, header_position + [real_content, header_position] end end end diff --git a/lib/annotate/constants.rb b/lib/annotate/constants.rb index 0d3225659..a8c608abd 100644 --- a/lib/annotate/constants.rb +++ b/lib/annotate/constants.rb @@ -1,31 +1,22 @@ +# frozen_string_literal: true + module Annotate module Constants - TRUE_RE = /^(true|t|yes|y|1)$/i.freeze + TRUE_RE = /^(true|t|yes|y|1)$/i ## # The set of available options to customize the behavior of Annotate. # POSITION_OPTIONS = [ - :position_in_routes, :position_in_class, :position_in_test, - :position_in_fixture, :position_in_factory, :position, - :position_in_serializer + :position_in_routes, :position_in_class, :position_in_test, :position_in_fixture, :position_in_factory, :position, :position_in_serializer ].freeze FLAG_OPTIONS = [ - :show_indexes, :simple_indexes, :include_version, :exclude_tests, - :exclude_fixtures, :exclude_factories, :ignore_model_sub_dir, - :format_bare, :format_rdoc, :format_yard, :format_markdown, :sort, :force, :frozen, - :trace, :timestamp, :exclude_serializers, :classified_sort, - :show_foreign_keys, :show_complete_foreign_keys, - :exclude_scaffolds, :exclude_controllers, :exclude_helpers, - :exclude_sti_subclasses, :ignore_unknown_models, :with_comment, :with_comment_column, - :show_check_constraints + :show_indexes, :simple_indexes, :include_version, :exclude_tests, :exclude_fixtures, :exclude_factories, :ignore_model_sub_dir, :format_bare, :format_rdoc, :format_yard, :format_markdown, :sort, :force, :frozen, :trace, :timestamp, :exclude_serializers, :classified_sort, :show_foreign_keys, :show_complete_foreign_keys, :exclude_scaffolds, :exclude_controllers, :exclude_helpers, :exclude_sti_subclasses, :ignore_unknown_models, :with_comment, :with_comment_column, :show_check_constraints ].freeze OTHER_OPTIONS = [ - :additional_file_patterns, :ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close, - :wrapper, :routes, :models, :hide_limit_column_types, :hide_default_column_types, - :ignore_routes, :active_admin + :additional_file_patterns, :ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close, :wrapper, :routes, :models, :hide_limit_column_types, :hide_default_column_types, :ignore_routes, :active_admin ].freeze PATH_OPTIONS = [ diff --git a/lib/annotate/helpers.rb b/lib/annotate/helpers.rb index 705685790..d5b91b948 100644 --- a/lib/annotate/helpers.rb +++ b/lib/annotate/helpers.rb @@ -1,17 +1,20 @@ +# frozen_string_literal: true + module Annotate # Class for holding helper methods. Done to make lib/annotate.rb less bloated. class Helpers class << self def skip_on_migration? - ENV['ANNOTATE_SKIP_ON_DB_MIGRATE'] =~ Constants::TRUE_RE || ENV['skip_on_db_migrate'] =~ Constants::TRUE_RE + ENV.fetch('ANNOTATE_SKIP_ON_DB_MIGRATE', + nil) =~ Constants::TRUE_RE || ENV.fetch('skip_on_db_migrate', nil) =~ Constants::TRUE_RE end def include_routes? - ENV['routes'] =~ Constants::TRUE_RE + ENV.fetch('routes', nil) =~ Constants::TRUE_RE end def include_models? - ENV['models'] =~ Constants::TRUE_RE + ENV.fetch('models', nil) =~ Constants::TRUE_RE end def true?(val) diff --git a/lib/annotate/parser.rb b/lib/annotate/parser.rb index ad85caf50..f84896c16 100644 --- a/lib/annotate/parser.rb +++ b/lib/annotate/parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'optparse' module Annotate @@ -15,7 +17,8 @@ def self.parse(args, env = {}) }.freeze ANNOTATION_POSITIONS = %w[before top after bottom].freeze - FILE_TYPE_POSITIONS = %w[position_in_class position_in_factory position_in_fixture position_in_test position_in_routes position_in_serializer].freeze + FILE_TYPE_POSITIONS = %w[position_in_class position_in_factory position_in_fixture position_in_test + position_in_routes position_in_serializer].freeze EXCLUSION_LIST = %w[tests fixtures factories serializers].freeze FORMAT_TYPES = %w[bare rdoc yard markdown].freeze @@ -55,7 +58,7 @@ def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength, option_parser.on('--additional-file-patterns path1,path2,path3', Array, - "Additional file paths or globs to annotate, separated by commas (e.g. `/foo/bar/%model_name%/*.rb,/baz/%model_name%.rb`)") do |additional_file_patterns| + 'Additional file paths or globs to annotate, separated by commas (e.g. `/foo/bar/%model_name%/*.rb,/baz/%model_name%.rb`)') do |additional_file_patterns| ENV['additional_file_patterns'] = additional_file_patterns end @@ -150,7 +153,7 @@ def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength, end option_parser.on('--models', - "Annotate ActiveRecord models") do + 'Annotate ActiveRecord models') do env['models'] = 'true' end @@ -205,33 +208,33 @@ def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength, end option_parser.on('--model-dir dir', - "Annotate model files stored in dir rather than app/models, separate multiple dirs with commas") do |dir| + 'Annotate model files stored in dir rather than app/models, separate multiple dirs with commas') do |dir| env['model_dir'] = dir end option_parser.on('--root-dir dir', - "Annotate files stored within root dir projects, separate multiple dirs with commas") do |dir| + 'Annotate files stored within root dir projects, separate multiple dirs with commas') do |dir| env['root_dir'] = dir end option_parser.on('--ignore-model-subdirects', - "Ignore subdirectories of the models directory") do + 'Ignore subdirectories of the models directory') do env['ignore_model_sub_dir'] = 'yes' end option_parser.on('--sort', - "Sort columns alphabetically, rather than in creation order") do + 'Sort columns alphabetically, rather than in creation order') do env['sort'] = 'yes' end option_parser.on('--classified-sort', - "Sort columns alphabetically, but first goes id, then the rest columns, then the timestamp columns and then the association columns") do + 'Sort columns alphabetically, but first goes id, then the rest columns, then the timestamp columns and then the association columns') do env['classified_sort'] = 'yes' end option_parser.on('-R', '--require path', - "Additional file to require before loading models, may be used multiple times") do |path| + 'Additional file to require before loading models, may be used multiple times') do |path| env['require'] = if env['require'].present? "#{env['require']},#{path}" else @@ -242,7 +245,7 @@ def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength, option_parser.on('-e', '--exclude [tests,fixtures,factories,serializers]', Array, - "Do not annotate fixtures, test files, factories, and/or serializers") do |exclusions| + 'Do not annotate fixtures, test files, factories, and/or serializers') do |exclusions| exclusions ||= EXCLUSION_LIST exclusions.each { |exclusion| env["exclude_#{exclusion}"] = 'yes' } end @@ -301,12 +304,12 @@ def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength, end option_parser.on('--with-comment', - "include database comments in model annotations") do + 'include database comments in model annotations') do env['with_comment'] = 'true' end option_parser.on('--with-comment-column', - "include database comments in model annotations, as its own column, after all others") do + 'include database comments in model annotations, as its own column, after all others') do env['with_comment_column'] = 'true' end end diff --git a/lib/annotate/tasks.rb b/lib/annotate/tasks.rb index 9a77a5039..3f57da2be 100644 --- a/lib/annotate/tasks.rb +++ b/lib/annotate/tasks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rubygems' require 'rake' diff --git a/lib/annotate/version.rb b/lib/annotate/version.rb index e103c6b87..e2cecb2ec 100644 --- a/lib/annotate/version.rb +++ b/lib/annotate/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Annotate def self.version '3.2.0' diff --git a/lib/generators/annotate/install_generator.rb b/lib/generators/annotate/install_generator.rb index 383c5cdd5..568294045 100644 --- a/lib/generators/annotate/install_generator.rb +++ b/lib/generators/annotate/install_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'annotate' module Annotate diff --git a/lib/generators/annotate/templates/auto_annotate_models.rake b/lib/generators/annotate/templates/auto_annotate_models.rake index 61cdcd7a1..37c98d87b 100644 --- a/lib/generators/annotate/templates/auto_annotate_models.rake +++ b/lib/generators/annotate/templates/auto_annotate_models.rake @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # NOTE: only doing this in development as some production environments (Heroku) # NOTE: are sensitive to local FS writes, and besides -- it's just not proper # NOTE: to have a dev-mode tool do its thing in production. @@ -7,53 +9,53 @@ if Rails.env.development? # You can override any of these by setting an environment variable of the # same name. Annotate.set_defaults( - 'active_admin' => 'false', - 'additional_file_patterns' => [], - 'routes' => 'false', - 'models' => 'true', - 'position_in_routes' => 'before', - 'position_in_class' => 'before', - 'position_in_test' => 'before', - 'position_in_fixture' => 'before', - 'position_in_factory' => 'before', - 'position_in_serializer' => 'before', - 'show_check_constraints' => 'false', - 'show_foreign_keys' => 'true', - 'show_complete_foreign_keys' => 'false', - 'show_indexes' => 'true', - 'simple_indexes' => 'false', - 'model_dir' => 'app/models', - 'root_dir' => '', - 'include_version' => 'false', - 'require' => '', - 'exclude_tests' => 'false', - 'exclude_fixtures' => 'false', - 'exclude_factories' => 'false', - 'exclude_serializers' => 'false', - 'exclude_scaffolds' => 'true', - 'exclude_controllers' => 'true', - 'exclude_helpers' => 'true', - 'exclude_sti_subclasses' => 'false', - 'ignore_model_sub_dir' => 'false', - 'ignore_columns' => nil, - 'ignore_routes' => nil, - 'ignore_unknown_models' => 'false', - 'hide_limit_column_types' => '<%= AnnotateModels::NO_LIMIT_COL_TYPES.join(",") %>', - 'hide_default_column_types' => '<%= AnnotateModels::NO_DEFAULT_COL_TYPES.join(",") %>', - 'skip_on_db_migrate' => 'false', - 'format_bare' => 'true', - 'format_rdoc' => 'false', - 'format_yard' => 'false', - 'format_markdown' => 'false', - 'sort' => 'false', - 'force' => 'false', - 'frozen' => 'false', - 'classified_sort' => 'true', - 'trace' => 'false', - 'wrapper_open' => nil, - 'wrapper_close' => nil, - 'with_comment' => 'true', - 'with_comment_column' => 'false' + 'active_admin' => 'false', + 'additional_file_patterns' => [], + 'routes' => 'false', + 'models' => 'true', + 'position_in_routes' => 'before', + 'position_in_class' => 'before', + 'position_in_test' => 'before', + 'position_in_fixture' => 'before', + 'position_in_factory' => 'before', + 'position_in_serializer' => 'before', + 'show_check_constraints' => 'false', + 'show_foreign_keys' => 'true', + 'show_complete_foreign_keys' => 'false', + 'show_indexes' => 'true', + 'simple_indexes' => 'false', + 'model_dir' => 'app/models', + 'root_dir' => '', + 'include_version' => 'false', + 'require' => '', + 'exclude_tests' => 'false', + 'exclude_fixtures' => 'false', + 'exclude_factories' => 'false', + 'exclude_serializers' => 'false', + 'exclude_scaffolds' => 'true', + 'exclude_controllers' => 'true', + 'exclude_helpers' => 'true', + 'exclude_sti_subclasses' => 'false', + 'ignore_model_sub_dir' => 'false', + 'ignore_columns' => nil, + 'ignore_routes' => nil, + 'ignore_unknown_models' => 'false', + 'hide_limit_column_types' => '<%= AnnotateModels::NO_LIMIT_COL_TYPES.join(",") %>', + 'hide_default_column_types' => '<%= AnnotateModels::NO_DEFAULT_COL_TYPES.join(",") %>', + 'skip_on_db_migrate' => 'false', + 'format_bare' => 'true', + 'format_rdoc' => 'false', + 'format_yard' => 'false', + 'format_markdown' => 'false', + 'sort' => 'false', + 'force' => 'false', + 'frozen' => 'false', + 'classified_sort' => 'true', + 'trace' => 'false', + 'wrapper_open' => nil, + 'wrapper_close' => nil, + 'with_comment' => 'true', + 'with_comment_column' => 'false' ) end diff --git a/lib/tasks/annotate_models.rake b/lib/tasks/annotate_models.rake index 776f97ba3..e7927a2db 100644 --- a/lib/tasks/annotate_models.rake +++ b/lib/tasks/annotate_models.rake @@ -1,4 +1,6 @@ -annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__))) +# frozen_string_literal: true + +annotate_lib = File.expand_path(File.dirname(__FILE__, 2)) unless ENV['is_cli'] task :set_annotation_options @@ -10,49 +12,54 @@ task annotate_models: :environment do require "#{annotate_lib}/annotate/annotate_models" require "#{annotate_lib}/annotate/active_record_patch" - options = {is_rake: true} - ENV['position'] = options[:position] = Annotate::Helpers.fallback(ENV['position'], 'before') + options = { is_rake: true } + ENV['position'] = options[:position] = Annotate::Helpers.fallback(ENV.fetch('position', nil), 'before') options[:additional_file_patterns] = ENV['additional_file_patterns'] ? ENV['additional_file_patterns'].split(',') : [] - options[:position_in_class] = Annotate::Helpers.fallback(ENV['position_in_class'], ENV['position']) - options[:position_in_fixture] = Annotate::Helpers.fallback(ENV['position_in_fixture'], ENV['position']) - options[:position_in_factory] = Annotate::Helpers.fallback(ENV['position_in_factory'], ENV['position']) - options[:position_in_test] = Annotate::Helpers.fallback(ENV['position_in_test'], ENV['position']) - options[:position_in_serializer] = Annotate::Helpers.fallback(ENV['position_in_serializer'], ENV['position']) - options[:show_check_constraints] = Annotate::Helpers.true?(ENV['show_check_constraints']) - options[:show_foreign_keys] = Annotate::Helpers.true?(ENV['show_foreign_keys']) - options[:show_complete_foreign_keys] = Annotate::Helpers.true?(ENV['show_complete_foreign_keys']) - options[:show_indexes] = Annotate::Helpers.true?(ENV['show_indexes']) - options[:simple_indexes] = Annotate::Helpers.true?(ENV['simple_indexes']) + options[:position_in_class] = + Annotate::Helpers.fallback(ENV.fetch('position_in_class', nil), ENV.fetch('position', nil)) + options[:position_in_fixture] = + Annotate::Helpers.fallback(ENV.fetch('position_in_fixture', nil), ENV.fetch('position', nil)) + options[:position_in_factory] = + Annotate::Helpers.fallback(ENV.fetch('position_in_factory', nil), ENV.fetch('position', nil)) + options[:position_in_test] = + Annotate::Helpers.fallback(ENV.fetch('position_in_test', nil), ENV.fetch('position', nil)) + options[:position_in_serializer] = + Annotate::Helpers.fallback(ENV.fetch('position_in_serializer', nil), ENV.fetch('position', nil)) + options[:show_check_constraints] = Annotate::Helpers.true?(ENV.fetch('show_check_constraints', nil)) + options[:show_foreign_keys] = Annotate::Helpers.true?(ENV.fetch('show_foreign_keys', nil)) + options[:show_complete_foreign_keys] = Annotate::Helpers.true?(ENV.fetch('show_complete_foreign_keys', nil)) + options[:show_indexes] = Annotate::Helpers.true?(ENV.fetch('show_indexes', nil)) + options[:simple_indexes] = Annotate::Helpers.true?(ENV.fetch('simple_indexes', nil)) options[:model_dir] = ENV['model_dir'] ? ENV['model_dir'].split(',') : ['app/models'] - options[:root_dir] = ENV['root_dir'] - options[:include_version] = Annotate::Helpers.true?(ENV['include_version']) + options[:root_dir] = ENV.fetch('root_dir', nil) + options[:include_version] = Annotate::Helpers.true?(ENV.fetch('include_version', nil)) options[:require] = ENV['require'] ? ENV['require'].split(',') : [] - options[:exclude_tests] = Annotate::Helpers.true?(ENV['exclude_tests']) - options[:exclude_factories] = Annotate::Helpers.true?(ENV['exclude_factories']) - options[:exclude_fixtures] = Annotate::Helpers.true?(ENV['exclude_fixtures']) - options[:exclude_serializers] = Annotate::Helpers.true?(ENV['exclude_serializers']) - options[:exclude_scaffolds] = Annotate::Helpers.true?(ENV['exclude_scaffolds']) + options[:exclude_tests] = Annotate::Helpers.true?(ENV.fetch('exclude_tests', nil)) + options[:exclude_factories] = Annotate::Helpers.true?(ENV.fetch('exclude_factories', nil)) + options[:exclude_fixtures] = Annotate::Helpers.true?(ENV.fetch('exclude_fixtures', nil)) + options[:exclude_serializers] = Annotate::Helpers.true?(ENV.fetch('exclude_serializers', nil)) + options[:exclude_scaffolds] = Annotate::Helpers.true?(ENV.fetch('exclude_scaffolds', nil)) options[:exclude_controllers] = Annotate::Helpers.true?(ENV.fetch('exclude_controllers', 'true')) options[:exclude_helpers] = Annotate::Helpers.true?(ENV.fetch('exclude_helpers', 'true')) - options[:exclude_sti_subclasses] = Annotate::Helpers.true?(ENV['exclude_sti_subclasses']) - options[:ignore_model_sub_dir] = Annotate::Helpers.true?(ENV['ignore_model_sub_dir']) - options[:format_bare] = Annotate::Helpers.true?(ENV['format_bare']) - options[:format_rdoc] = Annotate::Helpers.true?(ENV['format_rdoc']) - options[:format_yard] = Annotate::Helpers.true?(ENV['format_yard']) - options[:format_markdown] = Annotate::Helpers.true?(ENV['format_markdown']) - options[:sort] = Annotate::Helpers.true?(ENV['sort']) - options[:force] = Annotate::Helpers.true?(ENV['force']) - options[:frozen] = Annotate::Helpers.true?(ENV['frozen']) - options[:classified_sort] = Annotate::Helpers.true?(ENV['classified_sort']) - options[:trace] = Annotate::Helpers.true?(ENV['trace']) - options[:wrapper_open] = Annotate::Helpers.fallback(ENV['wrapper_open'], ENV['wrapper']) - options[:wrapper_close] = Annotate::Helpers.fallback(ENV['wrapper_close'], ENV['wrapper']) + options[:exclude_sti_subclasses] = Annotate::Helpers.true?(ENV.fetch('exclude_sti_subclasses', nil)) + options[:ignore_model_sub_dir] = Annotate::Helpers.true?(ENV.fetch('ignore_model_sub_dir', nil)) + options[:format_bare] = Annotate::Helpers.true?(ENV.fetch('format_bare', nil)) + options[:format_rdoc] = Annotate::Helpers.true?(ENV.fetch('format_rdoc', nil)) + options[:format_yard] = Annotate::Helpers.true?(ENV.fetch('format_yard', nil)) + options[:format_markdown] = Annotate::Helpers.true?(ENV.fetch('format_markdown', nil)) + options[:sort] = Annotate::Helpers.true?(ENV.fetch('sort', nil)) + options[:force] = Annotate::Helpers.true?(ENV.fetch('force', nil)) + options[:frozen] = Annotate::Helpers.true?(ENV.fetch('frozen', nil)) + options[:classified_sort] = Annotate::Helpers.true?(ENV.fetch('classified_sort', nil)) + options[:trace] = Annotate::Helpers.true?(ENV.fetch('trace', nil)) + options[:wrapper_open] = Annotate::Helpers.fallback(ENV.fetch('wrapper_open', nil), ENV.fetch('wrapper', nil)) + options[:wrapper_close] = Annotate::Helpers.fallback(ENV.fetch('wrapper_close', nil), ENV.fetch('wrapper', nil)) options[:ignore_columns] = ENV.fetch('ignore_columns', nil) options[:ignore_routes] = ENV.fetch('ignore_routes', nil) - options[:hide_limit_column_types] = Annotate::Helpers.fallback(ENV['hide_limit_column_types'], '') - options[:hide_default_column_types] = Annotate::Helpers.fallback(ENV['hide_default_column_types'], '') - options[:with_comment] = Annotate::Helpers.true?(ENV['with_comment']) - options[:with_comment_column] = Annotate::Helpers.true?(ENV['with_comment_column']) + options[:hide_limit_column_types] = Annotate::Helpers.fallback(ENV.fetch('hide_limit_column_types', nil), '') + options[:hide_default_column_types] = Annotate::Helpers.fallback(ENV.fetch('hide_default_column_types', nil), '') + options[:with_comment] = Annotate::Helpers.true?(ENV.fetch('with_comment', nil)) + options[:with_comment_column] = Annotate::Helpers.true?(ENV.fetch('with_comment_column', nil)) options[:ignore_unknown_models] = Annotate::Helpers.true?(ENV.fetch('ignore_unknown_models', 'false')) AnnotateModels.do_annotations(options) @@ -63,10 +70,10 @@ task remove_annotation: :environment do require "#{annotate_lib}/annotate/annotate_models" require "#{annotate_lib}/annotate/active_record_patch" - options = {is_rake: true} - options[:model_dir] = ENV['model_dir'] - options[:root_dir] = ENV['root_dir'] + options = { is_rake: true } + options[:model_dir] = ENV.fetch('model_dir', nil) + options[:root_dir] = ENV.fetch('root_dir', nil) options[:require] = ENV['require'] ? ENV['require'].split(',') : [] - options[:trace] = Annotate::Helpers.true?(ENV['trace']) + options[:trace] = Annotate::Helpers.true?(ENV.fetch('trace', nil)) AnnotateModels.remove_annotations(options) end diff --git a/lib/tasks/annotate_models_migrate.rake b/lib/tasks/annotate_models_migrate.rake index 58c07a5a9..51a385917 100644 --- a/lib/tasks/annotate_models_migrate.rake +++ b/lib/tasks/annotate_models_migrate.rake @@ -1,17 +1,19 @@ +# frozen_string_literal: true + # These tasks are added to the project if you install annotate as a Rails plugin. # (They are not used to build annotate itself.) # Append annotations to Rake tasks for ActiveRecord, so annotate automatically gets # run after doing db:migrate. -migration_tasks = %w(db:migrate db:migrate:up db:migrate:down db:migrate:reset db:migrate:redo db:rollback) +migration_tasks = %w[db:migrate db:migrate:up db:migrate:down db:migrate:reset db:migrate:redo db:rollback] if defined?(Rails::Application) && Rails.version.split('.').first.to_i >= 6 require 'active_record' databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name| - migration_tasks.concat(%w(db:migrate db:migrate:up db:migrate:down).map { |task| "#{task}:#{spec_name}" }) + migration_tasks.concat(%w[db:migrate db:migrate:up db:migrate:down].map { |task| "#{task}:#{spec_name}" }) end end @@ -36,27 +38,27 @@ module Annotate @@working = false def self.update_annotations - unless @@working || Annotate::Helpers.skip_on_migration? - @@working = true + return if @@working || Annotate::Helpers.skip_on_migration? - self.update_models if Annotate::Helpers.include_models? - self.update_routes if Annotate::Helpers.include_routes? - end + @@working = true + + update_models if Annotate::Helpers.include_models? + update_routes if Annotate::Helpers.include_routes? end def self.update_models - if Rake::Task.task_defined?("annotate_models") - Rake::Task["annotate_models"].invoke - elsif Rake::Task.task_defined?("app:annotate_models") - Rake::Task["app:annotate_models"].invoke + if Rake::Task.task_defined?('annotate_models') + Rake::Task['annotate_models'].invoke + elsif Rake::Task.task_defined?('app:annotate_models') + Rake::Task['app:annotate_models'].invoke end end def self.update_routes - if Rake::Task.task_defined?("annotate_routes") - Rake::Task["annotate_routes"].invoke - elsif Rake::Task.task_defined?("app:annotate_routes") - Rake::Task["app:annotate_routes"].invoke + if Rake::Task.task_defined?('annotate_routes') + Rake::Task['annotate_routes'].invoke + elsif Rake::Task.task_defined?('app:annotate_routes') + Rake::Task['app:annotate_routes'].invoke end end end diff --git a/lib/tasks/annotate_routes.rake b/lib/tasks/annotate_routes.rake index b2832d443..4b7d9df38 100644 --- a/lib/tasks/annotate_routes.rake +++ b/lib/tasks/annotate_routes.rake @@ -1,31 +1,34 @@ -annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__))) +# frozen_string_literal: true + +annotate_lib = File.expand_path(File.dirname(__FILE__, 2)) unless ENV['is_cli'] task :set_annotation_options task annotate_routes: :set_annotation_options end -desc "Adds the route map to routes.rb" -task :annotate_routes => :environment do +desc 'Adds the route map to routes.rb' +task annotate_routes: :environment do require "#{annotate_lib}/annotate/annotate_routes" - options={} - ENV['position'] = options[:position] = Annotate::Helpers.fallback(ENV['position'], 'before') - options[:position_in_routes] = Annotate::Helpers.fallback(ENV['position_in_routes'], ENV['position']) - options[:ignore_routes] = Annotate::Helpers.fallback(ENV['ignore_routes'], nil) + options = {} + ENV['position'] = options[:position] = Annotate::Helpers.fallback(ENV.fetch('position', nil), 'before') + options[:position_in_routes] = + Annotate::Helpers.fallback(ENV.fetch('position_in_routes', nil), ENV.fetch('position', nil)) + options[:ignore_routes] = Annotate::Helpers.fallback(ENV.fetch('ignore_routes', nil), nil) options[:require] = ENV['require'] ? ENV['require'].split(',') : [] - options[:frozen] = Annotate::Helpers.true?(ENV['frozen']) - options[:wrapper_open] = Annotate::Helpers.fallback(ENV['wrapper_open'], ENV['wrapper']) - options[:wrapper_close] = Annotate::Helpers.fallback(ENV['wrapper_close'], ENV['wrapper']) + options[:frozen] = Annotate::Helpers.true?(ENV.fetch('frozen', nil)) + options[:wrapper_open] = Annotate::Helpers.fallback(ENV.fetch('wrapper_open', nil), ENV.fetch('wrapper', nil)) + options[:wrapper_close] = Annotate::Helpers.fallback(ENV.fetch('wrapper_close', nil), ENV.fetch('wrapper', nil)) AnnotateRoutes.do_annotations(options) end -desc "Removes the route map from routes.rb" -task :remove_routes => :environment do - annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__))) +desc 'Removes the route map from routes.rb' +task remove_routes: :environment do + annotate_lib = File.expand_path(File.dirname(__FILE__, 2)) require "#{annotate_lib}/annotate/annotate_routes" - options={} + options = {} options[:require] = ENV['require'] ? ENV['require'].split(',') : [] AnnotateRoutes.remove_annotations(options) end diff --git a/spec/lib/annotate/annotate_models/file_patterns_spec.rb b/spec/lib/annotate/annotate_models/file_patterns_spec.rb index eabc1c5da..41ae5fc97 100644 --- a/spec/lib/annotate/annotate_models/file_patterns_spec.rb +++ b/spec/lib/annotate/annotate_models/file_patterns_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../../spec_helper' require 'annotate/annotate_models' @@ -13,10 +15,10 @@ it 'returns patterns of test files' do is_expected.to eq([ - '/root/test/unit/%MODEL_NAME%_test.rb', - '/root/test/models/%MODEL_NAME%_test.rb', - '/root/spec/models/%MODEL_NAME%_spec.rb' - ]) + '/root/test/unit/%MODEL_NAME%_test.rb', + '/root/test/models/%MODEL_NAME%_test.rb', + '/root/spec/models/%MODEL_NAME%_spec.rb' + ]) end end @@ -25,11 +27,11 @@ it 'returns patterns of fixture files' do is_expected.to eq([ - '/root/test/fixtures/%TABLE_NAME%.yml', - '/root/spec/fixtures/%TABLE_NAME%.yml', - '/root/test/fixtures/%PLURALIZED_MODEL_NAME%.yml', - '/root/spec/fixtures/%PLURALIZED_MODEL_NAME%.yml' - ]) + '/root/test/fixtures/%TABLE_NAME%.yml', + '/root/spec/fixtures/%TABLE_NAME%.yml', + '/root/test/fixtures/%PLURALIZED_MODEL_NAME%.yml', + '/root/spec/fixtures/%PLURALIZED_MODEL_NAME%.yml' + ]) end end @@ -38,11 +40,11 @@ it 'returns patterns of scaffold files' do is_expected.to eq([ - '/root/test/controllers/%PLURALIZED_MODEL_NAME%_controller_test.rb', - '/root/spec/controllers/%PLURALIZED_MODEL_NAME%_controller_spec.rb', - '/root/spec/requests/%PLURALIZED_MODEL_NAME%_spec.rb', - '/root/spec/routing/%PLURALIZED_MODEL_NAME%_routing_spec.rb' - ]) + '/root/test/controllers/%PLURALIZED_MODEL_NAME%_controller_test.rb', + '/root/spec/controllers/%PLURALIZED_MODEL_NAME%_controller_spec.rb', + '/root/spec/requests/%PLURALIZED_MODEL_NAME%_spec.rb', + '/root/spec/routing/%PLURALIZED_MODEL_NAME%_routing_spec.rb' + ]) end end @@ -51,19 +53,19 @@ it 'returns patterns of factory files' do is_expected.to eq([ - '/root/test/exemplars/%MODEL_NAME%_exemplar.rb', - '/root/spec/exemplars/%MODEL_NAME%_exemplar.rb', - '/root/test/blueprints/%MODEL_NAME%_blueprint.rb', - '/root/spec/blueprints/%MODEL_NAME%_blueprint.rb', - '/root/test/factories/%MODEL_NAME%_factory.rb', - '/root/spec/factories/%MODEL_NAME%_factory.rb', - '/root/test/factories/%TABLE_NAME%.rb', - '/root/spec/factories/%TABLE_NAME%.rb', - '/root/test/factories/%PLURALIZED_MODEL_NAME%.rb', - '/root/spec/factories/%PLURALIZED_MODEL_NAME%.rb', - '/root/test/fabricators/%MODEL_NAME%_fabricator.rb', - '/root/spec/fabricators/%MODEL_NAME%_fabricator.rb' - ]) + '/root/test/exemplars/%MODEL_NAME%_exemplar.rb', + '/root/spec/exemplars/%MODEL_NAME%_exemplar.rb', + '/root/test/blueprints/%MODEL_NAME%_blueprint.rb', + '/root/spec/blueprints/%MODEL_NAME%_blueprint.rb', + '/root/test/factories/%MODEL_NAME%_factory.rb', + '/root/spec/factories/%MODEL_NAME%_factory.rb', + '/root/test/factories/%TABLE_NAME%.rb', + '/root/spec/factories/%TABLE_NAME%.rb', + '/root/test/factories/%PLURALIZED_MODEL_NAME%.rb', + '/root/spec/factories/%PLURALIZED_MODEL_NAME%.rb', + '/root/test/fabricators/%MODEL_NAME%_fabricator.rb', + '/root/spec/fabricators/%MODEL_NAME%_fabricator.rb' + ]) end end @@ -72,10 +74,10 @@ it 'returns patterns of serializer files' do is_expected.to eq([ - '/root/app/serializers/%MODEL_NAME%_serializer.rb', - '/root/test/serializers/%MODEL_NAME%_serializer_test.rb', - '/root/spec/serializers/%MODEL_NAME%_serializer_spec.rb' - ]) + '/root/app/serializers/%MODEL_NAME%_serializer.rb', + '/root/test/serializers/%MODEL_NAME%_serializer_test.rb', + '/root/spec/serializers/%MODEL_NAME%_serializer_spec.rb' + ]) end end @@ -90,7 +92,7 @@ ] end - let(:options) { { additional_file_patterns: additional_file_patterns } } + let(:options) { { additional_file_patterns: } } it 'returns additional_file_patterns in the argument "options"' do is_expected.to eq(additional_file_patterns) @@ -111,8 +113,8 @@ it 'returns patterns of controller files' do is_expected.to eq([ - '/root/app/controllers/%PLURALIZED_MODEL_NAME%_controller.rb' - ]) + '/root/app/controllers/%PLURALIZED_MODEL_NAME%_controller.rb' + ]) end end @@ -129,8 +131,8 @@ it 'returns patterns of helper files' do is_expected.to eq([ - '/root/app/helpers/%PLURALIZED_MODEL_NAME%_helper.rb' - ]) + '/root/app/helpers/%PLURALIZED_MODEL_NAME%_helper.rb' + ]) end end end diff --git a/spec/lib/annotate/annotate_models_spec.rb b/spec/lib/annotate/annotate_models_spec.rb index 096474610..cfd7b15e3 100644 --- a/spec/lib/annotate/annotate_models_spec.rb +++ b/spec/lib/annotate/annotate_models_spec.rb @@ -1,4 +1,5 @@ -# encoding: utf-8 +# frozen_string_literal: true + require_relative '../../spec_helper' require 'annotate/annotate_models' require 'annotate/active_record_patch' @@ -7,51 +8,53 @@ require 'tmpdir' describe AnnotateModels do - MAGIC_COMMENTS = [ - '# encoding: UTF-8', - '# coding: UTF-8', - '# -*- coding: UTF-8 -*-', - '#encoding: utf-8', - '# encoding: utf-8', - '# -*- encoding : utf-8 -*-', - "# encoding: utf-8\n# frozen_string_literal: true", - "# frozen_string_literal: true\n# encoding: utf-8", - '# frozen_string_literal: true', - '#frozen_string_literal: false', - '# -*- frozen_string_literal : true -*-' - ].freeze unless const_defined?(:MAGIC_COMMENTS) + unless const_defined?(:MAGIC_COMMENTS) + MAGIC_COMMENTS = [ + '# encoding: UTF-8', + '# coding: UTF-8', + '# -*- coding: UTF-8 -*-', + '#encoding: utf-8', + '# encoding: utf-8', + '# -*- encoding : utf-8 -*-', + "# encoding: utf-8\n# frozen_string_literal: true", + "# frozen_string_literal: true\n# encoding: utf-8", + '# frozen_string_literal: true', + '#frozen_string_literal: false', + '# -*- frozen_string_literal : true -*-' + ].freeze + end def mock_index(name, params = {}) double('IndexKeyDefinition', - name: name, - columns: params[:columns] || [], - unique: params[:unique] || false, - orders: params[:orders] || {}, - where: params[:where], - using: params[:using]) + name:, + columns: params[:columns] || [], + unique: params[:unique] || false, + orders: params[:orders] || {}, + where: params[:where], + using: params[:using]) end def mock_foreign_key(name, from_column, to_table, to_column = 'id', constraints = {}) double('ForeignKeyDefinition', - name: name, - column: from_column, - to_table: to_table, - primary_key: to_column, - on_delete: constraints[:on_delete], - on_update: constraints[:on_update]) + name:, + column: from_column, + to_table:, + primary_key: to_column, + on_delete: constraints[:on_delete], + on_update: constraints[:on_update]) end def mock_check_constraint(name, expression) double('CheckConstraintDefinition', - name: name, - expression: expression) + name:, + expression:) end def mock_connection(indexes = [], foreign_keys = [], check_constraints = []) double('Conn', - indexes: indexes, - foreign_keys: foreign_keys, - check_constraints: check_constraints, + indexes:, + foreign_keys:, + check_constraints:, supports_foreign_keys?: true, supports_check_constraints?: true, table_exists?: true) @@ -60,13 +63,13 @@ def mock_connection(indexes = [], foreign_keys = [], check_constraints = []) # rubocop:disable Metrics/ParameterLists def mock_class(table_name, primary_key, columns, indexes = [], foreign_keys = [], check_constraints = []) options = { - connection: mock_connection(indexes, foreign_keys, check_constraints), - table_exists?: true, - table_name: table_name, - primary_key: primary_key, - column_names: columns.map { |col| col.name.to_s }, - columns: columns, - column_defaults: Hash[columns.map { |col| [col.name, col.default] }], + connection: mock_connection(indexes, foreign_keys, check_constraints), + table_exists?: true, + table_name:, + primary_key:, + column_names: columns.map { |col| col.name.to_s }, + columns:, + column_defaults: Hash[columns.map { |col| [col.name, col.default] }], table_name_prefix: '' } @@ -291,7 +294,7 @@ def mock_column(name, type, options = {}) let :columns do [ mock_column(:id, :integer), - mock_column(:name, :enum, limit: [:enum1, :enum2]) + mock_column(:name, :enum, limit: %i[enum1 enum2]) ] end @@ -320,7 +323,7 @@ def mock_column(name, type, options = {}) mock_column(:bigint, :integer, unsigned?: true, bigint?: true), mock_column(:bigint, :bigint, unsigned?: true), mock_column(:float, :float, unsigned?: true), - mock_column(:decimal, :decimal, unsigned?: true, precision: 10, scale: 2), + mock_column(:decimal, :decimal, unsigned?: true, precision: 10, scale: 2) ] end @@ -406,7 +409,7 @@ def mock_column(name, type, options = {}) end end - context 'with Globalize gem' do # rubocop:disable RSpec/MultipleMemoizedHelpers + context 'with Globalize gem' do let :translation_klass do double('Folder::Post::Translation', to_s: 'Folder::Post::Translation', @@ -414,7 +417,7 @@ def mock_column(name, type, options = {}) mock_column(:id, :integer, limit: 8), mock_column(:post_id, :integer, limit: 8), mock_column(:locale, :string, limit: 50), - mock_column(:title, :string, limit: 50), + mock_column(:title, :string, limit: 50) ]) end @@ -427,7 +430,7 @@ def mock_column(name, type, options = {}) let :columns do [ mock_column(:id, :integer, limit: 8), - mock_column(:author_name, :string, limit: 50), + mock_column(:author_name, :string, limit: 50) ] end @@ -452,7 +455,7 @@ def mock_column(name, type, options = {}) context 'when the primary key is an array (using composite_primary_keys)' do let :primary_key do - [:a_id, :b_id] + %i[a_id b_id] end let :columns do @@ -542,10 +545,10 @@ def mock_column(name, type, options = {}) context 'when one of indexes includes ordered index key' do let :columns do [ - mock_column("id", :integer), - mock_column("firstname", :string), - mock_column("surname", :string), - mock_column("value", :string) + mock_column('id', :integer), + mock_column('firstname', :string), + mock_column('surname', :string), + mock_column('value', :string) ] end @@ -553,7 +556,7 @@ def mock_column(name, type, options = {}) [ mock_index('index_rails_02e851e3b7', columns: ['id']), mock_index('index_rails_02e851e3b8', - columns: %w(firstname surname value), + columns: %w[firstname surname value], orders: { 'surname' => :asc, 'value' => :desc }) ] end @@ -585,10 +588,10 @@ def mock_column(name, type, options = {}) context 'when one of indexes includes "where" clause' do let :columns do [ - mock_column("id", :integer), - mock_column("firstname", :string), - mock_column("surname", :string), - mock_column("value", :string) + mock_column('id', :integer), + mock_column('firstname', :string), + mock_column('surname', :string), + mock_column('value', :string) ] end @@ -596,7 +599,7 @@ def mock_column(name, type, options = {}) [ mock_index('index_rails_02e851e3b7', columns: ['id']), mock_index('index_rails_02e851e3b8', - columns: %w(firstname surname), + columns: %w[firstname surname], where: 'value IS NOT NULL') ] end @@ -628,10 +631,10 @@ def mock_column(name, type, options = {}) context 'when one of indexes includes "using" clause other than "btree"' do let :columns do [ - mock_column("id", :integer), - mock_column("firstname", :string), - mock_column("surname", :string), - mock_column("value", :string) + mock_column('id', :integer), + mock_column('firstname', :string), + mock_column('surname', :string), + mock_column('value', :string) ] end @@ -639,7 +642,7 @@ def mock_column(name, type, options = {}) [ mock_index('index_rails_02e851e3b7', columns: ['id']), mock_index('index_rails_02e851e3b8', - columns: %w(firstname surname), + columns: %w[firstname surname], using: 'hash') ] end @@ -696,10 +699,10 @@ def mock_column(name, type, options = {}) is_expected.to eq expected_result end - # rubocop:disable RSpec/NestedGroups context 'when the unprefixed table name does not exist' do let :klass do - mock_class(:users, primary_key, columns, indexes, foreign_keys).tap do |mock_klass| + mock_class(:users, primary_key, columns, indexes, + foreign_keys).tap do |mock_klass| allow(mock_klass).to receive(:table_name_prefix).and_return('my_prefix_') allow(mock_klass.connection).to receive(:table_exists?).with('users').and_return(false) allow(mock_klass.connection).to receive(:indexes).with('users').and_raise('error fetching indexes on nonexistent table') @@ -712,7 +715,6 @@ def mock_column(name, type, options = {}) expect(klass.connection).to have_received(:table_exists?).with('users') end end - # rubocop:enable RSpec/NestedGroups end end @@ -758,8 +760,8 @@ def mock_column(name, type, options = {}) context 'when one of indexes is in string form' do let :columns do [ - mock_column("id", :integer), - mock_column("name", :string) + mock_column('id', :integer), + mock_column('name', :string) ] end @@ -1944,7 +1946,7 @@ def mock_column(name, type, options = {}) describe '.set_defaults' do subject do - Annotate::Helpers.true?(ENV['show_complete_foreign_keys']) + Annotate::Helpers.true?(ENV.fetch('show_complete_foreign_keys', nil)) end after :each do @@ -1986,7 +1988,7 @@ def mock_column(name, type, options = {}) ] end - let(:options) { { additional_file_patterns: additional_file_patterns } } + let(:options) { { additional_file_patterns: } } it 'returns additional_file_patterns in the argument "options"' do is_expected.to eq(additional_file_patterns) @@ -2079,12 +2081,10 @@ def mock_column(name, type, options = {}) context 'when a model file outside `model_dir` directory is specified' do it 'exits with the status code' do - begin - subject - raise - rescue SystemExit => e - expect(e.status).to eq(1) - end + subject + raise + rescue SystemExit => e + expect(e.status).to eq(1) end end end @@ -2108,12 +2108,10 @@ def mock_column(name, type, options = {}) let(:options) { {} } it 'exits with the status code' do - begin - subject - raise - rescue SystemExit => e - expect(e.status).to eq(1) - end + subject + raise + rescue SystemExit => e + expect(e.status).to eq(1) end end end @@ -2842,7 +2840,7 @@ class User < ActiveRecord::Base def write_model(file_name, file_content) fname = File.join(@model_dir, file_name) FileUtils.mkdir_p(File.dirname(fname)) - File.open(fname, 'wb') { |f| f.write file_content } + File.binwrite(fname, file_content) [fname, file_content] end @@ -2861,7 +2859,7 @@ def annotate_one_file(options = {}) ['before', :before, 'top', :top].each do |position| it "should put annotation before class if :position == #{position}" do - annotate_one_file position: position + annotate_one_file(position:) expect(File.read(@model_file_name)) .to eq("#{@schema_info}#{@file_content}") end @@ -2869,7 +2867,7 @@ def annotate_one_file(options = {}) ['after', :after, 'bottom', :bottom].each do |position| it "should put annotation after class if position: #{position}" do - annotate_one_file position: position + annotate_one_file(position:) expect(File.read(@model_file_name)) .to eq("#{@file_content}\n#{@schema_info}") end @@ -2927,7 +2925,8 @@ def annotate_one_file(options = {}) describe 'with existing annotation => :before' do before do annotate_one_file position: :before - another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), '== Schema Info') + another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), + '== Schema Info') @schema_info = another_schema_info end @@ -2950,7 +2949,8 @@ def annotate_one_file(options = {}) describe 'with existing annotation => :after' do before do annotate_one_file position: :after - another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), '== Schema Info') + another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), + '== Schema Info') @schema_info = another_schema_info end @@ -2972,7 +2972,7 @@ def annotate_one_file(options = {}) it 'should skip columns with option[:ignore_columns] set' do output = AnnotateModels.get_schema_info(@klass, '== Schema Info', - :ignore_columns => '(id|updated_at|created_at)') + ignore_columns: '(id|updated_at|created_at)') expect(output.match(/id/)).to be_nil end @@ -2982,7 +2982,7 @@ class Foo::User < ActiveRecord::Base end EOS - klass = mock_class(:'foo_users', + klass = mock_class(:foo_users, :id, [ mock_column(:id, :integer), @@ -3060,13 +3060,25 @@ class User < ActiveRecord::Base end it 'displays just the error message with trace disabled (default)' do - expect { AnnotateModels.do_annotations model_dir: @model_dir, is_rake: true }.to output(a_string_including("Unable to annotate #{@model_dir}/user.rb: oops")).to_stderr - expect { AnnotateModels.do_annotations model_dir: @model_dir, is_rake: true }.not_to output(a_string_including('/spec/annotate/annotate_models_spec.rb:')).to_stderr + expect do + AnnotateModels.do_annotations model_dir: @model_dir, + is_rake: true + end.to output(a_string_including("Unable to annotate #{@model_dir}/user.rb: oops")).to_stderr + expect do + AnnotateModels.do_annotations model_dir: @model_dir, + is_rake: true + end.not_to output(a_string_including('/spec/annotate/annotate_models_spec.rb:')).to_stderr end it 'displays the error message and stacktrace with trace enabled' do - expect { AnnotateModels.do_annotations model_dir: @model_dir, is_rake: true, trace: true }.to output(a_string_including("Unable to annotate #{@model_dir}/user.rb: oops")).to_stderr - expect { AnnotateModels.do_annotations model_dir: @model_dir, is_rake: true, trace: true }.to output(a_string_including('/spec/lib/annotate/annotate_models_spec.rb:')).to_stderr + expect do + AnnotateModels.do_annotations model_dir: @model_dir, is_rake: true, + trace: true + end.to output(a_string_including("Unable to annotate #{@model_dir}/user.rb: oops")).to_stderr + expect do + AnnotateModels.do_annotations model_dir: @model_dir, is_rake: true, + trace: true + end.to output(a_string_including('/spec/lib/annotate/annotate_models_spec.rb:')).to_stderr end end @@ -3082,30 +3094,49 @@ class User < ActiveRecord::Base end it 'displays just the error message with trace disabled (default)' do - expect { AnnotateModels.remove_annotations model_dir: @model_dir, is_rake: true }.to output(a_string_including("Unable to deannotate #{@model_dir}/user.rb: oops")).to_stderr - expect { AnnotateModels.remove_annotations model_dir: @model_dir, is_rake: true }.not_to output(a_string_including("/user.rb:2:in `'")).to_stderr + expect do + AnnotateModels.remove_annotations model_dir: @model_dir, + is_rake: true + end.to output(a_string_including("Unable to deannotate #{@model_dir}/user.rb: oops")).to_stderr + expect do + AnnotateModels.remove_annotations model_dir: @model_dir, + is_rake: true + end.not_to output(a_string_including("/user.rb:2:in `'")).to_stderr end it 'displays the error message and stacktrace with trace enabled' do - expect { AnnotateModels.remove_annotations model_dir: @model_dir, is_rake: true, trace: true }.to output(a_string_including("Unable to deannotate #{@model_dir}/user.rb: oops")).to_stderr - expect { AnnotateModels.remove_annotations model_dir: @model_dir, is_rake: true, trace: true }.to output(a_string_including("/user.rb:2:in `'")).to_stderr + expect do + AnnotateModels.remove_annotations model_dir: @model_dir, is_rake: true, + trace: true + end.to output(a_string_including("Unable to deannotate #{@model_dir}/user.rb: oops")).to_stderr + expect do + AnnotateModels.remove_annotations model_dir: @model_dir, is_rake: true, + trace: true + end.to output(a_string_including("/user.rb:2:in `'")).to_stderr end end describe 'frozen option' do - it "should abort without existing annotation when frozen: true " do - expect { annotate_one_file frozen: true }.to raise_error SystemExit, /user.rb needs to be updated, but annotate was run with `--frozen`./ + it 'should abort without existing annotation when frozen: true' do + expect do + annotate_one_file frozen: true + end.to raise_error SystemExit, + /user.rb needs to be updated, but annotate was run with `--frozen`./ end - it "should abort with different annotation when frozen: true " do + it 'should abort with different annotation when frozen: true' do annotate_one_file - another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), '== Schema Info') + another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), + '== Schema Info') @schema_info = another_schema_info - expect { annotate_one_file frozen: true }.to raise_error SystemExit, /user.rb needs to be updated, but annotate was run with `--frozen`./ + expect do + annotate_one_file frozen: true + end.to raise_error SystemExit, + /user.rb needs to be updated, but annotate was run with `--frozen`./ end - it "should NOT abort with same annotation when frozen: true " do + it 'should NOT abort with same annotation when frozen: true' do annotate_one_file expect { annotate_one_file frozen: true }.not_to raise_error end @@ -3131,7 +3162,7 @@ class Foo < ActiveRecord::Base; end context 'with a non-class' do before do - NotAClass = 'foo'.freeze # rubocop:disable Naming/ConstantName + NotAClass = 'foo' # rubocop:disable Naming/ConstantName allow(AnnotateModels).to receive(:get_model_class).with('foo.rb') { NotAClass } end diff --git a/spec/lib/annotate/annotate_routes_spec.rb b/spec/lib/annotate/annotate_routes_spec.rb index 2d27b7458..b131198cc 100644 --- a/spec/lib/annotate/annotate_routes_spec.rb +++ b/spec/lib/annotate/annotate_routes_spec.rb @@ -1,27 +1,31 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' require 'annotate/annotate_routes' describe AnnotateRoutes do - ROUTE_FILE = 'config/routes.rb'.freeze - - MESSAGE_ANNOTATED = "#{ROUTE_FILE} was annotated.".freeze - MESSAGE_UNCHANGED = "#{ROUTE_FILE} was not changed.".freeze - MESSAGE_NOT_FOUND = "#{ROUTE_FILE} could not be found.".freeze - MESSAGE_REMOVED = "Annotations were removed from #{ROUTE_FILE}.".freeze - - MAGIC_COMMENTS = [ - '# encoding: UTF-8', - '# coding: UTF-8', - '# -*- coding: UTF-8 -*-', - '#encoding: utf-8', - '# encoding: utf-8', - '# -*- encoding : utf-8 -*-', - "# encoding: utf-8\n# frozen_string_literal: true", - "# frozen_string_literal: true\n# encoding: utf-8", - '# frozen_string_literal: true', - '#frozen_string_literal: false', - '# -*- frozen_string_literal : true -*-' - ].freeze unless const_defined?(:MAGIC_COMMENTS) + ROUTE_FILE = 'config/routes.rb' + + MESSAGE_ANNOTATED = "#{ROUTE_FILE} was annotated." + MESSAGE_UNCHANGED = "#{ROUTE_FILE} was not changed." + MESSAGE_NOT_FOUND = "#{ROUTE_FILE} could not be found." + MESSAGE_REMOVED = "Annotations were removed from #{ROUTE_FILE}." + + unless const_defined?(:MAGIC_COMMENTS) + MAGIC_COMMENTS = [ + '# encoding: UTF-8', + '# coding: UTF-8', + '# -*- coding: UTF-8 -*-', + '#encoding: utf-8', + '# encoding: utf-8', + '# -*- encoding : utf-8 -*-', + "# encoding: utf-8\n# frozen_string_literal: true", + "# frozen_string_literal: true\n# encoding: utf-8", + '# frozen_string_literal: true', + '#frozen_string_literal: false', + '# -*- frozen_string_literal : true -*-' + ].freeze + end let :stubs do {} @@ -33,7 +37,7 @@ describe '.do_annotations' do context 'When "config/routes.rb" does not exist' do - before :each do + before do expect(File).to receive(:exist?).with(ROUTE_FILE).and_return(false).once end @@ -45,7 +49,7 @@ end context 'When "config/routes.rb" exists' do - before :each do + before do expect(File).to receive(:exist?).with(ROUTE_FILE).and_return(true).once expect(File).to receive(:read).with(ROUTE_FILE).and_return(route_file_content).once @@ -97,7 +101,7 @@ # ## Route Map # - # Prefix | Verb | URI Pattern | Controller#Action + # Prefix | Verb | URI Pattern | Controller#Action#{' '} # --------- | ---------- | --------------- | -------------------- # myaction1 | GET | /url1(.:format) | mycontroller1#action # myaction2 | POST | /url2(.:format) | mycontroller2#action @@ -189,7 +193,7 @@ # ## Route Map # - # Prefix | Verb | URI Pattern | Controller#Action + # Prefix | Verb | URI Pattern | Controller#Action#{' '} # --------- | ---------- | --------------- | -------------------- # myaction1 | GET | /url1(.:format) | mycontroller1#action # myaction2 | POST | /url2(.:format) | mycontroller2#action @@ -469,7 +473,7 @@ EOS end - it 'should skip annotations if file does already contain annotation' do + it 'skips annotations if file does already contain annotation' do expect(File).not_to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) expect(mock_file).not_to receive(:puts) expect(AnnotateRoutes).to receive(:puts).with(MESSAGE_UNCHANGED).once @@ -571,7 +575,7 @@ EOS end - before :each do + before do expect(File).to receive(:exist?).with(ROUTE_FILE).and_return(true).once expect(File).to receive(:read).with(ROUTE_FILE).and_return(route_file_content).once @@ -624,7 +628,7 @@ end describe '.remove_annotations' do - before :each do + before do expect(File).to receive(:exist?).with(ROUTE_FILE).and_return(true).once expect(File).to receive(:read).with(ROUTE_FILE).and_return(route_file_content).once expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file).once diff --git a/spec/lib/annotate/helpers_spec.rb b/spec/lib/annotate/helpers_spec.rb index b8de5df52..f15300ee3 100644 --- a/spec/lib/annotate/helpers_spec.rb +++ b/spec/lib/annotate/helpers_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' RSpec.describe Annotate::Helpers do @@ -5,7 +7,7 @@ subject { described_class.skip_on_migration? } before do - allow(ENV).to receive(:[]).and_return(nil) + allow(ENV).to receive(:fetch).and_return(nil) end it { is_expected.to be_falsy } @@ -15,7 +17,7 @@ let(:env_value) { '1' } before do - allow(ENV).to receive(:[]).with(key).and_return(env_value) + allow(ENV).to receive(:fetch).with(key, nil).and_return(env_value) end it { is_expected.to be_truthy } @@ -26,7 +28,7 @@ let(:env_value) { '1' } before do - allow(ENV).to receive(:[]).with(key).and_return(env_value) + allow(ENV).to receive(:fetch).with(key, nil).and_return(env_value) end it { is_expected.to be_truthy } @@ -37,7 +39,7 @@ subject { described_class.include_routes? } before do - allow(ENV).to receive(:[]).and_return(nil) + allow(ENV).to receive(:fetch).and_return(nil) end it { is_expected.to be_falsy } @@ -47,7 +49,7 @@ let(:env_value) { '1' } before do - allow(ENV).to receive(:[]).with(key).and_return(env_value) + allow(ENV).to receive(:fetch).with(key, nil).and_return(env_value) end it { is_expected.to be_truthy } @@ -58,7 +60,7 @@ subject { described_class.include_models? } before do - allow(ENV).to receive(:[]).and_return(nil) + allow(ENV).to receive(:fetch).and_return(nil) end it { is_expected.to be_falsy } @@ -68,7 +70,7 @@ let(:env_value) { '1' } before do - allow(ENV).to receive(:[]).with(key).and_return(env_value) + allow(ENV).to receive(:fetch).with(key, nil).and_return(env_value) end it { is_expected.to be_truthy } @@ -79,6 +81,7 @@ subject { described_class.true?(val) } let(:val) { nil } + it { is_expected.to be_falsy } context 'when val is blank' do @@ -94,7 +97,7 @@ let(:val) { truthy_value } it "returns truthy for '#{truthy_value}'" do - is_expected.to be_truthy + expect(subject).to be_truthy end end end @@ -102,13 +105,14 @@ describe '.fallback' do subject { described_class.fallback(*args) } + let(:args) { [arg_1, arg_2] } let(:arg_1) { '' } # is considered blank let(:arg_2) { 'yes' } it 'returns the first non-blank argument' do - is_expected.to eq(arg_2) + expect(subject).to eq(arg_2) end context 'when the first argument is non-blank' do @@ -133,7 +137,7 @@ it 'resets ENV value' do expect(ENV).to receive(:[]=).with(included_option.to_s, reset_value) - expect(ENV).to_not receive(:[]=).with(excluded_option.to_s, reset_value) + expect(ENV).not_to receive(:[]=).with(excluded_option.to_s, reset_value) subject end diff --git a/spec/lib/annotate/parser_spec.rb b/spec/lib/annotate/parser_spec.rb index 16084b02b..b55006fc5 100644 --- a/spec/lib/annotate/parser_spec.rb +++ b/spec/lib/annotate/parser_spec.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' module Annotate # rubocop:disable Metrics/ModuleLength describe Parser do - before(:example) do + before do ENV.clear end @@ -72,8 +74,8 @@ module Annotate # rubocop:disable Metrics/ModuleLength options = other_commands + position_command Parser.parse(options) - expect(ENV['position_in_class']).to eq('top') - expect(ENV['position']).to eq('bottom') + expect(ENV.fetch('position_in_class', nil)).to eq('top') + expect(ENV.fetch('position', nil)).to eq('bottom') end end end @@ -178,6 +180,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'wrapper' } let(:set_value) { 'STR' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option, set_value]) @@ -189,6 +192,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'wrapper_open' } let(:set_value) { 'STR' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option, set_value]) @@ -200,6 +204,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'wrapper_close' } let(:set_value) { 'STR' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option, set_value]) @@ -211,6 +216,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'routes' } let(:set_value) { 'true' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -222,6 +228,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'models' } let(:set_value) { 'true' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -233,6 +240,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'active_admin' } let(:set_value) { 'true' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -253,6 +261,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'include_version' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -264,6 +273,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'show_check_constraints' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -275,6 +285,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'show_foreign_keys' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -298,6 +309,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'show_indexes' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -309,6 +321,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'simple_indexes' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -320,6 +333,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--model-dir' } let(:env_key) { 'model_dir' } let(:set_value) { 'some_dir/' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option, set_value]) @@ -330,6 +344,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--root-dir' } let(:env_key) { 'root_dir' } let(:set_value) { 'some_dir/' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option, set_value]) @@ -340,6 +355,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--ignore-model-subdirects' } let(:env_key) { 'ignore_model_sub_dir' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -350,6 +366,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--sort' } let(:env_key) { 'sort' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -360,6 +377,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--classified-sort' } let(:env_key) { 'classified_sort' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -370,6 +388,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength describe option do let(:env_key) { 'require' } let(:set_value) { 'another_dir' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option, set_value]) @@ -377,6 +396,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength context "when ENV['require'] is already set" do let(:preset_require_value) { 'some_dir/' } + it "appends the path to ENV['require']" do env = { 'require' => preset_require_value } expect(ENV).to receive(:[]=).with(env_key, "#{preset_require_value},#{set_value}") @@ -419,7 +439,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength end context 'when a type is passed in' do - let(:exclusions) { "tests" } + let(:exclusions) { 'tests' } it "sets the exclusion ENV variable for 'tests' only" do expect(ENV).to receive(:[]=).with('exclude_tests', set_value) @@ -428,7 +448,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength end context 'when two types are passed in' do - let(:exclusions) { "tests,fixtures" } + let(:exclusions) { 'tests,fixtures' } it "sets the exclusion ENV variable for 'tests' and 'fixtures'" do allow(ENV).to receive(:[]=) @@ -460,6 +480,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--force' } let(:env_key) { 'force' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -470,6 +491,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--frozen' } let(:env_key) { 'frozen' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -480,6 +502,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--timestamp' } let(:env_key) { 'timestamp' } let(:set_value) { 'true' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -490,6 +513,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--trace' } let(:env_key) { 'trace' } let(:set_value) { 'yes' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -545,6 +569,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--ignore-unknown-models' } let(:env_key) { 'ignore_unknown_models' } let(:set_value) { 'true' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -555,6 +580,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--with-comment' } let(:env_key) { 'with_comment' } let(:set_value) { 'true' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) @@ -565,6 +591,7 @@ module Annotate # rubocop:disable Metrics/ModuleLength let(:option) { '--with-comment-column' } let(:env_key) { 'with_comment_column' } let(:set_value) { 'true' } + it 'sets the ENV variable' do expect(ENV).to receive(:[]=).with(env_key, set_value) Parser.parse([option]) diff --git a/spec/lib/annotate_spec.rb b/spec/lib/annotate_spec.rb index d2c2748df..26103072f 100644 --- a/spec/lib/annotate_spec.rb +++ b/spec/lib/annotate_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../spec_helper' describe Annotate do diff --git a/spec/lib/tasks/annotate_models_migrate_spec.rb b/spec/lib/tasks/annotate_models_migrate_spec.rb index 7172658a5..412bb5c76 100644 --- a/spec/lib/tasks/annotate_models_migrate_spec.rb +++ b/spec/lib/tasks/annotate_models_migrate_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' describe 'ActiveRecord migration rake task hooks' do @@ -5,7 +7,7 @@ Rake.application = Rake::Application.new # Stub migration tasks - %w(db:migrate db:migrate:up db:migrate:down db:migrate:reset db:rollback).each do |task| + %w[db:migrate db:migrate:up db:migrate:down db:migrate:reset db:rollback].each do |task| Rake::Task.define_task(task) end Rake::Task.define_task('db:migrate:redo') do @@ -20,42 +22,42 @@ end describe 'db:migrate' do - it 'should update annotations' do + it 'updates annotations' do expect(Annotate::Migration).to receive(:update_annotations) Rake.application.top_level end end describe 'db:migrate:up' do - it 'should update annotations' do + it 'updates annotations' do expect(Annotate::Migration).to receive(:update_annotations) Rake.application.top_level end end describe 'db:migrate:down' do - it 'should update annotations' do + it 'updates annotations' do expect(Annotate::Migration).to receive(:update_annotations) Rake.application.top_level end end describe 'db:migrate:reset' do - it 'should update annotations' do + it 'updates annotations' do expect(Annotate::Migration).to receive(:update_annotations) Rake.application.top_level end end describe 'db:rollback' do - it 'should update annotations' do + it 'updates annotations' do expect(Annotate::Migration).to receive(:update_annotations) Rake.application.top_level end end describe 'db:migrate:redo' do - it 'should update annotations after all migration tasks' do + it 'updates annotations after all migration tasks' do allow(Annotate::Migration).to receive(:update_annotations) # Confirm that update_annotations isn't called when the original redo task finishes diff --git a/spec/lib/tasks/annotate_models_spec.rb b/spec/lib/tasks/annotate_models_spec.rb index 03f82391f..2774f77c3 100644 --- a/spec/lib/tasks/annotate_models_spec.rb +++ b/spec/lib/tasks/annotate_models_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require_relative '../../spec_helper' -describe 'Annotate annotate_models rake task and Annotate.set_defaults' do # rubocop:disable RSpec/DescribeClass +describe 'Annotate annotate_models rake task and Annotate.set_defaults' do before do Rake.application = Rake::Application.new Rake::Task.define_task('environment') From 7ebaff244e8af771e1b777fd0855bb67c7299b7b Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 13:51:22 +0100 Subject: [PATCH 06/14] chore: update rubocop ruby version and todos to match modern ruby --- .rubocop.yml | 1 + .rubocop_todo.yml | 663 +++++++--------------------------------------- 2 files changed, 96 insertions(+), 568 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 3332cb79b..dd1fbb9e2 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,6 +6,7 @@ plugins: - rubocop-rspec AllCops: + TargetRubyVersion: 3.2.2 Exclude: - 'vendor/**/*' - 'spec/fixtures/**/*' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8d3c7701d..4faa9e578 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,180 +1,33 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2022-06-14 03:17:11 UTC using RuboCop version 1.12.1. +# on 2025-06-03 11:39:41 UTC using RuboCop version 1.75.8. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include. -# Include: **/*.gemspec -Gemspec/OrderedDependencies: - Exclude: - - 'annotate.gemspec' - -# Offense count: 1 -# Configuration parameters: Include. -# Include: **/*.gemspec -Gemspec/RequiredRubyVersion: - Exclude: - - 'annotate.gemspec' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyleAlignWith. -# SupportedStylesAlignWith: either, start_of_block, start_of_line -Layout/BlockAlignment: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 9 -# Cop supports --auto-correct. -Layout/EmptyLineAfterGuardClause: - Exclude: - - 'Rakefile' - - 'lib/annotate.rb' - - 'lib/annotate/annotate_models.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Layout/EmptyLineAfterMagicComment: - Exclude: - - 'annotate.gemspec' - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 3 -# Cop supports --auto-correct. +# This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment. Layout/ExtraSpacing: Exclude: - - 'Guardfile' - 'lib/annotate/annotate_models.rb' - - 'lib/tasks/annotate_routes.rake' - -# Offense count: 14 -# Cop supports --auto-correct. -# Configuration parameters: IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_brackets -Layout/FirstArrayElementIndentation: - EnforcedStyle: consistent - -# Offense count: 65 -# Cop supports --auto-correct. -# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. -# SupportedHashRocketStyles: key, separator, table -# SupportedColonStyles: key, separator, table -# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit -Layout/HashAlignment: - Exclude: - - 'lib/generators/annotate/templates/auto_annotate_models.rake' - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 5 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: aligned, indented -Layout/MultilineOperationIndentation: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: space, no_space -Layout/SpaceAroundEqualsInParameterDefault: - Exclude: - - 'lib/annotate/annotate_routes.rb' - -# Offense count: 4 -# Cop supports --auto-correct. -# Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator. -# SupportedStylesForExponentOperator: space, no_space -Layout/SpaceAroundOperators: - Exclude: - - 'lib/annotate/annotate_models.rb' - - 'lib/tasks/annotate_routes.rake' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. -# SupportedStyles: space, no_space -# SupportedStylesForEmptyBraces: space, no_space -Layout/SpaceBeforeBlockBraces: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Layout/SpaceBeforeComment: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 4 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. -# SupportedStyles: space, no_space -# SupportedStylesForEmptyBraces: space, no_space -Layout/SpaceInsideBlockBraces: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 4 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. -# SupportedStyles: space, no_space, compact -# SupportedStylesForEmptyBraces: space, no_space -Layout/SpaceInsideHashLiteralBraces: - Exclude: - - 'lib/tasks/annotate_models.rake' - -# Offense count: 4 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: space, no_space -Layout/SpaceInsideParens: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 4 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: space, no_space -Layout/SpaceInsideStringInterpolation: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: AllowInHeredoc. -Layout/TrailingWhitespace: - Exclude: - - 'spec/lib/annotate/annotate_routes_spec.rb' # Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowSafeAssignment. Lint/AssignmentInCondition: Exclude: - 'lib/annotate/annotate_models.rb' -# Offense count: 7 +# Offense count: 5 # Configuration parameters: AllowedMethods. # AllowedMethods: enums Lint/ConstantDefinitionInBlock: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/annotate_routes_spec.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: runtime_error, standard_error -Lint/InheritException: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 1 +# Offense count: 2 # Configuration parameters: MaximumRangeSize. Lint/MissingCopEnableDirective: Exclude: @@ -185,71 +38,52 @@ Lint/RescueException: Exclude: - 'Rakefile' -# Offense count: 1 -Lint/ShadowingOuterLocalVariable: - Exclude: - - 'Rakefile' - # Offense count: 1 # Configuration parameters: AllowComments, AllowNil. Lint/SuppressedException: Exclude: - 'bin/annotate' -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: strict, consistent -Lint/SymbolConversion: - Exclude: - - 'lib/annotate/annotate_models.rb' - - 'spec/lib/annotate/annotate_models_spec.rb' - # Offense count: 20 -# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: - Max: 155 + Max: 104 # Offense count: 7 -# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. -# IgnoredMethods: refine +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. +# AllowedMethods: refine Metrics/BlockLength: Max: 53 # Offense count: 1 -# Configuration parameters: CountBlocks. -Metrics/BlockNesting: - Max: 4 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 719 # Offense count: 16 -# Configuration parameters: IgnoredMethods. +# Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/CyclomaticComplexity: Max: 30 -# Offense count: 31 -# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. +# Offense count: 28 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: - Max: 40 + Max: 36 # Offense count: 15 -# Configuration parameters: IgnoredMethods. +# Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/PerceivedComplexity: Max: 33 -# Offense count: 1 -Naming/AccessorMethodName: - Exclude: - - 'lib/annotate.rb' - -# Offense count: 105 +# Offense count: 37 # Configuration parameters: ForbiddenDelimiters. -# ForbiddenDelimiters: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$)) +# ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$)) Naming/HeredocDelimiterNaming: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/annotate_routes_spec.rb' # Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyleForLeadingUnderscores. # SupportedStylesForLeadingUnderscores: disallowed, required, optional Naming/MemoizedInstanceVariableName: @@ -258,205 +92,110 @@ Naming/MemoizedInstanceVariableName: # Offense count: 1 # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. -# AllowedNames: at, by, db, id, in, io, ip, of, on, os, pp, to +# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to Naming/MethodParameterName: Exclude: - 'Rakefile' -# Offense count: 13 -# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers. +# Offense count: 4 +# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns. # SupportedStyles: snake_case, normalcase, non_integer -# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339 +# AllowedIdentifiers: TLS1_1, TLS1_2, capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64 Naming/VariableNumber: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/helpers_spec.rb' -# Offense count: 1 -RSpec/BeforeAfterAll: - Exclude: - - 'spec/spec_helper.rb' - - 'spec/rails_helper.rb' - - 'spec/support/**/*.rb' - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 46 -# Configuration parameters: Prefixes. +# Offense count: 38 +# Configuration parameters: Prefixes, AllowedPatterns. # Prefixes: when, with, without RSpec/ContextWording: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/annotate_routes_spec.rb' - 'spec/lib/annotate/parser_spec.rb' -# Offense count: 1 +# Offense count: 2 # Configuration parameters: IgnoredMetadata. RSpec/DescribeClass: Exclude: + - '**/spec/features/**/*' + - '**/spec/requests/**/*' + - '**/spec/routing/**/*' + - '**/spec/system/**/*' + - '**/spec/views/**/*' - 'spec/lib/tasks/annotate_models_migrate_spec.rb' + - 'spec/lib/tasks/annotate_models_spec.rb' -# Offense count: 149 -# Cop supports --auto-correct. -# Configuration parameters: SkipBlocks, EnforcedStyle. +# Offense count: 97 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: SkipBlocks, EnforcedStyle, OnlyStaticConstants. # SupportedStyles: described_class, explicit RSpec/DescribedClass: Exclude: - - 'spec/lib/annotate/annotate_models/file_patterns_spec.rb' - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/annotate_routes_spec.rb' - 'spec/lib/annotate/parser_spec.rb' - 'spec/lib/annotate_spec.rb' -# Offense count: 32 -# Cop supports --auto-correct. -RSpec/EmptyLineAfterFinalLet: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/annotate/helpers_spec.rb' - - 'spec/lib/annotate/parser_spec.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -RSpec/EmptyLineAfterSubject: - Exclude: - - 'spec/lib/annotate/helpers_spec.rb' - -# Offense count: 14 -# Configuration parameters: Max. +# Offense count: 3 +# Configuration parameters: CountAsOne. RSpec/ExampleLength: - Exclude: - - 'spec/lib/annotate/annotate_models/file_patterns_spec.rb' - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/annotate/parser_spec.rb' - - 'spec/lib/tasks/annotate_models_migrate_spec.rb' - -# Offense count: 22 -# Cop supports --auto-correct. -# Configuration parameters: CustomTransform, IgnoredWords. -RSpec/ExampleWording: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/annotate/annotate_routes_spec.rb' - - 'spec/lib/tasks/annotate_models_migrate_spec.rb' + Max: 6 -# Offense count: 9 +# Offense count: 10 RSpec/ExpectInHook: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/annotate_routes_spec.rb' -# Offense count: 10 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: implicit, each, example -RSpec/HookArgument: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/annotate/annotate_routes_spec.rb' - - 'spec/lib/annotate/parser_spec.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -RSpec/HooksBeforeExamples: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 78 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: single_line_only, single_statement_only, disallow -RSpec/ImplicitSubject: - Exclude: - - 'spec/lib/annotate/annotate_models/file_patterns_spec.rb' - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/annotate/helpers_spec.rb' - -# Offense count: 51 -# Configuration parameters: AssignmentOnly. -RSpec/InstanceVariable: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - # Offense count: 4 -# Cop supports --auto-correct. -RSpec/LeadingSubject: +# Configuration parameters: Max, AllowedIdentifiers, AllowedPatterns. +RSpec/IndexedLet: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' + - 'spec/lib/annotate/helpers_spec.rb' -# Offense count: 9 +# Offense count: 6 RSpec/LeakyConstantDeclaration: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/annotate_routes_spec.rb' -# Offense count: 108 +# Offense count: 109 # Configuration parameters: EnforcedStyle. # SupportedStyles: have_received, receive RSpec/MessageSpies: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/annotate_routes_spec.rb' - 'spec/lib/annotate/helpers_spec.rb' - 'spec/lib/annotate/parser_spec.rb' - 'spec/lib/tasks/annotate_models_migrate_spec.rb' -# Offense count: 36 +# Offense count: 29 RSpec/MultipleExpectations: Max: 4 -# Offense count: 66 -# Configuration parameters: AllowSubject. -RSpec/MultipleMemoizedHelpers: - Max: 9 - -# Offense count: 6 -# Configuration parameters: IgnoreSharedExamples. +# Offense count: 5 +# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. +# SupportedStyles: always, named_only RSpec/NamedSubject: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/helpers_spec.rb' - 'spec/lib/tasks/annotate_models_migrate_spec.rb' -# Offense count: 140 +# Offense count: 39 +# Configuration parameters: AllowedGroups. RSpec/NestedGroups: Max: 9 -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: not_to, to_not -RSpec/NotToNot: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/annotate/helpers_spec.rb' - # Offense count: 5 RSpec/RepeatedExampleGroupBody: Exclude: - 'spec/lib/tasks/annotate_models_migrate_spec.rb' -# Offense count: 2 -RSpec/RepeatedExampleGroupDescription: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: and_return, block -RSpec/ReturnFromStub: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 7 +# Offense count: 1 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - 'spec/lib/annotate/annotate_routes_spec.rb' # Offense count: 16 -# Cop supports --auto-correct. +# This cop supports safe autocorrection (--autocorrect). Rake/Desc: Exclude: - 'Rakefile' @@ -471,53 +210,17 @@ Rake/DuplicateTask: - 'lib/tasks/annotate_models.rake' - 'lib/tasks/annotate_routes.rake' -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: separated, grouped -Style/AccessorGrouping: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AllowOnConstant. -Style/CaseEquality: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/CaseLikeIf: - Exclude: - - 'lib/annotate/annotate_routes.rb' - # Offense count: 2 Style/ClassVars: Exclude: - 'lib/tasks/annotate_models_migrate.rake' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: Keywords. -# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW, NOTE -Style/CommentAnnotation: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/Dir: - Exclude: - - 'bin/annotate' - -# Offense count: 10 +# Offense count: 9 # Configuration parameters: AllowedConstants. Style/Documentation: Exclude: - 'spec/**/*' - 'test/**/*' - - 'lib/annotate.rb' - 'lib/annotate/active_record_patch.rb' - 'lib/annotate/annotate_models.rb' - 'lib/annotate/annotate_routes.rb' @@ -527,77 +230,32 @@ Style/Documentation: - 'lib/generators/annotate/install_generator.rb' - 'lib/tasks/annotate_models_migrate.rake' -# Offense count: 2 -# Cop supports --auto-correct. -Style/Encoding: - Exclude: - - 'annotate.gemspec' - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/ExpandPathArguments: - Exclude: - - 'annotate.gemspec' - -# Offense count: 9 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: format, sprintf, percent -Style/FormatString: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 12 -# Configuration parameters: MaxUnannotatedPlaceholdersAllowed, IgnoredMethods. +# Offense count: 13 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: MaxUnannotatedPlaceholdersAllowed, Mode, AllowedMethods, AllowedPatterns. # SupportedStyles: annotated, template, unannotated Style/FormatStringToken: EnforcedStyle: unannotated -# Offense count: 30 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: always, always_true, never -Style/FrozenStringLiteralComment: - Enabled: false - -# Offense count: 1 -# Configuration parameters: MinBodyLength. -Style/GuardClause: - Exclude: - - 'lib/tasks/annotate_models_migrate.rake' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AllowSplatArgument. -Style/HashConversion: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - # Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. -# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys -Style/HashSyntax: - Exclude: - - 'lib/tasks/annotate_routes.rake' - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 7 -# Cop supports --auto-correct. +# This cop supports safe autocorrection (--autocorrect). Style/IfUnlessModifier: Exclude: - - 'Rakefile' - - 'bin/annotate' - 'lib/annotate/annotate_models.rb' # Offense count: 1 -# Cop supports --auto-correct. +# This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: InverseMethods, InverseBlocks. Style/InverseMethods: Exclude: - 'Rakefile' +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/MapIntoArray: + Exclude: + - 'lib/annotate/annotate_routes/header_generator.rb' + # Offense count: 1 Style/MissingRespondToMissing: Exclude: @@ -614,30 +272,19 @@ Style/MultilineBlockChain: - 'Rakefile' - 'lib/annotate/annotate_models.rb' -# Offense count: 2 -# Cop supports --auto-correct. -Style/MultilineIfModifier: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/annotate/annotate_routes_spec.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/NegatedIfElseCondition: - Exclude: - - 'lib/annotate.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AllowedMethods. -# AllowedMethods: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with -Style/NestedParenthesizedCalls: +# Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: literals, strict +Style/MutableConstant: Exclude: - - 'bin/annotate' + - 'lib/annotate/annotate_models.rb' + - 'lib/annotate/annotate_routes/helpers.rb' + - 'lib/annotate/constants.rb' # Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, IgnoredMethods. +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. # SupportedStyles: predicate, comparison Style/NumericPredicate: Exclude: @@ -645,176 +292,56 @@ Style/NumericPredicate: - 'lib/annotate.rb' - 'lib/annotate/annotate_models.rb' -# Offense count: 13 -# Cop supports --auto-correct. -# Configuration parameters: PreferredDelimiters. -Style/PercentLiteralDelimiters: - Exclude: - - 'annotate.gemspec' - - 'lib/annotate/annotate_models.rb' - - 'lib/annotate/annotate_routes.rb' - - 'lib/tasks/annotate_models_migrate.rake' - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/tasks/annotate_models_migrate_spec.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, AllowedCompactTypes. -# SupportedStyles: compact, exploded -Style/RaiseArgs: - Exclude: - - 'lib/annotate/annotate_models.rb' - # Offense count: 2 -# Cop supports --auto-correct. +# This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: Methods. Style/RedundantArgument: Exclude: - 'lib/annotate/annotate_routes/header_generator.rb' -# Offense count: 3 -# Cop supports --auto-correct. -Style/RedundantBegin: - Exclude: - - 'lib/annotate/annotate_models.rb' - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/RedundantParentheses: - Exclude: - - 'lib/annotate/annotate_models.rb' - # Offense count: 2 -# Cop supports --auto-correct. -Style/RedundantPercentQ: - Exclude: - - 'annotate.gemspec' - -# Offense count: 3 -# Cop supports --auto-correct. -Style/RedundantRegexpCharacterClass: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -Style/RedundantRegexpEscape: - Exclude: - - 'lib/annotate/annotate_models.rb' - - 'lib/annotate/annotate_routes/header_generator.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AllowMultipleReturnValues. -Style/RedundantReturn: - Exclude: - - 'lib/annotate/annotate_routes/helpers.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/RedundantSelf: - Exclude: - - 'lib/tasks/annotate_models_migrate.rake' - -# Offense count: 12 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, AllowInnerSlashes. -# SupportedStyles: slashes, percent_r, mixed -Style/RegexpLiteral: - Exclude: - - 'Rakefile' - - 'lib/annotate/annotate_models.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/RescueModifier: +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/RedundantFormat: Exclude: - 'lib/annotate/annotate_models.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: implicit, explicit -Style/RescueStandardError: - Exclude: - - 'lib/annotate.rb' - # Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods. +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. # AllowedMethods: present?, blank?, presence, try, try! Style/SafeNavigation: Exclude: - 'lib/annotate/annotate_models.rb' -# Offense count: 3 -# Cop supports --auto-correct. -Style/SlicingWithRange: +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/SelectByRegexp: Exclude: - - 'lib/annotate/annotate_models.rb' - 'lib/annotate/annotate_routes/header_generator.rb' -# Offense count: 15 -# Cop supports --auto-correct. -Style/StderrPuts: - Exclude: - - 'Rakefile' - - 'lib/annotate.rb' - - 'lib/annotate/annotate_models.rb' - -# Offense count: 13 -# Cop supports --auto-correct. +# Offense count: 14 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: Mode. Style/StringConcatenation: Exclude: - 'lib/annotate/annotate_models.rb' -# Offense count: 57 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. -# SupportedStyles: single_quotes, double_quotes -Style/StringLiterals: - Exclude: - - 'annotate.gemspec' - - 'lib/annotate/annotate_models.rb' - - 'lib/annotate/parser.rb' - - 'lib/tasks/annotate_models_migrate.rake' - - 'lib/tasks/annotate_routes.rake' - - 'spec/lib/annotate/annotate_models_spec.rb' - - 'spec/lib/annotate/parser_spec.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: single_quotes, double_quotes -Style/StringLiteralsInInterpolation: - Exclude: - - 'lib/annotate/annotate_models.rb' - -# Offense count: 8 -# Cop supports --auto-correct. +# Offense count: 6 +# This cop supports safe autocorrection (--autocorrect). # Configuration parameters: MinSize. # SupportedStyles: percent, brackets Style/SymbolArray: EnforcedStyle: brackets # Offense count: 1 -# Cop supports --auto-correct. -Style/SymbolLiteral: +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/ZeroLengthPredicate: Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyleForMultiline. -# SupportedStylesForMultiline: comma, consistent_comma, no_comma -Style/TrailingCommaInArrayLiteral: - Exclude: - - 'spec/lib/annotate/annotate_models_spec.rb' + - 'lib/annotate/annotate_routes/header_generator.rb' -# Offense count: 52 -# Cop supports --auto-correct. -# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# Offense count: 29 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings. # URISchemes: http, https Layout/LineLength: - Max: 264 + Max: 496 From b13db9139688640c945615badf103d6c2d261c42 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 13:52:04 +0100 Subject: [PATCH 07/14] run all tests on guard start --- Guardfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Guardfile b/Guardfile index 9c49ea77d..e38e1165f 100644 --- a/Guardfile +++ b/Guardfile @@ -8,7 +8,7 @@ # installed the spring binstubs per the docs) # * zeus: 'zeus rspec' (requires the server to be started separetly) # * 'just' rspec: 'rspec' -guard :rspec, cmd: 'bundle exec rspec' do +guard :rspec, cmd: 'bundle exec rspec', all_on_start: true do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } watch('spec/spec_helper.rb') { 'spec' } From 2ca2f7568c24453519bbf1cbe49e60ef6c601f1f Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 17:00:20 +0100 Subject: [PATCH 08/14] chore: update robocop todos with non-obvious spec violations --- .rubocop_todo.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 4faa9e578..d133b9273 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -345,3 +345,23 @@ Style/ZeroLengthPredicate: # URISchemes: http, https Layout/LineLength: Max: 496 + +RSpec/ExampleLength: + Exclude: + - 'spec/**/*' + +RSpec/MultipleMemoizedHelpers: + Exclude: + - 'spec/**/*' + +RSpec/InstanceVariable: + Exclude: + - 'spec/**/*' + +RSpec/NamedSubject: + Exclude: + - 'spec/**/*' + +RSpec/NestedGroups: + Exclude: + - 'spec/**/*' \ No newline at end of file From 8111e0f947d9209d2c56a8bb27e086c9eb17ea34 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 17:02:53 +0100 Subject: [PATCH 09/14] chore: bump ruby version --- annotate.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/annotate.gemspec b/annotate.gemspec index b59bcebb5..15f2653d2 100644 --- a/annotate.gemspec +++ b/annotate.gemspec @@ -8,7 +8,7 @@ Gem::Specification.new do |s| s.name = 'annotate' s.version = Annotate.version - s.required_ruby_version = '>= 2.4.0' + s.required_ruby_version = '>= 3.2.2' s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version= s.authors = ['Alex Chaffee', 'Cuong Tran', 'Marcos Piccinini', 'Turadg Aleahmad', 'Jon Frisby'] s.description = 'Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema.' From 30cb78d3a6c8bea752efcb3323acf45cd86ba0aa Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 17:09:31 +0100 Subject: [PATCH 10/14] fix: fix obvious cop violations --- lib/annotate.rb | 5 +- lib/annotate/annotate_models.rb | 8 +- .../annotate_routes/header_generator.rb | 4 +- lib/annotate/parser.rb | 2 +- .../annotate_models/file_patterns_spec.rb | 92 +- spec/lib/annotate/annotate_models_spec.rb | 963 +++++++++--------- spec/lib/annotate/annotate_routes_spec.rb | 8 +- 7 files changed, 539 insertions(+), 543 deletions(-) diff --git a/lib/annotate.rb b/lib/annotate.rb index b722477c7..9fc9160c4 100644 --- a/lib/annotate.rb +++ b/lib/annotate.rb @@ -17,7 +17,8 @@ require 'active_support/core_ext/blank' end -module Annotate +# Defines the Annotate module +module Annotate # rubocop:disable Metrics/ModuleLength ## # Set default values that can be overridden via environment variables. # @@ -95,7 +96,7 @@ def self.eager_load(options) if Rails.version.split('.').first.to_i < 3 Rails.configuration.eager_load_paths.each do |load_path| matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/ - Dir.glob("#{load_path}/**/*.rb").sort.each do |file| + Dir.glob("#{load_path}/**/*.rb").each do |file| require_dependency file.sub(matcher, '\1') end end diff --git a/lib/annotate/annotate_models.rb b/lib/annotate/annotate_models.rb index 7079632cf..12ec5d93c 100644 --- a/lib/annotate/annotate_models.rb +++ b/lib/annotate/annotate_models.rb @@ -156,7 +156,7 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho with_comments_column = with_comments_column?(klass, options) # Precalculate Values - cols_meta = cols.map do |col| + cols_meta = cols.to_h do |col| col_comment = with_comments || with_comments_column ? col.comment&.gsub("\n", '\\n') : nil col_type = get_col_type(col) attrs = get_attributes(col, col_type, klass, options) @@ -172,7 +172,7 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho col_name: col_name, simple_formatted_attrs: simple_formatted_attrs, col_comment: col_comment }] - end.to_h + end # Output annotation bare_max_attrs_length = cols_meta.map { |_, m| m[:simple_formatted_attrs].length }.max @@ -215,7 +215,7 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho end def get_schema_header_text(klass, options = {}) - info = String.new("#\n") # Create a new mutable string + info = String.new("#\n") # Create a new mutable string if options[:format_markdown] info << "# Table name: `#{klass.table_name}`\n" info << "#\n" @@ -658,7 +658,7 @@ def get_model_class(file) if File.file?(file_path) && Kernel.require(file_path) retry elsif model_path =~ %r{/} - model_path = model_path.split('/')[1..-1].join('/').to_s + model_path = model_path.split('/')[1..].join('/').to_s retry else raise diff --git a/lib/annotate/annotate_routes/header_generator.rb b/lib/annotate/annotate_routes/header_generator.rb index 36852cc19..459c5e8c2 100644 --- a/lib/annotate/annotate_routes/header_generator.rb +++ b/lib/annotate/annotate_routes/header_generator.rb @@ -59,7 +59,7 @@ def generate out << comment return out if contents_without_magic_comments.size.zero? - maxs = [HEADER_ROW.map(&:size)] + contents_without_magic_comments[1..-1].map { |line| line.split.map(&:size) } + maxs = [HEADER_ROW.map(&:size)] + contents_without_magic_comments[1..].map { |line| line.split.map(&:size) } if markdown? max = maxs.map(&:max).compact.max @@ -70,7 +70,7 @@ def generate out << comment(content(contents_without_magic_comments[0], maxs)) end - out += contents_without_magic_comments[1..-1].map do |line| + out += contents_without_magic_comments[1..].map do |line| comment(content(markdown? ? line.split(' ') : line, maxs)) end out << comment(options[:wrapper_close]) if options[:wrapper_close] diff --git a/lib/annotate/parser.rb b/lib/annotate/parser.rb index f84896c16..d12bd33a5 100644 --- a/lib/annotate/parser.rb +++ b/lib/annotate/parser.rb @@ -4,7 +4,7 @@ module Annotate # Class for handling command line arguments - class Parser # rubocop:disable Metrics/ClassLength + class Parser def self.parse(args, env = {}) new(args, env).parse end diff --git a/spec/lib/annotate/annotate_models/file_patterns_spec.rb b/spec/lib/annotate/annotate_models/file_patterns_spec.rb index 41ae5fc97..f6f460da7 100644 --- a/spec/lib/annotate/annotate_models/file_patterns_spec.rb +++ b/spec/lib/annotate/annotate_models/file_patterns_spec.rb @@ -5,7 +5,7 @@ describe AnnotateModels::FilePatterns do describe '.by_pattern' do - subject { AnnotateModels::FilePatterns.generate(root_directory, pattern_type, options) } + let(:file_patterns) { described_class.generate(root_directory, pattern_type, options) } let(:root_directory) { '/root' } let(:options) { {} } @@ -14,11 +14,11 @@ let(:pattern_type) { 'test' } it 'returns patterns of test files' do - is_expected.to eq([ - '/root/test/unit/%MODEL_NAME%_test.rb', - '/root/test/models/%MODEL_NAME%_test.rb', - '/root/spec/models/%MODEL_NAME%_spec.rb' - ]) + expect(file_patterns).to eq([ + '/root/test/unit/%MODEL_NAME%_test.rb', + '/root/test/models/%MODEL_NAME%_test.rb', + '/root/spec/models/%MODEL_NAME%_spec.rb' + ]) end end @@ -26,12 +26,12 @@ let(:pattern_type) { 'fixture' } it 'returns patterns of fixture files' do - is_expected.to eq([ - '/root/test/fixtures/%TABLE_NAME%.yml', - '/root/spec/fixtures/%TABLE_NAME%.yml', - '/root/test/fixtures/%PLURALIZED_MODEL_NAME%.yml', - '/root/spec/fixtures/%PLURALIZED_MODEL_NAME%.yml' - ]) + expect(file_patterns).to eq([ + '/root/test/fixtures/%TABLE_NAME%.yml', + '/root/spec/fixtures/%TABLE_NAME%.yml', + '/root/test/fixtures/%PLURALIZED_MODEL_NAME%.yml', + '/root/spec/fixtures/%PLURALIZED_MODEL_NAME%.yml' + ]) end end @@ -39,12 +39,12 @@ let(:pattern_type) { 'scaffold' } it 'returns patterns of scaffold files' do - is_expected.to eq([ - '/root/test/controllers/%PLURALIZED_MODEL_NAME%_controller_test.rb', - '/root/spec/controllers/%PLURALIZED_MODEL_NAME%_controller_spec.rb', - '/root/spec/requests/%PLURALIZED_MODEL_NAME%_spec.rb', - '/root/spec/routing/%PLURALIZED_MODEL_NAME%_routing_spec.rb' - ]) + expect(file_patterns).to eq([ + '/root/test/controllers/%PLURALIZED_MODEL_NAME%_controller_test.rb', + '/root/spec/controllers/%PLURALIZED_MODEL_NAME%_controller_spec.rb', + '/root/spec/requests/%PLURALIZED_MODEL_NAME%_spec.rb', + '/root/spec/routing/%PLURALIZED_MODEL_NAME%_routing_spec.rb' + ]) end end @@ -52,20 +52,20 @@ let(:pattern_type) { 'factory' } it 'returns patterns of factory files' do - is_expected.to eq([ - '/root/test/exemplars/%MODEL_NAME%_exemplar.rb', - '/root/spec/exemplars/%MODEL_NAME%_exemplar.rb', - '/root/test/blueprints/%MODEL_NAME%_blueprint.rb', - '/root/spec/blueprints/%MODEL_NAME%_blueprint.rb', - '/root/test/factories/%MODEL_NAME%_factory.rb', - '/root/spec/factories/%MODEL_NAME%_factory.rb', - '/root/test/factories/%TABLE_NAME%.rb', - '/root/spec/factories/%TABLE_NAME%.rb', - '/root/test/factories/%PLURALIZED_MODEL_NAME%.rb', - '/root/spec/factories/%PLURALIZED_MODEL_NAME%.rb', - '/root/test/fabricators/%MODEL_NAME%_fabricator.rb', - '/root/spec/fabricators/%MODEL_NAME%_fabricator.rb' - ]) + expect(file_patterns).to eq([ + '/root/test/exemplars/%MODEL_NAME%_exemplar.rb', + '/root/spec/exemplars/%MODEL_NAME%_exemplar.rb', + '/root/test/blueprints/%MODEL_NAME%_blueprint.rb', + '/root/spec/blueprints/%MODEL_NAME%_blueprint.rb', + '/root/test/factories/%MODEL_NAME%_factory.rb', + '/root/spec/factories/%MODEL_NAME%_factory.rb', + '/root/test/factories/%TABLE_NAME%.rb', + '/root/spec/factories/%TABLE_NAME%.rb', + '/root/test/factories/%PLURALIZED_MODEL_NAME%.rb', + '/root/spec/factories/%PLURALIZED_MODEL_NAME%.rb', + '/root/test/fabricators/%MODEL_NAME%_fabricator.rb', + '/root/spec/fabricators/%MODEL_NAME%_fabricator.rb' + ]) end end @@ -73,11 +73,11 @@ let(:pattern_type) { 'serializer' } it 'returns patterns of serializer files' do - is_expected.to eq([ - '/root/app/serializers/%MODEL_NAME%_serializer.rb', - '/root/test/serializers/%MODEL_NAME%_serializer_test.rb', - '/root/spec/serializers/%MODEL_NAME%_serializer_spec.rb' - ]) + expect(file_patterns).to eq([ + '/root/app/serializers/%MODEL_NAME%_serializer.rb', + '/root/test/serializers/%MODEL_NAME%_serializer_test.rb', + '/root/spec/serializers/%MODEL_NAME%_serializer_spec.rb' + ]) end end @@ -95,7 +95,7 @@ let(:options) { { additional_file_patterns: } } it 'returns additional_file_patterns in the argument "options"' do - is_expected.to eq(additional_file_patterns) + expect(file_patterns).to eq(additional_file_patterns) end end @@ -103,7 +103,7 @@ let(:options) { {} } it 'returns an empty array' do - is_expected.to eq([]) + expect(file_patterns).to eq([]) end end end @@ -112,9 +112,9 @@ let(:pattern_type) { 'controller' } it 'returns patterns of controller files' do - is_expected.to eq([ - '/root/app/controllers/%PLURALIZED_MODEL_NAME%_controller.rb' - ]) + expect(file_patterns).to eq([ + '/root/app/controllers/%PLURALIZED_MODEL_NAME%_controller.rb' + ]) end end @@ -122,7 +122,7 @@ let(:pattern_type) { 'admin' } it 'returns both singular and pluralized model names' do - is_expected.to eq(['/root/app/admin/%MODEL_NAME%.rb', '/root/app/admin/%PLURALIZED_MODEL_NAME%.rb']) + expect(file_patterns).to eq(['/root/app/admin/%MODEL_NAME%.rb', '/root/app/admin/%PLURALIZED_MODEL_NAME%.rb']) end end @@ -130,9 +130,9 @@ let(:pattern_type) { 'helper' } it 'returns patterns of helper files' do - is_expected.to eq([ - '/root/app/helpers/%PLURALIZED_MODEL_NAME%_helper.rb' - ]) + expect(file_patterns).to eq([ + '/root/app/helpers/%PLURALIZED_MODEL_NAME%_helper.rb' + ]) end end end diff --git a/spec/lib/annotate/annotate_models_spec.rb b/spec/lib/annotate/annotate_models_spec.rb index cfd7b15e3..e7a902017 100644 --- a/spec/lib/annotate/annotate_models_spec.rb +++ b/spec/lib/annotate/annotate_models_spec.rb @@ -6,10 +6,11 @@ require 'active_support/core_ext/string' require 'files' require 'tmpdir' +require 'active_record' describe AnnotateModels do - unless const_defined?(:MAGIC_COMMENTS) - MAGIC_COMMENTS = [ + before do + stub_const('MAGIC_COMMENTS', [ '# encoding: UTF-8', '# coding: UTF-8', '# -*- coding: UTF-8 -*-', @@ -21,43 +22,43 @@ '# frozen_string_literal: true', '#frozen_string_literal: false', '# -*- frozen_string_literal : true -*-' - ].freeze + ].freeze) end def mock_index(name, params = {}) - double('IndexKeyDefinition', - name:, - columns: params[:columns] || [], - unique: params[:unique] || false, - orders: params[:orders] || {}, - where: params[:where], - using: params[:using]) + instance_double(ActiveRecord::ConnectionAdapters::IndexDefinition, + name:, + columns: params[:columns] || [], + unique: params[:unique] || false, + orders: params[:orders] || {}, + where: params[:where], + using: params[:using]) end def mock_foreign_key(name, from_column, to_table, to_column = 'id', constraints = {}) - double('ForeignKeyDefinition', - name:, - column: from_column, - to_table:, - primary_key: to_column, - on_delete: constraints[:on_delete], - on_update: constraints[:on_update]) + instance_double(ActiveRecord::ConnectionAdapters::ForeignKeyDefinition, + name:, + column: from_column, + to_table:, + primary_key: to_column, + on_delete: constraints[:on_delete], + on_update: constraints[:on_update]) end def mock_check_constraint(name, expression) - double('CheckConstraintDefinition', - name:, - expression:) + instance_double(ActiveRecord::ConnectionAdapters::CheckConstraintDefinition, + name:, + expression:) end def mock_connection(indexes = [], foreign_keys = [], check_constraints = []) - double('Conn', - indexes:, - foreign_keys:, - check_constraints:, - supports_foreign_keys?: true, - supports_check_constraints?: true, - table_exists?: true) + instance_double(ActiveRecord::ConnectionAdapters::AbstractAdapter, + indexes:, + foreign_keys:, + check_constraints:, + supports_foreign_keys?: true, + supports_check_constraints?: true, + table_exists?: true) end # rubocop:disable Metrics/ParameterLists @@ -69,11 +70,11 @@ def mock_class(table_name, primary_key, columns, indexes = [], foreign_keys = [] primary_key:, column_names: columns.map { |col| col.name.to_s }, columns:, - column_defaults: Hash[columns.map { |col| [col.name, col.default] }], + column_defaults: columns.map.to_h { |col| [col.name, col.default] }, table_name_prefix: '' } - double('An ActiveRecord class', options) + double('An ActiveRecord class', options) # rubocop:disable RSpec/VerifiedDoubles end # rubocop:enable Metrics/ParameterLists @@ -90,69 +91,77 @@ def mock_column(name, type, options = {}) stubs[:name] = name stubs[:type] = type - double('Column', stubs) + double('Column', stubs) # rubocop:disable RSpec/VerifiedDoubles end describe '.quote' do - subject do - AnnotateModels.quote(value) + let(:quote) do + described_class.quote(value) end context 'when the argument is nil' do let(:value) { nil } + it 'returns string "NULL"' do - is_expected.to eq('NULL') + expect(quote).to eq('NULL') end end context 'when the argument is true' do let(:value) { true } + it 'returns string "TRUE"' do - is_expected.to eq('TRUE') + expect(quote).to eq('TRUE') end end context 'when the argument is false' do let(:value) { false } + it 'returns string "FALSE"' do - is_expected.to eq('FALSE') + expect(quote).to eq('FALSE') end end context 'when the argument is an integer' do let(:value) { 25 } + it 'returns the integer as a string' do - is_expected.to eq('25') + expect(quote).to eq('25') end end context 'when the argument is a float number' do context 'when the argument is like 25.6' do let(:value) { 25.6 } + it 'returns the float number as a string' do - is_expected.to eq('25.6') + expect(quote).to eq('25.6') end end context 'when the argument is like 1e-20' do let(:value) { 1e-20 } + it 'returns the float number as a string' do - is_expected.to eq('1.0e-20') + expect(quote).to eq('1.0e-20') end end end context 'when the argument is a BigDecimal number' do let(:value) { BigDecimal('1.2') } + it 'returns the float number as a string' do - is_expected.to eq('1.2') + expect(quote).to eq('1.2') end end context 'when the argument is an array' do let(:value) { [BigDecimal('1.2')] } + it 'returns an array of which elements are converted to string' do - is_expected.to eq(['1.2']) + expect(quote).to eq(['1.2']) end end end @@ -166,40 +175,40 @@ def mock_column(name, type, options = {}) } end - before :each do - AnnotateModels.parse_options(options) + before do + described_class.parse_options(options) end - after :each do - AnnotateModels.parse_options({ skip_subdirectory_model_load: false }) + after do + described_class.parse_options({ skip_subdirectory_model_load: false }) end describe '@root_dir' do - subject do - AnnotateModels.instance_variable_get(:@root_dir) + let(:root_dir) do + described_class.instance_variable_get(:@root_dir) end it 'sets @root_dir' do - is_expected.to eq('/root') + expect(root_dir).to eq('/root') end end - describe '@model_dir' do - subject do - AnnotateModels.instance_variable_get(:@model_dir) + describe 'model_dir' do + let(:model_dir) do + described_class.instance_variable_get(:@model_dir) end - it 'separates option "model_dir" with commas and sets @model_dir as an array of string' do - is_expected.to eq(['app/models', 'app/one', 'app/two', 'app/three']) + it 'separates option "model_dir" with commas and sets model_dir as an array of string' do + expect(model_dir).to eq(['app/models', 'app/one', 'app/two', 'app/three']) end end describe '@skip_subdirectory_model_load' do - subject do - AnnotateModels.instance_variable_get(:@skip_subdirectory_model_load) + let(:skip_subdirectory_model_load) do + described_class.instance_variable_get(:@skip_subdirectory_model_load) end - context 'option is set to true' do + context 'when option is set to true' do let(:options) do { root_dir: '/root', @@ -209,11 +218,11 @@ def mock_column(name, type, options = {}) end it 'sets skip_subdirectory_model_load to true' do - is_expected.to eq(true) + expect(skip_subdirectory_model_load).to be(true) end end - context 'option is set to false' do + context 'when option is set to false' do let(:options) do { root_dir: '/root', @@ -223,7 +232,7 @@ def mock_column(name, type, options = {}) end it 'sets skip_subdirectory_model_load to false' do - is_expected.to eq(false) + expect(skip_subdirectory_model_load).to be(false) end end end @@ -231,7 +240,11 @@ def mock_column(name, type, options = {}) describe '.get_schema_info' do subject do - AnnotateModels.get_schema_info(klass, header, **options) + described_class.get_schema_info(klass, header, **options) + end + + let!(:get_schema_info) do + subject end let :klass do @@ -274,7 +287,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -282,11 +295,11 @@ def mock_column(name, type, options = {}) # id :integer not null # name :string(50) not null # - EOS + COMMENT end it 'returns schema info' do - is_expected.to eq(expected_result) + expect(get_schema_info).to eq(expected_result) end end @@ -294,12 +307,12 @@ def mock_column(name, type, options = {}) let :columns do [ mock_column(:id, :integer), - mock_column(:name, :enum, limit: %i[enum1 enum2]) + mock_column(:name, :enum, limit: [:enum1, :enum2]) ] end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -307,11 +320,11 @@ def mock_column(name, type, options = {}) # id :integer not null # name :enum not null, (enum1, enum2) # - EOS + COMMENT end it 'returns schema info' do - is_expected.to eq(expected_result) + expect(get_schema_info).to eq(expected_result) end end @@ -328,7 +341,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -340,11 +353,11 @@ def mock_column(name, type, options = {}) # float :float unsigned, not null # decimal :decimal(10, 2) unsigned, not null # - EOS + COMMENT end it 'returns schema info' do - is_expected.to eq(expected_result) + expect(get_schema_info).to eq(expected_result) end end end @@ -365,7 +378,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -374,11 +387,11 @@ def mock_column(name, type, options = {}) # name :string(50) not null # notes :text(55) not null # - EOS + COMMENT end it 'returns schema info' do - is_expected.to eq(expected_result) + expect(get_schema_info).to eq(expected_result) end end @@ -392,7 +405,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -401,24 +414,24 @@ def mock_column(name, type, options = {}) # size :integer default(20), not null # flag :boolean default(FALSE), not null # - EOS + COMMENT end it 'returns schema info with default values' do - is_expected.to eq(expected_result) + expect(get_schema_info).to eq(expected_result) end end context 'with Globalize gem' do let :translation_klass do - double('Folder::Post::Translation', - to_s: 'Folder::Post::Translation', - columns: [ - mock_column(:id, :integer, limit: 8), - mock_column(:post_id, :integer, limit: 8), - mock_column(:locale, :string, limit: 50), - mock_column(:title, :string, limit: 50) - ]) + instance_double('Folder::Post::Translation', # rubocop:disable RSpec/VerifiedDoubleReference + to_s: 'Folder::Post::Translation', + columns: [ + mock_column(:id, :integer, limit: 8), + mock_column(:post_id, :integer, limit: 8), + mock_column(:locale, :string, limit: 50), + mock_column(:title, :string, limit: 50) + ]) end let :klass do @@ -435,7 +448,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: posts @@ -444,18 +457,18 @@ def mock_column(name, type, options = {}) # author_name :string(50) not null # title :string(50) not null # - EOS + COMMENT end it 'returns schema info' do - is_expected.to eq expected_result + expect(get_schema_info).to eq expected_result end end end context 'when the primary key is an array (using composite_primary_keys)' do let :primary_key do - %i[a_id b_id] + [:a_id, :b_id] end let :columns do @@ -467,7 +480,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -476,11 +489,11 @@ def mock_column(name, type, options = {}) # b_id :integer not null, primary key # name :string(50) not null # - EOS + COMMENT end it 'returns schema info' do - is_expected.to eq(expected_result) + expect(get_schema_info).to eq(expected_result) end end end @@ -521,7 +534,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -534,11 +547,11 @@ def mock_column(name, type, options = {}) # index_rails_02e851e3b7 (id) # index_rails_02e851e3b8 (foreign_thing_id) # - EOS + COMMENT end it 'returns schema info with index information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -562,7 +575,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -577,11 +590,11 @@ def mock_column(name, type, options = {}) # index_rails_02e851e3b7 (id) # index_rails_02e851e3b8 (firstname,surname ASC,value DESC) # - EOS + COMMENT end it 'returns schema info with index information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -605,7 +618,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -620,11 +633,11 @@ def mock_column(name, type, options = {}) # index_rails_02e851e3b7 (id) # index_rails_02e851e3b8 (firstname,surname) WHERE value IS NOT NULL # - EOS + COMMENT end it 'returns schema info with index information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -648,7 +661,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -663,11 +676,11 @@ def mock_column(name, type, options = {}) # index_rails_02e851e3b7 (id) # index_rails_02e851e3b8 (firstname,surname) USING hash # - EOS + COMMENT end it 'returns schema info with index information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -684,7 +697,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -692,11 +705,11 @@ def mock_column(name, type, options = {}) # id :integer not null, primary key # foreign_thing_id :integer not null # - EOS + COMMENT end it 'returns schema info without index information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end context 'when the unprefixed table name does not exist' do @@ -710,7 +723,7 @@ def mock_column(name, type, options = {}) end it 'returns schema info without index information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result expect(klass).to have_received(:table_name_prefix).at_least(:once) expect(klass.connection).to have_received(:table_exists?).with('users') end @@ -741,7 +754,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -749,11 +762,11 @@ def mock_column(name, type, options = {}) # id :integer not null, primary key # foreign_thing_id :integer not null # - EOS + COMMENT end it 'returns schema info with index information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -773,7 +786,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -781,11 +794,11 @@ def mock_column(name, type, options = {}) # id :integer not null, primary key, indexed # name :string not null # - EOS + COMMENT end it 'returns schema info with index information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -820,7 +833,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -835,11 +848,11 @@ def mock_column(name, type, options = {}) # multiline_test (CASE WHEN (age >= 18) THEN (age <= 21) ELSE true END) # must_be_adult (age >= 18) # - EOS + COMMENT end it 'returns schema info with check constraint information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -849,7 +862,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -857,11 +870,11 @@ def mock_column(name, type, options = {}) # id :integer not null, primary key # age :integer not null # - EOS + COMMENT end it 'returns schema info without check constraint information' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -890,7 +903,7 @@ def mock_column(name, type, options = {}) context 'when foreign_keys does not have option' do let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -904,11 +917,11 @@ def mock_column(name, type, options = {}) # fk_rails_... (foreign_thing_id => foreign_things.id) # fk_rails_... (third_thing_id => third_things.id) # - EOS + COMMENT end it 'returns schema info with foreign keys' do - is_expected.to eq(expected_result) + expect(subject).to eq(expected_result) end end @@ -925,7 +938,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -937,11 +950,11 @@ def mock_column(name, type, options = {}) # # fk_rails_... (foreign_thing_id => foreign_things.id) ON DELETE => on_delete_value ON UPDATE => on_update_value # - EOS + COMMENT end it 'returns schema info with foreign keys' do - is_expected.to eq(expected_result) + expect(subject).to eq(expected_result) end end end @@ -952,7 +965,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -966,11 +979,11 @@ def mock_column(name, type, options = {}) # fk_rails_a70234b26c (third_thing_id => third_things.id) # fk_rails_cf2568e89e (foreign_thing_id => foreign_things.id) # - EOS + COMMENT end it 'returns schema info with foreign keys' do - is_expected.to eq(expected_result) + expect(subject).to eq(expected_result) end end end @@ -991,7 +1004,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1001,11 +1014,11 @@ def mock_column(name, type, options = {}) # name :string(50) not null # notes :text(55) not null # - EOS + COMMENT end it 'works with option "hide_limit_column_types"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1015,7 +1028,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1025,11 +1038,11 @@ def mock_column(name, type, options = {}) # name :string(50) not null # notes :text(55) not null # - EOS + COMMENT end it 'works with option "hide_limit_column_types"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1039,7 +1052,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1049,11 +1062,11 @@ def mock_column(name, type, options = {}) # name :string not null # notes :text not null # - EOS + COMMENT end it 'works with option "hide_limit_column_types"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1073,7 +1086,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1082,11 +1095,11 @@ def mock_column(name, type, options = {}) # settings :jsonb not null # parameters :hstore not null # - EOS + COMMENT end it 'works with option "hide_default_column_types"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1096,7 +1109,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1105,11 +1118,11 @@ def mock_column(name, type, options = {}) # settings :jsonb default({}), not null # parameters :hstore default({}), not null # - EOS + COMMENT end it 'works with option "hide_default_column_types"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1119,7 +1132,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1128,11 +1141,11 @@ def mock_column(name, type, options = {}) # settings :jsonb default({}), not null # parameters :hstore default({}), not null # - EOS + COMMENT end it 'works with option "hide_limit_column_types"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1152,7 +1165,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1161,11 +1174,11 @@ def mock_column(name, type, options = {}) # name :string(50) not null # notes :text(55) not null # - EOS + COMMENT end it 'works with option "classified_sort"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1188,7 +1201,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1199,11 +1212,11 @@ def mock_column(name, type, options = {}) # notes(Notes) :text(55) not null # no_comment :text(20) not null # - EOS + COMMENT end it 'works with option "with_comment"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1223,7 +1236,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1238,11 +1251,11 @@ def mock_column(name, type, options = {}) # no_comment :text(20) not null # location :geometry_collect not null # - EOS + COMMENT end it 'works with option "with_comment"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1256,7 +1269,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1265,11 +1278,11 @@ def mock_column(name, type, options = {}) # notes(Notes.\\nMay include things like notes.):text(55) not null # no_comment :text(20) not null # - EOS + COMMENT end it 'works with option "with_comment"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1291,7 +1304,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1302,11 +1315,11 @@ def mock_column(name, type, options = {}) # location :geography not null, point, 0 # non_srid :geography not null, point # - EOS + COMMENT end it 'works with option "with_comment"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1328,7 +1341,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1339,11 +1352,11 @@ def mock_column(name, type, options = {}) # notes :text(55) not null Notes # no_comment :text(20) not null # - EOS + COMMENT end it 'works with option "with_comment_column"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1363,7 +1376,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1378,11 +1391,11 @@ def mock_column(name, type, options = {}) # no_comment :text(20) not null # location :geometry_collect not null # - EOS + COMMENT end it 'works with option "with_comment_column"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1396,7 +1409,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1405,11 +1418,11 @@ def mock_column(name, type, options = {}) # notes :text(55) not null Notes.\\nMay include things like notes. # no_comment :text(20) not null # - EOS + COMMENT end it 'works with option "with_comment_column"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1431,7 +1444,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # Schema Info # # Table name: users @@ -1442,11 +1455,11 @@ def mock_column(name, type, options = {}) # location :geography not null, point, 0 # non_srid :geography not null, point # - EOS + COMMENT end it 'works with option "with_comment_column"' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1457,7 +1470,7 @@ def mock_column(name, type, options = {}) context 'when header is "== Schema Information"' do let :header do - AnnotateModels::PREFIX + described_class::PREFIX end context 'when the primary key is specified' do @@ -1479,7 +1492,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: users @@ -1489,11 +1502,11 @@ def mock_column(name, type, options = {}) #-- # == Schema Information End #++ - EOS + COMMENT end it 'returns schema info in RDoc format' do - is_expected.to eq(expected_result) + expect(subject).to eq(expected_result) end end @@ -1503,7 +1516,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: users @@ -1513,11 +1526,11 @@ def mock_column(name, type, options = {}) # @!attribute name # @return [String] # - EOS + COMMENT end it 'returns schema info in YARD format' do - is_expected.to eq(expected_result) + expect(subject).to eq(expected_result) end end @@ -1528,7 +1541,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1540,11 +1553,11 @@ def mock_column(name, type, options = {}) # **`id`** | `integer` | `not null, primary key` # **`name`** | `string(50)` | `not null` # - EOS + COMMENT end it 'returns schema info in Markdown format' do - is_expected.to eq(expected_result) + expect(subject).to eq(expected_result) end end @@ -1562,7 +1575,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1581,11 +1594,11 @@ def mock_column(name, type, options = {}) # * `index_rails_02e851e3b8`: # * **`foreign_thing_id`** # - EOS + COMMENT end it 'returns schema info with index information in Markdown format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1600,7 +1613,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1619,11 +1632,11 @@ def mock_column(name, type, options = {}) # * `index_rails_02e851e3b8` (_unique_): # * **`foreign_thing_id`** # - EOS + COMMENT end it 'returns schema info with index information in Markdown format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1638,7 +1651,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1657,11 +1670,11 @@ def mock_column(name, type, options = {}) # * `index_rails_02e851e3b8`: # * **`foreign_thing_id DESC`** # - EOS + COMMENT end it 'returns schema info with index information in Markdown format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1677,7 +1690,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1696,11 +1709,11 @@ def mock_column(name, type, options = {}) # * `index_rails_02e851e3b8` (_unique_ _where_ name IS NOT NULL): # * **`foreign_thing_id`** # - EOS + COMMENT end it 'returns schema info with index information in Markdown format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1715,7 +1728,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1734,11 +1747,11 @@ def mock_column(name, type, options = {}) # * `index_rails_02e851e3b8` (_using_ hash): # * **`foreign_thing_id`** # - EOS + COMMENT end it 'returns schema info with index information in Markdown format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1763,7 +1776,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1781,11 +1794,11 @@ def mock_column(name, type, options = {}) # * `missing_expression` # * `multiline_test`: `(CASE WHEN (age >= 18) THEN (age <= 21) ELSE true END)` # - EOS + COMMENT end it 'returns schema info with check constraint information in Markdown format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1815,7 +1828,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1832,11 +1845,11 @@ def mock_column(name, type, options = {}) # * `fk_rails_...` (_ON DELETE => on_delete_value ON UPDATE => on_update_value_): # * **`foreign_thing_id => foreign_things.id`** # - EOS + COMMENT end it 'returns schema info with foreign_keys in Markdown format' do - is_expected.to eq(expected_result) + expect(subject).to eq(expected_result) end end end @@ -1856,7 +1869,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: users @@ -1866,11 +1879,11 @@ def mock_column(name, type, options = {}) #-- # == Schema Information End #++ - EOS + COMMENT end it 'returns schema info in RDoc format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1889,7 +1902,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1901,11 +1914,11 @@ def mock_column(name, type, options = {}) # **`id(ID)`** | `integer` | `not null, primary key` # **`name(Name)`** | `string(50)` | `not null` # - EOS + COMMENT end it 'returns schema info in Markdown format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end @@ -1918,7 +1931,7 @@ def mock_column(name, type, options = {}) end let :expected_result do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: `users` @@ -1930,11 +1943,11 @@ def mock_column(name, type, options = {}) # **`id(ID)`** | `integer` | `not null, primary key` # **`name(NAME)`** | `string(50)` | `not null` # - EOS + COMMENT end it 'returns schema info in Markdown format' do - is_expected.to eq expected_result + expect(subject).to eq expected_result end end end @@ -1945,17 +1958,17 @@ def mock_column(name, type, options = {}) end describe '.set_defaults' do - subject do + let(:set_defaults) do Annotate::Helpers.true?(ENV.fetch('show_complete_foreign_keys', nil)) end - after :each do + after do ENV.delete('show_complete_foreign_keys') end context 'when default value of "show_complete_foreign_keys" is not set' do it 'returns false' do - is_expected.to be(false) + expect(set_defaults).to be(false) end end @@ -1969,13 +1982,13 @@ def mock_column(name, type, options = {}) end it 'returns true' do - is_expected.to be(true) + expect(set_defaults).to be(true) end end end describe '.get_patterns' do - subject { AnnotateModels.get_patterns(options, pattern_type) } + let(:get_patterns) { described_class.get_patterns(options, pattern_type) } context 'when pattern_type is "additional_file_patterns"' do let(:pattern_type) { 'additional_file_patterns' } @@ -1991,7 +2004,7 @@ def mock_column(name, type, options = {}) let(:options) { { additional_file_patterns: } } it 'returns additional_file_patterns in the argument "options"' do - is_expected.to eq(additional_file_patterns) + expect(get_patterns).to eq(additional_file_patterns) end end @@ -1999,14 +2012,14 @@ def mock_column(name, type, options = {}) let(:options) { {} } it 'returns an empty array' do - is_expected.to eq([]) + expect(get_patterns).to eq([]) end end end end describe '.get_model_files' do - subject { described_class.get_model_files(options) } + let(:get_model_files) { described_class.get_model_files(options) } before do ARGV.clear @@ -2035,7 +2048,7 @@ def mock_column(name, type, options = {}) let(:options) { {} } it 'returns all model files under `model_dir` directory' do - is_expected.to contain_exactly( + expect(get_model_files).to contain_exactly( [model_dir, 'foo.rb'], [model_dir, File.join('bar', 'baz.rb')], [model_dir, File.join('bar', 'qux', 'quux.rb')] @@ -2047,7 +2060,7 @@ def mock_column(name, type, options = {}) let(:options) { { ignore_model_sub_dir: true } } it 'returns model files just below `model_dir` directory' do - is_expected.to contain_exactly([model_dir, 'foo.rb']) + expect(get_model_files).to contain_exactly([model_dir, 'foo.rb']) end end end @@ -2072,7 +2085,7 @@ def mock_column(name, type, options = {}) end it 'returns specified files' do - is_expected.to contain_exactly( + expect(get_model_files).to contain_exactly( [model_dir, 'foo.rb'], [additional_model_dir, 'corge/grault.rb'] ) @@ -2081,7 +2094,7 @@ def mock_column(name, type, options = {}) context 'when a model file outside `model_dir` directory is specified' do it 'exits with the status code' do - subject + get_model_files raise rescue SystemExit => e expect(e.status).to eq(1) @@ -2093,7 +2106,7 @@ def mock_column(name, type, options = {}) let(:options) { { is_rake: true } } it 'returns all model files under `model_dir` directory' do - is_expected.to contain_exactly( + expect(get_model_files).to contain_exactly( [model_dir, 'foo.rb'], [model_dir, File.join('bar', 'baz.rb')], [model_dir, File.join('bar', 'qux', 'quux.rb')] @@ -2108,7 +2121,7 @@ def mock_column(name, type, options = {}) let(:options) { {} } it 'exits with the status code' do - subject + get_model_files raise rescue SystemExit => e expect(e.status).to eq(1) @@ -2117,19 +2130,23 @@ def mock_column(name, type, options = {}) end describe '.get_model_class' do - before :each do - @model_dir = Dir.mktmpdir('annotate_models') - AnnotateModels.model_dir = @model_dir + let(:model_dir) { Dir.mktmpdir('annotate_models') } + let :klass do + described_class.get_model_class(File.join(described_class.model_dir[0], filename)) + end + + before do + described_class.model_dir = model_dir create(filename, file_content) end - after :each do - FileUtils.remove_dir(@model_dir, true) + after do + FileUtils.remove_dir(model_dir, true) end # TODO: use 'files' gem instead def create(filename, file_content) - File.join(AnnotateModels.model_dir[0], filename).tap do |path| + File.join(described_class.model_dir[0], filename).tap do |path| FileUtils.mkdir_p(File.dirname(path)) File.open(path, 'wb') do |f| f.puts(file_content) @@ -2137,23 +2154,19 @@ def create(filename, file_content) end end - let :klass do - AnnotateModels.get_model_class(File.join(AnnotateModels.model_dir[0], filename)) - end - context 'when class Foo is defined in "foo.rb"' do let :filename do 'foo.rb' end let :file_content do - <<~EOS + <<~COMMENT class Foo < ActiveRecord::Base end - EOS + COMMENT end - it 'works' do + it 'is named correctly' do expect(klass.name).to eq('Foo') end end @@ -2165,13 +2178,13 @@ class Foo < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class FooWithCAPITALS < ActiveRecord::Base end - EOS + COMMENT end - it 'works' do + it 'is named correctly' do expect(klass.name).to eq('FooWithCAPITALS') end end @@ -2184,15 +2197,15 @@ class FooWithCAPITALS < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT module Bar class FooInsideBar < ActiveRecord::Base end end - EOS + COMMENT end - it 'works' do + it 'is named correctly' do expect(klass.name).to eq('Bar::FooInsideBar') end end @@ -2205,15 +2218,15 @@ class FooInsideBar < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT module BAR class FooInsideCapitalsBAR < ActiveRecord::Base end end - EOS + COMMENT end - it 'works' do + it 'is named correctly' do expect(klass.name).to eq('BAR::FooInsideCapitalsBAR') end end @@ -2226,11 +2239,11 @@ class FooInsideCapitalsBAR < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class FooWithMacro < ActiveRecord::Base acts_as_awesome :yah end - EOS + COMMENT end it 'works and does not care about known macros' do @@ -2245,14 +2258,14 @@ class FooWithMacro < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class FooWithCAPITALS < ActiveRecord::Base acts_as_awesome :yah end - EOS + COMMENT end - it 'works' do + it 'is named correctly' do expect(klass.name).to eq('FooWithCAPITALS') end end @@ -2266,11 +2279,11 @@ class FooWithCAPITALS < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class FooWithKnownMacro < ActiveRecord::Base has_many :yah end - EOS + COMMENT end it 'works and does not care about known macros' do @@ -2286,12 +2299,12 @@ class FooWithKnownMacro < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT # encoding: utf-8 class FooWithUtf8 < ActiveRecord::Base UTF8STRINGS = %w[résumé façon âge] end - EOS + COMMENT end it 'works without complaining of invalid multibyte chars' do @@ -2307,13 +2320,13 @@ class FooWithUtf8 < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class NonNamespacedFooInsideBar < ActiveRecord::Base end - EOS + COMMENT end - it 'works' do + it 'is named correctly' do expect(klass.name).to eq('NonNamespacedFooInsideBar') end end @@ -2325,13 +2338,13 @@ class NonNamespacedFooInsideBar < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class NonNamespacedFooWithCapitalsInsideBar < ActiveRecord::Base end - EOS + COMMENT end - it 'works' do + it 'is named correctly' do expect(klass.name).to eq('NonNamespacedFooWithCapitalsInsideBar') end end @@ -2345,21 +2358,22 @@ class NonNamespacedFooWithCapitalsInsideBar < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class LoadedClass < ActiveRecord::Base CONSTANT = 1 end - EOS + COMMENT end - before :each do - path = File.expand_path(filename, AnnotateModels.model_dir[0]) + before do + path = File.expand_path(filename, described_class.model_dir[0]) Kernel.load(path) - expect(Kernel).not_to receive(:require) + allow(Kernel).to receive(:require) end it 'does not require model file twice' do expect(klass.name).to eq('LoadedClass') + expect(Kernel).not_to have_received(:require) end end @@ -2367,12 +2381,12 @@ class LoadedClass < ActiveRecord::Base dir = Array.new(8) { (0..9).to_a.sample(random: Random.new) }.join context "when class SubdirLoadedClass is defined in \"#{dir}/subdir_loaded_class.rb\"" do - before :each do - $LOAD_PATH.unshift(File.join(AnnotateModels.model_dir[0], dir)) + before do + $LOAD_PATH.unshift(File.join(described_class.model_dir[0], dir)) - path = File.expand_path(filename, AnnotateModels.model_dir[0]) + path = File.expand_path(filename, described_class.model_dir[0]) Kernel.load(path) - expect(Kernel).not_to receive(:require) + allow(Kernel).to receive(:require) end let :filename do @@ -2380,144 +2394,147 @@ class LoadedClass < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class SubdirLoadedClass < ActiveRecord::Base CONSTANT = 1 end - EOS + COMMENT end it 'does not require model file twice' do expect(klass.name).to eq('SubdirLoadedClass') + expect(Kernel).not_to have_received(:require) end end end end context 'when two class exist' do - before :each do - create(filename_2, file_content_2) + before do + create(filename2, file_content2) end - context 'the base names are duplicated' do + context 'when the base names are duplicated' do let :filename do 'foo.rb' end let :file_content do - <<-EOS + <<-COMMENT class Foo < ActiveRecord::Base end - EOS + COMMENT end - let :filename_2 do + let :filename2 do 'bar/foo.rb' end - let :file_content_2 do - <<-EOS + let :file_content2 do + <<-COMMENT module Bar class Foo < ActiveRecord::Base end end - EOS + COMMENT end - let :klass_2 do - AnnotateModels.get_model_class(File.join(AnnotateModels.model_dir[0], filename_2)) + let :klass2 do + described_class.get_model_class(File.join(described_class.model_dir[0], filename2)) end it 'finds valid model' do expect(klass.name).to eq('Foo') - expect(klass_2.name).to eq('Bar::Foo') + expect(klass2.name).to eq('Bar::Foo') end end - context 'the class name and base name clash' do + context 'when the class name and base name clash' do let :filename do 'foo.rb' end let :file_content do - <<-EOS + <<-COMMENT class Foo < ActiveRecord::Base end - EOS + COMMENT end - let :filename_2 do + let :filename2 do 'bar/foo.rb' end - let :file_content_2 do - <<-EOS + let :file_content2 do + <<-COMMENT module Bar class Foo < ActiveRecord::Base end end - EOS + COMMENT end - let :klass_2 do - AnnotateModels.get_model_class(File.join(AnnotateModels.model_dir[0], filename_2)) + let :klass2 do + described_class.get_model_class(File.join(described_class.model_dir[0], filename2)) end it 'finds valid model' do expect(klass.name).to eq('Foo') - expect(klass_2.name).to eq('Bar::Foo') + expect(klass2.name).to eq('Bar::Foo') end it 'attempts to load the model path without expanding if skip_subdirectory_model_load is false' do - allow(AnnotateModels).to receive(:skip_subdirectory_model_load).and_return(false) - full_path = File.join(AnnotateModels.model_dir[0], filename_2) + allow(described_class).to receive(:skip_subdirectory_model_load).and_return(false) + full_path = File.join(described_class.model_dir[0], filename2) Kernel.load(full_path) - expect(File).to_not receive(:expand_path).with(full_path) - AnnotateModels.get_model_class(full_path) + allow(File).to receive(:expand_path).with(full_path) + described_class.get_model_class(full_path) + expect(File).not_to have_received(:expand_path).with(full_path) end it 'does not attempt to load the model path without expanding if skip_subdirectory_model_load is true' do - $LOAD_PATH.unshift(AnnotateModels.model_dir[0]) - allow(AnnotateModels).to receive(:skip_subdirectory_model_load).and_return(true) - full_path = File.join(AnnotateModels.model_dir[0], filename_2) + $LOAD_PATH.unshift(described_class.model_dir[0]) + allow(described_class).to receive(:skip_subdirectory_model_load).and_return(true) + full_path = File.join(described_class.model_dir[0], filename2) Kernel.load(full_path) - expect(File).to receive(:expand_path).with(full_path).and_call_original - AnnotateModels.get_model_class(full_path) + allow(File).to receive(:expand_path).with(full_path).and_call_original + described_class.get_model_class(full_path) + expect(File).to have_received(:expand_path).with(full_path) end end - context 'one of the classes is nested in another class' do + context 'when one of the classes is nested in another class' do let :filename do 'voucher.rb' end let :file_content do - <<-EOS + <<-COMMENT class Voucher < ActiveRecord::Base end - EOS + COMMENT end - let :filename_2 do + let :filename2 do 'voucher/foo.rb' end - let :file_content_2 do - <<~EOS + let :file_content2 do + <<~COMMENT class Voucher class Foo < ActiveRecord::Base end end - EOS + COMMENT end - let :klass_2 do - AnnotateModels.get_model_class(File.join(AnnotateModels.model_dir[0], filename_2)) + let :klass2 do + described_class.get_model_class(File.join(described_class.model_dir[0], filename2)) end it 'finds valid model' do expect(klass.name).to eq('Voucher') - expect(klass_2.name).to eq('Voucher::Foo') + expect(klass2.name).to eq('Voucher::Foo') end end end @@ -2525,11 +2542,7 @@ class Foo < ActiveRecord::Base describe '.remove_annotation_of_file' do subject do - AnnotateModels.remove_annotation_of_file(path) - end - - after :each do - FileUtils.remove_dir(tmpdir, true) + described_class.remove_annotation_of_file(path) end let :tmpdir do @@ -2550,10 +2563,14 @@ class Foo < ActiveRecord::Base end let :expected_result do - <<~EOS + <<~COMMENT class Foo < ActiveRecord::Base end - EOS + COMMENT + end + + after do + FileUtils.remove_dir(tmpdir, true) end context 'when annotation is before main content' do @@ -2562,7 +2579,7 @@ class Foo < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: foo @@ -2574,7 +2591,7 @@ class Foo < ActiveRecord::Base class Foo < ActiveRecord::Base end - EOS + COMMENT end it 'removes annotation' do @@ -2588,7 +2605,7 @@ class Foo < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT # == Schema Information # # Table name: foo\r\n# @@ -2599,7 +2616,7 @@ class Foo < ActiveRecord::Base \r\n class Foo < ActiveRecord::Base end - EOS + COMMENT end it 'removes annotation' do @@ -2608,44 +2625,18 @@ class Foo < ActiveRecord::Base end context 'when annotation is before main content and with opening wrapper' do - let :filename do - 'opening_wrapper.rb' - end - - let :file_content do - <<~EOS - # wrapper - # == Schema Information - # - # Table name: foo - # - # id :integer not null, primary key - # created_at :datetime - # updated_at :datetime - # - - class Foo < ActiveRecord::Base - end - EOS - end - subject do - AnnotateModels.remove_annotation_of_file(path, wrapper_open: 'wrapper') - end - - it 'removes annotation' do - expect(file_content_after_removal).to eq expected_result + described_class.remove_annotation_of_file(path, wrapper_open: 'wrapper') end - end - context 'when annotation is before main content and with opening wrapper' do let :filename do 'opening_wrapper.rb' end let :file_content do - <<~EOS - # wrapper\r\n# == Schema Information + <<~COMMENT + # wrapper + # == Schema Information # # Table name: foo # @@ -2656,11 +2647,7 @@ class Foo < ActiveRecord::Base class Foo < ActiveRecord::Base end - EOS - end - - subject do - AnnotateModels.remove_annotation_of_file(path, wrapper_open: 'wrapper') + COMMENT end it 'removes annotation' do @@ -2674,7 +2661,7 @@ class Foo < ActiveRecord::Base end let :file_content do - <<~EOS + <<~COMMENT class Foo < ActiveRecord::Base end @@ -2687,7 +2674,7 @@ class Foo < ActiveRecord::Base # updated_at :datetime # - EOS + COMMENT end it 'removes annotation' do @@ -2696,12 +2683,16 @@ class Foo < ActiveRecord::Base end context 'when annotation is after main content and with closing wrapper' do + subject do + described_class.remove_annotation_of_file(path, wrapper_close: 'wrapper') + end + let :filename do 'closing_wrapper.rb' end let :file_content do - <<~EOS + <<~CLASSBASE class Foo < ActiveRecord::Base end @@ -2715,11 +2706,7 @@ class Foo < ActiveRecord::Base # # wrapper - EOS - end - - subject do - AnnotateModels.remove_annotation_of_file(path, wrapper_close: 'wrapper') + CLASSBASE end it 'removes annotation' do @@ -2733,7 +2720,7 @@ class Foo < ActiveRecord::Base end let :file_content do - <<~EOS + <<~CLASSBASE # -*- SkipSchemaAnnotations # == Schema Information # @@ -2746,7 +2733,7 @@ class Foo < ActiveRecord::Base class Foo < ActiveRecord::Base end - EOS + CLASSBASE end let :expected_result do @@ -2760,11 +2747,11 @@ class Foo < ActiveRecord::Base end describe '.resolve_filename' do - subject do - AnnotateModels.resolve_filename(filename_template, model_name, table_name) + let(:resolve_filename) do + described_class.resolve_filename(filename_template, model_name, table_name) end - context 'When model_name is "example_model" and table_name is "example_models"' do + context 'when model_name is "example_model" and table_name is "example_models"' do let(:model_name) { 'example_model' } let(:table_name) { 'example_models' } @@ -2772,7 +2759,7 @@ class Foo < ActiveRecord::Base let(:filename_template) { 'test/unit/%MODEL_NAME%_test.rb' } it 'returns the test path for a model' do - is_expected.to eq 'test/unit/example_model_test.rb' + expect(resolve_filename).to eq 'test/unit/example_model_test.rb' end end @@ -2780,7 +2767,7 @@ class Foo < ActiveRecord::Base let(:filename_template) { '/foo/bar/%MODEL_NAME%/testing.rb' } it 'returns the additional glob' do - is_expected.to eq '/foo/bar/example_model/testing.rb' + expect(resolve_filename).to eq '/foo/bar/example_model/testing.rb' end end @@ -2788,7 +2775,7 @@ class Foo < ActiveRecord::Base let(:filename_template) { '/foo/bar/%PLURALIZED_MODEL_NAME%/testing.rb' } it 'returns the additional glob' do - is_expected.to eq '/foo/bar/example_models/testing.rb' + expect(resolve_filename).to eq '/foo/bar/example_models/testing.rb' end end @@ -2796,12 +2783,12 @@ class Foo < ActiveRecord::Base let(:filename_template) { 'test/fixtures/%TABLE_NAME%.yml' } it 'returns the fixture path for a model' do - is_expected.to eq 'test/fixtures/example_models.yml' + expect(resolve_filename).to eq 'test/fixtures/example_models.yml' end end end - context 'When model_name is "parent/child" and table_name is "parent_children"' do + context 'when model_name is "parent/child" and table_name is "parent_children"' do let(:model_name) { 'parent/child' } let(:table_name) { 'parent_children' } @@ -2809,36 +2796,48 @@ class Foo < ActiveRecord::Base let(:filename_template) { 'test/fixtures/%PLURALIZED_MODEL_NAME%.yml' } it 'returns the fixture path for a nested model' do - is_expected.to eq 'test/fixtures/parent/children.yml' + expect(resolve_filename).to eq 'test/fixtures/parent/children.yml' end end end end describe 'annotating a file' do - before :each do - @model_dir = Dir.mktmpdir('annotate_models') - (@model_file_name, @file_content) = write_model 'user.rb', <<~EOS + let(:model_dir) { Dir.mktmpdir('annotate_models') } + let(:klass) do + mock_class(:users, + :id, + [ + mock_column(:id, :integer), + mock_column(:name, :string, limit: 50) + ]) + end + + let!(:model_data) do + write_model 'user.rb', <<~USERBASE class User < ActiveRecord::Base end - EOS + USERBASE + end + + let(:model_file_name) { model_data[0] } + let(:file_content) { model_data[1] } - @klass = mock_class(:users, - :id, - [ - mock_column(:id, :integer), - mock_column(:name, :string, limit: 50) - ]) - @schema_info = AnnotateModels.get_schema_info(@klass, '== Schema Info') + let!(:schema_info) do + described_class.get_schema_info(klass, '== Schema Info') + end + + before do + @schema_info = schema_info Annotate::Helpers.reset_options(Annotate::Constants::ALL_ANNOTATE_OPTIONS) end - after :each do - FileUtils.remove_dir(@model_dir, true) + after do + FileUtils.remove_dir(model_dir, true) end def write_model(file_name, file_content) - fname = File.join(@model_dir, file_name) + fname = File.join(model_dir, file_name) FileUtils.mkdir_p(File.dirname(fname)) File.binwrite(fname, file_content) @@ -2848,7 +2847,7 @@ def write_model(file_name, file_content) def annotate_one_file(options = {}) Annotate.set_defaults(options) options = Annotate.setup_options(options) - AnnotateModels.annotate_one_file(@model_file_name, @schema_info, :position_in_class, options) + described_class.annotate_one_file(model_file_name, @schema_info, :position_in_class, options) ensure # Wipe settings so the next call will pick up new values... Annotate.instance_variable_set('@has_set_defaults', false) @@ -2858,29 +2857,29 @@ def annotate_one_file(options = {}) end ['before', :before, 'top', :top].each do |position| - it "should put annotation before class if :position == #{position}" do + it "puts annotation before class if :position == #{position}" do annotate_one_file(position:) - expect(File.read(@model_file_name)) - .to eq("#{@schema_info}#{@file_content}") + expect(File.read(model_file_name)) + .to eq("#{@schema_info}#{file_content}") end end ['after', :after, 'bottom', :bottom].each do |position| - it "should put annotation after class if position: #{position}" do + it "puts annotation after class if position: #{position}" do annotate_one_file(position:) - expect(File.read(@model_file_name)) - .to eq("#{@file_content}\n#{@schema_info}") + expect(File.read(model_file_name)) + .to eq("#{file_content}\n#{@schema_info}") end end - it 'should wrap annotation if wrapper is specified' do + it 'wraps annotation if wrapper is specified' do annotate_one_file wrapper_open: 'START', wrapper_close: 'END' - expect(File.read(@model_file_name)) - .to eq("# START\n#{@schema_info}# END\n#{@file_content}") + expect(File.read(model_file_name)) + .to eq("# START\n#{@schema_info}# END\n#{file_content}") end describe 'with existing annotation' do - context 'of a foreign key' do + context 'with a foreign key' do before do klass = mock_class(:users, :id, @@ -2896,11 +2895,11 @@ def annotate_one_file(options = {}) 'id', on_delete: :cascade) ]) - @schema_info = AnnotateModels.get_schema_info(klass, '== Schema Info', show_foreign_keys: true) + @schema_info = described_class.get_schema_info(klass, '== Schema Info', show_foreign_keys: true) annotate_one_file end - it 'should update foreign key constraint' do + it 'updates foreign key constraint' do klass = mock_class(:users, :id, [ @@ -2915,9 +2914,9 @@ def annotate_one_file(options = {}) 'id', on_delete: :restrict) ]) - @schema_info = AnnotateModels.get_schema_info(klass, '== Schema Info', show_foreign_keys: true) + @schema_info = described_class.get_schema_info(klass, '== Schema Info', show_foreign_keys: true) annotate_one_file - expect(File.read(@model_file_name)).to eq("#{@schema_info}#{@file_content}") + expect(File.read(model_file_name)).to eq("#{@schema_info}#{file_content}") end end end @@ -2925,62 +2924,62 @@ def annotate_one_file(options = {}) describe 'with existing annotation => :before' do before do annotate_one_file position: :before - another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), - '== Schema Info') + another_schema_info = described_class.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), + '== Schema Info') @schema_info = another_schema_info end - it 'should retain current position' do + it 'retains current position' do annotate_one_file - expect(File.read(@model_file_name)).to eq("#{@schema_info}#{@file_content}") + expect(File.read(model_file_name)).to eq("#{@schema_info}#{file_content}") end - it 'should retain current position even when :position is changed to :after' do + it 'retains current position even when :position is changed to :after' do annotate_one_file position: :after - expect(File.read(@model_file_name)).to eq("#{@schema_info}#{@file_content}") + expect(File.read(model_file_name)).to eq("#{@schema_info}#{file_content}") end - it 'should change position to :after when force: true' do + it 'changes position to :after when force: true' do annotate_one_file position: :after, force: true - expect(File.read(@model_file_name)).to eq("#{@file_content}\n#{@schema_info}") + expect(File.read(model_file_name)).to eq("#{file_content}\n#{@schema_info}") end end describe 'with existing annotation => :after' do before do annotate_one_file position: :after - another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), - '== Schema Info') + another_schema_info = described_class.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), + '== Schema Info') @schema_info = another_schema_info end - it 'should retain current position' do + it 'retains current position' do annotate_one_file - expect(File.read(@model_file_name)).to eq("#{@file_content}\n#{@schema_info}") + expect(File.read(model_file_name)).to eq("#{file_content}\n#{@schema_info}") end - it 'should retain current position even when :position is changed to :before' do + it 'retains current position even when :position is changed to :before' do annotate_one_file position: :before - expect(File.read(@model_file_name)).to eq("#{@file_content}\n#{@schema_info}") + expect(File.read(model_file_name)).to eq("#{file_content}\n#{@schema_info}") end - it 'should change position to :before when force: true' do + it 'changes position to :before when force: true' do annotate_one_file position: :before, force: true - expect(File.read(@model_file_name)).to eq("#{@schema_info}#{@file_content}") + expect(File.read(model_file_name)).to eq("#{@schema_info}#{file_content}") end end - it 'should skip columns with option[:ignore_columns] set' do - output = AnnotateModels.get_schema_info(@klass, '== Schema Info', - ignore_columns: '(id|updated_at|created_at)') + it 'skips columns with option[:ignore_columns] set' do + output = described_class.get_schema_info(klass, '== Schema Info', + ignore_columns: '(id|updated_at|created_at)') expect(output.match(/id/)).to be_nil end it 'works with namespaced models (i.e. models inside modules/subdirectories)' do - (model_file_name, file_content) = write_model 'foo/user.rb', <<~EOS + (model_file_name, file_content) = write_model 'foo/user.rb', <<~FOOUSER class Foo::User < ActiveRecord::Base end - EOS + FOOUSER klass = mock_class(:foo_users, :id, @@ -2988,23 +2987,23 @@ class Foo::User < ActiveRecord::Base mock_column(:id, :integer), mock_column(:name, :string, limit: 50) ]) - schema_info = AnnotateModels.get_schema_info(klass, '== Schema Info') - AnnotateModels.annotate_one_file(model_file_name, schema_info, position: :before) + schema_info = described_class.get_schema_info(klass, '== Schema Info') + described_class.annotate_one_file(model_file_name, schema_info, position: :before) expect(File.read(model_file_name)).to eq("#{schema_info}#{file_content}") end - it 'should not touch magic comments' do + it 'does not touch magic comments' do MAGIC_COMMENTS.each do |magic_comment| - write_model 'user.rb', <<~EOS + write_model 'user.rb', <<~COMMENT #{magic_comment} class User < ActiveRecord::Base end - EOS + COMMENT annotate_one_file position: :before lines = magic_comment.split("\n") - File.open @model_file_name do |file| + File.open model_file_name do |file| lines.count.times do |index| expect(file.readline).to eq "#{lines[index]}\n" end @@ -3018,7 +3017,7 @@ class User < ActiveRecord::Base model_file_name, = write_model 'user.rb', "#{magic_comment}\n#{content}" annotate_one_file position: :before - schema_info = AnnotateModels.get_schema_info(@klass, '== Schema Info') + schema_info = described_class.get_schema_info(klass, '== Schema Info') expect(File.read(model_file_name)).to eq("#{magic_comment}\n\n#{schema_info}#{content}") end @@ -3027,7 +3026,7 @@ class User < ActiveRecord::Base it 'only keeps a single empty line around the annotation (position :before)' do content = "class User < ActiveRecord::Base\nend\n" MAGIC_COMMENTS.each do |magic_comment| - schema_info = AnnotateModels.get_schema_info(@klass, '== Schema Info') + schema_info = described_class.get_schema_info(klass, '== Schema Info') model_file_name, = write_model 'user.rb', "#{magic_comment}\n\n\n\n#{content}" annotate_one_file position: :before @@ -3042,7 +3041,7 @@ class User < ActiveRecord::Base model_file_name, = write_model 'user.rb', "#{magic_comment}\n#{content}" annotate_one_file position: :after - schema_info = AnnotateModels.get_schema_info(@klass, '== Schema Info') + schema_info = described_class.get_schema_info(klass, '== Schema Info') expect(File.read(model_file_name)).to eq("#{magic_comment}\n#{content}\n#{schema_info}") end @@ -3050,84 +3049,84 @@ class User < ActiveRecord::Base describe "if a file can't be annotated" do before do - allow(AnnotateModels).to receive(:get_loaded_model_by_path).with('user').and_return(nil) + allow(described_class).to receive(:get_loaded_model_by_path).with('user').and_return(nil) - write_model('user.rb', <<~EOS) + write_model('user.rb', <<~BODY) class User < ActiveRecord::Base raise "oops" end - EOS + BODY end it 'displays just the error message with trace disabled (default)' do expect do - AnnotateModels.do_annotations model_dir: @model_dir, - is_rake: true - end.to output(a_string_including("Unable to annotate #{@model_dir}/user.rb: oops")).to_stderr + described_class.do_annotations model_dir: model_dir, + is_rake: true + end.to output(a_string_including("Unable to annotate #{model_dir}/user.rb: oops")).to_stderr expect do - AnnotateModels.do_annotations model_dir: @model_dir, - is_rake: true + described_class.do_annotations model_dir: model_dir, + is_rake: true end.not_to output(a_string_including('/spec/annotate/annotate_models_spec.rb:')).to_stderr end it 'displays the error message and stacktrace with trace enabled' do expect do - AnnotateModels.do_annotations model_dir: @model_dir, is_rake: true, - trace: true - end.to output(a_string_including("Unable to annotate #{@model_dir}/user.rb: oops")).to_stderr + described_class.do_annotations model_dir: model_dir, is_rake: true, + trace: true + end.to output(a_string_including("Unable to annotate #{model_dir}/user.rb: oops")).to_stderr expect do - AnnotateModels.do_annotations model_dir: @model_dir, is_rake: true, - trace: true + described_class.do_annotations model_dir: model_dir, is_rake: true, + trace: true end.to output(a_string_including('/spec/lib/annotate/annotate_models_spec.rb:')).to_stderr end end describe "if a file can't be deannotated" do before do - allow(AnnotateModels).to receive(:get_loaded_model_by_path).with('user').and_return(nil) + allow(described_class).to receive(:get_loaded_model_by_path).with('user').and_return(nil) - write_model('user.rb', <<~EOS) + write_model('user.rb', <<~BODY) class User < ActiveRecord::Base raise "oops" end - EOS + BODY end it 'displays just the error message with trace disabled (default)' do expect do - AnnotateModels.remove_annotations model_dir: @model_dir, - is_rake: true - end.to output(a_string_including("Unable to deannotate #{@model_dir}/user.rb: oops")).to_stderr + described_class.remove_annotations model_dir: model_dir, + is_rake: true + end.to output(a_string_including("Unable to deannotate #{model_dir}/user.rb: oops")).to_stderr expect do - AnnotateModels.remove_annotations model_dir: @model_dir, - is_rake: true + described_class.remove_annotations model_dir: model_dir, + is_rake: true end.not_to output(a_string_including("/user.rb:2:in `'")).to_stderr end it 'displays the error message and stacktrace with trace enabled' do expect do - AnnotateModels.remove_annotations model_dir: @model_dir, is_rake: true, - trace: true - end.to output(a_string_including("Unable to deannotate #{@model_dir}/user.rb: oops")).to_stderr + described_class.remove_annotations model_dir: model_dir, is_rake: true, + trace: true + end.to output(a_string_including("Unable to deannotate #{model_dir}/user.rb: oops")).to_stderr expect do - AnnotateModels.remove_annotations model_dir: @model_dir, is_rake: true, - trace: true + described_class.remove_annotations model_dir: model_dir, is_rake: true, + trace: true end.to output(a_string_including("/user.rb:2:in `'")).to_stderr end end describe 'frozen option' do - it 'should abort without existing annotation when frozen: true' do + it 'aborts without existing annotation when frozen: true' do expect do annotate_one_file frozen: true end.to raise_error SystemExit, /user.rb needs to be updated, but annotate was run with `--frozen`./ end - it 'should abort with different annotation when frozen: true' do + it 'aborts with different annotation when frozen: true' do annotate_one_file - another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), - '== Schema Info') + another_schema_info = described_class.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer)]), + '== Schema Info') @schema_info = another_schema_info expect do @@ -3136,7 +3135,7 @@ class User < ActiveRecord::Base /user.rb needs to be updated, but annotate was run with `--frozen`./ end - it 'should NOT abort with same annotation when frozen: true' do + it 'does not abort with same annotation when frozen: true' do annotate_one_file expect { annotate_one_file frozen: true }.not_to raise_error end @@ -3144,32 +3143,28 @@ class User < ActiveRecord::Base end describe '.annotate_model_file' do - before do - class Foo < ActiveRecord::Base; end - allow(AnnotateModels).to receive(:get_model_class).with('foo.rb') { Foo } - allow(Foo).to receive(:table_exists?) { false } + let(:annotate_model_file) do + described_class.annotate_model_file([], 'foo.rb', nil, {}) end - subject do - AnnotateModels.annotate_model_file([], 'foo.rb', nil, {}) + before do + stub_const('Foo', Class.new(ActiveRecord::Base)) + allow(described_class).to receive(:get_model_class).with('foo.rb').and_return(Foo) + allow(Foo).to receive(:table_exists?).and_return(false) end - after { Object.send :remove_const, 'Foo' } - it 'skips attempt to annotate if no table exists for model' do - is_expected.to eq nil + expect(annotate_model_file).to be_nil end context 'with a non-class' do before do - NotAClass = 'foo' # rubocop:disable Naming/ConstantName - allow(AnnotateModels).to receive(:get_model_class).with('foo.rb') { NotAClass } + stub_const('NotAClass', 'foo') + allow(described_class).to receive(:get_model_class).with('foo.rb').and_return(NotAClass) end - after { Object.send :remove_const, 'NotAClass' } - it "doesn't output an error" do - expect { subject }.not_to output.to_stderr + expect { annotate_model_file }.not_to output.to_stderr end end end diff --git a/spec/lib/annotate/annotate_routes_spec.rb b/spec/lib/annotate/annotate_routes_spec.rb index b131198cc..34b90f523 100644 --- a/spec/lib/annotate/annotate_routes_spec.rb +++ b/spec/lib/annotate/annotate_routes_spec.rb @@ -6,10 +6,10 @@ describe AnnotateRoutes do ROUTE_FILE = 'config/routes.rb' - MESSAGE_ANNOTATED = "#{ROUTE_FILE} was annotated." - MESSAGE_UNCHANGED = "#{ROUTE_FILE} was not changed." - MESSAGE_NOT_FOUND = "#{ROUTE_FILE} could not be found." - MESSAGE_REMOVED = "Annotations were removed from #{ROUTE_FILE}." + MESSAGE_ANNOTATED = "#{ROUTE_FILE} was annotated.".freeze + MESSAGE_UNCHANGED = "#{ROUTE_FILE} was not changed.".freeze + MESSAGE_NOT_FOUND = "#{ROUTE_FILE} could not be found.".freeze + MESSAGE_REMOVED = "Annotations were removed from #{ROUTE_FILE}.".freeze unless const_defined?(:MAGIC_COMMENTS) MAGIC_COMMENTS = [ From 29d0e8255729ec96939711e403e6c24820bf50a8 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 17:12:57 +0100 Subject: [PATCH 11/14] fix: yml conflicts --- .rubocop_todo.yml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d133b9273..e20714c2b 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -139,6 +139,8 @@ RSpec/DescribedClass: # Configuration parameters: CountAsOne. RSpec/ExampleLength: Max: 6 + Exclude: + - 'spec/**/*' # Offense count: 10 RSpec/ExpectInHook: @@ -177,11 +179,14 @@ RSpec/NamedSubject: Exclude: - 'spec/lib/annotate/helpers_spec.rb' - 'spec/lib/tasks/annotate_models_migrate_spec.rb' + - 'spec/**/*' # Offense count: 39 # Configuration parameters: AllowedGroups. RSpec/NestedGroups: Max: 9 + Exclude: + - 'spec/**/*' # Offense count: 5 RSpec/RepeatedExampleGroupBody: @@ -346,22 +351,10 @@ Style/ZeroLengthPredicate: Layout/LineLength: Max: 496 -RSpec/ExampleLength: - Exclude: - - 'spec/**/*' - RSpec/MultipleMemoizedHelpers: Exclude: - 'spec/**/*' RSpec/InstanceVariable: - Exclude: - - 'spec/**/*' - -RSpec/NamedSubject: - Exclude: - - 'spec/**/*' - -RSpec/NestedGroups: Exclude: - 'spec/**/*' \ No newline at end of file From e7dcd10395827014585eab584476d7a81e7f6ba6 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 17:42:39 +0100 Subject: [PATCH 12/14] chore: version change, name change, info update --- README.md | 2 ++ annotate.gemspec | 10 +++++----- lib/annotate/version.rb | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bac488d5d..1288a9839 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ [![Coveralls](https://coveralls.io/repos/ctran/annotate_models/badge.svg?branch=develop)](https://coveralls.io/r/ctran/annotate_models?branch=develop) [![Maintenability](https://codeclimate.com/github/ctran/annotate_models/badges/gpa.svg)](https://codeclimate.com/github/ctran/annotate_models) +**This is a fork of the [annotate](https://github.com/ctran/annotate_models) gem, built for Rails 8 and Ruby 3.2.2+.** + Add a comment summarizing the current schema to the top or bottom of each of your... - ActiveRecord models diff --git a/annotate.gemspec b/annotate.gemspec index 15f2653d2..4b298611d 100644 --- a/annotate.gemspec +++ b/annotate.gemspec @@ -5,18 +5,18 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'annotate/version' Gem::Specification.new do |s| - s.name = 'annotate' + s.name = 'annot8' s.version = Annotate.version s.required_ruby_version = '>= 3.2.2' s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version= - s.authors = ['Alex Chaffee', 'Cuong Tran', 'Marcos Piccinini', 'Turadg Aleahmad', 'Jon Frisby'] - s.description = 'Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema.' - s.email = ['alex@stinky.com', 'cuong.tran@gmail.com', 'x@nofxx.com', 'turadg@aleahmad.net', 'jon@cloudability.com'] + s.authors = ['Alex Chaffee', 'Cuong Tran', 'Marcos Piccinini', 'Turadg Aleahmad', 'Jon Frisby', 'Benjamin Dunkley'] + s.description = 'Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema. This fork of the "annotate" gemis built for Rails 8 and Ruby 3.2.2+' + s.email = ['ben@chemica.co.uk'] s.executables = ['annotate'] s.extra_rdoc_files = ['README.md', 'CHANGELOG.md'] s.files = `git ls-files -z LICENSE.txt *.md *.gemspec bin lib`.split("\x0") - s.homepage = 'https://github.com/ctran/annotate_models' + s.homepage = 'https://github.com/chemica/annotate_models' s.licenses = ['Ruby'] s.require_paths = ['lib'] s.summary = 'Annotates Rails Models, routes, fixtures, and others based on the database schema.' diff --git a/lib/annotate/version.rb b/lib/annotate/version.rb index e2cecb2ec..37ee1023f 100644 --- a/lib/annotate/version.rb +++ b/lib/annotate/version.rb @@ -2,6 +2,6 @@ module Annotate def self.version - '3.2.0' + '1.0.0' end end From a990d92b2418219a40f84430e8456cd593bdf78c Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 18:01:26 +0100 Subject: [PATCH 13/14] chore: update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1288a9839..e2e6828aa 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Into Gemfile from rubygems.org: ```ruby group :development do - gem 'annotate' + gem 'annot8' end ``` @@ -92,17 +92,17 @@ Into Gemfile from Github: ```ruby group :development do - gem 'annotate', git: 'https://github.com/ctran/annotate_models.git' + gem 'annot8', git: 'https://github.com/chemica/annotate_models.git' end ``` Into environment gems from rubygems.org: - gem install annotate + gem install annot8 Into environment gems from Github checkout: - git clone https://github.com/ctran/annotate_models.git annotate_models + git clone https://github.com/chemica/annotate_models.git annotate_models cd annotate_models rake gem gem install dist/annotate-*.gem From 49e900c86610fc84b1ec9aa77912275cee452192 Mon Sep 17 00:00:00 2001 From: Benjamin E N Randles-Dunkley Date: Tue, 3 Jun 2025 21:24:34 +0100 Subject: [PATCH 14/14] chore: bump ruby version in ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f907097a..ab6c03d08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['2.7'] + ruby: ['3.2.2'] steps: - name: Checkout