annotate 3.0.2 → 3.2.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.
@@ -1,5 +1,3 @@
1
- # rubocop:disable Metrics/ModuleLength
2
-
3
1
  # == Annotate Routes
4
2
  #
5
3
  # Based on:
@@ -19,145 +17,73 @@
19
17
  #
20
18
  # Released under the same license as Ruby. No Support. No Warranty.
21
19
  #
22
- module AnnotateRoutes
23
- PREFIX = '== Route Map'.freeze
24
- PREFIX_MD = '## Route Map'.freeze
25
- HEADER_ROW = ['Prefix', 'Verb', 'URI Pattern', 'Controller#Action']
26
20
 
21
+ require_relative './annotate_routes/helpers'
22
+ require_relative './annotate_routes/header_generator'
23
+
24
+ module AnnotateRoutes
27
25
  class << self
28
26
  def do_annotations(options = {})
29
- return unless routes_exists?
30
- existing_text = File.read(routes_file)
31
-
32
- if rewrite_contents_with_header(existing_text, header(options), options)
33
- puts "#{routes_file} annotated."
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
+
33
+ if rewrite_contents(existing_text, new_text)
34
+ puts "#{routes_file} was annotated."
35
+ else
36
+ puts "#{routes_file} was not changed."
37
+ end
38
+ else
39
+ puts "#{routes_file} could not be found."
34
40
  end
35
41
  end
36
42
 
37
43
  def remove_annotations(_options={})
38
- return unless routes_exists?
39
- existing_text = File.read(routes_file)
40
- content, where_header_found = strip_annotations(existing_text)
41
- new_content = strip_on_removal(content, where_header_found)
42
- if rewrite_contents(existing_text, new_content)
43
- puts "Removed annotations from #{routes_file}."
44
+ if routes_file_exist?
45
+ existing_text = File.read(routes_file)
46
+ content, header_position = Helpers.strip_annotations(existing_text)
47
+ new_content = strip_on_removal(content, header_position)
48
+ new_text = new_content.join("\n")
49
+ if rewrite_contents(existing_text, new_text)
50
+ puts "Annotations were removed from #{routes_file}."
51
+ else
52
+ puts "#{routes_file} was not changed (Annotation did not exist)."
53
+ end
54
+ else
55
+ puts "#{routes_file} could not be found."
44
56
  end
45
57
  end
46
58
 
47
59
  private
48
60
 
49
- def routes_exists?
50
- routes_exists = File.exists?(routes_file)
51
- puts "Can't find routes.rb" unless routes_exists
52
-
53
- routes_exists
61
+ def routes_file_exist?
62
+ File.exist?(routes_file)
54
63
  end
55
64
 
56
65
  def routes_file
57
66
  @routes_rb ||= File.join('config', 'routes.rb')
58
67
  end
59
68
 
60
- def rewrite_contents_with_header(existing_text, header, options = {})
61
- content, where_header_found = strip_annotations(existing_text)
62
- new_content = annotate_routes(header, content, where_header_found, options)
63
-
64
- # Make sure we end on a trailing newline.
65
- new_content << '' unless new_content.last == ''
66
- new_text = new_content.join("\n")
67
-
68
- if existing_text == new_text
69
- puts "#{routes_file} unchanged."
70
- false
71
- else
72
- File.open(routes_file, 'wb') { |f| f.puts(new_text) }
73
- true
74
- end
75
- end
76
-
77
- def header(options = {})
78
- routes_map = app_routes_map(options)
79
-
80
- magic_comments_map, routes_map = extract_magic_comments_from_array(routes_map)
81
-
82
- out = []
83
-
84
- magic_comments_map.each do |magic_comment|
85
- out << magic_comment
86
- end
87
- out << '' if magic_comments_map.any?
88
-
89
- out += ["# #{options[:wrapper_open]}"] if options[:wrapper_open]
90
-
91
- out += ["# #{options[:format_markdown] ? PREFIX_MD : PREFIX}" + (options[:timestamp] ? " (Updated #{Time.now.strftime('%Y-%m-%d %H:%M')})" : '')]
92
- out += ['#']
93
- return out if routes_map.size.zero?
94
-
95
- maxs = [HEADER_ROW.map(&:size)] + routes_map[1..-1].map { |line| line.split.map(&:size) }
96
-
97
- if options[:format_markdown]
98
- max = maxs.map(&:max).compact.max
99
-
100
- out += ["# #{content(HEADER_ROW, maxs, options)}"]
101
- out += ["# #{content(['-' * max, '-' * max, '-' * max, '-' * max], maxs, options)}"]
102
- else
103
- out += ["# #{content(routes_map[0], maxs, options)}"]
104
- end
105
-
106
- out += routes_map[1..-1].map { |line| "# #{content(options[:format_markdown] ? line.split(' ') : line, maxs, options)}" }
107
- out += ["# #{options[:wrapper_close]}"] if options[:wrapper_close]
108
-
109
- out
110
- end
111
-
112
- # TODO: write the method doc using ruby rdoc formats
113
- # where_header_found => This will either be :before, :after, or
114
- # a number. If the number is > 0, the
115
- # annotation was found somewhere in the
116
- # middle of the file. If the number is
117
- # zero, no annotation was found.
118
- def strip_annotations(content)
119
- real_content = []
120
- mode = :content
121
- header_found_at = 0
122
-
123
- content.split(/\n/, -1).each_with_index do |line, line_number|
124
- if mode == :header && line !~ /\s*#/
125
- mode = :content
126
- real_content << line unless line.blank?
127
- elsif mode == :content
128
- if line =~ /^\s*#\s*== Route.*$/
129
- header_found_at = line_number + 1 # index start's at 0
130
- mode = :header
131
- else
132
- real_content << line
133
- end
134
- end
135
- end
136
-
137
- where_header_found(real_content, header_found_at)
138
- end
139
-
140
- def strip_on_removal(content, where_header_found)
141
- if where_header_found == :before
69
+ def strip_on_removal(content, header_position)
70
+ if header_position == :before
142
71
  content.shift while content.first == ''
