diff --git a/.envrc b/.envrc new file mode 100644 index 000000000..fe464f42a --- /dev/null +++ b/.envrc @@ -0,0 +1,6 @@ +use_devbox() { + watch_file devbox.json + eval $(devbox shell --print-env) +} + +# use devbox diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f907097a..540e25d31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,20 +14,26 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['2.7'] + ruby: ['2.7.6'] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - bundler-cache: true + bundler-cache: false + + - name: Update RubyGems and install dependencies + run: | + gem update --system 3.3.22 + bundle config set --local force_ruby_platform true + bundle install --jobs 4 --retry 3 - name: Run Tests run: bundle exec rspec - name: Rubocop - run: bundle exec rubocop + run: bundle exec rubocop \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 633796457..782237689 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.gitignore b/.gitignore index bd5cc0e0b..cee045635 100644 --- a/.gitignore +++ b/.gitignore @@ -2,13 +2,7 @@ .DS_Store .bundle .gems -.rbenv-version -.ruby-* -/.idea/ -/.rbx -/.rvmrc -/.yardoc/* -/Gemfile.lock +/out /coverage/* /dist /doc/* diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile new file mode 100644 index 000000000..f556d4709 --- /dev/null +++ b/.gitpod.Dockerfile @@ -0,0 +1,11 @@ +FROM gitpod/workspace-full +USER gitpod + +# Install Ruby version 2.7.6 and set it as default +RUN _ruby_version=ruby-2.7.6 \ + && printf "rvm_gems_path=/home/gitpod/.rvm\n" > ~/.rvmrc \ + && bash -lc "rvm reinstall ${_ruby_version} && \ + rvm use ${_ruby_version} --default" \ + && printf "rvm_gems_path=/workspace/.rvm" > ~/.rvmrc \ + && printf "{ rvm use \$(rvm current); } >/dev/null 2>&1\n" >> "$HOME/.bashrc.d/70-ruby" + diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 000000000..76f9bdd96 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,20 @@ +image: + file: .gitpod.Dockerfile + +github: + prebuilds: + develop: true + # enable for pull requests coming from this repo (defaults to true) + pullRequests: true + + # add a "Review in Gitpod" button as a comment to pull requests (defaults to true) + addComment: true + + # add a "Review in Gitpod" button to pull requests (defaults to false) + addBadge: true + + # add a label once the prebuild is ready to pull requests (defaults to false) + addLabel: prebuilt-in-gitpod + +tasks: + - init: bundle install diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..19f20a0a4 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager" version="2" project-jdk-name="rbenv: 2.7.6" project-jdk-type="RUBY_SDK"> + <output url="file://$PROJECT_DIR$/out" /> + </component> +</project> diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..be4c02422 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/annotate_models.iml" filepath="$PROJECT_DIR$/annotate_models2.iml" /> + </modules> + </component> +</project> diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 000000000..90b77e517 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="AutoImportSettings"> + <option name="autoReloadType" value="SELECTIVE" /> + </component> + <component name="ChangeListManager"> + <list default="true" id="b64f608a-08cf-47e7-bb0a-48e62ee0ebe4" name="Changes" comment="" /> + <option name="SHOW_DIALOG" value="false" /> + <option name="HIGHLIGHT_CONFLICTS" value="true" /> + <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> + <option name="LAST_RESOLUTION" value="IGNORE" /> + </component> + <component name="Git.Settings"> + <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> + </component> + <component name="MacroExpansionManager"> + <option name="directoryName" value="w81fe55f" /> + </component> + <component name="ProjectId" id="2JMR0RqCAUSI4iMuqzKXFYOHMrm" /> + <component name="ProjectViewState"> + <option name="autoscrollToSource" value="true" /> + <option name="hideEmptyMiddlePackages" value="true" /> + <option name="showExcludedFiles" value="false" /> + <option name="showLibraryContents" value="true" /> + </component> + <component name="PropertiesComponent">{ + "keyToString": { + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "WebServerToolWindowFactoryState": "false", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "project.structure.last.edited": "Modules", + "project.structure.proportion": "0.0", + "project.structure.side.proportion": "0.2", + "ruby.rails.projectView.checked": "true", + "vue.rearranger.settings.migration": "true" + } +}</component> + <component name="RubyModuleManagerSettings"> + <option name="blackListedRootsPaths"> + <list> + <option value="$PROJECT_DIR$" /> + </list> + </option> + </component> + <component name="RunManager"> + <configuration name="annotate_models_spec" type="RubyRunConfigurationType" factoryName="Ruby" temporary="true"> + <RUBY_RUN_CONFIG NAME="RUBY_ARGS" VALUE="" /> + <RUBY_RUN_CONFIG NAME="WORK DIR" VALUE="$PROJECT_DIR$" /> + <RUBY_RUN_CONFIG NAME="SHOULD_USE_SDK" VALUE="false" /> + <RUBY_RUN_CONFIG NAME="ALTERN_SDK_NAME" VALUE="" /> + <RUBY_RUN_CONFIG NAME="myPassParentEnvs" VALUE="true" /> + <EXTENSION ID="BundlerRunConfigurationExtension" BUNDLE_MODE="AUTO" bundleExecEnabled="true" /> + <EXTENSION ID="RubyCoverageRunConfigurationExtension" track_test_folders="true" runner="rcov" ENABLE_BRANCH_COVERAGE="true" ENABLE_FORKED_COVERAGE="true"> + <COVERAGE_PATTERN ENABLED="true"> + <PATTERN REGEXPS="/.rvm/" INCLUDED="false" /> + </COVERAGE_PATTERN> + </EXTENSION> + <EXTENSION ID="org.jetbrains.plugins.ruby.rails.run.RailsRunConfigurationExtension" SCRATCH_USE_RAILS_RUNNER="false" /> + <RUBY_RUN_CONFIG NAME="SCRIPT_PATH" VALUE="$PROJECT_DIR$/spec/lib/annotate/annotate_models_spec.rb" /> + <RUBY_RUN_CONFIG NAME="SCRIPT_ARGS" VALUE="" /> + <method v="2"> + <option name="Make" enabled="true" /> + </method> + </configuration> + <recent_temporary> + <list> + <item itemvalue="Ruby.annotate_models_spec" /> + </list> + </recent_temporary> + </component> + <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" /> + <component name="SpringUtil" SPRING_PRE_LOADER_OPTION="false" RAKE_SPRING_PRE_LOADER_OPTION="false" RAILS_SPRING_PRE_LOADER_OPTION="false" /> + <component name="TaskManager"> + <task active="true" id="Default" summary="Default task"> + <changelist id="b64f608a-08cf-47e7-bb0a-48e62ee0ebe4" name="Changes" comment="" /> + <created>1671885743351</created> + <option name="number" value="Default" /> + <option name="presentableId" value="Default" /> + <updated>1671885743351</updated> + <workItem from="1671885744568" duration="21000" /> + <workItem from="1671926398703" duration="724000" /> + </task> + <servers /> + </component> + <component name="TypeScriptGeneratedFilesManager"> + <option name="version" value="3" /> + </component> + <component name="com.intellij.coverage.CoverageDataManagerImpl"> + <SUITE FILE_PATH="coverage/annotate_models@file_patterns_spec.rcov" NAME="file_patterns_spec Coverage Results" MODIFIED="1671926022651" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="rcov" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" MODULE_NAME="annotate_models" /> + <SUITE FILE_PATH="coverage/annotate_models@annotate_models_spec.rcov" NAME="annotate_models_spec Coverage Results" MODIFIED="1671927602491" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="rcov" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" /> + <SUITE FILE_PATH="coverage/annotate_models@annotate_routes_spec.rcov" NAME="annotate_routes_spec Coverage Results" MODIFIED="1671926030854" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="rcov" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" MODULE_NAME="annotate_models" /> + <SUITE FILE_PATH="coverage/annotate_models@All_specs_in_spec__annotate_models.rcov" NAME="All specs in spec: annotate_models Coverage Results" MODIFIED="1671926004257" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="rcov" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" MODULE_NAME="annotate_models" /> + </component> +</project> \ No newline at end of file diff --git a/.rbenv-gemsets b/.rbenv-gemsets deleted file mode 100644 index a9606b749..000000000 --- a/.rbenv-gemsets +++ /dev/null @@ -1 +0,0 @@ -.gems diff --git a/.rubocop.yml b/.rubocop.yml index 4d06aa989..c34d3beef 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -12,7 +12,15 @@ AllCops: - 'tmp/**/*' - 'spec/integration/**/*' NewCops: enable + TargetRubyVersion: 2.7 + +Lint/FormatParameterMismatch: + Enabled: false Metrics/BlockLength: Exclude: - 'spec/**/*.rb' + +Metrics/ClassLength: + Exclude: + - 'lib/annotate/annotate_models.rb' diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 000000000..49cdd668e --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.7.6 diff --git a/.tool-versions b/.tool-versions index 9e83a384b..33a8789fa 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -ruby 2.7.3 +ruby 2.7.7 diff --git a/Gemfile b/Gemfile index 0998ee0d0..4d7cf902e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,14 +1,13 @@ source 'https://rubygems.org' -ruby '>= 2.4.0' +ruby '>= 2.7.6' -gem 'activerecord', '>= 4.2.5', '< 6', require: false +gem 'activerecord', '>= 4.2.5', require: false gem 'rake', require: false group :development do gem 'bump' gem 'mg', require: false - gem 'travis', require: false platforms :mri, :mingw do gem 'yard', require: false end @@ -19,17 +18,13 @@ group :development, :test do gem 'guard-rspec', require: false gem 'rspec', require: false - gem 'rubocop', '~> 1.12.0', require: false + gem 'rubocop', '~> 1.59.0', require: false gem 'rubocop-rake', require: false - gem 'rubocop-rspec', '~> 2.2.0', require: false + gem 'rubocop-rspec', '~> 2.25.0', require: false gem 'simplecov', require: false gem 'terminal-notifier-guard', require: false - gem 'codeclimate-test-reporter' - gem 'coveralls' - gem 'overcommit' - gem 'ruby_dep', '1.5.0' platforms :mri, :mingw do gem 'pry', require: false @@ -38,6 +33,5 @@ group :development, :test do end group :test do - gem 'files', require: false gem 'git', require: false end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..e4d98dc65 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,180 @@ +GEM + remote: https://rubygems.org/ + specs: + activemodel (7.1.5.1) + activesupport (= 7.1.5.1) + activerecord (7.1.5.1) + activemodel (= 7.1.5.1) + activesupport (= 7.1.5.1) + timeout (>= 0.4.0) + activesupport (7.1.5.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + mutex_m + securerandom (>= 0.3) + tzinfo (~> 2.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + ast (2.4.2) + base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) + bump (0.10.0) + byebug (11.1.3) + childprocess (5.1.0) + logger (~> 1.5) + coderay (1.1.3) + concurrent-ruby (1.3.4) + connection_pool (2.4.1) + diff-lcs (1.5.1) + docile (1.4.1) + drb (2.2.1) + ffi (1.17.0) + formatador (1.1.0) + git (1.19.1) + addressable (~> 2.8) + rchardet (~> 1.8) + guard (2.19.0) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + lumberjack (>= 1.0.12, < 2.0) + nenv (~> 0.1) + notiffany (~> 0.0) + 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) + i18n (1.14.6) + concurrent-ruby (~> 1.0) + iniparse (1.5.0) + json (2.9.1) + language_server-protocol (3.17.0.3) + listen (3.9.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.4) + lumberjack (1.2.10) + method_source (1.1.0) + mg (0.0.8) + rake + minitest (5.25.4) + mutex_m (0.3.0) + nenv (0.3.0) + notiffany (0.1.3) + nenv (~> 0.1) + shellany (~> 0.0) + overcommit (0.64.1) + childprocess (>= 0.6.3, < 6) + iniparse (~> 1.4) + rexml (>= 3.3.9) + parallel (1.26.3) + parser (3.3.6.0) + ast (~> 2.4.1) + racc + pry (0.15.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.8.0) + byebug (~> 11.0) + pry (~> 0.10) + public_suffix (5.1.1) + racc (1.8.1) + rainbow (3.1.1) + rake (13.2.1) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) + rchardet (1.8.0) + regexp_parser (2.10.0) + rexml (3.4.0) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.2) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.2) + rubocop (1.59.0) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.2.2.4) + 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.37.0) + parser (>= 3.3.1.0) + 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.25.0) + rubocop (~> 1.40) + rubocop-capybara (~> 2.17) + rubocop-factory_bot (~> 2.22) + ruby-progressbar (1.13.0) + securerandom (0.3.2) + shellany (0.0.1) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.13.1) + simplecov_json_formatter (0.1.4) + terminal-notifier-guard (1.7.0) + thor (1.3.2) + timeout (0.4.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (2.6.0) + yard (0.9.37) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord (>= 4.2.5) + bump + byebug + git + guard-rspec + mg + overcommit + pry + pry-byebug + rake + rspec + rubocop (~> 1.59.0) + rubocop-rake + rubocop-rspec (~> 2.25.0) + simplecov + terminal-notifier-guard + yard + +RUBY VERSION + ruby 2.7.7p221 + +BUNDLED WITH + 2.1.4 diff --git a/README.md b/README.md index bac488d5d..b2b4d79cb 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ when using `SpatialAdapter`, `PostgisAdapter` or `PostGISAdapter`: # path :geometry line_string, 4326 ``` -Also, if you pass the `-r` option, it'll annotate `routes.rb` with the output of `rake routes`. +Also, if you pass the `-r` option, it'll annotate `routes.rb` with the output of `rake/rails routes`. ## Upgrading to 3.X and annotate models not working? @@ -217,7 +217,7 @@ you can do so with a simple environment variable, instead of editing the If --w option is used, the same text will be used as opening and closing --wo, --wrapper-open STR Annotation wrapper opening. --wc, --wrapper-close STR Annotation wrapper closing - -r, --routes Annotate routes.rb with the output of 'rake routes' + -r, --routes Annotate routes.rb with the output of 'rake/rails routes' --models Annotate ActiveRecord models -a, --active-admin Annotate active_admin models -v, --version Show the current version of this gem diff --git a/annotate.gemspec b/annotate.gemspec index 43b2ac990..f04a0ff44 100644 --- a/annotate.gemspec +++ b/annotate.gemspec @@ -18,15 +18,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<rake>, '>= 10.4', '< 14.0') - s.add_runtime_dependency(%q<activerecord>, ['>= 3.2', '< 8.0']) + s.add_runtime_dependency(%q<activerecord>, ['>= 3.2']) s.metadata = { "bug_tracker_uri" => "https://github.com/ctran/annotate_models/issues/", - "source_code_uri" => "https://github.com/ctran/annotate_models.git" + "source_code_uri" => "https://github.com/ctran/annotate_models.git", + 'rubygems_mfa_required' => 'true' } end diff --git a/annotate_models.iml b/annotate_models.iml new file mode 100644 index 000000000..7a2f51e5b --- /dev/null +++ b/annotate_models.iml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="RUBY_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" /> + <sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" /> + <sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" /> + <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" /> + </content> + <orderEntry type="jdk" jdkName="rbenv: 2.7.6" jdkType="RUBY_SDK" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="library" scope="PROVIDED" name="activemodel (v5.2.8.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="activerecord (v5.2.8.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="activesupport (v5.2.8.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="addressable (v2.8.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="arel (v9.0.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="bump (v0.10.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="bundler (v2.4.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="byebug (v11.1.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="childprocess (v4.1.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="codeclimate-test-reporter (v1.0.7, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="coderay (v1.1.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.1.10, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="coveralls (v0.8.23, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.5.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="docile (v1.4.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday (v1.10.2, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-em_http (v1.0.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-em_synchrony (v1.0.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-excon (v1.1.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-httpclient (v1.0.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-multipart (v1.0.4, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-net_http (v1.0.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-net_http_persistent (v1.2.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-patron (v1.0.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-rack (v1.0.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday-retry (v1.0.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="faraday_middleware (v1.2.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="ffi (v1.15.5, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="files (v0.4.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="formatador (v1.1.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="gh (v0.18.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="git (v1.13.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="guard (v2.18.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="guard-compat (v1.2.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="guard-rspec (v4.7.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="highline (v2.0.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="i18n (v1.12.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="iniparse (v1.5.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="json (v2.6.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="json_pure (v2.6.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="launchy (v2.4.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="listen (v3.7.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="lumberjack (v1.2.8, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="method_source (v1.0.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="mg (v0.0.8, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="minitest (v5.16.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="multi_json (v1.15.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="multipart-post (v2.2.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="nenv (v0.3.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="net-http-persistent (v2.9.4, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="net-http-pipeline (v1.0.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="notiffany (v0.1.3, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="overcommit (v0.59.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="parallel (v1.22.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="parser (v3.1.3.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="pry (v0.14.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="pry-byebug (v3.10.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="public_suffix (v5.0.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="pusher-client (v0.6.2, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rainbow (v3.1.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rake (v13.0.6, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rb-fsevent (v0.11.2, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rb-inotify (v0.10.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rchardet (v1.8.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.6.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rexml (v3.2.5, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rspec (v3.12.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rspec-core (v3.12.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.12.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.12.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.12.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rubocop (v1.12.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.24.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rubocop-rake (v0.6.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="rubocop-rspec (v2.2.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.11.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="ruby2_keywords (v0.0.5, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="ruby_dep (v1.5.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="shellany (v0.0.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="simplecov (v0.16.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="simplecov-html (v0.10.2, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="sync (v0.5.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="term-ansicolor (v1.7.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="terminal-notifier-guard (v1.7.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="thor (v1.2.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="thread_safe (v0.3.6, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="tins (v1.32.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="travis (v1.11.1, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="tzinfo (v1.2.10, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v2.3.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="webrick (v1.7.0, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="websocket (v1.2.9, rbenv: 2.7.6) [gem]" level="application" /> + <orderEntry type="library" scope="PROVIDED" name="yard (v0.9.28, rbenv: 2.7.6) [gem]" level="application" /> + </component> +</module> \ No newline at end of file diff --git a/bin/annotate b/bin/annotate index feb0c0421..59643481f 100755 --- a/bin/annotate +++ b/bin/annotate @@ -24,7 +24,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/devbox.json b/devbox.json new file mode 100644 index 000000000..14d2b499d --- /dev/null +++ b/devbox.json @@ -0,0 +1,12 @@ +{ + "packages": [ + "ruby", + "bundler" + ], + "shell": { + "init_hook": "bundle install" + }, + "nixpkgs": { + "commit": "52e3e80afff4b16ccb7c52e9f0f5220552f03d04" + } +} \ No newline at end of file diff --git a/lib/annotate.rb b/lib/annotate.rb index 7c54e9ea6..279417581 100644 --- a/lib/annotate.rb +++ b/lib/annotate.rb @@ -44,13 +44,13 @@ 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? ? ENV.fetch(key.to_s, nil) : nil end Constants::PATH_OPTIONS.each do |key| options[key] = !ENV[key.to_s].blank? ? ENV[key.to_s].split(',') : [] diff --git a/lib/annotate/annotate_models.rb b/lib/annotate/annotate_models.rb index dc2901a32..b346c3c1c 100644 --- a/lib/annotate/annotate_models.rb +++ b/lib/annotate/annotate_models.rb @@ -39,7 +39,7 @@ 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))/.freeze class << self def annotate_pattern(options = {}) @@ -155,8 +155,8 @@ 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| - col_comment = with_comments || with_comments_column ? col.comment&.gsub(/\n/, "\\n") : nil + 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) col_name = if with_comments && col_comment @@ -166,7 +166,7 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho 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 }] - end.to_h + end # Output annotation bare_max_attrs_length = cols_meta.map { |_, m| m[:simple_formatted_attrs].length }.max @@ -179,15 +179,15 @@ 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<tt>%s</tt>", "*#{col_name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n" + info << (sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{col_name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n") elsif options[:format_yard] - info << sprintf("# @!attribute #{col_name}") + "\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" + 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 << ((sprintf("# **`%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) else @@ -433,7 +433,7 @@ def annotate_one_file(file_name, info_block, position, options = {}) old_header = old_content.match(header_pattern).to_s new_header = info_block.match(header_pattern).to_s - column_pattern = /^#[\t ]+[\w\*\.`]+[\t ]+.+$/ + column_pattern = /^#[\t ]+[^\t ]+[\t ]+.+$/ old_columns = old_header && old_header.scan(column_pattern).sort new_columns = new_header && new_header.scan(column_pattern).sort @@ -521,6 +521,7 @@ def matched_types(options) # :position_in_fixture<Symbol>:: where to place the annotated section in fixture file # :position_in_factory<Symbol>:: where to place the annotated section in factory file # :position_in_serializer<Symbol>:: where to place the annotated section in serializer file + # :position_in_additional_file_patterns<Symbol>:: where to place the annotated section in files that match additional patterns # :exclude_tests<Symbol>:: whether to skip modification of test/spec files # :exclude_fixtures<Symbol>:: whether to skip modification of fixture files # :exclude_factories<Symbol>:: whether to skip modification of factory files @@ -669,6 +670,15 @@ def get_loaded_model(model_path, file) $LOAD_PATH.map(&:to_s) .select { |path| absolute_file.include?(path) } .map { |path| absolute_file.sub(path, '').sub(/\.rb$/, '').sub(/^\//, '') } + + # Handle Rails apps with collapsed model paths + model_paths = model_paths + .select do |mpath| + defined?(Rails) && + Rails.autoloaders.main.collapse_dirs.any? && + Rails.autoloaders.main.collapse_dirs.select { |path| path.match(mpath) } + end.map { |mpath| mpath.sub(/\/models/, '') } + model_paths .map { |path| get_loaded_model_by_path(path) } .find { |loaded_model| !loaded_model.nil? } @@ -694,7 +704,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 diff --git a/lib/annotate/annotate_routes.rb b/lib/annotate/annotate_routes.rb index c9a2218ac..dd4e9fcdb 100644 --- a/lib/annotate/annotate_routes.rb +++ b/lib/annotate/annotate_routes.rb @@ -4,7 +4,7 @@ # # # -# Prepends the output of "rake routes" to the top of your routes.rb file. +# Prepends the output of "rake/rails routes" to the top of your routes.rb file. # Yes, it's simple but I'm thick and often need a reminder of what my routes # mean. # @@ -18,8 +18,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 @@ -95,7 +95,7 @@ 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 != '' + 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..ce370f720 100644 --- a/lib/annotate/annotate_routes/header_generator.rb +++ b/lib/annotate/annotate_routes/header_generator.rb @@ -1,3 +1,4 @@ +require 'active_record' require_relative './helpers' module AnnotateRoutes @@ -16,7 +17,8 @@ def generate(options = {}) private def routes_map(options) - result = `rake routes`.chomp("\n").split(/\n/, -1) + command = ActiveRecord.version.to_s.first.to_i > 5 ? `rails routes` : `rake routes` + result = command.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 @@ -29,7 +31,7 @@ def routes_map(options) # Skip routes which match given regex # Note: it matches the complete line (route_name, path, controller/action) if regexp_for_ignoring_routes - result.reject { |line| line =~ regexp_for_ignoring_routes } + result.grep_v(regexp_for_ignoring_routes) else result end @@ -53,9 +55,9 @@ 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? + return out if contents_without_magic_comments.empty? maxs = [HEADER_ROW.map(&:size)] + contents_without_magic_comments[1..-1].map { |line| line.split.map(&:size) } diff --git a/lib/annotate/annotate_routes/helpers.rb b/lib/annotate/annotate_routes/helpers.rb index 1dba65bbe..9cf0dc303 100644 --- a/lib/annotate/annotate_routes/helpers.rb +++ b/lib/annotate/annotate_routes/helpers.rb @@ -1,6 +1,6 @@ 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*:.+-\*-)/.freeze class << self # TODO: write the method doc using ruby rdoc formats @@ -15,7 +15,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? diff --git a/lib/annotate/constants.rb b/lib/annotate/constants.rb index 0d3225659..24b978acd 100644 --- a/lib/annotate/constants.rb +++ b/lib/annotate/constants.rb @@ -8,7 +8,7 @@ module Constants POSITION_OPTIONS = [ :position_in_routes, :position_in_class, :position_in_test, :position_in_fixture, :position_in_factory, :position, - :position_in_serializer + :position_in_serializer, :position_in_additional_file_patterns ].freeze FLAG_OPTIONS = [ diff --git a/lib/annotate/helpers.rb b/lib/annotate/helpers.rb index 705685790..b65b46747 100644 --- a/lib/annotate/helpers.rb +++ b/lib/annotate/helpers.rb @@ -3,15 +3,15 @@ module Annotate 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..93f9ff1e5 100644 --- a/lib/annotate/parser.rb +++ b/lib/annotate/parser.rb @@ -15,7 +15,7 @@ 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 position_in_additional_file_patterns].freeze EXCLUSION_LIST = %w[tests fixtures factories serializers].freeze FORMAT_TYPES = %w[bare rdoc yard markdown].freeze @@ -124,6 +124,14 @@ def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength, has_set_position['position_in_serializer'] = true end + option_parser.on('--pa', + '--position-in-additional-file-patterns [before|top|after|bottom]', + ANNOTATION_POSITIONS, + 'Place the annotations at the top (before) or the bottom (after) of files that match additional patterns') do |position_in_additional_file_patterns| + env['position_in_additional_file_patterns'] = position_in_additional_file_patterns + has_set_position['position_in_additional_file_patterns'] = true + end + option_parser.on('--w', '--wrapper STR', 'Wrap annotation with the text passed as parameter.', @@ -145,7 +153,7 @@ def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength, option_parser.on('-r', '--routes', - "Annotate routes.rb with the output of 'rake routes'") do + "Annotate routes.rb with the output of 'rake/rails routes'") do env['routes'] = 'true' end diff --git a/lib/generators/annotate/templates/auto_annotate_models.rake b/lib/generators/annotate/templates/auto_annotate_models.rake index 61cdcd7a1..3dfed2d4e 100644 --- a/lib/generators/annotate/templates/auto_annotate_models.rake +++ b/lib/generators/annotate/templates/auto_annotate_models.rake @@ -7,53 +7,52 @@ 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', + 'position_in_additional_file_patterns' => 'before', + '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' ) end diff --git a/lib/tasks/annotate_models.rake b/lib/tasks/annotate_models.rake index 776f97ba3..385afddf5 100644 --- a/lib/tasks/annotate_models.rake +++ b/lib/tasks/annotate_models.rake @@ -11,48 +11,48 @@ task annotate_models: :environment do require "#{annotate_lib}/annotate/active_record_patch" options = {is_rake: true} - ENV['position'] = options[:position] = Annotate::Helpers.fallback(ENV['position'], 'before') + 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) @@ -64,9 +64,9 @@ task remove_annotation: :environment do require "#{annotate_lib}/annotate/active_record_patch" options = {is_rake: true} - options[:model_dir] = ENV['model_dir'] - options[:root_dir] = ENV['root_dir'] + 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_routes.rake b/lib/tasks/annotate_routes.rake index b2832d443..d882803f6 100644 --- a/lib/tasks/annotate_routes.rake +++ b/lib/tasks/annotate_routes.rake @@ -10,13 +10,13 @@ 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) + 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 diff --git a/spec/lib/annotate/annotate_models_spec.rb b/spec/lib/annotate/annotate_models_spec.rb index 096474610..ede8091f9 100644 --- a/spec/lib/annotate/annotate_models_spec.rb +++ b/spec/lib/annotate/annotate_models_spec.rb @@ -3,7 +3,6 @@ require 'annotate/annotate_models' require 'annotate/active_record_patch' require 'active_support/core_ext/string' -require 'files' require 'tmpdir' describe AnnotateModels do @@ -206,7 +205,7 @@ def mock_column(name, type, options = {}) end it 'sets skip_subdirectory_model_load to true' do - is_expected.to eq(true) + is_expected.to be(true) end end @@ -220,7 +219,7 @@ def mock_column(name, type, options = {}) end it 'sets skip_subdirectory_model_load to false' do - is_expected.to eq(false) + is_expected.to be(false) end end end @@ -1944,7 +1943,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 @@ -2014,18 +2013,15 @@ def mock_column(name, type, options = {}) context 'when `model_dir` is valid' do let(:model_dir) do - Files do - file 'foo.rb' - dir 'bar' do - file 'baz.rb' - dir 'qux' do - file 'quux.rb' - end - end - dir 'concerns' do - file 'corge.rb' - end - end + dir = Dir.mktmpdir + FileUtils.touch(File.join(dir, 'foo.rb')) + FileUtils.mkdir_p(File.join(dir, 'bar')) + FileUtils.touch(File.join(dir, 'bar', 'baz.rb')) + FileUtils.mkdir_p(File.join(dir, 'bar', 'qux')) + FileUtils.touch(File.join(dir, 'bar', 'qux', 'quux.rb')) + FileUtils.mkdir_p(File.join(dir, 'concerns')) + FileUtils.touch(File.join(dir, 'concerns', 'corge.rb')) + dir end context 'when the model files are not specified' do @@ -2198,6 +2194,37 @@ class FooInsideBar < ActiveRecord::Base expect(klass.name).to eq('Bar::FooInsideBar') end end + + context 'when class Bar::Foo is defined in Rails collapsed directory' do + before do + Rails = double('Rails') + # rubocop:disable RSpec/MessageChain + allow(Rails).to receive_message_chain(:autoloaders, :main, :collapse_dirs) { Set.new(["bar/models"]) } + # rubocop:enable RSpec/MessageChain + $LOAD_PATH.unshift(dir) + end + + let :dir do + AnnotateModels.model_dir[0] + end + + let :filename do + 'bar/models/foo.rb' + end + + let :file_content do + <<~EOS + module Bar + class Foo < ActiveRecord::Base + end + end + EOS + end + + it 'works' do + expect(klass.name).to eql('Bar::Foo') + end + end end context 'when class is defined inside module and class name is not capitalized normally' do @@ -2842,7 +2869,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 @@ -2922,6 +2949,34 @@ def annotate_one_file(options = {}) expect(File.read(@model_file_name)).to eq("#{@schema_info}#{@file_content}") end end + + context 'of multibyte comments' do + before do + klass = mock_class(:users, + :id, + [ + mock_column(:id, :integer, comment: 'ID'), + ], + [], + []) + @schema_info = AnnotateModels.get_schema_info(klass, '== Schema Info', with_comment: true) + annotate_one_file + end + + it 'should update columns' do + klass = mock_class(:users, + :id, + [ + mock_column(:id, :integer, comment: 'ID'), + mock_column(:active, :boolean, limit: 1, comment: 'ACTIVE'), + ], + [], + []) + @schema_info = AnnotateModels.get_schema_info(klass, '== Schema Info', with_comment: true) + annotate_one_file + expect(File.read(@model_file_name)).to eq("#{@schema_info}#{@file_content}") + end + end end describe 'with existing annotation => :before' do @@ -3093,11 +3148,11 @@ class User < ActiveRecord::Base end describe 'frozen option' do - it "should abort without existing annotation when frozen: true " 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`./ 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') @schema_info = another_schema_info @@ -3105,7 +3160,7 @@ class User < ActiveRecord::Base expect { annotate_one_file frozen: true }.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 @@ -3126,7 +3181,7 @@ class Foo < ActiveRecord::Base; end after { Object.send :remove_const, 'Foo' } it 'skips attempt to annotate if no table exists for model' do - is_expected.to eq nil + is_expected.to be_nil end context 'with a non-class' do diff --git a/spec/lib/annotate/helpers_spec.rb b/spec/lib/annotate/helpers_spec.rb index b8de5df52..c413c3b70 100644 --- a/spec/lib/annotate/helpers_spec.rb +++ b/spec/lib/annotate/helpers_spec.rb @@ -5,7 +5,7 @@ subject { described_class.skip_on_migration? } before do - allow(ENV).to receive(:[]).and_return(nil) + allow(ENV).to receive(:fetch).with(anything, nil).and_return(nil) end it { is_expected.to be_falsy } @@ -15,7 +15,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 +26,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 +37,7 @@ subject { described_class.include_routes? } before do - allow(ENV).to receive(:[]).and_return(nil) + allow(ENV).to receive(:fetch).with(anything, nil).and_return(nil) end it { is_expected.to be_falsy } @@ -47,7 +47,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 } @@ -68,7 +68,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 } @@ -102,20 +102,20 @@ describe '.fallback' do subject { described_class.fallback(*args) } - let(:args) { [arg_1, arg_2] } + let(:args) { [first_arg, second_arg] } - let(:arg_1) { '' } # is considered blank - let(:arg_2) { 'yes' } + let(:first_arg) { '' } # is considered blank + let(:second_arg) { 'yes' } it 'returns the first non-blank argument' do - is_expected.to eq(arg_2) + is_expected.to eq(second_arg) end context 'when the first argument is non-blank' do - let(:arg_1) { 'yes' } - let(:arg_2) { 'no' } + let(:first_arg) { 'yes' } + let(:second_arg) { 'no' } - it { is_expected.to eq(arg_1) } + it { is_expected.to eq(first_arg) } end end diff --git a/spec/lib/annotate/parser_spec.rb b/spec/lib/annotate/parser_spec.rb index 16084b02b..ced05f013 100644 --- a/spec/lib/annotate/parser_spec.rb +++ b/spec/lib/annotate/parser_spec.rb @@ -72,8 +72,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 @@ -174,6 +174,22 @@ module Annotate # rubocop:disable Metrics/ModuleLength end end + %w[--pa --position-in-additional-file-patterns].each do |option| + describe option do + let(:env_key) { 'position_in_additional_file_patterns' } + + Parser::ANNOTATION_POSITIONS.each do |position| + context "when specifying #{position}" do + it "sets the ENV variable to #{position}" do + allow(ENV).to receive(:[]=) + Parser.parse([option, position]) + expect(ENV).to have_received(:[]=).with(env_key, position) + end + end + end + end + end + %w[--w --wrapper].each do |option| describe option do let(:env_key) { 'wrapper' }