annotate 3.0.3 → 3.1.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 +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
|