annotaterb 4.0.0.beta.1
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/CHANGELOG.md +0 -0
- data/LICENSE.txt +55 -0
- data/README.md +91 -0
- data/VERSION +1 -0
- data/exe/annotaterb +21 -0
- data/lib/annotate_rb/active_record_patch.rb +9 -0
- data/lib/annotate_rb/commands/annotate_models.rb +22 -0
- data/lib/annotate_rb/commands/annotate_routes.rb +19 -0
- data/lib/annotate_rb/commands/print_help.rb +16 -0
- data/lib/annotate_rb/commands/print_version.rb +12 -0
- data/lib/annotate_rb/commands.rb +10 -0
- data/lib/annotate_rb/config_finder.rb +21 -0
- data/lib/annotate_rb/config_loader.rb +63 -0
- data/lib/annotate_rb/core.rb +23 -0
- data/lib/annotate_rb/eager_loader.rb +23 -0
- data/lib/annotate_rb/env.rb +30 -0
- data/lib/annotate_rb/model_annotator/annotation_pattern_generator.rb +19 -0
- data/lib/annotate_rb/model_annotator/annotator.rb +74 -0
- data/lib/annotate_rb/model_annotator/bad_model_file_error.rb +11 -0
- data/lib/annotate_rb/model_annotator/constants.rb +22 -0
- data/lib/annotate_rb/model_annotator/file_annotation_remover.rb +25 -0
- data/lib/annotate_rb/model_annotator/file_annotator.rb +79 -0
- data/lib/annotate_rb/model_annotator/file_name_resolver.rb +16 -0
- data/lib/annotate_rb/model_annotator/file_patterns.rb +129 -0
- data/lib/annotate_rb/model_annotator/helper.rb +54 -0
- data/lib/annotate_rb/model_annotator/model_class_getter.rb +63 -0
- data/lib/annotate_rb/model_annotator/model_file_annotator.rb +118 -0
- data/lib/annotate_rb/model_annotator/model_files_getter.rb +62 -0
- data/lib/annotate_rb/model_annotator/pattern_getter.rb +27 -0
- data/lib/annotate_rb/model_annotator/schema_info.rb +480 -0
- data/lib/annotate_rb/model_annotator.rb +20 -0
- data/lib/annotate_rb/options.rb +204 -0
- data/lib/annotate_rb/parser.rb +385 -0
- data/lib/annotate_rb/rake_bootstrapper.rb +34 -0
- data/lib/annotate_rb/route_annotator/annotation_processor.rb +56 -0
- data/lib/annotate_rb/route_annotator/annotator.rb +40 -0
- data/lib/annotate_rb/route_annotator/base_processor.rb +104 -0
- data/lib/annotate_rb/route_annotator/header_generator.rb +113 -0
- data/lib/annotate_rb/route_annotator/helper.rb +104 -0
- data/lib/annotate_rb/route_annotator/removal_processor.rb +40 -0
- data/lib/annotate_rb/route_annotator.rb +12 -0
- data/lib/annotate_rb/runner.rb +34 -0
- data/lib/annotate_rb/tasks/annotate_models_migrate.rake +30 -0
- data/lib/annotate_rb.rb +30 -0
- data/lib/generators/annotate_rb/USAGE +4 -0
- data/lib/generators/annotate_rb/install_generator.rb +15 -0
- data/lib/generators/annotate_rb/templates/auto_annotate_models.rake +7 -0
- metadata +96 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class FileNameResolver
|
6
|
+
class << self
|
7
|
+
def call(filename_template, model_name, table_name)
|
8
|
+
filename_template
|
9
|
+
.gsub('%MODEL_NAME%', model_name)
|
10
|
+
.gsub('%PLURALIZED_MODEL_NAME%', model_name.pluralize)
|
11
|
+
.gsub('%TABLE_NAME%', table_name || model_name.pluralize)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module AnnotateRb
|
2
|
+
module ModelAnnotator
|
3
|
+
# This module provides module method to get file paths.
|
4
|
+
module FilePatterns
|
5
|
+
# Controller files
|
6
|
+
CONTROLLER_DIR = File.join('app', 'controllers')
|
7
|
+
|
8
|
+
# Active admin registry files
|
9
|
+
ACTIVEADMIN_DIR = File.join('app', 'admin')
|
10
|
+
|
11
|
+
# Helper files
|
12
|
+
HELPER_DIR = File.join('app', 'helpers')
|
13
|
+
|
14
|
+
# File.join for windows reverse bar compat?
|
15
|
+
# I dont use windows, can`t test
|
16
|
+
UNIT_TEST_DIR = File.join('test', 'unit')
|
17
|
+
MODEL_TEST_DIR = File.join('test', 'models') # since rails 4.0
|
18
|
+
SPEC_MODEL_DIR = File.join('spec', 'models')
|
19
|
+
|
20
|
+
FIXTURE_TEST_DIR = File.join('test', 'fixtures')
|
21
|
+
FIXTURE_SPEC_DIR = File.join('spec', 'fixtures')
|
22
|
+
|
23
|
+
# Other test files
|
24
|
+
CONTROLLER_TEST_DIR = File.join('test', 'controllers')
|
25
|
+
CONTROLLER_SPEC_DIR = File.join('spec', 'controllers')
|
26
|
+
REQUEST_SPEC_DIR = File.join('spec', 'requests')
|
27
|
+
ROUTING_SPEC_DIR = File.join('spec', 'routing')
|
28
|
+
|
29
|
+
# Object Daddy http://github.com/flogic/object_daddy/tree/master
|
30
|
+
EXEMPLARS_TEST_DIR = File.join('test', 'exemplars')
|
31
|
+
EXEMPLARS_SPEC_DIR = File.join('spec', 'exemplars')
|
32
|
+
|
33
|
+
# Machinist http://github.com/notahat/machinist
|
34
|
+
BLUEPRINTS_TEST_DIR = File.join('test', 'blueprints')
|
35
|
+
BLUEPRINTS_SPEC_DIR = File.join('spec', 'blueprints')
|
36
|
+
|
37
|
+
# Factory Bot https://github.com/thoughtbot/factory_bot
|
38
|
+
FACTORY_BOT_TEST_DIR = File.join('test', 'factories')
|
39
|
+
FACTORY_BOT_SPEC_DIR = File.join('spec', 'factories')
|
40
|
+
|
41
|
+
# Fabrication https://github.com/paulelliott/fabrication.git
|
42
|
+
FABRICATORS_TEST_DIR = File.join('test', 'fabricators')
|
43
|
+
FABRICATORS_SPEC_DIR = File.join('spec', 'fabricators')
|
44
|
+
|
45
|
+
# Serializers https://github.com/rails-api/active_model_serializers
|
46
|
+
SERIALIZERS_DIR = File.join('app', 'serializers')
|
47
|
+
SERIALIZERS_TEST_DIR = File.join('test', 'serializers')
|
48
|
+
SERIALIZERS_SPEC_DIR = File.join('spec', 'serializers')
|
49
|
+
|
50
|
+
class << self
|
51
|
+
def generate(root_directory, pattern_type, options)
|
52
|
+
case pattern_type
|
53
|
+
when 'test' then test_files(root_directory)
|
54
|
+
when 'fixture' then fixture_files(root_directory)
|
55
|
+
when 'scaffold' then scaffold_files(root_directory)
|
56
|
+
when 'factory' then factory_files(root_directory)
|
57
|
+
when 'serializer' then serialize_files(root_directory)
|
58
|
+
when 'additional_file_patterns'
|
59
|
+
[options[:additional_file_patterns] || []].flatten
|
60
|
+
when 'controller'
|
61
|
+
[File.join(root_directory, CONTROLLER_DIR, '%PLURALIZED_MODEL_NAME%_controller.rb')]
|
62
|
+
when 'admin'
|
63
|
+
[
|
64
|
+
File.join(root_directory, ACTIVEADMIN_DIR, '%MODEL_NAME%.rb'),
|
65
|
+
File.join(root_directory, ACTIVEADMIN_DIR, '%PLURALIZED_MODEL_NAME%.rb')
|
66
|
+
]
|
67
|
+
when 'helper'
|
68
|
+
[File.join(root_directory, HELPER_DIR, '%PLURALIZED_MODEL_NAME%_helper.rb')]
|
69
|
+
else
|
70
|
+
[]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def test_files(root_directory)
|
77
|
+
[
|
78
|
+
File.join(root_directory, UNIT_TEST_DIR, '%MODEL_NAME%_test.rb'),
|
79
|
+
File.join(root_directory, MODEL_TEST_DIR, '%MODEL_NAME%_test.rb'),
|
80
|
+
File.join(root_directory, SPEC_MODEL_DIR, '%MODEL_NAME%_spec.rb')
|
81
|
+
]
|
82
|
+
end
|
83
|
+
|
84
|
+
def fixture_files(root_directory)
|
85
|
+
[
|
86
|
+
File.join(root_directory, FIXTURE_TEST_DIR, '%TABLE_NAME%.yml'),
|
87
|
+
File.join(root_directory, FIXTURE_SPEC_DIR, '%TABLE_NAME%.yml'),
|
88
|
+
File.join(root_directory, FIXTURE_TEST_DIR, '%PLURALIZED_MODEL_NAME%.yml'),
|
89
|
+
File.join(root_directory, FIXTURE_SPEC_DIR, '%PLURALIZED_MODEL_NAME%.yml')
|
90
|
+
]
|
91
|
+
end
|
92
|
+
|
93
|
+
def scaffold_files(root_directory)
|
94
|
+
[
|
95
|
+
File.join(root_directory, CONTROLLER_TEST_DIR, '%PLURALIZED_MODEL_NAME%_controller_test.rb'),
|
96
|
+
File.join(root_directory, CONTROLLER_SPEC_DIR, '%PLURALIZED_MODEL_NAME%_controller_spec.rb'),
|
97
|
+
File.join(root_directory, REQUEST_SPEC_DIR, '%PLURALIZED_MODEL_NAME%_spec.rb'),
|
98
|
+
File.join(root_directory, ROUTING_SPEC_DIR, '%PLURALIZED_MODEL_NAME%_routing_spec.rb')
|
99
|
+
]
|
100
|
+
end
|
101
|
+
|
102
|
+
def factory_files(root_directory)
|
103
|
+
[
|
104
|
+
File.join(root_directory, EXEMPLARS_TEST_DIR, '%MODEL_NAME%_exemplar.rb'),
|
105
|
+
File.join(root_directory, EXEMPLARS_SPEC_DIR, '%MODEL_NAME%_exemplar.rb'),
|
106
|
+
File.join(root_directory, BLUEPRINTS_TEST_DIR, '%MODEL_NAME%_blueprint.rb'),
|
107
|
+
File.join(root_directory, BLUEPRINTS_SPEC_DIR, '%MODEL_NAME%_blueprint.rb'),
|
108
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, '%MODEL_NAME%_factory.rb'), # (old style)
|
109
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, '%MODEL_NAME%_factory.rb'), # (old style)
|
110
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, '%TABLE_NAME%.rb'), # (new style)
|
111
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, '%TABLE_NAME%.rb'), # (new style)
|
112
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, '%PLURALIZED_MODEL_NAME%.rb'), # (new style)
|
113
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, '%PLURALIZED_MODEL_NAME%.rb'), # (new style)
|
114
|
+
File.join(root_directory, FABRICATORS_TEST_DIR, '%MODEL_NAME%_fabricator.rb'),
|
115
|
+
File.join(root_directory, FABRICATORS_SPEC_DIR, '%MODEL_NAME%_fabricator.rb')
|
116
|
+
]
|
117
|
+
end
|
118
|
+
|
119
|
+
def serialize_files(root_directory)
|
120
|
+
[
|
121
|
+
File.join(root_directory, SERIALIZERS_DIR, '%MODEL_NAME%_serializer.rb'),
|
122
|
+
File.join(root_directory, SERIALIZERS_TEST_DIR, '%MODEL_NAME%_serializer_test.rb'),
|
123
|
+
File.join(root_directory, SERIALIZERS_SPEC_DIR, '%MODEL_NAME%_serializer_spec.rb')
|
124
|
+
]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
module Helper
|
6
|
+
MATCHED_TYPES = %w(test fixture factory serializer scaffold controller helper).freeze
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def matched_types(options)
|
10
|
+
types = MATCHED_TYPES.dup
|
11
|
+
types << 'admin' if options[:active_admin] =~ Constants::TRUE_RE && !types.include?('admin')
|
12
|
+
types << 'additional_file_patterns' if options[:additional_file_patterns].present?
|
13
|
+
|
14
|
+
types
|
15
|
+
end
|
16
|
+
|
17
|
+
def magic_comments_as_string(content)
|
18
|
+
magic_comments = content.scan(Annotator::MAGIC_COMMENT_MATCHER).flatten.compact
|
19
|
+
|
20
|
+
if magic_comments.any?
|
21
|
+
magic_comments.join
|
22
|
+
else
|
23
|
+
''
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def skip_on_migration?
|
28
|
+
Env.read('ANNOTATE_SKIP_ON_DB_MIGRATE') =~ Constants::TRUE_RE || Env.read('skip_on_db_migrate') =~ Constants::TRUE_RE
|
29
|
+
end
|
30
|
+
|
31
|
+
def include_routes?
|
32
|
+
Env.read('routes') =~ Constants::TRUE_RE
|
33
|
+
end
|
34
|
+
|
35
|
+
def include_models?
|
36
|
+
Env.read('models') =~ Constants::TRUE_RE
|
37
|
+
end
|
38
|
+
|
39
|
+
def true?(val)
|
40
|
+
val.present? && Constants::TRUE_RE.match?(val)
|
41
|
+
end
|
42
|
+
|
43
|
+
# TODO: Find another implementation that doesn't depend on ActiveSupport
|
44
|
+
def fallback(*args)
|
45
|
+
args.compact.detect(&:present?)
|
46
|
+
end
|
47
|
+
|
48
|
+
def reset_options(options)
|
49
|
+
options.flatten.each { |key| Env.write(key, nil) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class ModelClassGetter
|
6
|
+
class << self
|
7
|
+
# Retrieve the classes belonging to the model names we're asked to process
|
8
|
+
# Check for namespaced models in subdirectories as well as models
|
9
|
+
# in subdirectories without namespacing.
|
10
|
+
def call(file, options)
|
11
|
+
model_path = file.gsub(/\.rb$/, '')
|
12
|
+
options[:model_dir].each { |dir| model_path = model_path.gsub(/^#{dir}/, '').gsub(/^\//, '') }
|
13
|
+
|
14
|
+
begin
|
15
|
+
get_loaded_model(model_path, file) || raise(BadModelFileError.new)
|
16
|
+
rescue LoadError
|
17
|
+
# this is for non-rails projects, which don't get Rails auto-require magic
|
18
|
+
file_path = File.expand_path(file)
|
19
|
+
if File.file?(file_path) && Kernel.require(file_path)
|
20
|
+
retry
|
21
|
+
elsif model_path =~ /\//
|
22
|
+
model_path = model_path.split('/')[1..-1].join('/').to_s
|
23
|
+
retry
|
24
|
+
else
|
25
|
+
raise
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Retrieve loaded model class
|
33
|
+
def get_loaded_model(model_path, file)
|
34
|
+
loaded_model_class = get_loaded_model_by_path(model_path)
|
35
|
+
return loaded_model_class if loaded_model_class
|
36
|
+
|
37
|
+
# We cannot get loaded model when `model_path` is loaded by Rails
|
38
|
+
# auto_load/eager_load paths. Try all possible model paths one by one.
|
39
|
+
absolute_file = File.expand_path(file)
|
40
|
+
model_paths =
|
41
|
+
$LOAD_PATH.select { |path| absolute_file.include?(path) }
|
42
|
+
.map { |path| absolute_file.sub(path, '').sub(/\.rb$/, '').sub(/^\//, '') }
|
43
|
+
model_paths
|
44
|
+
.map { |path| get_loaded_model_by_path(path) }
|
45
|
+
.find { |loaded_model| !loaded_model.nil? }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Retrieve loaded model class by path to the file where it's supposed to be defined.
|
49
|
+
def get_loaded_model_by_path(model_path)
|
50
|
+
::ActiveSupport::Inflector.constantize(::ActiveSupport::Inflector.camelize(model_path))
|
51
|
+
rescue StandardError, LoadError
|
52
|
+
# Revert to the old way but it is not really robust
|
53
|
+
ObjectSpace.each_object(::Class)
|
54
|
+
.select do |c|
|
55
|
+
Class === c && # note: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a?
|
56
|
+
c.ancestors.respond_to?(:include?) && # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82
|
57
|
+
c.ancestors.include?(::ActiveRecord::Base)
|
58
|
+
end.detect { |c| ::ActiveSupport::Inflector.underscore(c.to_s) == model_path }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
# Not sure yet what the difference is between this and FileAnnotator
|
6
|
+
class ModelFileAnnotator
|
7
|
+
class << self
|
8
|
+
def call(annotated, file, header, options)
|
9
|
+
begin
|
10
|
+
return false if /#{Constants::SKIP_ANNOTATION_PREFIX}.*/ =~ (File.exist?(file) ? File.read(file) : '')
|
11
|
+
klass = ModelClassGetter.call(file, options)
|
12
|
+
|
13
|
+
klass_is_a_class = klass.is_a?(Class)
|
14
|
+
klass_inherits_active_record_base = klass < ActiveRecord::Base
|
15
|
+
klass_is_not_abstract = !klass.abstract_class?
|
16
|
+
klass_table_exists = klass.table_exists?
|
17
|
+
|
18
|
+
not_sure_this_conditional = (!options[:exclude_sti_subclasses] || !(klass.superclass < ActiveRecord::Base && klass.table_name == klass.superclass.table_name))
|
19
|
+
|
20
|
+
annotate_conditions = [
|
21
|
+
klass_is_a_class,
|
22
|
+
klass_inherits_active_record_base,
|
23
|
+
not_sure_this_conditional,
|
24
|
+
klass_is_not_abstract,
|
25
|
+
klass_table_exists
|
26
|
+
]
|
27
|
+
|
28
|
+
do_annotate = annotate_conditions.all?
|
29
|
+
|
30
|
+
if do_annotate
|
31
|
+
files_annotated = annotate(klass, file, header, options)
|
32
|
+
annotated.concat(files_annotated)
|
33
|
+
end
|
34
|
+
|
35
|
+
rescue BadModelFileError => e
|
36
|
+
unless options[:ignore_unknown_models]
|
37
|
+
$stderr.puts "Unable to annotate #{file}: #{e.message}"
|
38
|
+
$stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace]
|
39
|
+
end
|
40
|
+
rescue StandardError => e
|
41
|
+
$stderr.puts "Unable to annotate #{file}: #{e.message}"
|
42
|
+
$stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Given the name of an ActiveRecord class, create a schema
|
49
|
+
# info block (basically a comment containing information
|
50
|
+
# on the columns and their types) and put it at the front
|
51
|
+
# of the model and fixture source files.
|
52
|
+
#
|
53
|
+
# === Options (opts)
|
54
|
+
# :position_in_class<Symbol>:: where to place the annotated section in model file
|
55
|
+
# :position_in_test<Symbol>:: where to place the annotated section in test/spec file(s)
|
56
|
+
# :position_in_fixture<Symbol>:: where to place the annotated section in fixture file
|
57
|
+
# :position_in_factory<Symbol>:: where to place the annotated section in factory file
|
58
|
+
# :position_in_serializer<Symbol>:: where to place the annotated section in serializer file
|
59
|
+
# :exclude_tests<Symbol>:: whether to skip modification of test/spec files
|
60
|
+
# :exclude_fixtures<Symbol>:: whether to skip modification of fixture files
|
61
|
+
# :exclude_factories<Symbol>:: whether to skip modification of factory files
|
62
|
+
# :exclude_serializers<Symbol>:: whether to skip modification of serializer files
|
63
|
+
# :exclude_scaffolds<Symbol>:: whether to skip modification of scaffold files
|
64
|
+
# :exclude_controllers<Symbol>:: whether to skip modification of controller files
|
65
|
+
# :exclude_helpers<Symbol>:: whether to skip modification of helper files
|
66
|
+
# :exclude_sti_subclasses<Symbol>:: whether to skip modification of files for STI subclasses
|
67
|
+
#
|
68
|
+
# == Returns:
|
69
|
+
# an array of file names that were annotated.
|
70
|
+
#
|
71
|
+
def annotate(klass, file, header, options = {})
|
72
|
+
begin
|
73
|
+
klass.reset_column_information
|
74
|
+
info = SchemaInfo.generate(klass, header, options)
|
75
|
+
model_name = klass.name.underscore
|
76
|
+
table_name = klass.table_name
|
77
|
+
model_file_name = File.join(file)
|
78
|
+
annotated = []
|
79
|
+
|
80
|
+
if FileAnnotator.call(model_file_name, info, :position_in_class, options)
|
81
|
+
annotated << model_file_name
|
82
|
+
end
|
83
|
+
|
84
|
+
Helper.matched_types(options).each do |key|
|
85
|
+
exclusion_key = "exclude_#{key.pluralize}".to_sym
|
86
|
+
position_key = "position_in_#{key}".to_sym
|
87
|
+
|
88
|
+
# Same options for active_admin models
|
89
|
+
if key == 'admin'
|
90
|
+
exclusion_key = 'exclude_class'.to_sym
|
91
|
+
position_key = 'position_in_class'.to_sym
|
92
|
+
end
|
93
|
+
|
94
|
+
next if options[exclusion_key]
|
95
|
+
|
96
|
+
patterns = PatternGetter.call(options, key)
|
97
|
+
|
98
|
+
patterns
|
99
|
+
.map { |f| FileNameResolver.call(f, model_name, table_name) }
|
100
|
+
.map { |f| Dir.glob(f) }
|
101
|
+
.flatten
|
102
|
+
.each do |f|
|
103
|
+
if FileAnnotator.call(f, info, position_key, options)
|
104
|
+
annotated << f
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
rescue StandardError => e
|
109
|
+
$stderr.puts "Unable to annotate #{file}: #{e.message}"
|
110
|
+
$stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace]
|
111
|
+
end
|
112
|
+
|
113
|
+
annotated
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class ModelFilesGetter
|
6
|
+
class << self
|
7
|
+
# Return a list of the model files to annotate.
|
8
|
+
# If we have command line arguments, they're assumed to the path
|
9
|
+
# of model files from root dir. Otherwise we take all the model files
|
10
|
+
# in the model_dir directory.
|
11
|
+
def call(options)
|
12
|
+
model_files = []
|
13
|
+
|
14
|
+
model_files = list_model_files_from_argument(options) if !options[:is_rake]
|
15
|
+
|
16
|
+
return model_files if !model_files.empty?
|
17
|
+
|
18
|
+
options[:model_dir].each do |dir|
|
19
|
+
Dir.chdir(dir) do
|
20
|
+
list = if options[:ignore_model_sub_dir]
|
21
|
+
Dir["*.rb"].map { |f| [dir, f] }
|
22
|
+
else
|
23
|
+
Dir["**/*.rb"].reject { |f| f["concerns/"] }.map { |f| [dir, f] }
|
24
|
+
end
|
25
|
+
model_files.concat(list)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
model_files
|
30
|
+
rescue SystemCallError
|
31
|
+
$stderr.puts "No models found in directory '#{options[:model_dir].join("', '")}'."
|
32
|
+
$stderr.puts "Either specify models on the command line, or use the --model-dir option."
|
33
|
+
$stderr.puts "Call 'annotate --help' for more info."
|
34
|
+
# exit 1 # TODO: Return exit code back to caller. Right now it messes up RSpec being able to run
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def list_model_files_from_argument(options)
|
40
|
+
return [] if ARGV.empty?
|
41
|
+
|
42
|
+
specified_files = ARGV.map { |file| File.expand_path(file) }
|
43
|
+
|
44
|
+
model_files = options[:model_dir].flat_map do |dir|
|
45
|
+
absolute_dir_path = File.expand_path(dir)
|
46
|
+
specified_files
|
47
|
+
.find_all { |file| file.start_with?(absolute_dir_path) }
|
48
|
+
.map { |file| [dir, file.sub("#{absolute_dir_path}/", '')] }
|
49
|
+
end
|
50
|
+
|
51
|
+
if model_files.size != specified_files.size
|
52
|
+
$stderr.puts "The specified file could not be found in directory '#{options[:model_dir].join("', '")}'."
|
53
|
+
$stderr.puts "Call 'annotate --help' for more info."
|
54
|
+
# exit 1 # TODO: Return exit code back to caller. Right now it messes up RSpec being able to run
|
55
|
+
end
|
56
|
+
|
57
|
+
model_files
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class PatternGetter
|
6
|
+
class << self
|
7
|
+
def call(options, pattern_types = [])
|
8
|
+
current_patterns = []
|
9
|
+
|
10
|
+
options[:root_dir].each do |root_directory|
|
11
|
+
Array(pattern_types).each do |pattern_type|
|
12
|
+
patterns = FilePatterns.generate(root_directory, pattern_type, options)
|
13
|
+
|
14
|
+
current_patterns += if pattern_type.to_sym == :additional_file_patterns
|
15
|
+
patterns
|
16
|
+
else
|
17
|
+
patterns.map { |p| p.sub(/^[\/]*/, '') }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
current_patterns
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|