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,123 @@
1
+ require File.expand_path("../test_helper", File.dirname(__FILE__))
2
+
3
+ class CardinalityTest < ActiveSupport::TestCase
4
+ def setup
5
+ @n = Domain::Relationship::Cardinality::N
6
+ end
7
+
8
+ # Cardinality ==============================================================
9
+ test "inspect should show source and destination ranges" do
10
+ assert_match %r{#<RailsERD::Domain::Relationship::Cardinality:.* @source_range=1\.\.1 @destination_range=1\.\.Infinity>},
11
+ Domain::Relationship::Cardinality.new(1, 1..@n).inspect
12
+ end
13
+
14
+ # Cardinality construction =================================================
15
+ test "new should return cardinality object" do
16
+ assert_kind_of Domain::Relationship::Cardinality, Domain::Relationship::Cardinality.new(1, 1..@n)
17
+ end
18
+
19
+ # Cardinality properties ===================================================
20
+ test "source_optional should return true if source range starts at zero" do
21
+ assert_equal true, Domain::Relationship::Cardinality.new(0..1, 1).source_optional?
22
+ end
23
+
24
+ test "source_optional should return false if source range starts at one or more" do
25
+ assert_equal false, Domain::Relationship::Cardinality.new(1..2, 0..1).source_optional?
26
+ end
27
+
28
+ test "destination_optional should return true if destination range starts at zero" do
29
+ assert_equal true, Domain::Relationship::Cardinality.new(1, 0..1).destination_optional?
30
+ end
31
+
32
+ test "destination_optional should return false if destination range starts at one or more" do
33
+ assert_equal false, Domain::Relationship::Cardinality.new(0..1, 1..2).destination_optional?
34
+ end
35
+
36
+ test "inverse should return inverse cardinality" do
37
+ assert_equal Domain::Relationship::Cardinality.new(23..45, 0..15), Domain::Relationship::Cardinality.new(0..15, 23..45).inverse
38
+ end
39
+
40
+ # Cardinality equality =====================================================
41
+ test "cardinalities are equal if they have the same boundaries" do
42
+ assert_equal Domain::Relationship::Cardinality.new(1, 1..Domain::Relationship::Cardinality::N),
43
+ Domain::Relationship::Cardinality.new(1, 1..Domain::Relationship::Cardinality::N)
44
+ end
45
+
46
+ test "cardinalities are not equal if they have a different source range" do
47
+ assert_not_equal Domain::Relationship::Cardinality.new(0..1, 1..Domain::Relationship::Cardinality::N),
48
+ Domain::Relationship::Cardinality.new(1..1, 1..Domain::Relationship::Cardinality::N)
49
+ end
50
+
51
+ test "cardinalities are not equal if they have a different destination range" do
52
+ assert_not_equal Domain::Relationship::Cardinality.new(0..1, 1..Domain::Relationship::Cardinality::N),
53
+ Domain::Relationship::Cardinality.new(0..1, 2..Domain::Relationship::Cardinality::N)
54
+ end
55
+
56
+ # Cardinal names ===========================================================
57
+ test "one_to_one should return true if source and destination are exactly one" do
58
+ assert_equal true, Domain::Relationship::Cardinality.new(1, 1).one_to_one?
59
+ end
60
+
61
+ test "one_to_one should return true if source and destination range are less than or equal to one" do
62
+ assert_equal true, Domain::Relationship::Cardinality.new(0..1, 0..1).one_to_one?
63
+ end
64
+
65
+ test "one_to_one should return false if source range upper limit is more than one" do
66
+ assert_equal false, Domain::Relationship::Cardinality.new(0..15, 0..1).one_to_one?
67
+ end
68
+
69
+ test "one_to_one should return false if destination range upper limit is more than one" do
70
+ assert_equal false, Domain::Relationship::Cardinality.new(0..1, 0..15).one_to_one?
71
+ end
72
+
73
+ test "one_to_many should return true if source is exactly one and destination is higher than one" do
74
+ assert_equal true, Domain::Relationship::Cardinality.new(1, 15).one_to_many?
75
+ end
76
+
77
+ test "one_to_many should return true if source is less than or equal to one and destination is higher than one" do
78
+ assert_equal true, Domain::Relationship::Cardinality.new(0..1, 0..15).one_to_many?
79
+ end
80
+
81
+ test "one_to_many should return false if source range upper limit is more than one" do
82
+ assert_equal false, Domain::Relationship::Cardinality.new(0..15, 0..15).one_to_many?
83
+ end
84
+
85
+ test "one_to_many should return false if destination range upper limit is one" do
86
+ assert_equal false, Domain::Relationship::Cardinality.new(0..1, 1).one_to_many?
87
+ end
88
+
89
+ test "many_to_many should return true if source and destination are higher than one" do
90
+ assert_equal true, Domain::Relationship::Cardinality.new(15, 15).many_to_many?
91
+ end
92
+
93
+ test "many_to_many should return true if source and destination upper limits are higher than one" do
94
+ assert_equal true, Domain::Relationship::Cardinality.new(0..15, 0..15).many_to_many?
95
+ end
96
+
97
+ test "many_to_many should return false if source range upper limit is is one" do
98
+ assert_equal false, Domain::Relationship::Cardinality.new(1, 0..15).many_to_many?
99
+ end
100
+
101
+ test "many_to_many should return false if destination range upper limit is one" do
102
+ assert_equal false, Domain::Relationship::Cardinality.new(0..1, 1).many_to_many?
103
+ end
104
+
105
+ test "inverse of one_to_many should be many_to_one" do
106
+ assert_equal true, Domain::Relationship::Cardinality.new(0..1, 0..@n).inverse.many_to_one?
107
+ end
108
+
109
+ # Cardinality order ========================================================
110
+ test "cardinalities should be sorted in order of maniness" do
111
+ card1 = Domain::Relationship::Cardinality.new(0..1, 1)
112
+ card2 = Domain::Relationship::Cardinality.new(1, 1)
113
+ card3 = Domain::Relationship::Cardinality.new(0..1, 1..3)
114
+ card4 = Domain::Relationship::Cardinality.new(1, 1..2)
115
+ card5 = Domain::Relationship::Cardinality.new(1, 1..@n)
116
+ card6 = Domain::Relationship::Cardinality.new(1..5, 1..3)
117
+ card7 = Domain::Relationship::Cardinality.new(1..2, 1..15)
118
+ card8 = Domain::Relationship::Cardinality.new(1..15, 1..@n)
119
+ card9 = Domain::Relationship::Cardinality.new(1..@n, 1..@n)
120
+ assert_equal [card1, card2, card3, card4, card5, card6, card7, card8, card9],
121
+ [card9, card5, card8, card2, card4, card7, card1, card6, card3].sort
122
+ end
123
+ end
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+ require File.expand_path("../test_helper", File.dirname(__FILE__))
3
+
4
+ class ConfigTest < ActiveSupport::TestCase
5
+
6
+ test "load_config_gile should return blank hash when neither CURRENT_CONFIG_FILE nor USER_WIDE_CONFIG_FILE exist." do
7
+ expected_hash = {}
8
+ assert_equal expected_hash, RailsERD::Config.load
9
+ end
10
+
11
+ test "load_config_gile should return a hash from USER_WIDE_CONFIG_FILE when only USER_WIDE_CONFIG_FILE exists." do
12
+ set_user_config_file_to("erdconfig.example")
13
+
14
+ expected_hash = {
15
+ attributes: [:content, :foreign_key, :inheritance, :false],
16
+ disconnected: true,
17
+ filename: "erd",
18
+ filetype: :pdf,
19
+ indirect: true,
20
+ inheritance: false,
21
+ markup: true,
22
+ notation: :simple,
23
+ orientation: :horizontal,
24
+ polymorphism: false,
25
+ warn: true,
26
+ title: "sample title",
27
+ exclude: [],
28
+ only: []
29
+ }
30
+ assert_equal expected_hash, RailsERD::Config.load
31
+ end
32
+
33
+ test "load_config_file should return a hash from USER_WIDE_CONFIG_FILE when only USER_WIDE_CONFIG_FILE exists." do
34
+ set_user_config_file_to("erdconfig.exclude.example")
35
+
36
+ expected_hash = {
37
+ attributes: [:content, :foreign_key, :inheritance, :false],
38
+ disconnected: true,
39
+ filename: "erd",
40
+ filetype: :pdf,
41
+ indirect: true,
42
+ inheritance: false,
43
+ markup: true,
44
+ notation: :simple,
45
+ orientation: :horizontal,
46
+ polymorphism: false,
47
+ warn: true,
48
+ title: "sample title",
49
+ exclude: ['Book', 'Author'],
50
+ only: []
51
+ }
52
+ assert_equal expected_hash, RailsERD::Config.load
53
+ end
54
+
55
+ test "load_config_gile should return a hash from CURRENT_CONFIG_FILE when only CURRENT_CONFIG_FILE exists." do
56
+ set_local_config_file_to("erdconfig.another_example")
57
+
58
+ expected_hash = {
59
+ :attributes => [:primary_key]
60
+ }
61
+ assert_equal expected_hash, RailsERD::Config.load
62
+ end
63
+
64
+ test "load_config_gile should return a hash from CURRENT_CONFIG_FILE overriding USER_WIDE_CONFIG_FILE when both of them exist." do
65
+ set_user_config_file_to("erdconfig.example")
66
+ set_local_config_file_to("erdconfig.another_example")
67
+
68
+ expected_hash = {
69
+ attributes: [:primary_key],
70
+ disconnected: true,
71
+ filename: "erd",
72
+ filetype: :pdf,
73
+ indirect: true,
74
+ inheritance: false,
75
+ markup: true,
76
+ notation: :simple,
77
+ orientation: :horizontal,
78
+ polymorphism: false,
79
+ warn: true,
80
+ title: "sample title",
81
+ exclude: [],
82
+ only: []
83
+ }
84
+ assert_equal expected_hash, RailsERD::Config.load
85
+ end
86
+
87
+ test "normalize_value should return symbols in an array when key is :attributes and value is a comma-joined string." do
88
+ assert_equal [:content, :foreign_keys], normalize_value(:attributes, "content,foreign_keys")
89
+ end
90
+
91
+ test "normalize_value should return symbols in an array when key is :attributes and value is strings in an array." do
92
+ assert_equal [:content, :primary_keys], normalize_value(:attributes, ["content", "primary_keys"])
93
+ end
94
+
95
+ def normalize_value(key, value)
96
+ RailsERD::Config.new.send(:normalize_value, key, value)
97
+ end
98
+
99
+ def set_user_config_file_to(config_file)
100
+ RailsERD::Config.send :remove_const, :USER_WIDE_CONFIG_FILE
101
+ RailsERD::Config.send :const_set, :USER_WIDE_CONFIG_FILE,
102
+ File.expand_path("test/support_files/#{config_file}")
103
+ end
104
+
105
+ def set_local_config_file_to(config_file)
106
+ RailsERD::Config.send :remove_const, :CURRENT_CONFIG_FILE
107
+ RailsERD::Config.send :const_set, :CURRENT_CONFIG_FILE,
108
+ File.expand_path("test/support_files/#{config_file}")
109
+ end
110
+ end
@@ -0,0 +1,352 @@
1
+ require File.expand_path("../test_helper", File.dirname(__FILE__))
2
+ require "rails_erd/diagram"
3
+
4
+ class DiagramTest < ActiveSupport::TestCase
5
+ def retrieve_entities(options = {})
6
+ klass = Class.new(Diagram)
7
+ [].tap do |entities|
8
+ klass.class_eval do
9
+ each_entity do |entity, attributes|
10
+ entities << entity
11
+ end
12
+ end
13
+ klass.create(options)
14
+ end
15
+ end
16
+
17
+ def retrieve_relationships(options = {})
18
+ klass = Class.new(Diagram)
19
+ [].tap do |relationships|
20
+ klass.class_eval do
21
+ each_relationship do |relationship|
22
+ relationships << relationship
23
+ end
24
+ end
25
+ klass.create(options)
26
+ end
27
+ end
28
+
29
+ def retrieve_specializations(options = {})
30
+ klass = Class.new(Diagram)
31
+ [].tap do |specializations|
32
+ klass.class_eval do
33
+ each_specialization do |specialization|
34
+ specializations << specialization
35
+ end
36
+ end
37
+ klass.create(options)
38
+ end
39
+ end
40
+
41
+ def retrieve_attribute_lists(options = {})
42
+ klass = Class.new(Diagram)
43
+ {}.tap do |attribute_lists|
44
+ klass.class_eval do
45
+ each_entity do |entity, attributes|
46
+ attribute_lists[entity.model] = attributes
47
+ end
48
+ end
49
+ klass.create(options)
50
+ end
51
+ end
52
+
53
+ # Diagram ==================================================================
54
+ test "domain sould return given domain" do
55
+ domain = Object.new
56
+ assert_same domain, Class.new(Diagram).new(domain).domain
57
+ end
58
+
59
+ # Diagram DSL ==============================================================
60
+ test "create should succeed silently if called on abstract class" do
61
+ create_simple_domain
62
+ assert_nothing_raised do
63
+ Diagram.create
64
+ end
65
+ end
66
+
67
+ test "create should succeed if called on subclass" do
68
+ create_simple_domain
69
+ assert_nothing_raised do
70
+ Class.new(Diagram).create
71
+ end
72
+ end
73
+
74
+ test "create should call callbacks in instance in specific order" do
75
+ create_simple_domain
76
+ executed_calls = Class.new(Diagram) do
77
+ setup do
78
+ calls << :setup
79
+ end
80
+
81
+ each_entity do
82
+ calls << :entity
83
+ end
84
+
85
+ each_relationship do
86
+ calls << :relationship
87
+ end
88
+
89
+ save do
90
+ calls << :save
91
+ end
92
+
93
+ def calls
94
+ @calls ||= []
95
+ end
96
+ end.create
97
+ assert_equal [:setup, :entity, :entity, :relationship, :save], executed_calls
98
+ end
99
+
100
+ test "create class method should return result of save" do
101
+ create_simple_domain
102
+ subclass = Class.new(Diagram) do
103
+ save do
104
+ "foobar"
105
+ end
106
+ end
107
+ assert_equal "foobar", subclass.create
108
+ end
109
+
110
+ test "create should return result of save" do
111
+ create_simple_domain
112
+ diagram = Class.new(Diagram) do
113
+ save do
114
+ "foobar"
115
+ end
116
+ end.new(Domain.generate)
117
+ assert_equal "foobar", diagram.create
118
+ end
119
+
120
+ # Entity filtering =========================================================
121
+ test "generate should yield entities" do
122
+ create_model "Foo"
123
+ assert_equal [Foo], retrieve_entities.map(&:model)
124
+ end
125
+
126
+ test "generate should filter excluded entity" do
127
+ create_model "Book"
128
+ create_model "Author"
129
+ assert_equal [Book], retrieve_entities(:exclude => [:Author]).map(&:model)
130
+ end
131
+
132
+ test "generate should filter excluded entities" do
133
+ create_model "Book"
134
+ create_model "Author"
135
+ create_model "Editor"
136
+ assert_equal [Book], retrieve_entities(:exclude => [:Author, :Editor]).map(&:model)
137
+ end
138
+
139
+ test "generate should include only specified entity" do
140
+ create_model "Book"
141
+ create_model "Author"
142
+ assert_equal [Book], retrieve_entities(:only => [:Book]).map(&:model)
143
+ end
144
+
145
+ test "generate should include only specified entities" do
146
+ create_model "Book"
147
+ create_model "Author"
148
+ create_model "Editor"
149
+ assert_equal [Author, Editor], retrieve_entities(:only => [:Author, :Editor]).map(&:model)
150
+ end
151
+
152
+ test "generate should include only specified entities (With the class names as strings)" do
153
+ create_model "Book"
154
+ create_model "Author"
155
+ create_model "Editor"
156
+ assert_equal [Author, Editor], retrieve_entities(:only => ['Author', 'Editor']).map(&:model)
157
+ end
158
+
159
+ test "generate should filter disconnected entities if disconnected is false" do
160
+ create_model "Book", :author => :references do
161
+ belongs_to :author
162
+ end
163
+ create_model "Author"
164
+ create_model "Table", :type => :string
165
+ assert_equal [Author, Book], retrieve_entities(:disconnected => false).map(&:model)
166
+ end
167
+
168
+ test "generate should yield disconnected entities if disconnected is true" do
169
+ create_model "Foo", :type => :string
170
+ assert_equal [Foo], retrieve_entities(:disconnected => true).map(&:model)
171
+ end
172
+
173
+ test "generate should filter specialized entities" do
174
+ create_model "Foo", :type => :string
175
+ Object.const_set :SpecialFoo, Class.new(Foo)
176
+ assert_equal [Foo], retrieve_entities.map(&:model)
177
+ end
178
+
179
+ test "generate should yield specialized entities if inheritance is true" do
180
+ create_model "Foo", :type => :string
181
+ Object.const_set :SpecialFoo, Class.new(Foo)
182
+ assert_equal [Foo, SpecialFoo], retrieve_entities(:inheritance => true).map(&:model)
183
+ end
184
+
185
+ test "generate should yield specialized entities with distinct tables" do
186
+ create_model "Foo"
187
+ Object.const_set :SpecialFoo, Class.new(Foo)
188
+ SpecialFoo.class_eval do
189
+ self.table_name = "special_foo"
190
+ end
191
+ create_table "special_foo", {}, true
192
+ assert_equal [Foo, SpecialFoo], retrieve_entities.map(&:model)
193
+ end
194
+
195
+ test "generate should filter generalized entities" do
196
+ create_model "Cannon"
197
+ create_model "Galleon" do
198
+ has_many :cannons, :as => :defensible
199
+ end
200
+ assert_equal ["Cannon", "Galleon"], retrieve_entities.map(&:name)
201
+ end
202
+
203
+ test "generate should yield generalized entities if polymorphism is true" do
204
+ create_model "Cannon"
205
+ create_model "Galleon" do
206
+ has_many :cannons, :as => :defensible
207
+ end
208
+ assert_equal ["Cannon", "Defensible", "Galleon"], retrieve_entities(:polymorphism => true).map(&:name)
209
+ end
210
+
211
+ # Relationship filtering ===================================================
212
+ test "generate should yield relationships" do
213
+ create_simple_domain
214
+ assert_equal 1, retrieve_relationships.length
215
+ end
216
+
217
+ test "generate should yield indirect relationships if indirect is true" do
218
+ create_model "Foo" do
219
+ has_many :bazs
220
+ has_many :bars
221
+ end
222
+ create_model "Bar", :foo => :references do
223
+ belongs_to :foo
224
+ has_many :bazs, :through => :foo
225
+ end
226
+ create_model "Baz", :foo => :references do
227
+ belongs_to :foo
228
+ end
229
+ assert_equal [false, false, true], retrieve_relationships(:indirect => true).map(&:indirect?)
230
+ end
231
+
232
+ test "generate should filter indirect relationships if indirect is false" do
233
+ create_model "Foo" do
234
+ has_many :bazs
235
+ has_many :bars
236
+ end
237
+ create_model "Bar", :foo => :references do
238
+ belongs_to :foo
239
+ has_many :bazs, :through => :foo
240
+ end
241
+ create_model "Baz", :foo => :references do
242
+ belongs_to :foo
243
+ end
244
+ assert_equal [false, false], retrieve_relationships(:indirect => false).map(&:indirect?)
245
+ end
246
+
247
+ test "generate should yield relationships from specialized entities" do
248
+ create_model "Foo", :bar => :references
249
+ create_model "Bar", :type => :string
250
+ Object.const_set :SpecialBar, Class.new(Bar)
251
+ SpecialBar.class_eval do
252
+ has_many :foos
253
+ end
254
+ assert_equal 1, retrieve_relationships.length
255
+ end
256
+
257
+ test "generate should yield relationships to specialized entities" do
258
+ create_model "Foo", :type => :string, :bar => :references
259
+ Object.const_set :SpecialFoo, Class.new(Foo)
260
+ create_model "Bar" do
261
+ has_many :special_foos
262
+ end
263
+ assert_equal 1, retrieve_relationships.length
264
+ end
265
+
266
+ # Specialization filtering =================================================
267
+ test "generate should not yield specializations" do
268
+ create_specialization
269
+ create_polymorphic_generalization
270
+ create_abstract_generalization
271
+ assert_equal [], retrieve_specializations
272
+ end
273
+
274
+ test "generate should yield specializations but not generalizations if inheritance is true" do
275
+ create_specialization
276
+ create_polymorphic_generalization
277
+ create_abstract_generalization
278
+ assert_equal ["Beer"], retrieve_specializations(:inheritance => true).map { |s| s.specialized.name }
279
+ end
280
+
281
+ test "generate should yield generalizations but not specializations if polymorphism is true" do
282
+ create_specialization
283
+ create_polymorphic_generalization
284
+ create_abstract_generalization
285
+ assert_equal ["Galleon", "Palace"], retrieve_specializations(:polymorphism => true).map { |s| s.specialized.name }
286
+ end
287
+
288
+ test "generate should yield specializations and generalizations if polymorphism and inheritance is true" do
289
+ create_specialization
290
+ create_polymorphic_generalization
291
+ create_abstract_generalization
292
+ assert_equal ["Beer", "Galleon", "Palace"], retrieve_specializations(:inheritance => true,
293
+ :polymorphism => true).map { |s| s.specialized.name }
294
+ end
295
+
296
+ # Attribute filtering ======================================================
297
+ test "generate should yield content attributes by default" do
298
+ create_model "Book", :title => :string, :created_at => :datetime, :author => :references do
299
+ belongs_to :author
300
+ end
301
+ create_model "Author"
302
+ assert_equal %w{title}, retrieve_attribute_lists[Book].map(&:name)
303
+ end
304
+
305
+ test "generate should yield primary key attributes if included" do
306
+ create_model "Book", :title => :string
307
+ create_model "Page", :book => :references do
308
+ belongs_to :book
309
+ end
310
+ assert_equal %w{id}, retrieve_attribute_lists(:attributes => [:primary_keys])[Book].map(&:name)
311
+ end
312
+
313
+ test "generate should yield [] if attributes = false" do
314
+ create_model "Book", :title => :string
315
+ create_model "Page", :book => :references do
316
+ belongs_to :book
317
+ end
318
+ assert_equal [], retrieve_attribute_lists(:attributes => [:false])[Book].map(&:name)
319
+ end
320
+
321
+ test "generate should yield foreign key attributes if included" do
322
+ create_model "Book", :author => :references do
323
+ belongs_to :author
324
+ end
325
+ create_model "Author"
326
+ assert_equal %w{author_id}, retrieve_attribute_lists(:attributes => [:foreign_keys])[Book].map(&:name)
327
+ end
328
+
329
+ test "generate should yield timestamp attributes if included" do
330
+ create_model "Book", :created_at => :datetime, :created_on => :date, :updated_at => :datetime, :updated_on => :date
331
+ create_model "Page", :book => :references do
332
+ belongs_to :book
333
+ end
334
+ assert_equal %w{created_at created_on updated_at updated_on},
335
+ retrieve_attribute_lists(:attributes => [:timestamps])[Book].map(&:name)
336
+ end
337
+
338
+ test "generate should yield combinations of attributes if included" do
339
+ create_model "Book", :created_at => :datetime, :title => :string, :author => :references do
340
+ belongs_to :author
341
+ end
342
+ create_model "Author"
343
+ assert_equal %w{created_at title},
344
+ retrieve_attribute_lists(:attributes => [:content, :timestamps])[Book].map(&:name)
345
+ end
346
+
347
+ test "generate should yield no attributes for specialized entities" do
348
+ create_model "Beverage", :type => :string, :name => :string, :distillery => :string, :age => :integer
349
+ Object.const_set :Whisky, Class.new(Beverage)
350
+ assert_equal [], retrieve_attribute_lists(:inheritance => true)[Whisky].map(&:name)
351
+ end
352
+ end