dm-core 0.9.2 → 0.9.3
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.
- data/.autotest +26 -0
- data/{CHANGELOG → History.txt} +78 -77
- data/Manifest.txt +123 -0
- data/{README → README.txt} +0 -0
- data/Rakefile +29 -0
- data/SPECS +63 -0
- data/TODO +1 -0
- data/lib/dm-core.rb +6 -1
- data/lib/dm-core/adapters/data_objects_adapter.rb +29 -32
- data/lib/dm-core/adapters/mysql_adapter.rb +1 -1
- data/lib/dm-core/adapters/postgres_adapter.rb +1 -1
- data/lib/dm-core/adapters/sqlite3_adapter.rb +2 -2
- data/lib/dm-core/associations.rb +26 -0
- data/lib/dm-core/associations/many_to_many.rb +34 -25
- data/lib/dm-core/associations/many_to_one.rb +4 -4
- data/lib/dm-core/associations/one_to_many.rb +48 -13
- data/lib/dm-core/associations/one_to_one.rb +4 -4
- data/lib/dm-core/associations/relationship.rb +144 -42
- data/lib/dm-core/associations/relationship_chain.rb +31 -24
- data/lib/dm-core/auto_migrations.rb +0 -4
- data/lib/dm-core/collection.rb +40 -7
- data/lib/dm-core/dependency_queue.rb +31 -0
- data/lib/dm-core/hook.rb +2 -2
- data/lib/dm-core/is.rb +2 -2
- data/lib/dm-core/logger.rb +10 -10
- data/lib/dm-core/model.rb +94 -41
- data/lib/dm-core/property.rb +72 -41
- data/lib/dm-core/property_set.rb +8 -14
- data/lib/dm-core/query.rb +34 -9
- data/lib/dm-core/repository.rb +0 -0
- data/lib/dm-core/resource.rb +13 -13
- data/lib/dm-core/scope.rb +25 -2
- data/lib/dm-core/type.rb +3 -3
- data/lib/dm-core/types/discriminator.rb +10 -8
- data/lib/dm-core/types/object.rb +4 -0
- data/lib/dm-core/types/paranoid_boolean.rb +15 -4
- data/lib/dm-core/types/paranoid_datetime.rb +15 -4
- data/lib/dm-core/version.rb +3 -0
- data/script/all +5 -0
- data/script/performance.rb +191 -0
- data/script/profile.rb +86 -0
- data/spec/integration/association_spec.rb +288 -204
- data/spec/integration/association_through_spec.rb +9 -3
- data/spec/integration/associations/many_to_many_spec.rb +97 -31
- data/spec/integration/associations/many_to_one_spec.rb +41 -6
- data/spec/integration/associations/one_to_many_spec.rb +18 -2
- data/spec/integration/auto_migrations_spec.rb +0 -0
- data/spec/integration/collection_spec.rb +89 -42
- data/spec/integration/dependency_queue_spec.rb +58 -0
- data/spec/integration/model_spec.rb +67 -8
- data/spec/integration/postgres_adapter_spec.rb +19 -20
- data/spec/integration/property_spec.rb +17 -8
- data/spec/integration/query_spec.rb +273 -191
- data/spec/integration/resource_spec.rb +108 -10
- data/spec/integration/strategic_eager_loading_spec.rb +138 -0
- data/spec/integration/transaction_spec.rb +3 -3
- data/spec/integration/type_spec.rb +121 -0
- data/spec/lib/logging_helper.rb +18 -0
- data/spec/lib/model_loader.rb +91 -0
- data/spec/lib/publicize_methods.rb +28 -0
- data/spec/models/vehicles.rb +34 -0
- data/spec/models/zoo.rb +48 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +25 -62
- data/spec/unit/adapters/data_objects_adapter_spec.rb +1 -0
- data/spec/unit/associations/many_to_many_spec.rb +3 -0
- data/spec/unit/associations/many_to_one_spec.rb +9 -1
- data/spec/unit/associations/one_to_many_spec.rb +12 -4
- data/spec/unit/associations/relationship_spec.rb +19 -15
- data/spec/unit/associations_spec.rb +37 -0
- data/spec/unit/collection_spec.rb +8 -0
- data/spec/unit/data_mapper_spec.rb +14 -0
- data/spec/unit/model_spec.rb +2 -2
- data/spec/unit/property_set_spec.rb +0 -13
- data/spec/unit/property_spec.rb +92 -21
- data/spec/unit/query_spec.rb +49 -4
- data/spec/unit/resource_spec.rb +122 -60
- data/spec/unit/scope_spec.rb +11 -0
- data/tasks/ci.rb +68 -0
- data/tasks/dm.rb +63 -0
- data/tasks/doc.rb +20 -0
- data/tasks/hoe.rb +38 -0
- data/tasks/install.rb +20 -0
- metadata +63 -22
@@ -0,0 +1,91 @@
|
|
1
|
+
# ---
|
2
|
+
# Overview
|
3
|
+
# ========
|
4
|
+
# ModelLoader is a method for loading methods models for specs in a way
|
5
|
+
# that will ensure that each spec will be an a pristine state when run.
|
6
|
+
#
|
7
|
+
# The problem is that if a spec needs to modify a model, the modifications
|
8
|
+
# should not carry over to the next spec. As such, all models are
|
9
|
+
# destroyed at the end of the spec and reloaded at the start.
|
10
|
+
#
|
11
|
+
# The second problem is that DataMapper::Resource keeps track
|
12
|
+
# of every class that it is included in. This is used for automigration.
|
13
|
+
# A number of specs run automigrate, and we don't want all the classes
|
14
|
+
# that were defined in other specs to be migrated as well.
|
15
|
+
#
|
16
|
+
# Usage
|
17
|
+
# =====
|
18
|
+
#
|
19
|
+
# Sets the specified model metaphors to be loaded before each spec and
|
20
|
+
# destroyed after each spec in the current example group. This method
|
21
|
+
# can be used in a describe block or in a before block.
|
22
|
+
#
|
23
|
+
# ==== Parameters
|
24
|
+
# *metaphor<Symbol>:: The name of the metaphor to load (this is just the filename of
|
25
|
+
# file in specs/models)
|
26
|
+
#
|
27
|
+
# ==== Example
|
28
|
+
#
|
29
|
+
# describe "DataMapper::Associations" do
|
30
|
+
#
|
31
|
+
# load_models_for_metaphor :zoo, :blog
|
32
|
+
#
|
33
|
+
# it "should be awesome" do
|
34
|
+
# Zoo.new.should be_awesome
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
module ModelLoader
|
38
|
+
|
39
|
+
def self.included(base)
|
40
|
+
base.extend(ClassMethods)
|
41
|
+
base.class_eval { include InstanceMethods }
|
42
|
+
# base.before(:each) { load_models(:global) }
|
43
|
+
base.after(:each) { unload_models }
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
|
48
|
+
def load_models_for_metaphor(*metaphors)
|
49
|
+
before(:each) { load_models_for_metaphor(*metaphors) }
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
module InstanceMethods
|
55
|
+
|
56
|
+
def load_models_for_metaphor(*metaphors)
|
57
|
+
files = metaphors.map { |m| DataMapper.root / "spec" / "models" / "#{m}.rb" }
|
58
|
+
|
59
|
+
klasses = object_space_classes.dup
|
60
|
+
files.each { |file| load file }
|
61
|
+
loaded_models.concat(object_space_classes - klasses)
|
62
|
+
end
|
63
|
+
|
64
|
+
def unload_models
|
65
|
+
while model = loaded_models.pop
|
66
|
+
remove_model(model)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def loaded_models
|
71
|
+
@loaded_models ||= []
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def object_space_classes
|
77
|
+
klasses = []
|
78
|
+
ObjectSpace.each_object(Class) {|o| klasses << o}
|
79
|
+
klasses
|
80
|
+
end
|
81
|
+
|
82
|
+
def remove_model(klass)
|
83
|
+
DataMapper::Resource.descendants.delete(klass)
|
84
|
+
Object.module_eval { remove_const klass.to_s }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Spec::Runner.configure do |config|
|
90
|
+
config.include(ModelLoader)
|
91
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Class
|
2
|
+
def publicize_methods
|
3
|
+
klass = class << self; self; end
|
4
|
+
|
5
|
+
saved_private_class_methods = klass.private_instance_methods
|
6
|
+
saved_protected_class_methods = klass.protected_instance_methods
|
7
|
+
saved_private_instance_methods = self.private_instance_methods
|
8
|
+
saved_protected_instance_methods = self.protected_instance_methods
|
9
|
+
|
10
|
+
self.class_eval do
|
11
|
+
klass.send(:public, *saved_private_class_methods)
|
12
|
+
klass.send(:public, *saved_protected_class_methods)
|
13
|
+
public(*saved_private_instance_methods)
|
14
|
+
public(*saved_protected_instance_methods)
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
yield
|
19
|
+
ensure
|
20
|
+
self.class_eval do
|
21
|
+
klass.send(:private, *saved_private_class_methods)
|
22
|
+
klass.send(:protected, *saved_protected_class_methods)
|
23
|
+
private(*saved_private_instance_methods)
|
24
|
+
protected(*saved_protected_instance_methods)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# ==========================
|
2
|
+
# Used for Association specs
|
3
|
+
# ---
|
4
|
+
# These models will probably
|
5
|
+
# end up removed. So, I wouldn't
|
6
|
+
# use this metaphor
|
7
|
+
class Vehicle
|
8
|
+
include DataMapper::Resource
|
9
|
+
|
10
|
+
property :id, Serial
|
11
|
+
property :name, String
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :mock_relationship
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Manufacturer
|
19
|
+
include DataMapper::Resource
|
20
|
+
|
21
|
+
property :id, Serial
|
22
|
+
property :name, String
|
23
|
+
|
24
|
+
class << self
|
25
|
+
attr_accessor :mock_relationship
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Supplier
|
30
|
+
include DataMapper::Resource
|
31
|
+
|
32
|
+
property :id, Serial
|
33
|
+
property :name, String
|
34
|
+
end
|
data/spec/models/zoo.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
class Zoo
|
2
|
+
include DataMapper::Resource
|
3
|
+
|
4
|
+
property :id, Serial
|
5
|
+
property :name, String
|
6
|
+
property :description, Text
|
7
|
+
property :inception, DateTime
|
8
|
+
property :open, Boolean, :default => false
|
9
|
+
property :size, Integer
|
10
|
+
|
11
|
+
has n, :animals
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Species
|
19
|
+
include DataMapper::Resource
|
20
|
+
|
21
|
+
property :id, Serial
|
22
|
+
property :name, String
|
23
|
+
property :classification, String, :reader => :private
|
24
|
+
|
25
|
+
has n, :animals
|
26
|
+
end
|
27
|
+
|
28
|
+
class Animal
|
29
|
+
include DataMapper::Resource
|
30
|
+
|
31
|
+
property :id, Serial
|
32
|
+
property :name, String
|
33
|
+
|
34
|
+
belongs_to :zoo
|
35
|
+
belongs_to :species
|
36
|
+
belongs_to :keeper
|
37
|
+
end
|
38
|
+
|
39
|
+
class Employee
|
40
|
+
include DataMapper::Resource
|
41
|
+
|
42
|
+
property :id, Serial
|
43
|
+
property :name, String
|
44
|
+
end
|
45
|
+
|
46
|
+
class Keeper < Employee
|
47
|
+
has n, :animals
|
48
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
CHANGED
@@ -3,8 +3,13 @@ gem 'rspec', '>=1.1.3'
|
|
3
3
|
require 'spec'
|
4
4
|
require 'pathname'
|
5
5
|
|
6
|
-
|
7
|
-
require
|
6
|
+
SPEC_ROOT = Pathname(__FILE__).dirname.expand_path
|
7
|
+
require SPEC_ROOT.parent + 'lib/dm-core'
|
8
|
+
|
9
|
+
# Load the various helpers for the spec suite
|
10
|
+
Dir[DataMapper.root / 'spec' / 'lib' / '*.rb'].each do |file|
|
11
|
+
require file
|
12
|
+
end
|
8
13
|
|
9
14
|
# setup mock adapters
|
10
15
|
[ :default, :mock, :legacy, :west_coast, :east_coast ].each do |repository_name|
|
@@ -33,6 +38,22 @@ HAS_POSTGRES = setup_adapter(:postgres, 'postgres://postgres@localhost/dm_core_t
|
|
33
38
|
|
34
39
|
DataMapper::Logger.new(nil, :debug)
|
35
40
|
|
41
|
+
# ----------------------------------------------------------------------
|
42
|
+
# --- Do not declare new models unless absolutely necessary. Instead ---
|
43
|
+
# --- pick a metaphor and use those models. If you do need new ---
|
44
|
+
# --- models, define them according to the metaphor being used. ---
|
45
|
+
# ----------------------------------------------------------------------
|
46
|
+
|
47
|
+
Spec::Runner.configure do |config|
|
48
|
+
config.before(:each) do
|
49
|
+
# load_models_for_metaphor :vehicles
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# ----------------------------------------------------------------------
|
54
|
+
# --- All these models are going to be removed. Don't use them!!! ---
|
55
|
+
# ----------------------------------------------------------------------
|
56
|
+
|
36
57
|
class Article
|
37
58
|
include DataMapper::Resource
|
38
59
|
|
@@ -45,68 +66,10 @@ end
|
|
45
66
|
|
46
67
|
class Comment
|
47
68
|
include DataMapper::Resource
|
69
|
+
|
70
|
+
property :id, Serial # blah
|
48
71
|
end
|
49
72
|
|
50
73
|
class NormalClass
|
51
74
|
# should not include DataMapper::Resource
|
52
75
|
end
|
53
|
-
|
54
|
-
# ==========================
|
55
|
-
# Used for Association specs
|
56
|
-
class Vehicle
|
57
|
-
include DataMapper::Resource
|
58
|
-
|
59
|
-
property :id, Serial
|
60
|
-
property :name, String
|
61
|
-
|
62
|
-
class << self
|
63
|
-
attr_accessor :mock_relationship
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class Manufacturer
|
68
|
-
include DataMapper::Resource
|
69
|
-
|
70
|
-
property :id, Serial
|
71
|
-
property :name, String
|
72
|
-
|
73
|
-
class << self
|
74
|
-
attr_accessor :mock_relationship
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class Supplier
|
79
|
-
include DataMapper::Resource
|
80
|
-
|
81
|
-
property :id, Serial
|
82
|
-
property :name, String
|
83
|
-
end
|
84
|
-
|
85
|
-
class Class
|
86
|
-
def publicize_methods
|
87
|
-
klass = class << self; self; end
|
88
|
-
|
89
|
-
saved_private_class_methods = klass.private_instance_methods
|
90
|
-
saved_protected_class_methods = klass.protected_instance_methods
|
91
|
-
saved_private_instance_methods = self.private_instance_methods
|
92
|
-
saved_protected_instance_methods = self.protected_instance_methods
|
93
|
-
|
94
|
-
self.class_eval do
|
95
|
-
klass.send(:public, *saved_private_class_methods)
|
96
|
-
klass.send(:public, *saved_protected_class_methods)
|
97
|
-
public(*saved_private_instance_methods)
|
98
|
-
public(*saved_protected_instance_methods)
|
99
|
-
end
|
100
|
-
|
101
|
-
begin
|
102
|
-
yield
|
103
|
-
ensure
|
104
|
-
self.class_eval do
|
105
|
-
klass.send(:private, *saved_private_class_methods)
|
106
|
-
klass.send(:protected, *saved_protected_class_methods)
|
107
|
-
private(*saved_private_instance_methods)
|
108
|
-
protected(*saved_protected_instance_methods)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
@@ -247,6 +247,7 @@ describe DataMapper::Adapters::DataObjectsAdapter do
|
|
247
247
|
@order = [ @direction ]
|
248
248
|
|
249
249
|
@query = mock('query', :model => @model, :kind_of? => true, :links => @links, :fields => @fields, :conditions => @conditions, :order => @order, :limit => 111, :offset => 222, :bind_values => @bind_values)
|
250
|
+
@query.should_receive(:unique?).with(no_args).and_return(false)
|
250
251
|
|
251
252
|
@reader = mock('reader', :close => true, :next! => false)
|
252
253
|
@command = mock('command', :set_types => nil, :execute_reader => @reader)
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
2
|
|
3
3
|
describe DataMapper::Associations::ManyToOne do
|
4
|
+
|
5
|
+
load_models_for_metaphor :vehicles
|
6
|
+
|
4
7
|
it 'should allow a declaration' do
|
5
8
|
lambda do
|
6
9
|
class Vehicle
|
@@ -11,10 +14,13 @@ describe DataMapper::Associations::ManyToOne do
|
|
11
14
|
end
|
12
15
|
|
13
16
|
describe DataMapper::Associations::ManyToOne::Proxy do
|
17
|
+
|
18
|
+
load_models_for_metaphor :vehicles
|
19
|
+
|
14
20
|
before do
|
15
21
|
@child = mock('child', :kind_of? => true)
|
16
22
|
@parent = mock('parent')
|
17
|
-
@relationship = mock('relationship', :kind_of? => true, :
|
23
|
+
@relationship = mock('relationship', :kind_of? => true, :get_parent => @parent, :attach_parent => nil)
|
18
24
|
@association = DataMapper::Associations::ManyToOne::Proxy.new(@relationship, @child)
|
19
25
|
|
20
26
|
@association.replace(@parent)
|
@@ -89,11 +95,13 @@ describe DataMapper::Associations::ManyToOne::Proxy do
|
|
89
95
|
end
|
90
96
|
|
91
97
|
it 'should save the parent' do
|
98
|
+
@relationship.should_receive(:with_repository).and_yield(@repository)
|
92
99
|
@parent.should_receive(:save).with(no_args)
|
93
100
|
@association.save
|
94
101
|
end
|
95
102
|
|
96
103
|
it 'should return the result of the save' do
|
104
|
+
@relationship.should_receive(:with_repository).and_yield(@repository)
|
97
105
|
save_results = mock('save results')
|
98
106
|
@parent.should_receive(:save).with(no_args).and_return(save_results)
|
99
107
|
@association.save.object_id.should == save_results.object_id
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
2
|
|
3
3
|
describe DataMapper::Associations::OneToMany do
|
4
|
+
|
5
|
+
load_models_for_metaphor :vehicles
|
6
|
+
|
4
7
|
before do
|
5
8
|
@class = Class.new do
|
6
9
|
def self.name
|
@@ -30,7 +33,7 @@ describe DataMapper::Associations::OneToMany do
|
|
30
33
|
|
31
34
|
it 'should receive the name' do
|
32
35
|
DataMapper::Associations::Relationship.should_receive(:new) do |name,_,_,_,_|
|
33
|
-
name.should == :
|
36
|
+
name.should == :orders
|
34
37
|
end
|
35
38
|
@class.has(@class.n, :orders)
|
36
39
|
end
|
@@ -60,7 +63,7 @@ describe DataMapper::Associations::OneToMany do
|
|
60
63
|
|
61
64
|
it 'should receive the parent model name' do
|
62
65
|
DataMapper::Associations::Relationship.should_receive(:new) do |_,_,_,parent_model_name,_|
|
63
|
-
parent_model_name.should ==
|
66
|
+
parent_model_name.should == @class
|
64
67
|
end
|
65
68
|
@class.has(@class.n, :orders)
|
66
69
|
end
|
@@ -106,8 +109,9 @@ describe DataMapper::Associations::OneToMany::Proxy do
|
|
106
109
|
@parent = mock('parent', :new_record? => true, :kind_of? => true)
|
107
110
|
@resource = mock('resource', :null_object => true)
|
108
111
|
@collection = []
|
112
|
+
@parent_key = mock('parent key', :get => [])
|
109
113
|
@repository = mock('repository', :save => nil, :kind_of? => true)
|
110
|
-
@relationship = mock('relationship', :get_children => @collection, :
|
114
|
+
@relationship = mock('relationship', :get_children => @collection, :query => {}, :kind_of? => true, :child_key => [], :parent_key => @parent_key)
|
111
115
|
@association = DataMapper::Associations::OneToMany::Proxy.new(@relationship, @parent)
|
112
116
|
end
|
113
117
|
|
@@ -124,6 +128,7 @@ describe DataMapper::Associations::OneToMany::Proxy do
|
|
124
128
|
end
|
125
129
|
|
126
130
|
it 'should persist the addition after saving the association' do
|
131
|
+
@relationship.should_receive(:with_repository).with(@resource).and_yield(@repository)
|
127
132
|
do_add.should == return_value
|
128
133
|
@relationship.should_receive(:attach_parent).with(@resource, @parent)
|
129
134
|
@association.save
|
@@ -147,6 +152,7 @@ describe DataMapper::Associations::OneToMany::Proxy do
|
|
147
152
|
end
|
148
153
|
|
149
154
|
it 'should persist the removal after saving the association' do
|
155
|
+
@relationship.should_receive(:with_repository).with(@resource).and_yield(@repository)
|
150
156
|
do_remove.should == return_value
|
151
157
|
@relationship.should_receive(:attach_parent).with(@resource, nil)
|
152
158
|
@association.save
|
@@ -237,6 +243,7 @@ describe DataMapper::Associations::OneToMany::Proxy do
|
|
237
243
|
|
238
244
|
it 'should persist the removal after saving the association' do
|
239
245
|
do_replace.should == return_value
|
246
|
+
@relationship.should_receive(:with_repository).exactly(3).times.and_yield(@repository)
|
240
247
|
@relationship.should_receive(:attach_parent).with(@resource, nil)
|
241
248
|
@association.save
|
242
249
|
end
|
@@ -248,6 +255,7 @@ describe DataMapper::Associations::OneToMany::Proxy do
|
|
248
255
|
|
249
256
|
it 'should persist the addition after saving the association' do
|
250
257
|
do_replace.should == return_value
|
258
|
+
@relationship.should_receive(:with_repository).exactly(3).times.and_yield(@repository)
|
251
259
|
@relationship.should_receive(:attach_parent).with(@children[0], @parent)
|
252
260
|
@relationship.should_receive(:attach_parent).with(@children[1], @parent)
|
253
261
|
@association.save
|
@@ -334,7 +342,7 @@ describe DataMapper::Associations::OneToMany::Proxy do
|
|
334
342
|
it_should_behave_like 'a method that orphans the resource'
|
335
343
|
|
336
344
|
it 'should empty the collection' do
|
337
|
-
@association << mock('other resource')
|
345
|
+
@association << mock('other resource', :new_record? => false)
|
338
346
|
@association.should have(2).entries
|
339
347
|
do_remove
|
340
348
|
@association.should be_empty
|