annotate 3.0.3 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{AUTHORS.rdoc → AUTHORS.md} +2 -2
- data/CHANGELOG.md +312 -0
- data/{README.rdoc → README.md} +138 -105
- data/RELEASE.md +19 -0
- data/annotate.gemspec +2 -2
- data/bin/annotate +3 -3
- data/lib/annotate.rb +21 -80
- data/lib/annotate/annotate_models.rb +101 -37
- data/lib/annotate/annotate_routes.rb +69 -68
- data/lib/annotate/constants.rb +33 -0
- data/lib/annotate/helpers.rb +30 -0
- data/lib/annotate/parser.rb +127 -75
- data/lib/annotate/version.rb +1 -1
- data/lib/generators/annotate/templates/auto_annotate_models.rake +2 -0
- data/lib/tasks/annotate_models.rake +36 -35
- data/lib/tasks/annotate_models_migrate.rake +3 -3
- data/lib/tasks/annotate_routes.rake +5 -5
- data/potato.md +41 -0
- metadata +10 -10
- data/CHANGELOG.rdoc +0 -245
- data/RELEASE.rdoc +0 -17
- data/TODO.rdoc +0 -11
data/RELEASE.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
## Prerequisite
|
2
|
+
|
3
|
+
- Install "git-flow" (`brew install git-flow`)
|
4
|
+
- Install "bump" gem (`gem install bump`)
|
5
|
+
|
6
|
+
|
7
|
+
## Perform a release
|
8
|
+
|
9
|
+
- `git flow release start <release>`
|
10
|
+
- Update the `CHANGELOG.md` file
|
11
|
+
- `bump current`
|
12
|
+
- `bump patch`
|
13
|
+
- `rm -rf dist`
|
14
|
+
- `rake spec`
|
15
|
+
- `rake gem`
|
16
|
+
- `git flow release finish <release>`
|
17
|
+
|
18
|
+
- `rake gem:publish`
|
19
|
+
|
data/annotate.gemspec
CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.description = 'Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema.'
|
14
14
|
s.email = ['alex@stinky.com', 'cuong.tran@gmail.com', 'x@nofxx.com', 'turadg@aleahmad.net', 'jon@cloudability.com']
|
15
15
|
s.executables = ['annotate']
|
16
|
-
s.extra_rdoc_files = ['README.
|
17
|
-
s.files = `git ls-files -z LICENSE.txt *.
|
16
|
+
s.extra_rdoc_files = ['README.md', 'CHANGELOG.md']
|
17
|
+
s.files = `git ls-files -z LICENSE.txt *.md *.gemspec bin lib`.split("\x0")
|
18
18
|
s.homepage = 'http://github.com/ctran/annotate_models'
|
19
19
|
s.licenses = ['Ruby']
|
20
20
|
s.require_paths = ['lib']
|
data/bin/annotate
CHANGED
@@ -26,7 +26,7 @@ exit if options_result[:exit]
|
|
26
26
|
options = Annotate.setup_options(
|
27
27
|
is_rake: ENV['is_rake'] && !ENV['is_rake'].empty?
|
28
28
|
)
|
29
|
-
Annotate.eager_load(options) if Annotate.include_models?
|
29
|
+
Annotate.eager_load(options) if Annotate::Helpers.include_models?
|
30
30
|
|
31
|
-
AnnotateModels.send(options_result[:target_action], options) if Annotate.include_models?
|
32
|
-
AnnotateRoutes.send(options_result[:target_action], options) if Annotate.include_routes?
|
31
|
+
AnnotateModels.send(options_result[:target_action], options) if Annotate::Helpers.include_models?
|
32
|
+
AnnotateRoutes.send(options_result[:target_action], options) if Annotate::Helpers.include_routes?
|
data/lib/annotate.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
# rubocop:disable Metrics/ModuleLength
|
2
|
-
|
3
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
4
2
|
require 'annotate/version'
|
5
3
|
require 'annotate/annotate_models'
|
6
4
|
require 'annotate/annotate_routes'
|
7
5
|
require 'annotate/constants'
|
6
|
+
require 'annotate/helpers'
|
8
7
|
|
9
8
|
begin
|
10
9
|
# ActiveSupport 3.x...
|
@@ -17,36 +16,6 @@ rescue StandardError
|
|
17
16
|
end
|
18
17
|
|
19
18
|
module Annotate
|
20
|
-
##
|
21
|
-
# The set of available options to customize the behavior of Annotate.
|
22
|
-
#
|
23
|
-
POSITION_OPTIONS = [
|
24
|
-
:position_in_routes, :position_in_class, :position_in_test,
|
25
|
-
:position_in_fixture, :position_in_factory, :position,
|
26
|
-
:position_in_serializer
|
27
|
-
].freeze
|
28
|
-
FLAG_OPTIONS = [
|
29
|
-
:show_indexes, :simple_indexes, :include_version, :exclude_tests,
|
30
|
-
:exclude_fixtures, :exclude_factories, :ignore_model_sub_dir,
|
31
|
-
:format_bare, :format_rdoc, :format_markdown, :sort, :force, :frozen,
|
32
|
-
:trace, :timestamp, :exclude_serializers, :classified_sort,
|
33
|
-
:show_foreign_keys, :show_complete_foreign_keys,
|
34
|
-
:exclude_scaffolds, :exclude_controllers, :exclude_helpers,
|
35
|
-
:exclude_sti_subclasses, :ignore_unknown_models, :with_comment
|
36
|
-
].freeze
|
37
|
-
OTHER_OPTIONS = [
|
38
|
-
:additional_file_patterns, :ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close,
|
39
|
-
:wrapper, :routes, :models, :hide_limit_column_types, :hide_default_column_types,
|
40
|
-
:ignore_routes, :active_admin
|
41
|
-
].freeze
|
42
|
-
PATH_OPTIONS = [
|
43
|
-
:require, :model_dir, :root_dir
|
44
|
-
].freeze
|
45
|
-
|
46
|
-
def self.all_options
|
47
|
-
[POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS, OTHER_OPTIONS]
|
48
|
-
end
|
49
|
-
|
50
19
|
##
|
51
20
|
# Set default values that can be overridden via environment variables.
|
52
21
|
#
|
@@ -54,9 +23,9 @@ module Annotate
|
|
54
23
|
return if @has_set_defaults
|
55
24
|
@has_set_defaults = true
|
56
25
|
|
57
|
-
options = HashWithIndifferentAccess.new(options)
|
26
|
+
options = ActiveSupport::HashWithIndifferentAccess.new(options)
|
58
27
|
|
59
|
-
|
28
|
+
Constants::ALL_ANNOTATE_OPTIONS.flatten.each do |key|
|
60
29
|
if options.key?(key)
|
61
30
|
default_value = if options[key].is_a?(Array)
|
62
31
|
options[key].join(',')
|
@@ -74,69 +43,42 @@ module Annotate
|
|
74
43
|
# TODO: what is the difference between this and set_defaults?
|
75
44
|
#
|
76
45
|
def self.setup_options(options = {})
|
77
|
-
POSITION_OPTIONS.each do |key|
|
78
|
-
options[key] = fallback(ENV[key.to_s], ENV['position'], 'before')
|
46
|
+
Constants::POSITION_OPTIONS.each do |key|
|
47
|
+
options[key] = Annotate::Helpers.fallback(ENV[key.to_s], ENV['position'], 'before')
|
79
48
|
end
|
80
|
-
FLAG_OPTIONS.each do |key|
|
81
|
-
options[key] = true?(ENV[key.to_s])
|
49
|
+
Constants::FLAG_OPTIONS.each do |key|
|
50
|
+
options[key] = Annotate::Helpers.true?(ENV[key.to_s])
|
82
51
|
end
|
83
|
-
OTHER_OPTIONS.each do |key|
|
52
|
+
Constants::OTHER_OPTIONS.each do |key|
|
84
53
|
options[key] = !ENV[key.to_s].blank? ? ENV[key.to_s] : nil
|
85
54
|
end
|
86
|
-
PATH_OPTIONS.each do |key|
|
55
|
+
Constants::PATH_OPTIONS.each do |key|
|
87
56
|
options[key] = !ENV[key.to_s].blank? ? ENV[key.to_s].split(',') : []
|
88
57
|
end
|
89
58
|
|
90
59
|
options[:additional_file_patterns] ||= []
|
60
|
+
options[:additional_file_patterns] = options[:additional_file_patterns].split(',') if options[:additional_file_patterns].is_a?(String)
|
91
61
|
options[:model_dir] = ['app/models'] if options[:model_dir].empty?
|
92
62
|
|
93
63
|
options[:wrapper_open] ||= options[:wrapper]
|
94
64
|
options[:wrapper_close] ||= options[:wrapper]
|
95
65
|
|
96
66
|
# These were added in 2.7.0 but so this is to revert to old behavior by default
|
97
|
-
options[:exclude_scaffolds] = Annotate.true?(ENV.fetch('exclude_scaffolds', 'true'))
|
98
|
-
options[:exclude_controllers] = Annotate.true?(ENV.fetch('exclude_controllers', 'true'))
|
99
|
-
options[:exclude_helpers] = Annotate.true?(ENV.fetch('exclude_helpers', 'true'))
|
67
|
+
options[:exclude_scaffolds] = Annotate::Helpers.true?(ENV.fetch('exclude_scaffolds', 'true'))
|
68
|
+
options[:exclude_controllers] = Annotate::Helpers.true?(ENV.fetch('exclude_controllers', 'true'))
|
69
|
+
options[:exclude_helpers] = Annotate::Helpers.true?(ENV.fetch('exclude_helpers', 'true'))
|
100
70
|
|
101
71
|
options
|
102
72
|
end
|
103
73
|
|
104
|
-
def self.reset_options
|
105
|
-
all_options.flatten.each { |key| ENV[key.to_s] = nil }
|
106
|
-
end
|
107
|
-
|
108
|
-
def self.skip_on_migration?
|
109
|
-
ENV['ANNOTATE_SKIP_ON_DB_MIGRATE'] =~ Constants::TRUE_RE || ENV['skip_on_db_migrate'] =~ Constants::TRUE_RE
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.include_routes?
|
113
|
-
ENV['routes'] =~ Constants::TRUE_RE
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.include_models?
|
117
|
-
ENV['models'] =~ Constants::TRUE_RE
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.loaded_tasks=(val)
|
121
|
-
@loaded_tasks = val
|
122
|
-
end
|
123
|
-
|
124
|
-
def self.loaded_tasks
|
125
|
-
@loaded_tasks
|
126
|
-
end
|
127
|
-
|
128
74
|
def self.load_tasks
|
129
|
-
return if
|
130
|
-
self.loaded_tasks = true
|
75
|
+
return if @tasks_loaded
|
131
76
|
|
132
77
|
Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each do |rake|
|
133
78
|
load rake
|
134
79
|
end
|
135
|
-
end
|
136
80
|
|
137
|
-
|
138
|
-
options[:require].count > 0 &&
|
139
|
-
options[:require].each { |path| require path }
|
81
|
+
@tasks_loaded = true
|
140
82
|
end
|
141
83
|
|
142
84
|
def self.eager_load(options)
|
@@ -192,13 +134,12 @@ module Annotate
|
|
192
134
|
Rake::Task[:set_annotation_options].invoke
|
193
135
|
end
|
194
136
|
|
195
|
-
|
196
|
-
|
197
|
-
end
|
137
|
+
class << self
|
138
|
+
private
|
198
139
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
140
|
+
def load_requires(options)
|
141
|
+
options[:require].count > 0 &&
|
142
|
+
options[:require].each { |path| require path }
|
143
|
+
end
|
203
144
|
end
|
204
145
|
end
|
@@ -38,9 +38,9 @@ module AnnotateModels
|
|
38
38
|
BLUEPRINTS_TEST_DIR = File.join('test', "blueprints")
|
39
39
|
BLUEPRINTS_SPEC_DIR = File.join('spec', "blueprints")
|
40
40
|
|
41
|
-
# Factory Girl
|
42
|
-
|
43
|
-
|
41
|
+
# Factory Girl https://github.com/thoughtbot/factory_bot
|
42
|
+
FACTORY_BOT_TEST_DIR = File.join('test', "factories")
|
43
|
+
FACTORY_BOT_SPEC_DIR = File.join('spec', "factories")
|
44
44
|
|
45
45
|
# Fabrication https://github.com/paulelliott/fabrication.git
|
46
46
|
FABRICATORS_TEST_DIR = File.join('test', "fabricators")
|
@@ -82,6 +82,8 @@ module AnnotateModels
|
|
82
82
|
}
|
83
83
|
}.freeze
|
84
84
|
|
85
|
+
MAGIC_COMMENT_MATCHER = Regexp.new(/(^#\s*encoding:.*(?:\n|r\n))|(^# coding:.*(?:\n|\r\n))|(^# -\*- coding:.*(?:\n|\r\n))|(^# -\*- encoding\s?:.*(?:\n|\r\n))|(^#\s*frozen_string_literal:.+(?:\n|\r\n))|(^# -\*- frozen_string_literal\s*:.+-\*-(?:\n|\r\n))/).freeze
|
86
|
+
|
85
87
|
class << self
|
86
88
|
def annotate_pattern(options = {})
|
87
89
|
if options[:wrapper_open]
|
@@ -140,12 +142,12 @@ module AnnotateModels
|
|
140
142
|
File.join(root_directory, EXEMPLARS_SPEC_DIR, "%MODEL_NAME%_exemplar.rb"),
|
141
143
|
File.join(root_directory, BLUEPRINTS_TEST_DIR, "%MODEL_NAME%_blueprint.rb"),
|
142
144
|
File.join(root_directory, BLUEPRINTS_SPEC_DIR, "%MODEL_NAME%_blueprint.rb"),
|
143
|
-
File.join(root_directory,
|
144
|
-
File.join(root_directory,
|
145
|
-
File.join(root_directory,
|
146
|
-
File.join(root_directory,
|
147
|
-
File.join(root_directory,
|
148
|
-
File.join(root_directory,
|
145
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
|
146
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
|
147
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, "%TABLE_NAME%.rb"), # (new style)
|
148
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, "%TABLE_NAME%.rb"), # (new style)
|
149
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, "%PLURALIZED_MODEL_NAME%.rb"), # (new style)
|
150
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, "%PLURALIZED_MODEL_NAME%.rb"), # (new style)
|
149
151
|
File.join(root_directory, FABRICATORS_TEST_DIR, "%MODEL_NAME%_fabricator.rb"),
|
150
152
|
File.join(root_directory, FABRICATORS_SPEC_DIR, "%MODEL_NAME%_fabricator.rb")
|
151
153
|
]
|
@@ -154,7 +156,7 @@ module AnnotateModels
|
|
154
156
|
def serialize_files(root_directory)
|
155
157
|
[
|
156
158
|
File.join(root_directory, SERIALIZERS_DIR, "%MODEL_NAME%_serializer.rb"),
|
157
|
-
File.join(root_directory, SERIALIZERS_TEST_DIR, "%MODEL_NAME%
|
159
|
+
File.join(root_directory, SERIALIZERS_TEST_DIR, "%MODEL_NAME%_serializer_test.rb"),
|
158
160
|
File.join(root_directory, SERIALIZERS_SPEC_DIR, "%MODEL_NAME%_serializer_spec.rb")
|
159
161
|
]
|
160
162
|
end
|
@@ -211,7 +213,7 @@ module AnnotateModels
|
|
211
213
|
end
|
212
214
|
|
213
215
|
def schema_default(klass, column)
|
214
|
-
quote(klass.
|
216
|
+
quote(klass.columns.find { |x| x.name.to_s == column.name.to_s }.try(:default))
|
215
217
|
end
|
216
218
|
|
217
219
|
def retrieve_indexes_from_table(klass)
|
@@ -244,16 +246,7 @@ module AnnotateModels
|
|
244
246
|
info << "# #{ '-' * ( max_size + md_names_overhead ) } | #{'-' * md_type_allowance} | #{ '-' * 27 }\n"
|
245
247
|
end
|
246
248
|
|
247
|
-
cols =
|
248
|
-
klass.columns.reject do |col|
|
249
|
-
col.name.match(/#{ignore_columns}/)
|
250
|
-
end
|
251
|
-
else
|
252
|
-
klass.columns
|
253
|
-
end
|
254
|
-
|
255
|
-
cols = cols.sort_by(&:name) if options[:sort]
|
256
|
-
cols = classified_sort(cols) if options[:classified_sort]
|
249
|
+
cols = columns(klass, options)
|
257
250
|
cols.each do |col|
|
258
251
|
col_type = get_col_type(col)
|
259
252
|
attrs = []
|
@@ -264,8 +257,8 @@ module AnnotateModels
|
|
264
257
|
|
265
258
|
if col_type == 'decimal'
|
266
259
|
col_type << "(#{col.precision}, #{col.scale})"
|
267
|
-
elsif
|
268
|
-
if col.limit
|
260
|
+
elsif !%w[spatial geometry geography].include?(col_type)
|
261
|
+
if col.limit && !options[:format_yard]
|
269
262
|
if col.limit.is_a? Array
|
270
263
|
attrs << "(#{col.limit.join(', ')})"
|
271
264
|
else
|
@@ -304,8 +297,12 @@ module AnnotateModels
|
|
304
297
|
end
|
305
298
|
if options[:format_rdoc]
|
306
299
|
info << sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{col_name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n"
|
300
|
+
elsif options[:format_yard]
|
301
|
+
info << sprintf("# @!attribute #{col_name}") + "\n"
|
302
|
+
ruby_class = col.respond_to?(:array) && col.array ? "Array<#{map_col_type_to_ruby_classes(col_type)}>": map_col_type_to_ruby_classes(col_type)
|
303
|
+
info << sprintf("# @return [#{ruby_class}]") + "\n"
|
307
304
|
elsif options[:format_markdown]
|
308
|
-
name_remainder = max_size - col_name.length
|
305
|
+
name_remainder = max_size - col_name.length - non_ascii_length(col_name)
|
309
306
|
type_remainder = (md_type_allowance - 2) - col_type.length
|
310
307
|
info << (sprintf("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`", col_name, " ", col_type, " ", attrs.join(", ").rstrip)).gsub('``', ' ').rstrip + "\n"
|
311
308
|
else
|
@@ -472,7 +469,10 @@ module AnnotateModels
|
|
472
469
|
foreign_keys = klass.connection.foreign_keys(klass.table_name)
|
473
470
|
return '' if foreign_keys.empty?
|
474
471
|
|
475
|
-
format_name =
|
472
|
+
format_name = lambda do |fk|
|
473
|
+
return fk.options[:column] if fk.name.blank?
|
474
|
+
options[:show_complete_foreign_keys] ? fk.name : fk.name.gsub(/(?<=^fk_rails_)[0-9a-f]{10}$/, '...')
|
475
|
+
end
|
476
476
|
|
477
477
|
max_size = foreign_keys.map(&format_name).map(&:size).max + 1
|
478
478
|
foreign_keys.sort_by {|fk| [format_name.call(fk), fk.column]}.each do |fk|
|
@@ -515,7 +515,7 @@ module AnnotateModels
|
|
515
515
|
old_header = old_content.match(header_pattern).to_s
|
516
516
|
new_header = info_block.match(header_pattern).to_s
|
517
517
|
|
518
|
-
column_pattern = /^#[\t ]+[\w
|
518
|
+
column_pattern = /^#[\t ]+[\w\*\.`]+[\t ]+.+$/
|
519
519
|
old_columns = old_header && old_header.scan(column_pattern).sort
|
520
520
|
new_columns = new_header && new_header.scan(column_pattern).sort
|
521
521
|
|
@@ -534,15 +534,15 @@ module AnnotateModels
|
|
534
534
|
# need to insert it in correct position
|
535
535
|
if old_annotation.empty? || options[:force]
|
536
536
|
magic_comments_block = magic_comments_as_string(old_content)
|
537
|
-
old_content.gsub!(
|
537
|
+
old_content.gsub!(MAGIC_COMMENT_MATCHER, '')
|
538
538
|
old_content.sub!(annotate_pattern(options), '')
|
539
539
|
|
540
540
|
new_content = if %w(after bottom).include?(options[position].to_s)
|
541
541
|
magic_comments_block + (old_content.rstrip + "\n\n" + wrapped_info_block)
|
542
542
|
elsif magic_comments_block.empty?
|
543
|
-
magic_comments_block + wrapped_info_block +
|
543
|
+
magic_comments_block + wrapped_info_block + old_content.lstrip
|
544
544
|
else
|
545
|
-
magic_comments_block + "\n" + wrapped_info_block +
|
545
|
+
magic_comments_block + "\n" + wrapped_info_block + old_content.lstrip
|
546
546
|
end
|
547
547
|
else
|
548
548
|
# replace the old annotation with the new one
|
@@ -558,12 +558,8 @@ module AnnotateModels
|
|
558
558
|
true
|
559
559
|
end
|
560
560
|
|
561
|
-
def magic_comment_matcher
|
562
|
-
Regexp.new(/(^#\s*encoding:.*(?:\n|r\n))|(^# coding:.*(?:\n|\r\n))|(^# -\*- coding:.*(?:\n|\r\n))|(^# -\*- encoding\s?:.*(?:\n|\r\n))|(^#\s*frozen_string_literal:.+(?:\n|\r\n))|(^# -\*- frozen_string_literal\s*:.+-\*-(?:\n|\r\n))/)
|
563
|
-
end
|
564
|
-
|
565
561
|
def magic_comments_as_string(content)
|
566
|
-
magic_comments = content.scan(
|
562
|
+
magic_comments = content.scan(MAGIC_COMMENT_MATCHER).flatten.compact
|
567
563
|
|
568
564
|
if magic_comments.any?
|
569
565
|
magic_comments.join
|
@@ -902,13 +898,15 @@ module AnnotateModels
|
|
902
898
|
end
|
903
899
|
|
904
900
|
def max_schema_info_width(klass, options)
|
901
|
+
cols = columns(klass, options)
|
902
|
+
|
905
903
|
if with_comments?(klass, options)
|
906
|
-
max_size =
|
904
|
+
max_size = cols.map do |column|
|
907
905
|
column.name.size + (column.comment ? width(column.comment) : 0)
|
908
906
|
end.max || 0
|
909
907
|
max_size += 2
|
910
908
|
else
|
911
|
-
max_size =
|
909
|
+
max_size = cols.map(&:name).map(&:size).max
|
912
910
|
end
|
913
911
|
max_size += options[:format_rdoc] ? 5 : 1
|
914
912
|
|
@@ -920,7 +918,7 @@ module AnnotateModels
|
|
920
918
|
end
|
921
919
|
|
922
920
|
def width(string)
|
923
|
-
string.chars.inject(0) { |acc, elem| acc + (elem.bytesize ==
|
921
|
+
string.chars.inject(0) { |acc, elem| acc + (elem.bytesize == 3 ? 2 : 1) }
|
924
922
|
end
|
925
923
|
|
926
924
|
def mb_chars_ljust(string, length)
|
@@ -932,6 +930,72 @@ module AnnotateModels
|
|
932
930
|
string[0..length-1]
|
933
931
|
end
|
934
932
|
end
|
933
|
+
|
934
|
+
def non_ascii_length(string)
|
935
|
+
string.to_s.chars.reject(&:ascii_only?).length
|
936
|
+
end
|
937
|
+
|
938
|
+
def map_col_type_to_ruby_classes(col_type)
|
939
|
+
case col_type
|
940
|
+
when 'integer' then Integer.to_s
|
941
|
+
when 'float' then Float.to_s
|
942
|
+
when 'decimal' then BigDecimal.to_s
|
943
|
+
when 'datetime', 'timestamp', 'time' then Time.to_s
|
944
|
+
when 'date' then Date.to_s
|
945
|
+
when 'text', 'string', 'binary', 'inet', 'uuid' then String.to_s
|
946
|
+
when 'json', 'jsonb' then Hash.to_s
|
947
|
+
when 'boolean' then 'Boolean'
|
948
|
+
end
|
949
|
+
end
|
950
|
+
|
951
|
+
def columns(klass, options)
|
952
|
+
cols = klass.columns
|
953
|
+
cols += translated_columns(klass)
|
954
|
+
|
955
|
+
if ignore_columns = options[:ignore_columns]
|
956
|
+
cols = cols.reject do |col|
|
957
|
+
col.name.match(/#{ignore_columns}/)
|
958
|
+
end
|
959
|
+
end
|
960
|
+
|
961
|
+
cols = cols.sort_by(&:name) if options[:sort]
|
962
|
+
cols = classified_sort(cols) if options[:classified_sort]
|
963
|
+
|
964
|
+
cols
|
965
|
+
end
|
966
|
+
|
967
|
+
##
|
968
|
+
# Add columns managed by the globalize gem if this gem is being used.
|
969
|
+
def translated_columns(klass)
|
970
|
+
return [] unless klass.respond_to? :translation_class
|
971
|
+
|
972
|
+
ignored_cols = ignored_translation_table_colums(klass)
|
973
|
+
klass.translation_class.columns.reject do |col|
|
974
|
+
ignored_cols.include? col.name.to_sym
|
975
|
+
end
|
976
|
+
end
|
977
|
+
|
978
|
+
##
|
979
|
+
# These are the columns that the globalize gem needs to work but
|
980
|
+
# are not necessary for the models to be displayed as annotations.
|
981
|
+
def ignored_translation_table_colums(klass)
|
982
|
+
# Construct the foreign column name in the translations table
|
983
|
+
# eg. Model: Car, foreign column name: car_id
|
984
|
+
foreign_column_name = [
|
985
|
+
klass.translation_class.to_s
|
986
|
+
.gsub('::Translation', '').gsub('::', '_')
|
987
|
+
.downcase,
|
988
|
+
'_id'
|
989
|
+
].join.to_sym
|
990
|
+
|
991
|
+
[
|
992
|
+
:id,
|
993
|
+
:created_at,
|
994
|
+
:updated_at,
|
995
|
+
:locale,
|
996
|
+
foreign_column_name
|
997
|
+
]
|
998
|
+
end
|
935
999
|
end
|
936
1000
|
|
937
1001
|
class BadModelFileError < LoadError
|