Commit b4c19810 by Andrew W. Lee

Merge branch 'release/v3.0.0'

parents 111640d0 0ad3424e
......@@ -3,12 +3,9 @@ language: ruby
rvm:
- 2.2.10
- 2.3.8
- 2.4.6
- 2.5.5
- 2.6.0
- 2.6.1
- 2.6.2
- 2.6.3
- 2.4.7
- 2.5.6
- 2.6.4
- ruby-head
matrix:
......
== 3.0.0
* Added `--models` CLI option fixing issue #563 (#647)
* Added `--additional_file_patterns` option for additional file patterns (#633) #636) #637)
* Refactored CLI parser (#646)
* Fixed BigDecimal.new deprecation warning (#634)
* Fixed annotations for columns with long data types (#622)
* Made methods private in AnnotateRoutes (#598)
See https://github.com/ctran/annotate_models/releases/tag/v3.0.0
== 2.7.5
See https://github.com/ctran/annotate_models/releases/tag/v2.7.5
......
......@@ -6,7 +6,6 @@
{<img src="https://coveralls.io/repos/ctran/annotate_models/badge.svg?branch=develop" />}[https://coveralls.io/r/ctran/annotate_models?branch=develop]
{<img src="https://codeclimate.com/github/ctran/annotate_models/badges/gpa.svg" />}[https://codeclimate.com/github/ctran/annotate_models]
{<img src="http://inch-ci.org/github/ctran/annotate_models.svg?branch=develop" alt="Inline docs" />}[http://inch-ci.org/github/ctran/annotate_models]
{<img src="https://gemnasium.com/ctran/annotate_models.png" />}[https://gemnasium.com/ctran/annotate_models]
Add a comment summarizing the current schema to the top or bottom of each of
your...
......@@ -90,11 +89,11 @@ To annotate all your models, tests, fixtures, and factories:
To annotate just your models, tests, and factories:
annotate --exclude fixtures
annotate --models --exclude fixtures
To annotate just your models:
annotate --exclude tests,fixtures,factories,serializers
annotate --models
To annotate routes.rb:
......@@ -164,6 +163,7 @@ you can do so with a simple environment variable, instead of editing the
== Options
Usage: annotate [options] [model_file]*
--additional_file_patterns Additional file paths or globs to annotate, separated by commas (e.g. `/foo/bar/%model_name%/*.rb,/baz/%model_name%.rb`)
-d, --delete Remove annotations from all model files or the routes.rb file
-p [before|top|after|bottom], Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/route/serializer file(s)
--position
......@@ -184,6 +184,7 @@ you can do so with a simple environment variable, instead of editing the
--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'
--models Annotate ActiveRecord models
-a, --active-admin Annotate active_admin models
-v, --version Show the current version of this gem
-m, --show-migration Include the migration version number in the annotation
......@@ -206,16 +207,35 @@ you can do so with a simple environment variable, instead of editing the
--frozen Do not allow to change annotations. Exits non-zero if there are going to be changes to files.
--timestamp Include timestamp in (routes) annotation
--trace If unable to annotate a file, print the full stack trace, not just the exception message.
-I, --ignore-columns REGEX don't annotate columns that match a given REGEX (i.e., `annotate -I '^(id|updated_at|created_at)'`
--ignore-routes REGEX don't annotate routes that match a given REGEX (i.e., `annotate -I '(mobile|resque|pghero)'`
-I, --ignore-columns REGEX don't annotate columns that match a given REGEX (e.g. `annotate -I '^(id|updated_at|created_at)'`)
--ignore-routes REGEX don't annotate routes that match a given REGEX (e.g. `annotate -I '(mobile|resque|pghero)'`)_
--hide-limit-column-types VALUES
don't show limit for given column types, separated by commas (i.e., `integer,boolean,text`)
don't show limit for given column types, separated by commas (e.g. `integer,boolean,text`)
--hide-default-column-types VALUES
don't show default for given column types, separated by commas (i.e., `json,jsonb,hstore`)
don't show default for given column types, separated by commas (e.g. `json,jsonb,hstore`)
--ignore-unknown-models don't display warnings for bad model files
--with-comment include database comments in model annotations
=== Option: +additional_file_patterns+
CLI: +--additional_file_patterns+<br>
Ruby: +:additional_file_patterns+
Provide additional paths for the gem to annotate. These paths can include globs.
It is recommended to use absolute paths. Here are some examples:
- <code>/app/lib/decorates/%MODEL_NAME%/&ast;.rb</code>
- <code>/app/lib/forms/%PLURALIZED_MODEL_NAME%/&ast;&ast;/&ast;.rb</code>
- <code>/app/lib/forms/%TABLE_NAME%/&ast;.rb</code>
The appropriate model will be inferred using the <code>%*%</code> syntax, annotating any matching files.
It works with existing filename resolutions (options for which can be found in the +resolve_filename+ method of
+annotate_models.rb+).
When using in a Rails config, you can use the following:
<code>File.join(Rails.application.root, 'app/lib/forms/%PLURALIZED_MODEL_NAME%/**/*.rb')</code>
== Sorting
......
......@@ -38,7 +38,6 @@ Gem::Specification.new do |s|
s.homepage = 'http://github.com/ctran/annotate_models'
s.licenses = ['Ruby']
s.require_paths = ['lib']
s.rubyforge_project = 'annotate'
s.rubygems_version = '2.1.11'
s.summary = 'Annotates Rails Models, routes, fixtures, and others based on the database schema.'
......
......@@ -14,203 +14,19 @@ end
here = File.expand_path(File.dirname __FILE__)
$LOAD_PATH << "#{here}/../lib"
require 'optparse'
require 'annotate'
Annotate.bootstrap_rake
has_set_position = {}
target_action = :do_annotations
positions = %w(before top after bottom)
OptionParser.new do |opts|
opts.banner = 'Usage: annotate [options] [model_file]*'
opts.on('-d', '--delete', 'Remove annotations from all model files or the routes.rb file') do
target_action = :remove_annotations
end
opts.on('-p', '--position [before|top|after|bottom]', positions,
'Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/route/serializer file(s)') do |p|
ENV['position'] = p
%w(position_in_class position_in_factory position_in_fixture position_in_test position_in_routes position_in_serializer).each do |key|
ENV[key] = p unless has_set_position[key]
end
end
opts.on('--pc', '--position-in-class [before|top|after|bottom]', positions,
'Place the annotations at the top (before) or the bottom (after) of the model file') do |p|
ENV['position_in_class'] = p
has_set_position['position_in_class'] = true
end
opts.on('--pf', '--position-in-factory [before|top|after|bottom]', positions,
'Place the annotations at the top (before) or the bottom (after) of any factory files') do |p|
ENV['position_in_factory'] = p
has_set_position['position_in_factory'] = true
end
opts.on('--px', '--position-in-fixture [before|top|after|bottom]', positions,
'Place the annotations at the top (before) or the bottom (after) of any fixture files') do |p|
ENV['position_in_fixture'] = p
has_set_position['position_in_fixture'] = true
end
opts.on('--pt', '--position-in-test [before|top|after|bottom]', positions,
'Place the annotations at the top (before) or the bottom (after) of any test files') do |p|
ENV['position_in_test'] = p
has_set_position['position_in_test'] = true
end
opts.on('--pr', '--position-in-routes [before|top|after|bottom]', positions,
'Place the annotations at the top (before) or the bottom (after) of the routes.rb file') do |p|
ENV['position_in_routes'] = p
has_set_position['position_in_routes'] = true
end
opts.on('--ps', '--position-in-serializer [before|top|after|bottom]', positions,
'Place the annotations at the top (before) or the bottom (after) of the serializer files') do |p|
ENV['position_in_serializer'] = p
has_set_position['position_in_serializer'] = true
end
opts.on('--w', '--wrapper STR', 'Wrap annotation with the text passed as parameter.',
'If --w option is used, the same text will be used as opening and closing') do |p|
ENV['wrapper'] = p
end
opts.on('--wo', '--wrapper-open STR', 'Annotation wrapper opening.') do |p|
ENV['wrapper_open'] = p
end
opts.on('--wc', '--wrapper-close STR', 'Annotation wrapper closing') do |p|
ENV['wrapper_close'] = p
end
opts.on('-r', '--routes', "Annotate routes.rb with the output of 'rake routes'") do
ENV['routes'] = 'true'
end
opts.on('-a', '--active-admin', 'Annotate active_admin models') do
ENV['active_admin'] = 'true'
end
opts.on('-v', '--version', 'Show the current version of this gem') do
puts "annotate v#{Annotate.version}"; exit
end
opts.on('-m', '--show-migration', 'Include the migration version number in the annotation') do
ENV['include_version'] = 'yes'
end
opts.on('-k', '--show-foreign-keys',
"List the table's foreign key constraints in the annotation") do
ENV['show_foreign_keys'] = 'yes'
end
require 'annotate/parser'
opts.on('--ck',
'--complete-foreign-keys', 'Complete foreign key names in the annotation') do
ENV['show_foreign_keys'] = 'yes'
ENV['show_complete_foreign_keys'] = 'yes'
end
opts.on('-i', '--show-indexes',
"List the table's database indexes in the annotation") do
ENV['show_indexes'] = 'yes'
end
opts.on('-s', '--simple-indexes',
"Concat the column's related indexes in the annotation") do
ENV['simple_indexes'] = 'yes'
end
opts.on('--model-dir dir',
"Annotate model files stored in dir rather than app/models, separate multiple dirs with commas") do |dir|
ENV['model_dir'] = dir
end
opts.on('--root-dir dir',
"Annotate files stored within root dir projects, separate multiple dirs with commas") do |dir|
ENV['root_dir'] = dir
end
opts.on('--ignore-model-subdirects',
"Ignore subdirectories of the models directory") do |dir|
ENV['ignore_model_sub_dir'] = 'yes'
end
opts.on('--sort',
"Sort columns alphabetically, rather than in creation order") do |dir|
ENV['sort'] = 'yes'
end
opts.on('--classified-sort',
"Sort columns alphabetically, but first goes id, then the rest columns, then the timestamp columns and then the association columns") do |dir|
ENV['classified_sort'] = 'yes'
end
opts.on('-R', '--require path',
"Additional file to require before loading models, may be used multiple times") do |path|
if !ENV['require'].blank?
ENV['require'] = ENV['require'] + ",#{path}"
else
ENV['require'] = path
end
end
opts.on('-e', '--exclude [tests,fixtures,factories,serializers]', Array, "Do not annotate fixtures, test files, factories, and/or serializers") do |exclusions|
exclusions ||= %w(tests fixtures factories)
exclusions.each { |exclusion| ENV["exclude_#{exclusion}"] = 'yes' }
end
opts.on('-f', '--format [bare|rdoc|markdown]', %w(bare rdoc markdown), 'Render Schema Infomation as plain/RDoc/Markdown') do |fmt|
ENV["format_#{fmt}"] = 'yes'
end
opts.on('--force', 'Force new annotations even if there are no changes.') do |force|
ENV['force'] = 'yes'
end
opts.on('--frozen', 'Do not allow to change annotations. Exits non-zero if there are going to be changes to files.') do
ENV['frozen'] = 'yes'
end
opts.on('--timestamp', 'Include timestamp in (routes) annotation') do
ENV['timestamp'] = 'true'
end
opts.on('--trace', 'If unable to annotate a file, print the full stack trace, not just the exception message.') do |value|
ENV['trace'] = 'yes'
end
opts.on('-I', '--ignore-columns REGEX', "don't annotate columns that match a given REGEX (i.e., `annotate -I '^(id|updated_at|created_at)'`") do |regex|
ENV['ignore_columns'] = regex
end
opts.on('--ignore-routes REGEX', "don't annotate routes that match a given REGEX (i.e., `annotate -I '(mobile|resque|pghero)'`") do |regex|
ENV['ignore_routes'] = regex
end
opts.on('--hide-limit-column-types VALUES', "don't show limit for given column types, separated by commas (i.e., `integer,boolean,text`)") do |values|
ENV['hide_limit_column_types'] = "#{values}"
end
opts.on('--hide-default-column-types VALUES', "don't show default for given column types, separated by commas (i.e., `json,jsonb,hstore`)") do |values|
ENV['hide_default_column_types'] = "#{values}"
end
Annotate.bootstrap_rake
opts.on('--ignore-unknown-models', "don't display warnings for bad model files") do |values|
ENV['ignore_unknown_models'] = 'true'
end
options_result = Annotate::Parser.parse(ARGV)
opts.on('--with-comment', "include database comments in model annotations") do |values|
ENV['with_comment'] = 'true'
end
end.parse!
exit if options_result[:exit]
options = Annotate.setup_options(
is_rake: ENV['is_rake'] && !ENV['is_rake'].empty?
)
Annotate.eager_load(options) if Annotate.include_models?
AnnotateModels.send(target_action, options) if Annotate.include_models?
AnnotateRoutes.send(target_action, options) if Annotate.include_routes?
AnnotateModels.send(options_result[:target_action], options) if Annotate.include_models?
AnnotateRoutes.send(options_result[:target_action], options) if Annotate.include_routes?
......@@ -36,8 +36,8 @@ module Annotate
:exclude_sti_subclasses, :ignore_unknown_models, :with_comment
].freeze
OTHER_OPTIONS = [
:ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close,
:wrapper, :routes, :hide_limit_column_types, :hide_default_column_types,
: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 = [
......@@ -88,6 +88,7 @@ module Annotate
options[key] = !ENV[key.to_s].blank? ? ENV[key.to_s].split(',') : []
end
options[:additional_file_patterns] ||= []
options[:model_dir] = ['app/models'] if options[:model_dir].empty?
options[:wrapper_open] ||= options[:wrapper]
......@@ -114,7 +115,7 @@ module Annotate
end
def self.include_models?
ENV['routes'] !~ TRUE_RE
ENV['models'] =~ TRUE_RE
end
def self.loaded_tasks=(val)
......
......@@ -159,13 +159,15 @@ module AnnotateModels
]
end
def files_by_pattern(root_directory, pattern_type)
def files_by_pattern(root_directory, pattern_type, options)
case pattern_type
when 'test' then test_files(root_directory)
when 'fixture' then fixture_files(root_directory)
when 'scaffold' then scaffold_files(root_directory)
when 'factory' then factory_files(root_directory)
when 'serializer' then serialize_files(root_directory)
when 'additional_file_patterns'
[options[:additional_file_patterns] || []].flatten
when 'controller'
[File.join(root_directory, CONTROLLER_DIR, "%PLURALIZED_MODEL_NAME%_controller.rb")]
when 'admin'
......@@ -177,14 +179,20 @@ module AnnotateModels
end
end
def get_patterns(pattern_types = [])
def get_patterns(options, pattern_types = [])
current_patterns = []
root_dir.each do |root_directory|
Array(pattern_types).each do |pattern_type|
current_patterns += files_by_pattern(root_directory, pattern_type)
patterns = files_by_pattern(root_directory, pattern_type, options)
current_patterns += if pattern_type.to_sym == :additional_file_patterns
patterns
else
patterns.map { |p| p.sub(/^[\/]*/, '') }
end
end
end
current_patterns.map { |p| p.sub(/^[\/]*/, '') }
current_patterns
end
# Simple quoting for the default column value
......@@ -581,8 +589,9 @@ module AnnotateModels
end
def matched_types(options)
types = MATCHED_TYPES
types = MATCHED_TYPES.dup
types << 'admin' if options[:active_admin] =~ TRUE_RE && !types.include?('admin')
types << 'additional_file_patterns' if options[:additional_file_patterns].present?
types
end
......@@ -634,8 +643,11 @@ module AnnotateModels
end
next if options[exclusion_key]
get_patterns(key)
get_patterns(options, key)
.map { |f| resolve_filename(f, model_name, table_name) }
.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
......@@ -793,6 +805,10 @@ module AnnotateModels
end
end
def expand_glob_into_files(glob)
Dir.glob(glob)
end
def annotate_model_file(annotated, file, header, options)
begin
return false if /#{SKIP_ANNOTATION_PREFIX}.*/ =~ (File.exist?(file) ? File.read(file) : '')
......@@ -830,7 +846,7 @@ module AnnotateModels
model_file_name = file
deannotated_klass = true if remove_annotation_of_file(model_file_name, options)
get_patterns(matched_types(options))
get_patterns(options, matched_types(options))
.map { |f| resolve_filename(f, model_name, table_name) }
.each do |f|
if File.exist?(f)
......
......@@ -10,7 +10,7 @@
# Yes, it's simple but I'm thick and often need a reminder of what my routes
# mean.
#
# Running this task will replace any exising route comment generated by the
# Running this task will replace any existing route comment generated by the
# task. Best to back up your routes file before running:
#
# Author:
......
module Annotate
def self.version
'2.7.5'
'3.0.0'
end
end
......@@ -7,7 +7,9 @@ if Rails.env.development?
# You can override any of these by setting an environment variable of the
# same name.
Annotate.set_defaults(
'additional_file_patterns' => [],
'routes' => 'false',
'models' => 'false',
'position_in_routes' => 'before',
'position_in_class' => 'before',
'position_in_test' => 'before',
......
......@@ -12,6 +12,7 @@ task annotate_models: :environment do
options = {is_rake: true}
ENV['position'] = options[:position] = Annotate.fallback(ENV['position'], 'before')
options[:additional_file_patterns] = ENV['additional_file_patterns'] ? ENV['additional_file_patterns'].split(',') : []
options[:position_in_class] = Annotate.fallback(ENV['position_in_class'], ENV['position'])
options[:position_in_fixture] = Annotate.fallback(ENV['position_in_fixture'], ENV['position'])
options[:position_in_factory] = Annotate.fallback(ENV['position_in_factory'], ENV['position'])
......
# encoding: utf-8
require File.dirname(__FILE__) + '/../spec_helper.rb'
require_relative '../../spec_helper'
require 'annotate/annotate_models'
require 'annotate/active_record_patch'
require 'active_support/core_ext/string'
......@@ -70,8 +70,8 @@ describe AnnotateModels do # rubocop:disable Metrics/BlockLength
it { expect(AnnotateModels.quote(25)).to eql('25') }
it { expect(AnnotateModels.quote(25.6)).to eql('25.6') }
it { expect(AnnotateModels.quote(1e-20)).to eql('1.0e-20') }
it { expect(AnnotateModels.quote(BigDecimal.new('1.2'))).to eql('1.2') }
it { expect(AnnotateModels.quote([BigDecimal.new('1.2')])).to eql(['1.2']) }
it { expect(AnnotateModels.quote(BigDecimal('1.2'))).to eql('1.2') }
it { expect(AnnotateModels.quote([BigDecimal('1.2')])).to eql(['1.2']) }
describe '#parse_options' do
let(:options) do
......@@ -780,6 +780,69 @@ EOS
end
end
describe '#files_by_pattern' do
subject { AnnotateModels.files_by_pattern(root_directory, pattern_type, options) }
context 'when pattern_type=additional_file_patterns' do
let(:pattern_type) { 'additional_file_patterns' }
let(:root_directory) { nil }
context 'with additional_file_patterns' do
let(:additional_file_patterns) do
[
'%PLURALIZED_MODEL_NAME%/**/*.rb',
'%PLURALIZED_MODEL_NAME%/*_form'
]
end
let(:options) { { additional_file_patterns: additional_file_patterns } }
it do
expect(subject).to eq(additional_file_patterns)
end
end
context 'without additional_file_patterns' do
let(:options) { {} }
it do
expect(subject).to eq([])
end
end
end
end
describe '#get_patterns' do
subject { AnnotateModels.get_patterns(options, pattern_type) }
context 'when pattern_type=additional_file_patterns' do
let(:pattern_type) { 'additional_file_patterns' }
context 'with additional_file_patterns' do
let(:additional_file_patterns) do
[
'/%PLURALIZED_MODEL_NAME%/**/*.rb',
'/bar/%PLURALIZED_MODEL_NAME%/*_form'
]
end
let(:options) { { additional_file_patterns: additional_file_patterns } }
it do
expect(subject).to eq(additional_file_patterns)
end
end
context 'without additional_file_patterns' do
let(:options) { {} }
it do
expect(subject).to eq([])
end
end
end
end
describe '#get_schema_info with custom options' do
def self.when_called_with(options = {})
expected = options.delete(:returns)
......@@ -1505,6 +1568,24 @@ end
expect(filename). to eq 'test/unit/example_model_test.rb'
end
it 'should return the additional glob' do
filename_template = '/foo/bar/%MODEL_NAME%/testing.rb'
model_name = 'example_model'
table_name = 'example_models'
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq '/foo/bar/example_model/testing.rb'
end
it 'should return the additional glob' do
filename_template = '/foo/bar/%PLURALIZED_MODEL_NAME%/testing.rb'
model_name = 'example_model'
table_name = 'example_models'
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq '/foo/bar/example_models/testing.rb'
end
it 'should return the fixture path for a model' do
filename_template = 'test/fixtures/%TABLE_NAME%.yml'
model_name = 'example_model'
......@@ -1523,6 +1604,7 @@ end
expect(filename). to eq 'test/fixtures/parent/children.yml'
end
end
describe 'annotating a file' do
before do
@model_dir = Dir.mktmpdir('annotate_models')
......@@ -1737,7 +1819,7 @@ end
end
expect(error_output).to include("Unable to annotate #{@model_dir}/user.rb: oops")
expect(error_output).to include('/spec/annotate/annotate_models_spec.rb:')
expect(error_output).to include('/spec/lib/annotate/annotate_models_spec.rb:')
end
end
......
require File.dirname(__FILE__) + '/../spec_helper.rb'
require_relative '../../spec_helper'
require 'annotate/annotate_routes'
describe AnnotateRoutes do
......
require File.dirname(__FILE__) + '/spec_helper.rb'
require_relative '../spec_helper'
describe Annotate do
it 'should have a version' do
......
require_relative '../spec_helper'
require_relative '../../spec_helper'
describe 'ActiveRecord migration rake task hooks' do
before do
......
......@@ -28,6 +28,7 @@ require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/class/subclasses'
require 'active_support/core_ext/string/inflections'
require 'annotate'
require 'annotate/parser'
require 'byebug'
module Annotate
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment