annot8 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/AUTHORS.md +34 -0
- data/CHANGELOG.md +341 -0
- data/LICENSE.txt +55 -0
- data/README.md +331 -0
- data/RELEASE.md +19 -0
- data/annot8.gemspec +32 -0
- data/bin/annotate +31 -0
- data/lib/annotate/active_record_patch.rb +11 -0
- data/lib/annotate/annotate_models/file_patterns.rb +129 -0
- data/lib/annotate/annotate_models.rb +1005 -0
- data/lib/annotate/annotate_routes/header_generator.rb +117 -0
- data/lib/annotate/annotate_routes/helpers.rb +71 -0
- data/lib/annotate/annotate_routes.rb +121 -0
- data/lib/annotate/constants.rb +30 -0
- data/lib/annotate/helpers.rb +33 -0
- data/lib/annotate/parser.rb +317 -0
- data/lib/annotate/tasks.rb +8 -0
- data/lib/annotate/version.rb +7 -0
- data/lib/annotate.rb +152 -0
- data/lib/generators/annotate/USAGE +4 -0
- data/lib/generators/annotate/install_generator.rb +17 -0
- data/lib/generators/annotate/templates/auto_annotate_models.rake +63 -0
- data/lib/tasks/annotate_models.rake +79 -0
- data/lib/tasks/annotate_models_migrate.rake +65 -0
- data/lib/tasks/annotate_routes.rake +34 -0
- data/potato.md +41 -0
- metadata +120 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
module AnnotateRoutes
|
6
|
+
class HeaderGenerator
|
7
|
+
PREFIX = '== Route Map'
|
8
|
+
PREFIX_MD = '## Route Map'
|
9
|
+
HEADER_ROW = ['Prefix', 'Verb', 'URI Pattern', 'Controller#Action'].freeze
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def generate(options = {})
|
13
|
+
new(options, routes_map(options)).generate
|
14
|
+
end
|
15
|
+
|
16
|
+
private :new
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def routes_map(options)
|
21
|
+
result = `rake routes`.chomp("\n").split("\n", -1)
|
22
|
+
|
23
|
+
# In old versions of Rake, the first line of output was the cwd. Not so
|
24
|
+
# much in newer ones. We ditch that line if it exists, and if not, we
|
25
|
+
# keep the line around.
|
26
|
+
result.shift if result.first =~ %r{^\(in /}
|
27
|
+
|
28
|
+
ignore_routes = options[:ignore_routes]
|
29
|
+
regexp_for_ignoring_routes = ignore_routes ? /#{ignore_routes}/ : nil
|
30
|
+
|
31
|
+
# Skip routes which match given regex
|
32
|
+
# Note: it matches the complete line (route_name, path, controller/action)
|
33
|
+
if regexp_for_ignoring_routes
|
34
|
+
result.reject { |line| line =~ regexp_for_ignoring_routes }
|
35
|
+
else
|
36
|
+
result
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(options, routes_map)
|
42
|
+
@options = options
|
43
|
+
@routes_map = routes_map
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate
|
47
|
+
magic_comments_map, contents_without_magic_comments = Helpers.extract_magic_comments_from_array(routes_map)
|
48
|
+
|
49
|
+
out = []
|
50
|
+
|
51
|
+
magic_comments_map.each do |magic_comment|
|
52
|
+
out << magic_comment
|
53
|
+
end
|
54
|
+
out << '' if magic_comments_map.any?
|
55
|
+
|
56
|
+
out << comment(options[:wrapper_open]) if options[:wrapper_open]
|
57
|
+
|
58
|
+
out << (comment(markdown? ? PREFIX_MD : PREFIX) + timestamp_if_required)
|
59
|
+
out << comment
|
60
|
+
return out if contents_without_magic_comments.size.zero?
|
61
|
+
|
62
|
+
maxs = [HEADER_ROW.map(&:size)] + contents_without_magic_comments[1..].map { |line| line.split.map(&:size) }
|
63
|
+
|
64
|
+
if markdown?
|
65
|
+
max = maxs.map(&:max).compact.max
|
66
|
+
|
67
|
+
out << comment(content(HEADER_ROW, maxs))
|
68
|
+
out << comment(content(['-' * max, '-' * max, '-' * max, '-' * max], maxs))
|
69
|
+
else
|
70
|
+
out << comment(content(contents_without_magic_comments[0], maxs))
|
71
|
+
end
|
72
|
+
|
73
|
+
out += contents_without_magic_comments[1..].map do |line|
|
74
|
+
comment(content(markdown? ? line.split(' ') : line, maxs))
|
75
|
+
end
|
76
|
+
out << comment(options[:wrapper_close]) if options[:wrapper_close]
|
77
|
+
|
78
|
+
out
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
attr_reader :options, :routes_map
|
84
|
+
|
85
|
+
def comment(row = '')
|
86
|
+
if row == ''
|
87
|
+
'#'
|
88
|
+
else
|
89
|
+
"# #{row}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def content(line, maxs)
|
94
|
+
return line.rstrip unless markdown?
|
95
|
+
|
96
|
+
line.each_with_index.map { |elem, index| format_line_element(elem, maxs, index) }.join(' | ')
|
97
|
+
end
|
98
|
+
|
99
|
+
def format_line_element(elem, maxs, index)
|
100
|
+
min_length = maxs.map { |arr| arr[index] }.max || 0
|
101
|
+
format("%-#{min_length}.#{min_length}s", elem.tr('|', '-'))
|
102
|
+
end
|
103
|
+
|
104
|
+
def markdown?
|
105
|
+
options[:format_markdown]
|
106
|
+
end
|
107
|
+
|
108
|
+
def timestamp_if_required(time = Time.now)
|
109
|
+
if options[:timestamp]
|
110
|
+
time_formatted = time.strftime('%Y-%m-%d %H:%M')
|
111
|
+
" (Updated #{time_formatted})"
|
112
|
+
else
|
113
|
+
''
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRoutes
|
4
|
+
module Helpers
|
5
|
+
MAGIC_COMMENT_MATCHER = /(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# TODO: write the method doc using ruby rdoc formats
|
9
|
+
# This method returns an array of 'real_content' and 'header_position'.
|
10
|
+
# 'header_position' will either be :before, :after, or
|
11
|
+
# a number. If the number is > 0, the
|
12
|
+
# annotation was found somewhere in the
|
13
|
+
# middle of the file. If the number is
|
14
|
+
# zero, no annotation was found.
|
15
|
+
def strip_annotations(content)
|
16
|
+
real_content = []
|
17
|
+
mode = :content
|
18
|
+
header_position = 0
|
19
|
+
|
20
|
+
content.split("\n", -1).each_with_index do |line, line_number|
|
21
|
+
if mode == :header && line !~ /\s*#/
|
22
|
+
mode = :content
|
23
|
+
real_content << line unless line.blank?
|
24
|
+
elsif mode == :content
|
25
|
+
if line =~ /^\s*#\s*== Route.*$/
|
26
|
+
header_position = line_number + 1 # index start's at 0
|
27
|
+
mode = :header
|
28
|
+
else
|
29
|
+
real_content << line
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
real_content_and_header_position(real_content, header_position)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param [Array<String>] content
|
38
|
+
# @return [Array<String>] all found magic comments
|
39
|
+
# @return [Array<String>] content without magic comments
|
40
|
+
def extract_magic_comments_from_array(content_array)
|
41
|
+
magic_comments = []
|
42
|
+
new_content = []
|
43
|
+
|
44
|
+
content_array.each do |row|
|
45
|
+
if row =~ MAGIC_COMMENT_MATCHER
|
46
|
+
magic_comments << row.strip
|
47
|
+
else
|
48
|
+
new_content << row
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
[magic_comments, new_content]
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def real_content_and_header_position(real_content, header_position)
|
58
|
+
# By default assume the annotation was found in the middle of the file
|
59
|
+
|
60
|
+
# ... unless we have evidence it was at the beginning ...
|
61
|
+
return real_content, :before if header_position == 1
|
62
|
+
|
63
|
+
# ... or that it was at the end.
|
64
|
+
return real_content, :after if header_position >= real_content.count
|
65
|
+
|
66
|
+
# and the default
|
67
|
+
[real_content, header_position]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Annotate Routes
|
4
|
+
#
|
5
|
+
# Based on:
|
6
|
+
#
|
7
|
+
#
|
8
|
+
#
|
9
|
+
# Prepends the output of "rake routes" to the top of your routes.rb file.
|
10
|
+
# Yes, it's simple but I'm thick and often need a reminder of what my routes
|
11
|
+
# mean.
|
12
|
+
#
|
13
|
+
# Running this task will replace any existing route comment generated by the
|
14
|
+
# task. Best to back up your routes file before running:
|
15
|
+
#
|
16
|
+
# Author:
|
17
|
+
# Gavin Montague
|
18
|
+
# gavin@leftbrained.co.uk
|
19
|
+
#
|
20
|
+
# Released under the same license as Ruby. No Support. No Warranty.
|
21
|
+
#
|
22
|
+
|
23
|
+
require_relative 'annotate_routes/helpers'
|
24
|
+
require_relative 'annotate_routes/header_generator'
|
25
|
+
|
26
|
+
module AnnotateRoutes
|
27
|
+
class << self
|
28
|
+
def do_annotations(options = {})
|
29
|
+
if routes_file_exist?
|
30
|
+
existing_text = File.read(routes_file)
|
31
|
+
content, header_position = Helpers.strip_annotations(existing_text)
|
32
|
+
new_content = annotate_routes(HeaderGenerator.generate(options), content, header_position, options)
|
33
|
+
new_text = new_content.join("\n")
|
34
|
+
if rewrite_contents(existing_text, new_text, options[:frozen])
|
35
|
+
puts "#{routes_file} was annotated."
|
36
|
+
else
|
37
|
+
puts "#{routes_file} was not changed."
|
38
|
+
end
|
39
|
+
else
|
40
|
+
puts "#{routes_file} could not be found."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove_annotations(options = {})
|
45
|
+
if routes_file_exist?
|
46
|
+
existing_text = File.read(routes_file)
|
47
|
+
content, header_position = Helpers.strip_annotations(existing_text)
|
48
|
+
new_content = strip_on_removal(content, header_position)
|
49
|
+
new_text = new_content.join("\n")
|
50
|
+
if rewrite_contents(existing_text, new_text, options[:frozen])
|
51
|
+
puts "Annotations were removed from #{routes_file}."
|
52
|
+
else
|
53
|
+
puts "#{routes_file} was not changed (Annotation did not exist)."
|
54
|
+
end
|
55
|
+
else
|
56
|
+
puts "#{routes_file} could not be found."
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def routes_file_exist?
|
63
|
+
File.exist?(routes_file)
|
64
|
+
end
|
65
|
+
|
66
|
+
def routes_file
|
67
|
+
@routes_rb ||= File.join('config', 'routes.rb')
|
68
|
+
end
|
69
|
+
|
70
|
+
def strip_on_removal(content, header_position)
|
71
|
+
if header_position == :before
|
72
|
+
content.shift while content.first == ''
|
73
|
+
elsif header_position == :after
|
74
|
+
content.pop while content.last == ''
|
75
|
+
end
|
76
|
+
|
77
|
+
# Make sure we end on a trailing newline.
|
78
|
+
content << '' unless content.last == ''
|
79
|
+
|
80
|
+
# TODO: If the user buried it in the middle, we should probably see about
|
81
|
+
# TODO: preserving a single line of space between the content above and
|
82
|
+
# TODO: below...
|
83
|
+
content
|
84
|
+
end
|
85
|
+
|
86
|
+
def rewrite_contents(existing_text, new_text, frozen)
|
87
|
+
content_changed = (existing_text != new_text)
|
88
|
+
|
89
|
+
if content_changed
|
90
|
+
abort "annotate error. #{routes_file} needs to be updated, but annotate was run with `--frozen`." if frozen
|
91
|
+
File.open(routes_file, 'wb') { |f| f.puts(new_text) }
|
92
|
+
end
|
93
|
+
|
94
|
+
content_changed
|
95
|
+
end
|
96
|
+
|
97
|
+
def annotate_routes(header, content, header_position, options = {})
|
98
|
+
magic_comments_map, content = Helpers.extract_magic_comments_from_array(content)
|
99
|
+
if %w[before top].include?(options[:position_in_routes])
|
100
|
+
header <<= '' if content.first != ''
|
101
|
+
magic_comments_map << '' if magic_comments_map.any?
|
102
|
+
new_content = magic_comments_map + header + content
|
103
|
+
else
|
104
|
+
# Ensure we have adequate trailing newlines at the end of the file to
|
105
|
+
# ensure a blank line separating the content from the annotation.
|
106
|
+
content << '' unless content.last == ''
|
107
|
+
|
108
|
+
# We're moving something from the top of the file to the bottom, so ditch
|
109
|
+
# the spacer we put in the first time around.
|
110
|
+
content.shift if header_position == :before && content.first == ''
|
111
|
+
|
112
|
+
new_content = magic_comments_map + content + header
|
113
|
+
end
|
114
|
+
|
115
|
+
# Make sure we end on a trailing newline.
|
116
|
+
new_content << '' unless new_content.last == ''
|
117
|
+
|
118
|
+
new_content
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Annotate
|
4
|
+
module Constants
|
5
|
+
TRUE_RE = /^(true|t|yes|y|1)$/i
|
6
|
+
|
7
|
+
##
|
8
|
+
# The set of available options to customize the behavior of Annotate.
|
9
|
+
#
|
10
|
+
POSITION_OPTIONS = [
|
11
|
+
:position_in_routes, :position_in_class, :position_in_test, :position_in_fixture, :position_in_factory, :position, :position_in_serializer
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
FLAG_OPTIONS = [
|
15
|
+
: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
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
OTHER_OPTIONS = [
|
19
|
+
: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
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
PATH_OPTIONS = [
|
23
|
+
:require, :model_dir, :root_dir
|
24
|
+
].freeze
|
25
|
+
|
26
|
+
ALL_ANNOTATE_OPTIONS = [
|
27
|
+
POSITION_OPTIONS, FLAG_OPTIONS, OTHER_OPTIONS, PATH_OPTIONS
|
28
|
+
].freeze
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Annotate
|
4
|
+
# Class for holding helper methods. Done to make lib/annotate.rb less bloated.
|
5
|
+
class Helpers
|
6
|
+
class << self
|
7
|
+
def skip_on_migration?
|
8
|
+
ENV.fetch('ANNOTATE_SKIP_ON_DB_MIGRATE',
|
9
|
+
nil) =~ Constants::TRUE_RE || ENV.fetch('skip_on_db_migrate', nil) =~ Constants::TRUE_RE
|
10
|
+
end
|
11
|
+
|
12
|
+
def include_routes?
|
13
|
+
ENV.fetch('routes', nil) =~ Constants::TRUE_RE
|
14
|
+
end
|
15
|
+
|
16
|
+
def include_models?
|
17
|
+
ENV.fetch('models', nil) =~ Constants::TRUE_RE
|
18
|
+
end
|
19
|
+
|
20
|
+
def true?(val)
|
21
|
+
val.present? && Constants::TRUE_RE.match?(val)
|
22
|
+
end
|
23
|
+
|
24
|
+
def fallback(*args)
|
25
|
+
args.detect(&:present?)
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_options(options)
|
29
|
+
options.flatten.each { |key| ENV[key.to_s] = nil }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
module Annotate
|
6
|
+
# Class for handling command line arguments
|
7
|
+
class Parser
|
8
|
+
def self.parse(args, env = {})
|
9
|
+
new(args, env).parse
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :args, :options, :env
|
13
|
+
|
14
|
+
DEFAULT_OPTIONS = {
|
15
|
+
target_action: :do_annotations,
|
16
|
+
exit: false
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
ANNOTATION_POSITIONS = %w[before top after bottom].freeze
|
20
|
+
FILE_TYPE_POSITIONS = %w[position_in_class position_in_factory position_in_fixture position_in_test
|
21
|
+
position_in_routes position_in_serializer].freeze
|
22
|
+
EXCLUSION_LIST = %w[tests fixtures factories serializers].freeze
|
23
|
+
FORMAT_TYPES = %w[bare rdoc yard markdown].freeze
|
24
|
+
|
25
|
+
def initialize(args, env)
|
26
|
+
@args = args
|
27
|
+
@options = DEFAULT_OPTIONS.dup
|
28
|
+
@env = env
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse
|
32
|
+
# To split up because right now this method parses and commits
|
33
|
+
parser.parse!(args)
|
34
|
+
|
35
|
+
commit
|
36
|
+
|
37
|
+
options
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def parser
|
43
|
+
OptionParser.new do |option_parser|
|
44
|
+
add_options_to_parser(option_parser)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def commit
|
49
|
+
env.each_pair do |key, value|
|
50
|
+
ENV[key] = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
55
|
+
has_set_position = {}
|
56
|
+
|
57
|
+
option_parser.banner = 'Usage: annotate [options] [model_file]*'
|
58
|
+
|
59
|
+
option_parser.on('--additional-file-patterns path1,path2,path3',
|
60
|
+
Array,
|
61
|
+
'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|
|
62
|
+
ENV['additional_file_patterns'] = additional_file_patterns
|
63
|
+
end
|
64
|
+
|
65
|
+
option_parser.on('-d',
|
66
|
+
'--delete',
|
67
|
+
'Remove annotations from all model files or the routes.rb file') do
|
68
|
+
@options[:target_action] = :remove_annotations
|
69
|
+
end
|
70
|
+
|
71
|
+
option_parser.on('-p',
|
72
|
+
'--position [before|top|after|bottom]',
|
73
|
+
ANNOTATION_POSITIONS,
|
74
|
+
'Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/route/serializer file(s)') do |position|
|
75
|
+
env['position'] = position
|
76
|
+
|
77
|
+
FILE_TYPE_POSITIONS.each do |key|
|
78
|
+
env[key] = position unless has_set_position[key]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
option_parser.on('--pc',
|
83
|
+
'--position-in-class [before|top|after|bottom]',
|
84
|
+
ANNOTATION_POSITIONS,
|
85
|
+
'Place the annotations at the top (before) or the bottom (after) of the model file') do |position_in_class|
|
86
|
+
env['position_in_class'] = position_in_class
|
87
|
+
has_set_position['position_in_class'] = true
|
88
|
+
end
|
89
|
+
|
90
|
+
option_parser.on('--pf',
|
91
|
+
'--position-in-factory [before|top|after|bottom]',
|
92
|
+
ANNOTATION_POSITIONS,
|
93
|
+
'Place the annotations at the top (before) or the bottom (after) of any factory files') do |position_in_factory|
|
94
|
+
env['position_in_factory'] = position_in_factory
|
95
|
+
has_set_position['position_in_factory'] = true
|
96
|
+
end
|
97
|
+
|
98
|
+
option_parser.on('--px',
|
99
|
+
'--position-in-fixture [before|top|after|bottom]',
|
100
|
+
ANNOTATION_POSITIONS,
|
101
|
+
'Place the annotations at the top (before) or the bottom (after) of any fixture files') do |position_in_fixture|
|
102
|
+
env['position_in_fixture'] = position_in_fixture
|
103
|
+
has_set_position['position_in_fixture'] = true
|
104
|
+
end
|
105
|
+
|
106
|
+
option_parser.on('--pt',
|
107
|
+
'--position-in-test [before|top|after|bottom]',
|
108
|
+
ANNOTATION_POSITIONS,
|
109
|
+
'Place the annotations at the top (before) or the bottom (after) of any test files') do |position_in_test|
|
110
|
+
env['position_in_test'] = position_in_test
|
111
|
+
has_set_position['position_in_test'] = true
|
112
|
+
end
|
113
|
+
|
114
|
+
option_parser.on('--pr',
|
115
|
+
'--position-in-routes [before|top|after|bottom]',
|
116
|
+
ANNOTATION_POSITIONS,
|
117
|
+
'Place the annotations at the top (before) or the bottom (after) of the routes.rb file') do |position_in_routes|
|
118
|
+
env['position_in_routes'] = position_in_routes
|
119
|
+
has_set_position['position_in_routes'] = true
|
120
|
+
end
|
121
|
+
|
122
|
+
option_parser.on('--ps',
|
123
|
+
'--position-in-serializer [before|top|after|bottom]',
|
124
|
+
ANNOTATION_POSITIONS,
|
125
|
+
'Place the annotations at the top (before) or the bottom (after) of the serializer files') do |position_in_serializer|
|
126
|
+
env['position_in_serializer'] = position_in_serializer
|
127
|
+
has_set_position['position_in_serializer'] = true
|
128
|
+
end
|
129
|
+
|
130
|
+
option_parser.on('--w',
|
131
|
+
'--wrapper STR',
|
132
|
+
'Wrap annotation with the text passed as parameter.',
|
133
|
+
'If --w option is used, the same text will be used as opening and closing') do |wrapper|
|
134
|
+
env['wrapper'] = wrapper
|
135
|
+
end
|
136
|
+
|
137
|
+
option_parser.on('--wo',
|
138
|
+
'--wrapper-open STR',
|
139
|
+
'Annotation wrapper opening.') do |wrapper_open|
|
140
|
+
env['wrapper_open'] = wrapper_open
|
141
|
+
end
|
142
|
+
|
143
|
+
option_parser.on('--wc',
|
144
|
+
'--wrapper-close STR',
|
145
|
+
'Annotation wrapper closing') do |wrapper_close|
|
146
|
+
env['wrapper_close'] = wrapper_close
|
147
|
+
end
|
148
|
+
|
149
|
+
option_parser.on('-r',
|
150
|
+
'--routes',
|
151
|
+
"Annotate routes.rb with the output of 'rake routes'") do
|
152
|
+
env['routes'] = 'true'
|
153
|
+
end
|
154
|
+
|
155
|
+
option_parser.on('--models',
|
156
|
+
'Annotate ActiveRecord models') do
|
157
|
+
env['models'] = 'true'
|
158
|
+
end
|
159
|
+
|
160
|
+
option_parser.on('-a',
|
161
|
+
'--active-admin',
|
162
|
+
'Annotate active_admin models') do
|
163
|
+
env['active_admin'] = 'true'
|
164
|
+
end
|
165
|
+
|
166
|
+
option_parser.on('-v',
|
167
|
+
'--version',
|
168
|
+
'Show the current version of this gem') do
|
169
|
+
puts "annotate v#{Annotate.version}"
|
170
|
+
@options[:exit] = true
|
171
|
+
end
|
172
|
+
|
173
|
+
option_parser.on('-m',
|
174
|
+
'--show-migration',
|
175
|
+
'Include the migration version number in the annotation') do
|
176
|
+
env['include_version'] = 'yes'
|
177
|
+
end
|
178
|
+
|
179
|
+
option_parser.on('-c',
|
180
|
+
'--show-check-constraints',
|
181
|
+
"List the table's check constraints in the annotation") do
|
182
|
+
env['show_check_constraints'] = 'yes'
|
183
|
+
end
|
184
|
+
|
185
|
+
option_parser.on('-k',
|
186
|
+
'--show-foreign-keys',
|
187
|
+
"List the table's foreign key constraints in the annotation") do
|
188
|
+
env['show_foreign_keys'] = 'yes'
|
189
|
+
end
|
190
|
+
|
191
|
+
option_parser.on('--ck',
|
192
|
+
'--complete-foreign-keys',
|
193
|
+
'Complete foreign key names in the annotation') do
|
194
|
+
env['show_foreign_keys'] = 'yes'
|
195
|
+
env['show_complete_foreign_keys'] = 'yes'
|
196
|
+
end
|
197
|
+
|
198
|
+
option_parser.on('-i',
|
199
|
+
'--show-indexes',
|
200
|
+
"List the table's database indexes in the annotation") do
|
201
|
+
env['show_indexes'] = 'yes'
|
202
|
+
end
|
203
|
+
|
204
|
+
option_parser.on('-s',
|
205
|
+
'--simple-indexes',
|
206
|
+
"Concat the column's related indexes in the annotation") do
|
207
|
+
env['simple_indexes'] = 'yes'
|
208
|
+
end
|
209
|
+
|
210
|
+
option_parser.on('--model-dir dir',
|
211
|
+
'Annotate model files stored in dir rather than app/models, separate multiple dirs with commas') do |dir|
|
212
|
+
env['model_dir'] = dir
|
213
|
+
end
|
214
|
+
|
215
|
+
option_parser.on('--root-dir dir',
|
216
|
+
'Annotate files stored within root dir projects, separate multiple dirs with commas') do |dir|
|
217
|
+
env['root_dir'] = dir
|
218
|
+
end
|
219
|
+
|
220
|
+
option_parser.on('--ignore-model-subdirects',
|
221
|
+
'Ignore subdirectories of the models directory') do
|
222
|
+
env['ignore_model_sub_dir'] = 'yes'
|
223
|
+
end
|
224
|
+
|
225
|
+
option_parser.on('--sort',
|
226
|
+
'Sort columns alphabetically, rather than in creation order') do
|
227
|
+
env['sort'] = 'yes'
|
228
|
+
end
|
229
|
+
|
230
|
+
option_parser.on('--classified-sort',
|
231
|
+
'Sort columns alphabetically, but first goes id, then the rest columns, then the timestamp columns and then the association columns') do
|
232
|
+
env['classified_sort'] = 'yes'
|
233
|
+
end
|
234
|
+
|
235
|
+
option_parser.on('-R',
|
236
|
+
'--require path',
|
237
|
+
'Additional file to require before loading models, may be used multiple times') do |path|
|
238
|
+
env['require'] = if env['require'].present?
|
239
|
+
"#{env['require']},#{path}"
|
240
|
+
else
|
241
|
+
path
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
option_parser.on('-e',
|
246
|
+
'--exclude [tests,fixtures,factories,serializers]',
|
247
|
+
Array,
|
248
|
+
'Do not annotate fixtures, test files, factories, and/or serializers') do |exclusions|
|
249
|
+
exclusions ||= EXCLUSION_LIST
|
250
|
+
exclusions.each { |exclusion| env["exclude_#{exclusion}"] = 'yes' }
|
251
|
+
end
|
252
|
+
|
253
|
+
option_parser.on('-f',
|
254
|
+
'--format [bare|rdoc|yard|markdown]',
|
255
|
+
FORMAT_TYPES,
|
256
|
+
'Render Schema Infomation as plain/RDoc/Yard/Markdown') do |format_type|
|
257
|
+
env["format_#{format_type}"] = 'yes'
|
258
|
+
end
|
259
|
+
|
260
|
+
option_parser.on('--force',
|
261
|
+
'Force new annotations even if there are no changes.') do
|
262
|
+
env['force'] = 'yes'
|
263
|
+
end
|
264
|
+
|
265
|
+
option_parser.on('--frozen',
|
266
|
+
'Do not allow to change annotations. Exits non-zero if there are going to be changes to files.') do
|
267
|
+
env['frozen'] = 'yes'
|
268
|
+
end
|
269
|
+
|
270
|
+
option_parser.on('--timestamp',
|
271
|
+
'Include timestamp in (routes) annotation') do
|
272
|
+
env['timestamp'] = 'true'
|
273
|
+
end
|
274
|
+
|
275
|
+
option_parser.on('--trace',
|
276
|
+
'If unable to annotate a file, print the full stack trace, not just the exception message.') do
|
277
|
+
env['trace'] = 'yes'
|
278
|
+
end
|
279
|
+
|
280
|
+
option_parser.on('-I',
|
281
|
+
'--ignore-columns REGEX',
|
282
|
+
"don't annotate columns that match a given REGEX (i.e., `annotate -I '^(id|updated_at|created_at)'`") do |regex|
|
283
|
+
env['ignore_columns'] = regex
|
284
|
+
end
|
285
|
+
|
286
|
+
option_parser.on('--ignore-routes REGEX',
|
287
|
+
"don't annotate routes that match a given REGEX (i.e., `annotate -I '(mobile|resque|pghero)'`") do |regex|
|
288
|
+
env['ignore_routes'] = regex
|
289
|
+
end
|
290
|
+
|
291
|
+
option_parser.on('--hide-limit-column-types VALUES',
|
292
|
+
"don't show limit for given column types, separated by commas (i.e., `integer,boolean,text`)") do |values|
|
293
|
+
env['hide_limit_column_types'] = values.to_s
|
294
|
+
end
|
295
|
+
|
296
|
+
option_parser.on('--hide-default-column-types VALUES',
|
297
|
+
"don't show default for given column types, separated by commas (i.e., `json,jsonb,hstore`)") do |values|
|
298
|
+
env['hide_default_column_types'] = values.to_s
|
299
|
+
end
|
300
|
+
|
301
|
+
option_parser.on('--ignore-unknown-models',
|
302
|
+
"don't display warnings for bad model files") do
|
303
|
+
env['ignore_unknown_models'] = 'true'
|
304
|
+
end
|
305
|
+
|
306
|
+
option_parser.on('--with-comment',
|
307
|
+
'include database comments in model annotations') do
|
308
|
+
env['with_comment'] = 'true'
|
309
|
+
end
|
310
|
+
|
311
|
+
option_parser.on('--with-comment-column',
|
312
|
+
'include database comments in model annotations, as its own column, after all others') do
|
313
|
+
env['with_comment_column'] = 'true'
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|