143
- elsif where_header_found == :after
72
+ elsif header_position == :after
144
73
  content.pop while content.last == ''
145
74
  end
146
75
 
76
+ # Make sure we end on a trailing newline.
77
+ content << '' unless content.last == ''
78
+
147
79
  # TODO: If the user buried it in the middle, we should probably see about
148
80
  # TODO: preserving a single line of space between the content above and
149
81
  # TODO: below...
150
82
  content
151
83
  end
152
84
 
153
- # @param [String, Array<String>]
154
- def rewrite_contents(existing_text, new_content)
155
- # Make sure we end on a trailing newline.
156
- new_content << '' unless new_content.last == ''
157
- new_text = new_content.join("\n")
158
-
85
+ def rewrite_contents(existing_text, new_text)
159
86
  if existing_text == new_text
160
- puts "#{routes_file} unchanged."
161
87
  false
162
88
  else
163
89
  File.open(routes_file, 'wb') { |f| f.puts(new_text) }
@@ -165,8 +91,8 @@ module AnnotateRoutes
165
91
  end
166
92
  end
167
93
 
168
- def annotate_routes(header, content, where_header_found, options = {})
169
- magic_comments_map, content = extract_magic_comments_from_array(content)
94
+ def annotate_routes(header, content, header_position, options = {})
95
+ magic_comments_map, content = Helpers.extract_magic_comments_from_array(content)
170
96
  if %w(before top).include?(options[:position_in_routes])
171
97
  header = header << '' if content.first != ''
172
98
  magic_comments_map << '' if magic_comments_map.any?
@@ -178,74 +104,15 @@ module AnnotateRoutes
178
104
 
179
105
  # We're moving something from the top of the file to the bottom, so ditch
180
106
  # the spacer we put in the first time around.
181
- content.shift if where_header_found == :before && content.first == ''
107
+ content.shift if header_position == :before && content.first == ''
182
108
 
183
109
  new_content = magic_comments_map + content + header
184
110
  end
185
111
 
186
- new_content
187
- end
188
-
189
- def app_routes_map(options)
190
- routes_map = `rake routes`.chomp("\n").split(/\n/, -1)
191
-
192
- # In old versions of Rake, the first line of output was the cwd. Not so
193
- # much in newer ones. We ditch that line if it exists, and if not, we
194
- # keep the line around.
195
- routes_map.shift if routes_map.first =~ /^\(in \//
196
-
197
- # Skip routes which match given regex
198
- # Note: it matches the complete line (route_name, path, controller/action)
199
- if options[:ignore_routes]
200
- routes_map.reject! { |line| line =~ /#{options[:ignore_routes]}/ }
201
- end
202
-
203
- routes_map
204
- end
205
-
206
- # @param [Array<String>] content
207
- # @return [Array<String>] all found magic comments
208
- # @return [Array<String>] content without magic comments
209
- def extract_magic_comments_from_array(content_array)
210
- magic_comments = []
211
- new_content = []
212
-
213
- content_array.map do |row|
214
- if row =~ magic_comment_matcher
215
- magic_comments << row.strip
216
- else
217
- new_content << row
218
- end
219
- end
220
-
221
- [magic_comments, new_content]
222
- end
223
-
224
- def content(line, maxs, options = {})
225
- return line.rstrip unless options[:format_markdown]
226
-
227
- line.each_with_index.map do |elem, index|
228
- min_length = maxs.map { |arr| arr[index] }.max || 0
229
-
230
- sprintf("%-#{min_length}.#{min_length}s", elem.tr('|', '-'))
231
- end.join(' | ')
232
- end
233
-
234
- def where_header_found(real_content, header_found_at)
235
- # By default assume the annotation was found in the middle of the file
236
-
237
- # ... unless we have evidence it was at the beginning ...
238
- return real_content, :before if header_found_at == 1
239
-
240
- # ... or that it was at the end.
241
- return real_content, :after if header_found_at >= real_content.count
242
-
243
- # and the default
244
- return real_content, header_found_at
245
- end
112
+ # Make sure we end on a trailing newline.
113
+ new_content << '' unless new_content.last == ''
246
114
 
247
- def magic_comment_matcher
248
- Regexp.new(/(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/)
115
+ new_content
249
116
  end
250
117
  end
251
118
  end
@@ -1,5 +1,38 @@
1
1
  module Annotate
2
2
  module Constants
3
3
  TRUE_RE = /^(true|t|yes|y|1)$/i.freeze
4
+
5
+ ##
6
+ # The set of available options to customize the behavior of Annotate.
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
22
+ ].freeze
23
+
24
+ OTHER_OPTIONS = [
25
+ :additional_file_patterns, :ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close,
26
+ :wrapper, :routes, :models, :hide_limit_column_types, :hide_default_column_types,
27
+ :ignore_routes, :active_admin
28
+ ].freeze
29
+
30
+ PATH_OPTIONS = [
31
+ :require, :model_dir, :root_dir
32
+ ].freeze
33
+
34
+ ALL_ANNOTATE_OPTIONS = [
35
+ POSITION_OPTIONS, FLAG_OPTIONS, OTHER_OPTIONS, PATH_OPTIONS
36
+ ].freeze
4
37
  end
5
38
  end
@@ -0,0 +1,30 @@
1
+ module Annotate
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