jw-rails-erd 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +86 -0
  3. data/Rakefile +20 -0
  4. data/bin/erd +4 -0
  5. data/lib/generators/erd/USAGE +4 -0
  6. data/lib/generators/erd/install_generator.rb +14 -0
  7. data/lib/generators/erd/templates/auto_generate_diagram.rake +6 -0
  8. data/lib/rails-erd.rb +1 -0
  9. data/lib/rails_erd/cli.rb +164 -0
  10. data/lib/rails_erd/config.rb +97 -0
  11. data/lib/rails_erd/custom.rb +99 -0
  12. data/lib/rails_erd/diagram/graphviz.rb +295 -0
  13. data/lib/rails_erd/diagram/templates/node.html.erb +14 -0
  14. data/lib/rails_erd/diagram/templates/node.record.erb +4 -0
  15. data/lib/rails_erd/diagram.rb +188 -0
  16. data/lib/rails_erd/domain/attribute.rb +160 -0
  17. data/lib/rails_erd/domain/entity.rb +104 -0
  18. data/lib/rails_erd/domain/relationship/cardinality.rb +118 -0
  19. data/lib/rails_erd/domain/relationship.rb +203 -0
  20. data/lib/rails_erd/domain/specialization.rb +90 -0
  21. data/lib/rails_erd/domain.rb +153 -0
  22. data/lib/rails_erd/railtie.rb +10 -0
  23. data/lib/rails_erd/tasks.rake +58 -0
  24. data/lib/rails_erd/version.rb +4 -0
  25. data/lib/rails_erd.rb +73 -0
  26. data/lib/tasks/auto_generate_diagram.rake +21 -0
  27. data/test/support_files/erdconfig.another_example +3 -0
  28. data/test/support_files/erdconfig.example +19 -0
  29. data/test/support_files/erdconfig.exclude.example +19 -0
  30. data/test/test_helper.rb +160 -0
  31. data/test/unit/attribute_test.rb +316 -0
  32. data/test/unit/cardinality_test.rb +123 -0
  33. data/test/unit/config_test.rb +110 -0
  34. data/test/unit/diagram_test.rb +352 -0
  35. data/test/unit/domain_test.rb +258 -0
  36. data/test/unit/entity_test.rb +252 -0
  37. data/test/unit/graphviz_test.rb +461 -0
  38. data/test/unit/rake_task_test.rb +174 -0
  39. data/test/unit/relationship_test.rb +476 -0
  40. data/test/unit/specialization_test.rb +67 -0
  41. metadata +155 -0
