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