dm-core 0.9.2
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/CHANGELOG +144 -0
- data/FAQ +74 -0
- data/MIT-LICENSE +22 -0
- data/QUICKLINKS +12 -0
- data/README +143 -0
- data/lib/dm-core.rb +213 -0
- data/lib/dm-core/adapters.rb +4 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
- data/lib/dm-core/adapters/data_objects_adapter.rb +701 -0
- data/lib/dm-core/adapters/mysql_adapter.rb +132 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +179 -0
- data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
- data/lib/dm-core/associations.rb +172 -0
- data/lib/dm-core/associations/many_to_many.rb +138 -0
- data/lib/dm-core/associations/many_to_one.rb +101 -0
- data/lib/dm-core/associations/one_to_many.rb +275 -0
- data/lib/dm-core/associations/one_to_one.rb +61 -0
- data/lib/dm-core/associations/relationship.rb +116 -0
- data/lib/dm-core/associations/relationship_chain.rb +74 -0
- data/lib/dm-core/auto_migrations.rb +64 -0
- data/lib/dm-core/collection.rb +604 -0
- data/lib/dm-core/hook.rb +11 -0
- data/lib/dm-core/identity_map.rb +45 -0
- data/lib/dm-core/is.rb +16 -0
- data/lib/dm-core/logger.rb +233 -0
- data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
- data/lib/dm-core/migrator.rb +29 -0
- data/lib/dm-core/model.rb +399 -0
- data/lib/dm-core/naming_conventions.rb +52 -0
- data/lib/dm-core/property.rb +611 -0
- data/lib/dm-core/property_set.rb +158 -0
- data/lib/dm-core/query.rb +590 -0
- data/lib/dm-core/repository.rb +159 -0
- data/lib/dm-core/resource.rb +618 -0
- data/lib/dm-core/scope.rb +35 -0
- data/lib/dm-core/support.rb +7 -0
- data/lib/dm-core/support/array.rb +13 -0
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/errors.rb +23 -0
- data/lib/dm-core/support/kernel.rb +7 -0
- data/lib/dm-core/support/symbol.rb +41 -0
- data/lib/dm-core/transaction.rb +267 -0
- data/lib/dm-core/type.rb +160 -0
- data/lib/dm-core/type_map.rb +80 -0
- data/lib/dm-core/types.rb +19 -0
- data/lib/dm-core/types/boolean.rb +7 -0
- data/lib/dm-core/types/discriminator.rb +32 -0
- data/lib/dm-core/types/object.rb +20 -0
- data/lib/dm-core/types/paranoid_boolean.rb +23 -0
- data/lib/dm-core/types/paranoid_datetime.rb +22 -0
- data/lib/dm-core/types/serial.rb +9 -0
- data/lib/dm-core/types/text.rb +10 -0
- data/spec/integration/association_spec.rb +1215 -0
- data/spec/integration/association_through_spec.rb +150 -0
- data/spec/integration/associations/many_to_many_spec.rb +171 -0
- data/spec/integration/associations/many_to_one_spec.rb +123 -0
- data/spec/integration/associations/one_to_many_spec.rb +66 -0
- data/spec/integration/auto_migrations_spec.rb +398 -0
- data/spec/integration/collection_spec.rb +1015 -0
- data/spec/integration/data_objects_adapter_spec.rb +32 -0
- data/spec/integration/model_spec.rb +68 -0
- data/spec/integration/mysql_adapter_spec.rb +85 -0
- data/spec/integration/postgres_adapter_spec.rb +732 -0
- data/spec/integration/property_spec.rb +224 -0
- data/spec/integration/query_spec.rb +376 -0
- data/spec/integration/repository_spec.rb +57 -0
- data/spec/integration/resource_spec.rb +324 -0
- data/spec/integration/sqlite3_adapter_spec.rb +352 -0
- data/spec/integration/sti_spec.rb +185 -0
- data/spec/integration/transaction_spec.rb +75 -0
- data/spec/integration/type_spec.rb +149 -0
- data/spec/lib/mock_adapter.rb +27 -0
- data/spec/spec_helper.rb +112 -0
- data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
- data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
- data/spec/unit/adapters/data_objects_adapter_spec.rb +627 -0
- data/spec/unit/adapters/postgres_adapter_spec.rb +125 -0
- data/spec/unit/associations/many_to_many_spec.rb +14 -0
- data/spec/unit/associations/many_to_one_spec.rb +138 -0
- data/spec/unit/associations/one_to_many_spec.rb +385 -0
- data/spec/unit/associations/one_to_one_spec.rb +7 -0
- data/spec/unit/associations/relationship_spec.rb +67 -0
- data/spec/unit/associations_spec.rb +205 -0
- data/spec/unit/auto_migrations_spec.rb +110 -0
- data/spec/unit/collection_spec.rb +174 -0
- data/spec/unit/data_mapper_spec.rb +21 -0
- data/spec/unit/identity_map_spec.rb +126 -0
- data/spec/unit/is_spec.rb +80 -0
- data/spec/unit/migrator_spec.rb +33 -0
- data/spec/unit/model_spec.rb +339 -0
- data/spec/unit/naming_conventions_spec.rb +28 -0
- data/spec/unit/property_set_spec.rb +96 -0
- data/spec/unit/property_spec.rb +447 -0
- data/spec/unit/query_spec.rb +485 -0
- data/spec/unit/repository_spec.rb +93 -0
- data/spec/unit/resource_spec.rb +557 -0
- data/spec/unit/scope_spec.rb +131 -0
- data/spec/unit/transaction_spec.rb +493 -0
- data/spec/unit/type_map_spec.rb +114 -0
- data/spec/unit/type_spec.rb +119 -0
- metadata +187 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
describe "DataMapper::NamingConventions" do
|
|
4
|
+
it "should coerce a string into the Underscored convention" do
|
|
5
|
+
DataMapper::NamingConventions::Underscored.call('User').should == 'user'
|
|
6
|
+
DataMapper::NamingConventions::Underscored.call('UserAccountSetting').should == 'user_account_setting'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should coerce a string into the UnderscoredAndPluralized convention" do
|
|
10
|
+
DataMapper::NamingConventions::UnderscoredAndPluralized.call('User').should == 'users'
|
|
11
|
+
DataMapper::NamingConventions::UnderscoredAndPluralized.call('UserAccountSetting').should == 'user_account_settings'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should coerce a string into the UnderscoredAndPluralized convention joining namespace with underscore" do
|
|
15
|
+
DataMapper::NamingConventions::UnderscoredAndPluralized.call('Model::User').should == 'model_users'
|
|
16
|
+
DataMapper::NamingConventions::UnderscoredAndPluralized.call('Model::UserAccountSetting').should == 'model_user_account_settings'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should coerce a string into the UnderscoredAndPluralizedWithoutModule convention" do
|
|
20
|
+
DataMapper::NamingConventions::UnderscoredAndPluralizedWithoutModule.call('Model::User').should == 'users'
|
|
21
|
+
DataMapper::NamingConventions::UnderscoredAndPluralizedWithoutModule.call('Model::UserAccountSetting').should == 'user_account_settings'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should coerce a string into the Yaml convention" do
|
|
25
|
+
DataMapper::NamingConventions::Yaml.call('UserSetting').should == 'user_settings.yaml'
|
|
26
|
+
DataMapper::NamingConventions::Yaml.call('User').should == 'users.yaml'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
class Icon
|
|
4
|
+
include DataMapper::Resource
|
|
5
|
+
|
|
6
|
+
property :id, Serial
|
|
7
|
+
property :name, String
|
|
8
|
+
property :width, Integer, :lazy => true
|
|
9
|
+
property :height, Integer, :lazy => true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Boat
|
|
13
|
+
include DataMapper::Resource
|
|
14
|
+
property :name, String #not lazy
|
|
15
|
+
property :text, DataMapper::Types::Text #Lazy by default
|
|
16
|
+
property :notes, String, :lazy => true
|
|
17
|
+
property :a1, String, :lazy => [:ctx_a,:ctx_c]
|
|
18
|
+
property :a2, String, :lazy => [:ctx_a,:ctx_b]
|
|
19
|
+
property :a3, String, :lazy => [:ctx_a]
|
|
20
|
+
property :b1, String, :lazy => [:ctx_b]
|
|
21
|
+
property :b2, String, :lazy => [:ctx_b]
|
|
22
|
+
property :b3, String, :lazy => [:ctx_b]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe DataMapper::PropertySet do
|
|
26
|
+
before :each do
|
|
27
|
+
@properties = Icon.properties(:default)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "#slice should find properties" do
|
|
31
|
+
@properties.slice(:name, 'width').should have(2).entries
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "#select should find properties" do
|
|
35
|
+
@properties.select { |property| property.primitive == Integer }.should have(3).entries
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "#[] should find properties by name (Symbol or String)" do
|
|
39
|
+
default_properties = [ :id, 'name', :width, 'height' ]
|
|
40
|
+
@properties.each_with_index do |property,i|
|
|
41
|
+
property.should == @properties[default_properties[i]]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should provide defaults" do
|
|
46
|
+
@properties.defaults.should have(2).entries
|
|
47
|
+
@properties.should have(4).entries
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'should add a property for lazy loading to the :default context if a context is not supplied' do
|
|
51
|
+
Boat.properties(:default).lazy_context(:default).length.should == 2 # text & notes
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'should return a list of contexts that a given field is in' do
|
|
55
|
+
props = Boat.properties(:default)
|
|
56
|
+
set = props.property_contexts(:a1)
|
|
57
|
+
set.include?(:ctx_a).should == true
|
|
58
|
+
set.include?(:ctx_c).should == true
|
|
59
|
+
set.include?(:ctx_b).should == false
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'should return a list of expanded fields that should be loaded with a given field' do
|
|
63
|
+
props = Boat.properties(:default)
|
|
64
|
+
set = props.lazy_load_context(:a2)
|
|
65
|
+
expect = [:a1,:a2,:a3,:b1,:b2,:b3]
|
|
66
|
+
expect.should == set.sort! {|a,b| a.to_s <=> b.to_s}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe 'when dup\'ed' do
|
|
70
|
+
it 'should duplicate the @entries ivar' do
|
|
71
|
+
@properties.dup.entries.should_not equal(@properties.entries)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'should reinitialize @properties_for' do
|
|
75
|
+
# force @properties_for to hold a property
|
|
76
|
+
Icon.properties(:default)[:name].should_not be_nil
|
|
77
|
+
@properties = Icon.properties(:default)
|
|
78
|
+
|
|
79
|
+
@properties.instance_variable_get("@property_for").should_not be_empty
|
|
80
|
+
@properties.dup.instance_variable_get("@property_for").should be_empty
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'should be able to retarget a new model' do
|
|
84
|
+
copy = Icon.properties.dup(Boat)
|
|
85
|
+
copy.should have(4).entries
|
|
86
|
+
|
|
87
|
+
copy.each do |property|
|
|
88
|
+
property.model.should == Boat
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
copy << DataMapper::Property.new(Icon, :z_index, Integer, {})
|
|
92
|
+
copy.should have(5).entries
|
|
93
|
+
Icon.properties.should have(4).entries
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
describe DataMapper::Property do
|
|
4
|
+
before :all do
|
|
5
|
+
class Zoo
|
|
6
|
+
include DataMapper::Resource
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Name < DataMapper::Type
|
|
10
|
+
primitive String
|
|
11
|
+
size 100
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Tomato
|
|
15
|
+
include DataMapper::Resource
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
@property = DataMapper::Property.new(Zoo, :name, String, :default => 'San Diego')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'should provide .new' do
|
|
24
|
+
DataMapper::Property.should respond_to(:new)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe '.new' do
|
|
28
|
+
[ Float, BigDecimal ].each do |primitive|
|
|
29
|
+
describe "with a #{primitive} primitive" do
|
|
30
|
+
it 'should raise an ArgumentError if precision is equal to or less than 0' do
|
|
31
|
+
lambda{
|
|
32
|
+
DataMapper::Property.new(Zoo, :test, primitive, :precision => 0)
|
|
33
|
+
}.should raise_error(ArgumentError)
|
|
34
|
+
|
|
35
|
+
lambda{
|
|
36
|
+
DataMapper::Property.new(Zoo, :test, primitive, :precision => -1)
|
|
37
|
+
}.should raise_error(ArgumentError)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'should raise an ArgumentError if scale is less than 0' do
|
|
41
|
+
lambda{
|
|
42
|
+
DataMapper::Property.new(Zoo, :test, primitive, :scale => -1)
|
|
43
|
+
}.should raise_error(ArgumentError)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'should raise an ArgumentError if precision is less than scale' do
|
|
47
|
+
lambda{
|
|
48
|
+
DataMapper::Property.new(Zoo, :test, primitive, :precision => 1, :scale => 2)
|
|
49
|
+
}.should raise_error(ArgumentError)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'should provide #get' do
|
|
56
|
+
@property.should respond_to(:get)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe '#get' do
|
|
60
|
+
before do
|
|
61
|
+
@original_values = {}
|
|
62
|
+
@resource = mock('resource', :kind_of? => true, :new_record? => true, :original_values => @original_values)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe 'when setting the default on initial access' do
|
|
66
|
+
before do
|
|
67
|
+
# make sure there was no original value
|
|
68
|
+
@original_values.should_not have_key(:name)
|
|
69
|
+
|
|
70
|
+
# force the default to be set
|
|
71
|
+
@resource.should_receive(:instance_variable_get).with('@name').twice.and_return(nil)
|
|
72
|
+
@resource.should_receive(:attribute_loaded?).with(:name).and_return(false)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'should set the ivar to the default' do
|
|
76
|
+
@resource.should_receive(:instance_variable_set).with('@name', 'San Diego')
|
|
77
|
+
|
|
78
|
+
@property.get(@resource).should == 'San Diego'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'should set the original value to nil' do
|
|
82
|
+
@property.get(@resource).should == 'San Diego'
|
|
83
|
+
|
|
84
|
+
@original_values.should == { :name => nil }
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'should provide #get!' do
|
|
90
|
+
@property.should respond_to(:get!)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe '#get!' do
|
|
94
|
+
it 'should get the resource instance variable' do
|
|
95
|
+
resource = mock('resource', :kind_of? => true)
|
|
96
|
+
resource.should_receive(:instance_variable_get).with('@name').and_return('Portland Zoo')
|
|
97
|
+
@property.get!(resource).should == 'Portland Zoo'
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'should provide #set' do
|
|
102
|
+
@property.should respond_to(:set)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe '#set' do
|
|
106
|
+
before do
|
|
107
|
+
@original_values = {}
|
|
108
|
+
@resource = mock('resource', :kind_of? => true, :original_values => @original_values)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'should typecast the value' do
|
|
112
|
+
@property.should_receive(:typecast).with(888)
|
|
113
|
+
@property.set(@resource, 888)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'should provide #set!' do
|
|
118
|
+
@property.should respond_to(:set!)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
describe '#set!' do
|
|
122
|
+
it 'should set the resource instance variable' do
|
|
123
|
+
resource = mock('resource', :kind_of? => true)
|
|
124
|
+
resource.should_receive(:instance_variable_set).with('@name', 'Seattle Zoo').and_return(resource)
|
|
125
|
+
@property.set!(resource, 'Seattle Zoo').object_id.should == resource.object_id
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "should evaluate two similar properties as equal" do
|
|
130
|
+
p1 = DataMapper::Property.new(Zoo, :name, String, { :size => 30 })
|
|
131
|
+
p2 = DataMapper::Property.new(Zoo, :name, String, { :size => 30 })
|
|
132
|
+
p3 = DataMapper::Property.new(Zoo, :title, String, { :size => 30 })
|
|
133
|
+
p1.eql?(p2).should == true
|
|
134
|
+
p1.hash.should == p2.hash
|
|
135
|
+
p1.eql?(p3).should == false
|
|
136
|
+
p1.hash.should_not == p3.hash
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "should create a String property" do
|
|
140
|
+
property = DataMapper::Property.new(Zoo, :name, String, { :size => 30 })
|
|
141
|
+
|
|
142
|
+
property.primitive.should == String
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "should not have key that is lazy" do
|
|
146
|
+
property = DataMapper::Property.new(Zoo, :id, DataMapper::Types::Text, { :key => true })
|
|
147
|
+
property.lazy?.should == false
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "should use a custom type Name property" do
|
|
151
|
+
class Name < DataMapper::Type
|
|
152
|
+
primitive String
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
property = DataMapper::Property.new(Zoo, :name, Name, {})
|
|
156
|
+
|
|
157
|
+
property.primitive.should == String
|
|
158
|
+
property.type.should == Name
|
|
159
|
+
property.primitive.should == property.type.primitive
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "should override type options with property options" do
|
|
163
|
+
property = DataMapper::Property.new(Zoo, :name, Name, { :size => 50 })
|
|
164
|
+
options = property.instance_variable_get(:@options)
|
|
165
|
+
|
|
166
|
+
options[:size].should == 50
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it "should determine nullness" do
|
|
170
|
+
DataMapper::Property.new(Tomato,:botanical_name,String,{:nullable => true}).options[:nullable].should == true
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it "should determine its name" do
|
|
174
|
+
DataMapper::Property.new(Tomato,:botanical_name,String,{}).name.should == :botanical_name
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "should determine laziness" do
|
|
178
|
+
DataMapper::Property.new(Tomato,:botanical_name,String,{:lazy => true}).lazy?.should == true
|
|
179
|
+
DataMapper::Property.new(Tomato,:seedless,TrueClass,{}).lazy?.should == false
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it "should automatically set laziness to true on text fields?" do
|
|
183
|
+
DataMapper::Property.new(Tomato,:botanical_name,DataMapper::Types::Text,{}).lazy?.should == true
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "should determine whether it is a key" do
|
|
187
|
+
DataMapper::Property.new(Tomato,:id,Integer,{:key => true}).key?.should == true
|
|
188
|
+
DataMapper::Property.new(Tomato,:botanical_name,String,{}).key?.should == false
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it "should determine whether it is serial" do
|
|
192
|
+
DataMapper::Property.new(Tomato,:id,Integer,{:serial => true}).serial?.should == true
|
|
193
|
+
DataMapper::Property.new(Tomato,:botanical_name,String,{}).serial?.should == false
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "should determine a default value" do
|
|
197
|
+
resource = mock('resource')
|
|
198
|
+
property = DataMapper::Property.new(Tomato, :botanical_name, String, :default => 'Tomato')
|
|
199
|
+
property.default_for(resource).should == 'Tomato'
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it "should determine visibility of readers and writers" do
|
|
203
|
+
name = DataMapper::Property.new(Tomato,:botanical_name,String,{})
|
|
204
|
+
name.reader_visibility.should == :public
|
|
205
|
+
name.writer_visibility.should == :public
|
|
206
|
+
|
|
207
|
+
seeds = DataMapper::Property.new(Tomato,:seeds,TrueClass,{:accessor=>:private})
|
|
208
|
+
seeds.reader_visibility.should == :private
|
|
209
|
+
seeds.writer_visibility.should == :private
|
|
210
|
+
|
|
211
|
+
family = DataMapper::Property.new(Tomato,:family,String,{:reader => :public, :writer => :private })
|
|
212
|
+
family.reader_visibility.should == :public
|
|
213
|
+
family.writer_visibility.should == :private
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it "should return an instance variable name" do
|
|
217
|
+
DataMapper::Property.new(Tomato, :flavor, String, {}).instance_variable_name.should == '@flavor'
|
|
218
|
+
DataMapper::Property.new(Tomato, :ripe, TrueClass, {}).instance_variable_name.should == '@ripe' #not @ripe?
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "should append ? to TrueClass property reader methods" do
|
|
222
|
+
class Potato
|
|
223
|
+
include DataMapper::Resource
|
|
224
|
+
property :id, Integer, :key => true
|
|
225
|
+
property :fresh, TrueClass
|
|
226
|
+
property :public, TrueClass
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
Potato.new().should respond_to(:fresh)
|
|
230
|
+
Potato.new().should respond_to(:fresh?)
|
|
231
|
+
|
|
232
|
+
Potato.new(:fresh => true).should be_fresh
|
|
233
|
+
|
|
234
|
+
Potato.new().should respond_to(:public)
|
|
235
|
+
Potato.new().should respond_to(:public?)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "should raise an ArgumentError when created with an invalid option" do
|
|
239
|
+
lambda{
|
|
240
|
+
DataMapper::Property.new(Tomato,:botanical_name,String,{:foo=>:bar})
|
|
241
|
+
}.should raise_error(ArgumentError)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it 'should return the attribute value from a given instance' do
|
|
245
|
+
class Tomato
|
|
246
|
+
include DataMapper::Resource
|
|
247
|
+
property :id, Integer, :key => true
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
tomato = Tomato.new(:id => 1)
|
|
251
|
+
tomato.model.properties(:default)[:id].get(tomato).should == 1
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
it 'should set the attribute value in a given instance' do
|
|
255
|
+
tomato = Tomato.new
|
|
256
|
+
tomato.model.properties(:default)[:id].set(tomato, 2)
|
|
257
|
+
tomato.id.should == 2
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
it 'should provide #custom?' do
|
|
261
|
+
DataMapper::Property.new(Zoo, :name, Name, { :size => 50 }).should be_custom
|
|
262
|
+
DataMapper::Property.new(Zoo, :state, String, { :size => 2 }).should_not be_custom
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
it "should set the field to the correct field_naming_convention" do
|
|
266
|
+
DataMapper::Property.new(Zoo, :species, String, {}).field.should == 'species'
|
|
267
|
+
DataMapper::Property.new(Tomato, :genetic_history, DataMapper::Types::Text, {}).field.should == "genetic_history"
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it "should provide the primitive mapping" do
|
|
271
|
+
DataMapper::Property.new(Zoo, :poverty, String, {}).primitive.should == String
|
|
272
|
+
DataMapper::Property.new(Zoo, :fortune, DataMapper::Types::Text, {}).primitive.should == String
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it "should provide a size/length" do
|
|
276
|
+
DataMapper::Property.new(Zoo, :cleanliness, String, { :size => 100 }).size.should == 100
|
|
277
|
+
DataMapper::Property.new(Zoo, :cleanliness, String, { :length => 200 }).size.should == 200
|
|
278
|
+
DataMapper::Property.new(Zoo, :cleanliness, String, { :size => (0..100) }).size.should == 100
|
|
279
|
+
DataMapper::Property.new(Zoo, :cleanliness, String, { :length => (0..200) }).size.should == 200
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it 'should provide #typecast' do
|
|
283
|
+
DataMapper::Property.new(Zoo, :name, String).should respond_to(:typecast)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
describe '#typecast' do
|
|
287
|
+
def self.format(value)
|
|
288
|
+
case value
|
|
289
|
+
when BigDecimal then "BigDecimal(#{value.to_s('F').inspect})"
|
|
290
|
+
when Float, Integer, String then "#{value.class}(#{value.inspect})"
|
|
291
|
+
else value.inspect
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
it 'should pass through the value if it is the same type when typecasting' do
|
|
296
|
+
value = 'San Diego'
|
|
297
|
+
property = DataMapper::Property.new(Zoo, :name, String)
|
|
298
|
+
property.typecast(value).object_id.should == value.object_id
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
it 'should pass through the value nil when typecasting' do
|
|
302
|
+
property = DataMapper::Property.new(Zoo, :string, String)
|
|
303
|
+
property.typecast(nil).should == nil
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
it 'should pass through the value for an Object property' do
|
|
307
|
+
value = 'a ruby object'
|
|
308
|
+
property = DataMapper::Property.new(Zoo, :object, Object)
|
|
309
|
+
property.typecast(value).object_id.should == value.object_id
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
[ true, 'true', 'TRUE', 1, '1', 't', 'T' ].each do |value|
|
|
313
|
+
it "should typecast #{value.inspect} to true for a TrueClass property" do
|
|
314
|
+
property = DataMapper::Property.new(Zoo, :true_class, TrueClass)
|
|
315
|
+
property.typecast(value).should == true
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
[ false, 'false', 'FALSE', 0, '0', 'f', 'F' ].each do |value|
|
|
320
|
+
it "should typecast #{value.inspect} to false for a Boolean property" do
|
|
321
|
+
property = DataMapper::Property.new(Zoo, :true_class, TrueClass)
|
|
322
|
+
property.typecast(value).should == false
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it 'should typecast nil to nil for a Boolean property' do
|
|
327
|
+
property = DataMapper::Property.new(Zoo, :true_class, TrueClass)
|
|
328
|
+
property.typecast(nil).should == nil
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
it 'should typecast "0" to "0" for a String property' do
|
|
332
|
+
property = DataMapper::Property.new(Zoo, :string, String)
|
|
333
|
+
property.typecast(0).should == '0'
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
{ '0' => 0.0, '0.0' => 0.0, 0 => 0.0, 0.0 => 0.0, BigDecimal('0.0') => 0.0 }.each do |value,expected|
|
|
337
|
+
it "should typecast #{format(value)} to #{format(expected)} for a Float property" do
|
|
338
|
+
property = DataMapper::Property.new(Zoo, :float, Float)
|
|
339
|
+
property.typecast(value).should == expected
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
{ '0' => 0, '0.0' => 0, 0 => 0, 0.0 => 0, BigDecimal('0.0') => 0 }.each do |value,expected|
|
|
344
|
+
it "should typecast #{format(value)} to #{format(expected)} for an Integer property" do
|
|
345
|
+
property = DataMapper::Property.new(Zoo, :integer, Integer)
|
|
346
|
+
property.typecast(value).should == expected
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
{ '0' => BigDecimal('0'), '0.0' => BigDecimal('0.0'), 0.0 => BigDecimal('0.0'), BigDecimal('0.0') => BigDecimal('0.0') }.each do |value,expected|
|
|
351
|
+
it "should typecast #{format(value)} to #{format(expected)} for a BigDecimal property" do
|
|
352
|
+
property = DataMapper::Property.new(Zoo, :big_decimal, BigDecimal)
|
|
353
|
+
property.typecast(value).should == expected
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it 'should typecast value for a DateTime property' do
|
|
358
|
+
property = DataMapper::Property.new(Zoo, :date_time, DateTime)
|
|
359
|
+
property.typecast('2000-01-01 00:00:00').should == DateTime.new(2000, 1, 1, 0, 0, 0)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
it 'should typecast value for a Date property' do
|
|
363
|
+
property = DataMapper::Property.new(Zoo, :date, Date)
|
|
364
|
+
property.typecast('2000-01-01').should == Date.new(2000, 1, 1)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
it 'should typecast value for a Time property' do
|
|
368
|
+
property = DataMapper::Property.new(Zoo, :time, Time)
|
|
369
|
+
property.typecast('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
it 'should typecast Hash for a Time property' do
|
|
373
|
+
property = DataMapper::Property.new(Zoo, :time, Time)
|
|
374
|
+
property.typecast(
|
|
375
|
+
:year => 2002, "month" => 1, :day => 1, "hour" => 12, :min => 0, :sec => 0
|
|
376
|
+
).should == Time.local(2002, 1, 1, 12, 0, 0)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
it 'should typecast Hash for a Date property' do
|
|
380
|
+
property = DataMapper::Property.new(Zoo, :date, Date)
|
|
381
|
+
property.typecast(:year => 2002, "month" => 1, :day => 1).should == Date.new(2002, 1, 1)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
it 'should typecast Hash for a DateTime property' do
|
|
385
|
+
property = DataMapper::Property.new(Zoo, :date_time, DateTime)
|
|
386
|
+
property.typecast(
|
|
387
|
+
:year => 2002, :month => 1, :day => 1, "hour" => 12, :min => 0, "sec" => 0
|
|
388
|
+
).should == DateTime.new(2002, 1, 1, 12, 0, 0)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
it 'should use now as defaults for missing parts of a Hash to Time typecast' do
|
|
392
|
+
now = Time.now
|
|
393
|
+
property = DataMapper::Property.new(Zoo, :time, Time)
|
|
394
|
+
property.typecast(
|
|
395
|
+
:month => 1, :day => 1
|
|
396
|
+
).should == Time.local(now.year, 1, 1, now.hour, now.min, now.sec)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
it 'should use now as defaults for missing parts of a Hash to Date typecast' do
|
|
400
|
+
now = Time.now
|
|
401
|
+
property = DataMapper::Property.new(Zoo, :date, Date)
|
|
402
|
+
property.typecast(
|
|
403
|
+
:month => 1, :day => 1
|
|
404
|
+
).should == Date.new(now.year, 1, 1)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
it 'should use now as defaults for missing parts of a Hash to DateTime typecast' do
|
|
408
|
+
now = Time.now
|
|
409
|
+
property = DataMapper::Property.new(Zoo, :date_time, DateTime)
|
|
410
|
+
property.typecast(
|
|
411
|
+
:month => 1, :day => 1
|
|
412
|
+
).should == DateTime.new(now.year, 1, 1, now.hour, now.min, now.sec)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
it 'should rescue after trying to typecast an invalid Date value from a hash' do
|
|
416
|
+
property = DataMapper::Property.new(Zoo, :date, Date)
|
|
417
|
+
property.typecast(:year => 2002, :month => 2, :day => 31).should == Date.new(2002, 3, 3)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
it 'should rescue after trying to typecast an invalid DateTime value from a hash' do
|
|
421
|
+
property = DataMapper::Property.new(Zoo, :date_time, DateTime)
|
|
422
|
+
property.typecast(
|
|
423
|
+
:year => 2002, :month => 2, :day => 31, :hour => 12, :min => 0, :sec => 0
|
|
424
|
+
).should == DateTime.new(2002, 3, 3, 12, 0, 0)
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
it 'should typecast value for a Class property' do
|
|
428
|
+
property = DataMapper::Property.new(Zoo, :class, Class)
|
|
429
|
+
property.typecast('Zoo').should == Zoo
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
it 'should provide #inspect' do
|
|
434
|
+
DataMapper::Property.new(Zoo, :name, String).should respond_to(:inspect)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
it "should use the Repository of its @model" do
|
|
438
|
+
p = DataMapper::Property.new(Zoo, :name, String)
|
|
439
|
+
repo = mock("repository")
|
|
440
|
+
Zoo.should_receive(:repository).and_return(repo)
|
|
441
|
+
p.repository.should == repo
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
it 'should return an abbreviated representation of the property when inspected' do
|
|
445
|
+
DataMapper::Property.new(Zoo, :name, String).inspect.should == '#<Property:Zoo:name>'
|
|
446
|
+
end
|
|
447
|
+
end
|