@@ -0,0 +1,58 @@
1
+ def say(message)
2
+ puts message unless Rake.application.options.silent
3
+ end
4
+
5
+ namespace :erd do
6
+ task :options do
7
+ (RailsERD.options.keys.map(&:to_s) & ENV.keys).each do |option|
8
+ RailsERD.options[option.to_sym] = case ENV[option]
9
+ when "true", "yes" then true
10
+ when "false", "no" then false
11
+ when /,/ then ENV[option].split(/\s*,\s*/)
12
+ else ENV[option].to_sym
13
+ end
14
+ end
15
+ end
16
+
17
+ task :load_models do
18
+ say "Loading application environment..."
19
+ Rake::Task[:environment].invoke
20
+
21
+ say "Loading code in search of Active Record models..."
22
+ begin
23
+ Rails.application.eager_load!
24
+ rescue Exception => err
25
+ if Rake.application.options.trace
26
+ raise
27
+ else
28
+ trace = Rails.backtrace_cleaner.clean(err.backtrace)
29
+ error = (["Loading models failed!\nError occurred while loading application: #{err} (#{err.class})"] + trace).join("\n ")
30
+ raise error
31
+ end
32
+ end
33
+
34
+ raise "Active Record was not loaded." unless defined? ActiveRecord
35
+ end
36
+
37
+ task :generate => [:options, :load_models] do
38
+ say "Generating Entity-Relationship Diagram for #{ActiveRecord::Base.descendants.length} models..."
39
+
40
+ require "rails_erd/diagram/graphviz"
41
+ file = RailsERD::Diagram::Graphviz.create
42
+
43
+ say "Done! Saved diagram to #{file}."
44
+ end
45
+ end
46
+
47
+ desc "Generate an Entity-Relationship Diagram based on your models"
48
+ task :erd => "erd:generate", :arg1, :arg2, :arg3 do |t, args|
49
+ say "Usage: rake erd <classname> <outputfile> <traversal depth>"
50
+ if args[0] == nil
51
+ say "Required field: Root Class node to start with"
52
+ end
53
+ if args[1] == nil
54
+ say "Required field: output file name"
55
+ end
56
+ args[2] ||= 1
57
+ RailsERD::Custom.new(args[0], args[1], args[2])
58
+ end
@@ -0,0 +1,4 @@
1
+ module RailsERD
2
+ VERSION = "1.4.5"
3
+ BANNER = "RailsERD #{VERSION}"
4
+ end
data/lib/rails_erd.rb ADDED
@@ -0,0 +1,73 @@
1
+ require "active_support/ordered_options"
2
+ require "rails_erd/railtie" if defined? Rails
3
+ require "rails_erd/config"
4
+
5
+ # Welcome to the API documentation of Rails ERD. If you wish to extend or
6
+ # customise the output that is generated by Rails ERD, you have come to the
7
+ # right place.
8
+ #
9
+ # == Creating custom output
10
+ #
11
+ # If you want to create your own kind of diagrams, or some other output, a
12
+ # good starting point is the RailsERD::Diagram class. It can serve as the base
13
+ # of your output generation code.
14
+ #
15
+ # == Options
16
+ #
17
+ # Rails ERD provides several options that allow you to customise the
18
+ # generation of the diagram and the domain model itself. For an overview of
19
+ # all options available in Rails ERD, see README.rdoc.
20
+ #
21
+ # You can specify the option on the command line if you use Rails ERD with
22
+ # Rake:
23
+ #
24
+ # % rake erd orientation=vertical title='My model diagram'
25
+ #
26
+ # When using Rails ERD from within Ruby, you can set the options on the
27
+ # RailsERD namespace module:
28
+ #
29
+ # RailsERD.options.orientation = :vertical
30
+ # RailsERD.options.title = "My model diagram"
31
+ module RailsERD
32
+ class << self
33
+ # Access to default options. Any instance of RailsERD::Domain and
34
+ # RailsERD::Diagram will use these options unless overridden.
35
+ attr_accessor :options
36
+
37
+ def default_options
38
+ ActiveSupport::OrderedOptions[
39
+ :attributes, :content,
40
+ :disconnected, true,
41
+ :filename, "erd",
42
+ :filetype, :pdf,
43
+ :indirect, true,
44
+ :inheritance, false,
45
+ :markup, true,
46
+ :notation, :simple,
47
+ :orientation, :horizontal,
48
+ :polymorphism, false,
49
+ :sort, true,
50
+ :warn, true,
51
+ :title, true,
52
+ :exclude, nil,
53
+ :only, nil,
54
+ :prepend_primary, false
55
+ ]
56
+ end
57
+ end
58
+
59
+ module Inspectable # @private :nodoc:
60
+ def inspection_attributes(*attributes)
61
+ attribute_inspection = attributes.collect { |attribute|
62
+ " @#{attribute}=\#{[Symbol, String].include?(#{attribute}.class) ? #{attribute}.inspect : #{attribute}}"
63
+ }.join
64
+ class_eval <<-RUBY
65
+ def inspect
66
+ "#<\#{self.class}:0x%.14x#{attribute_inspection}>" % (object_id << 1)
67
+ end
68
+ RUBY
69
+ end
70
+ end
71
+
72
+ self.options = default_options.merge(Config.load)
73
+ end
@@ -0,0 +1,21 @@
1
+ namespace :db do
2
+ task :migrate do
3
+ ERDGraph::Migration.update_model
4
+ end
5
+
6
+ namespace :migrate do
7
+ [:change, :up, :down, :reset, :redo].each do |t|
8
+ task t do
9
+ ERDGraph::Migration.update_model
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ module ERDGraph
16
+ class Migration
17
+ def self.update_model
18
+ Rake::Task['erd'].invoke
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ attributes:
2
+ - primary_key
3
+
@@ -0,0 +1,19 @@
1
+ attributes:
2
+ - content
3
+ - foreign_key
4
+ - inheritance
5
+ - false
6
+ disconnected: true
7
+ filename: erd
8
+ filetype: pdf
9
+ indirect: true
10
+ inheritance: false
11
+ markup: true
12
+ notation: simple
13
+ orientation: horizontal
14
+ polymorphism: false
15
+ warn: true
16
+ title: sample title
17
+ exclude:
18
+ only:
19
+
@@ -0,0 +1,19 @@
1
+ attributes:
2
+ - content
3
+ - foreign_key
4
+ - inheritance
5
+ - false
6
+ disconnected: true
7
+ filename: erd
8
+ filetype: pdf
9
+ indirect: true
10
+ inheritance: false
11
+ markup: true
12
+ notation: simple
13
+ orientation: horizontal
14
+ polymorphism: false
15
+ warn: true
16
+ title: sample title
17
+ exclude: Book,Author
18
+ only:
19
+
@@ -0,0 +1,160 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "active_record"
5
+
6
+ if ActiveSupport::VERSION::MAJOR >= 4
7
+ require "minitest/autorun"
8
+ require 'mocha/mini_test'
9
+ else
10
+ require "test/unit"
11
+ require 'mocha/test_unit'
12
+ end
13
+
14
+ require "rails_erd/domain"
15
+
16
+ ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
17
+
18
+ if ActiveSupport::TestCase.respond_to?(:test_order=)
19
+ ActiveSupport::TestCase.test_order = :random
20
+ end
21
+
22
+ class ActiveSupport::TestCase
23
+ include RailsERD
24
+
25
+ setup :reset_config_file
26
+ teardown :reset_domain
27
+
28
+ def create_table(table, columns = {}, pk = nil)
29
+ opts = if pk then { :primary_key => pk } else { :id => false } end
30
+ ActiveRecord::Schema.instance_eval do
31
+ suppress_messages do
32
+ create_table table, opts do |t|
33
+ columns.each do |column, type|
34
+ t.send type, column
35
+ end
36
+ end
37
+ end
38
+ end
39
+ ActiveRecord::Base.clear_cache!
40
+ end
41
+
42
+ def add_column(*args)
43
+ ActiveRecord::Schema.instance_eval do
44
+ suppress_messages do
45
+ add_column(*args)
46
+ end
47
+ end
48
+ ActiveRecord::Base.clear_cache!
49
+ end
50
+
51
+ def create_model(name, *args, &block)
52
+ superklass = args.first.kind_of?(Class) ? args.shift : ActiveRecord::Base
53
+ columns = args.first || {}
54
+ klass = Object.const_set name.to_sym, Class.new(superklass)
55
+ if superklass == ActiveRecord::Base || superklass.abstract_class?
56
+ create_table Object.const_get(name.to_sym).table_name, columns, Object.const_get(name.to_sym).primary_key rescue nil
57
+ end
58
+ klass.class_eval(&block) if block_given?
59
+ Object.const_get(name.to_sym)
60
+ end
61
+
62
+ def create_models(*names)
63
+ names.each do |name|
64
+ create_model name
65
+ end
66
+ end
67
+
68
+ def collect_stdout
69
+ stdout = $stdout
70
+ $stdout = StringIO.new
71
+ yield
72
+ $stdout.rewind
73
+ $stdout.read
74
+ ensure
75
+ $stdout = stdout
76
+ end
77
+
78
+ def create_simple_domain
79
+ create_model "Beer", :bar => :references do
80
+ belongs_to :bar
81
+ end
82
+ create_model "Bar"
83
+ end
84
+
85
+ def create_one_to_one_assoc_domain
86
+ create_model "One" do
87
+ has_one :other
88
+ end
89
+ create_model "Other", :one => :references do
90
+ belongs_to :one
91
+ end
92
+ end
93
+
94
+ def create_one_to_many_assoc_domain
95
+ create_model "One" do
96
+ has_many :many
97
+ end
98
+ create_model "Many", :one => :references do
99
+ belongs_to :one
100
+ end
101
+ end
102
+
103
+ def create_many_to_many_assoc_domain
104
+ create_model "Many" do
105
+ has_and_belongs_to_many :more
106
+ end
107
+ create_model "More" do
108
+ has_and_belongs_to_many :many
109
+ end
110
+ create_table "manies_mores", :many_id => :integer, :more_id => :integer
111
+ end
112
+
113
+ def create_specialization
114
+ create_model "Beverage", :type => :string
115
+ create_model "Beer", Beverage
116
+ end
117
+
118
+ def create_polymorphic_generalization
119
+ create_model "Cannon"
120
+ create_model "Galleon" do
121
+ has_many :cannons, :as => :defensible
122
+ end
123
+ end
124
+
125
+ def create_abstract_generalization
126
+ create_model "Structure" do
127
+ self.abstract_class = true
128
+ end
129
+ create_model "Palace", Structure
130
+ end
131
+
132
+ private
133
+
134
+ def reset_config_file
135
+ RailsERD::Config.send :remove_const, :USER_WIDE_CONFIG_FILE
136
+ RailsERD::Config.send :const_set, :USER_WIDE_CONFIG_FILE,
137
+ File.expand_path("../../examples/erdconfig.not_exists", __FILE__)
138
+
139
+ RailsERD::Config.send :remove_const, :CURRENT_CONFIG_FILE
140
+ RailsERD::Config.send :const_set, :CURRENT_CONFIG_FILE,
141
+ File.expand_path("../../examples/erdconfig.not_exists", __FILE__)
142
+
143
+ RailsERD.options = RailsERD.default_options.merge(Config.load)
144
+ end
145
+
146
+ def reset_domain
147
+ if defined? ActiveRecord
148
+ ActiveRecord::Base.descendants.each do |model|
149
+ model.reset_column_information
150
+ Object.send :remove_const, model.name.to_sym if Object.const_defined? model.name.to_sym
151
+ end
152
+ ActiveRecord::Base.connection.tables.each do |table|
153
+ ActiveRecord::Base.connection.drop_table table
154
+ end
155
+ ActiveRecord::Base.direct_descendants.clear
156
+ ActiveSupport::Dependencies::Reference.clear!
157
+ ActiveRecord::Base.clear_cache!
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,316 @@
1
+ # encoding: utf-8
2
+ require File.expand_path("../test_helper", File.dirname(__FILE__))
3
+
4
+ class AttributeTest < ActiveSupport::TestCase
5
+ def with_native_limit(type, new_limit)
6
+ ActiveRecord::Base.connection.class_eval do
7
+ define_method :native_database_types do
8
+ super().tap do |types|
9
+ types[type][:limit] = new_limit
10
+ end
11
+ end
12
+ end
13
+ yield
14
+ ensure
15
+ ActiveRecord::Base.connection.class_eval do
16
+ define_method :native_database_types do
17
+ super()
18
+ end
19
+ end
20
+ end
21
+
22
+ def create_attribute(model, name)
23
+ Domain::Attribute.new(Domain.generate, model, model.columns_hash[name])
24
+ end
25
+
26
+ # Attribute ================================================================
27
+ test "column should return database column" do
28
+ create_model "Foo", :my_column => :string
29
+ assert_equal Foo.columns_hash["my_column"],
30
+ Domain::Attribute.from_model(Domain.new, Foo).reject(&:primary_key?).first.column
31
+ end
32
+
33
+ test "from_model should return attributes with sorted order if sort is true" do
34
+ RailsERD.options[:sort] = true
35
+ create_model "Foo"
36
+ add_column :foos, :a, :string
37
+ assert_equal %w{a id}, Domain::Attribute.from_model(Domain.new, Foo).map(&:name)
38
+ end
39
+
40
+ test "from_model should return attributes with original order if sort is false" do
41
+ RailsERD.options[:sort] = false
42
+ create_model "Foo"
43
+ add_column :foos, :a, :string
44
+ assert_equal %w{id a}, Domain::Attribute.from_model(Domain.new, Foo).map(&:name)
45
+ end
46
+
47
+ test "from_model should return attributes with PK first if prepend_primary is true" do
48
+ RailsERD.options[:sort] = true
49
+ RailsERD.options[:prepend_primary] = true
50
+
51
+ create_model "Foo"
52
+ add_column :foos, :a, :string
53
+
54
+ assert_equal %w{id a}, Domain::Attribute.from_model(Domain.new, Foo).map(&:name)
55
+ end
56
+
57
+ test "spaceship should sort attributes by name" do
58
+ create_model "Foo", :a => :string, :b => :string, :c => :string
59
+ a = create_attribute(Foo, "a")
60
+ b = create_attribute(Foo, "b")
61
+ c = create_attribute(Foo, "c")
62
+ assert_equal [a, b, c], [c, a, b].sort
63
+ end
64
+
65
+ test "inspect should show column" do
66
+ create_model "Foo", :my_column => :string
67
+ assert_match %r{#<RailsERD::Domain::Attribute:.* @name="my_column" @type=:string>},
68
+ Domain::Attribute.new(Domain.new, Foo, Foo.columns_hash["my_column"]).inspect
69
+ end
70
+
71
+ test "type should return attribute type" do
72
+ create_model "Foo", :a => :binary
73
+ assert_equal :binary, create_attribute(Foo, "a").type
74
+ end
75
+
76
+ test "type should return native type if unsupported by rails" do
77
+ create_model "Foo"
78
+ ActiveRecord::Schema.define do
79
+ suppress_messages do
80
+ add_column "foos", "a", "REAL"
81
+ end
82
+ end
83
+ assert_equal :real, create_attribute(Foo, "a").type
84
+ end
85
+
86
+ # Attribute properties =====================================================
87
+ test "mandatory should return false by default" do
88
+ create_model "Foo", :column => :string
89
+ assert_equal false, create_attribute(Foo, "column").mandatory?
90
+ end
91
+
92
+ test "mandatory should return true if attribute has a presence validator" do
93
+ create_model "Foo", :column => :string do
94
+ validates :column, :presence => true
95
+ end
96
+ assert_equal true, create_attribute(Foo, "column").mandatory?
97
+ end
98
+
99
+ test "mandatory should return true if attribute has a not null constraint" do
100
+ create_model "Foo"
101
+ add_column :foos, :column, :string, :null => false, :default => ""
102
+ assert_equal true, create_attribute(Foo, "column").mandatory?
103
+ end
104
+
105
+ test "primary_key should return false by default" do
106
+ create_model "Bar", :my_key => :integer
107
+ assert_equal false, create_attribute(Bar, "my_key").primary_key?
108
+ end
109
+
110
+ test "primary_key should return true if column is used as primary key" do
111
+ create_model "Bar", :my_key => :integer do
112
+ self.primary_key = :my_key
113
+ end
114
+ assert_equal true, create_attribute(Bar, "my_key").primary_key?
115
+ end
116
+
117
+ test "foreign_key should return false by default" do
118
+ create_model "Foo", :bar => :references
119
+ assert_equal false, create_attribute(Foo, "bar_id").foreign_key?
120
+ end
121
+
122
+ test "foreign_key should return true if it is used in an association" do
123
+ create_model "Foo", :bar => :references do
124
+ belongs_to :bar
125
+ end
126
+ create_model "Bar"
127
+ assert_equal true, create_attribute(Foo, "bar_id").foreign_key?
128
+ end
129
+
130
+ test "foreign_key should return true if it is used in a remote association" do
131
+ create_model "Foo", :bar => :references
132
+ create_model "Bar" do
133
+ has_many :foos
134
+ end
135
+ assert_equal true, create_attribute(Foo, "bar_id").foreign_key?
136
+ end
137
+
138
+ test "timestamp should return false by default" do
139
+ create_model "Foo", :created => :datetime
140
+ assert_equal false, create_attribute(Foo, "created").timestamp?
141
+ end
142
+
143
+ test "timestamp should return true if it is named created_at/on or updated_at/on" do
144
+ create_model "Foo", :created_at => :string, :updated_at => :string, :created_on => :string, :updated_on => :string
145
+ assert_equal [true] * 4, [create_attribute(Foo, "created_at"), create_attribute(Foo, "updated_at"),
146
+ create_attribute(Foo, "created_on"), create_attribute(Foo, "updated_on")].collect(&:timestamp?)
147
+ end
148
+
149
+ test "inheritance should return false by default" do
150
+ create_model "Foo", :type => :string, :alternative => :string do
151
+ self.inheritance_column = :alternative
152
+ end
153
+ assert_equal false, create_attribute(Foo, "type").inheritance?
154
+ end
155
+
156
+ test "inheritance should return if this column is used for single table inheritance" do
157
+ create_model "Foo", :type => :string, :alternative => :string do
158
+ self.inheritance_column = :alternative
159
+ end
160
+ assert_equal true, create_attribute(Foo, "alternative").inheritance?
161
+ end
162
+
163
+ test "content should return true by default" do
164
+ create_model "Foo", :my_first_column => :string
165
+ assert_equal true, create_attribute(Foo, "my_first_column").content?
166
+ end
167
+
168
+ test "content should return false for primary keys, foreign keys, timestamps and inheritance columns" do
169
+ create_model "Book", :type => :string, :created_at => :datetime, :case => :references do
170
+ belongs_to :case
171
+ end
172
+ create_model "Case"
173
+ assert_equal [false] * 4, %w{id type created_at case_id}.map { |a| create_attribute(Book, a).content? }
174
+ end
175
+
176
+ # Type descriptions ========================================================
177
+ test "type_description should return short type description" do
178
+ create_model "Foo", :a => :binary
179
+ assert_equal "binary", create_attribute(Foo, "a").type_description
180
+ end
181
+
182
+ test "type_description should return short type description if unsupported by rails" do
183
+ create_model "Foo"
184
+ ActiveRecord::Schema.define do
185
+ suppress_messages do
186
+ add_column "foos", "a", "REAL"
187
+ end
188
+ end
189
+ assert_equal "real", create_attribute(Foo, "a").type_description
190
+ end
191
+
192
+ test "type_description should return short type description without limit if standard" do
193
+ with_native_limit :string, 456 do
194
+ create_model "Foo"
195
+ add_column :foos, :my_str, :string, :limit => 255
196
+ ActiveRecord::Base.connection.native_database_types[:string]
197
+ assert_equal "string (255)", create_attribute(Foo, "my_str").type_description
198
+ end
199
+ end
200
+
201
+ test "type_description should return short type description with limit if nonstandard" do
202
+ with_native_limit :string, 456 do
203
+ create_model "Foo"
204
+ add_column :foos, :my_str, :string, :limit => 456
205
+ assert_equal "string", create_attribute(Foo, "my_str").type_description
206
+ end
207
+ end
208
+
209
+ test "type_description should append hair space and low asterisk if field is mandatory" do
210
+ create_model "Foo", :a => :integer do
211
+ validates_presence_of :a
212
+ end
213
+ assert_equal "integer ∗", create_attribute(Foo, "a").type_description
214
+ end
215
+
216
+ test "type_description should return short type description with scale and precision for decimal types if nonstandard" do
217
+ create_model "Foo"
218
+ add_column :foos, :num, :decimal, :precision => 5, :scale => 2
219
+ assert_equal "decimal (5,2)", create_attribute(Foo, "num").type_description
220
+ end
221
+
222
+ test "limit should return nil if there is no limit" do
223
+ create_model "Foo"
224
+ add_column :foos, :my_txt, :text
225
+ assert_equal nil, create_attribute(Foo, "my_txt").limit
226
+ end
227
+
228
+ test "limit should return nil if equal to standard database limit" do
229
+ with_native_limit :string, 456 do
230
+ create_model "Foo"
231
+ add_column :foos, :my_str, :string, :limit => 456
232
+ assert_equal nil, create_attribute(Foo, "my_str").limit
233
+ end
234
+ end
235
+
236
+ test "limit should return limit if nonstandard" do
237
+ with_native_limit :string, 456 do
238
+ create_model "Foo"
239
+ add_column :foos, :my_str, :string, :limit => 255
240
+ assert_equal 255, create_attribute(Foo, "my_str").limit
241
+ end
242
+ end
243
+
244
+ test "limit should return precision for decimal columns if nonstandard" do
245
+ create_model "Foo"
246
+ add_column :foos, :num, :decimal, :precision => 5, :scale => 2
247
+ assert_equal 5, create_attribute(Foo, "num").limit
248
+ end
249
+
250
+ test "limit should return nil for decimal columns if equal to standard database limit" do
251
+ create_model "Foo"
252
+ add_column :foos, :num, :decimal
253
+ assert_equal nil, create_attribute(Foo, "num").limit
254
+ end
255
+
256
+ test "limit should return nil if type is unsupported by rails" do
257
+ create_model "Foo"
258
+ ActiveRecord::Schema.define do
259
+ suppress_messages do
260
+ add_column "foos", "a", "REAL"
261
+ end
262
+ end
263
+ assert_equal nil, create_attribute(Foo, "a").limit
264
+ end
265
+
266
+ test "limit should return nil for oddball column types that misuse the limit attribute" do
267
+ create_model "Business", :location => :integer
268
+ attribute = create_attribute(Business, "location")
269
+ attribute.column.class_eval do
270
+ define_method :limit do
271
+ # https://github.com/voormedia/rails-erd/issues/21
272
+ { :srid => 4326, :type => "point", :geographic => true }
273
+ end
274
+ end
275
+ assert_equal nil, attribute.limit
276
+ end
277
+
278
+ test "scale should return scale for decimal columns if nonstandard" do
279
+ create_model "Foo"
280
+ add_column :foos, :num, :decimal, :precision => 5, :scale => 2
281
+ assert_equal 2, create_attribute(Foo, "num").scale
282
+ end
283
+
284
+ test "scale should return nil for decimal columns if equal to standard database limit" do
285
+ create_model "Foo"
286
+ add_column :foos, :num, :decimal
287
+ assert_equal nil, create_attribute(Foo, "num").scale
288
+ end
289
+
290
+ test "scale should return zero for decimal columns if left to default setting when specifying precision" do
291
+ create_model "Foo"
292
+ add_column :foos, :num, :decimal, :precision => 5
293
+ assert_equal 0, create_attribute(Foo, "num").scale
294
+ end
295
+
296
+ test "scale should return nil if type is unsupported by rails" do
297
+ create_model "Foo"
298
+ ActiveRecord::Schema.define do
299
+ suppress_messages do
300
+ add_column "foos", "a", "REAL"
301
+ end
302
+ end
303
+ assert_equal nil, create_attribute(Foo, "a").scale
304
+ end
305
+
306
+ test "scale should return nil for oddball column types that misuse the scale attribute" do
307
+ create_model "Kobold", :size => :integer
308
+ attribute = create_attribute(Kobold, "size")
309
+ attribute.column.class_eval do
310
+ define_method :scale do
311
+ 1..5
312
+ end
313
+ end
314
+ assert_equal nil, attribute.scale
315
+ end
316
+ end