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.
Files changed (84) hide show
  1. data/.autotest +26 -0
  2. data/{CHANGELOG → History.txt} +78 -77
  3. data/Manifest.txt +123 -0
  4. data/{README → README.txt} +0 -0
  5. data/Rakefile +29 -0
  6. data/SPECS +63 -0
  7. data/TODO +1 -0
  8. data/lib/dm-core.rb +6 -1
  9. data/lib/dm-core/adapters/data_objects_adapter.rb +29 -32
  10. data/lib/dm-core/adapters/mysql_adapter.rb +1 -1
  11. data/lib/dm-core/adapters/postgres_adapter.rb +1 -1
  12. data/lib/dm-core/adapters/sqlite3_adapter.rb +2 -2
  13. data/lib/dm-core/associations.rb +26 -0
  14. data/lib/dm-core/associations/many_to_many.rb +34 -25
  15. data/lib/dm-core/associations/many_to_one.rb +4 -4
  16. data/lib/dm-core/associations/one_to_many.rb +48 -13
  17. data/lib/dm-core/associations/one_to_one.rb +4 -4
  18. data/lib/dm-core/associations/relationship.rb +144 -42
  19. data/lib/dm-core/associations/relationship_chain.rb +31 -24
  20. data/lib/dm-core/auto_migrations.rb +0 -4
  21. data/lib/dm-core/collection.rb +40 -7
  22. data/lib/dm-core/dependency_queue.rb +31 -0
  23. data/lib/dm-core/hook.rb +2 -2
  24. data/lib/dm-core/is.rb +2 -2
  25. data/lib/dm-core/logger.rb +10 -10
  26. data/lib/dm-core/model.rb +94 -41
  27. data/lib/dm-core/property.rb +72 -41
  28. data/lib/dm-core/property_set.rb +8 -14
  29. data/lib/dm-core/query.rb +34 -9
  30. data/lib/dm-core/repository.rb +0 -0
  31. data/lib/dm-core/resource.rb +13 -13
  32. data/lib/dm-core/scope.rb +25 -2
  33. data/lib/dm-core/type.rb +3 -3
  34. data/lib/dm-core/types/discriminator.rb +10 -8
  35. data/lib/dm-core/types/object.rb +4 -0
  36. data/lib/dm-core/types/paranoid_boolean.rb +15 -4
  37. data/lib/dm-core/types/paranoid_datetime.rb +15 -4
  38. data/lib/dm-core/version.rb +3 -0
  39. data/script/all +5 -0
  40. data/script/performance.rb +191 -0
  41. data/script/profile.rb +86 -0
  42. data/spec/integration/association_spec.rb +288 -204
  43. data/spec/integration/association_through_spec.rb +9 -3
  44. data/spec/integration/associations/many_to_many_spec.rb +97 -31
  45. data/spec/integration/associations/many_to_one_spec.rb +41 -6
  46. data/spec/integration/associations/one_to_many_spec.rb +18 -2
  47. data/spec/integration/auto_migrations_spec.rb +0 -0
  48. data/spec/integration/collection_spec.rb +89 -42
  49. data/spec/integration/dependency_queue_spec.rb +58 -0
  50. data/spec/integration/model_spec.rb +67 -8
  51. data/spec/integration/postgres_adapter_spec.rb +19 -20
  52. data/spec/integration/property_spec.rb +17 -8
  53. data/spec/integration/query_spec.rb +273 -191
  54. data/spec/integration/resource_spec.rb +108 -10
  55. data/spec/integration/strategic_eager_loading_spec.rb +138 -0
  56. data/spec/integration/transaction_spec.rb +3 -3
  57. data/spec/integration/type_spec.rb +121 -0
  58. data/spec/lib/logging_helper.rb +18 -0
  59. data/spec/lib/model_loader.rb +91 -0
  60. data/spec/lib/publicize_methods.rb +28 -0
  61. data/spec/models/vehicles.rb +34 -0
  62. data/spec/models/zoo.rb +48 -0
  63. data/spec/spec.opts +3 -0
  64. data/spec/spec_helper.rb +25 -62
  65. data/spec/unit/adapters/data_objects_adapter_spec.rb +1 -0
  66. data/spec/unit/associations/many_to_many_spec.rb +3 -0
  67. data/spec/unit/associations/many_to_one_spec.rb +9 -1
  68. data/spec/unit/associations/one_to_many_spec.rb +12 -4
  69. data/spec/unit/associations/relationship_spec.rb +19 -15
  70. data/spec/unit/associations_spec.rb +37 -0
  71. data/spec/unit/collection_spec.rb +8 -0
  72. data/spec/unit/data_mapper_spec.rb +14 -0
  73. data/spec/unit/model_spec.rb +2 -2
  74. data/spec/unit/property_set_spec.rb +0 -13
  75. data/spec/unit/property_spec.rb +92 -21
  76. data/spec/unit/query_spec.rb +49 -4
  77. data/spec/unit/resource_spec.rb +122 -60
  78. data/spec/unit/scope_spec.rb +11 -0
  79. data/tasks/ci.rb +68 -0
  80. data/tasks/dm.rb +63 -0
  81. data/tasks/doc.rb +20 -0
  82. data/tasks/hoe.rb +38 -0
  83. data/tasks/install.rb +20 -0
  84. 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
@@ -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
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --loadby random
3
+ --format progress
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
- require Pathname(__FILE__).dirname.expand_path.parent + 'lib/dm-core'
7
- require DataMapper.root / 'spec' / 'lib' / 'mock_adapter'
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::ManyToMany do
4
+
5
+ load_models_for_metaphor :vehicles
6
+
4
7
  it 'should allow a declaration' do
5
8
  lambda do
6
9
  class Supplier
@@ -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, :repository_name => :default, :get_parent => @parent, :attach_parent => nil)
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 == :user
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 == 'User'
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, :repository_name => :mock, :query => {}, :kind_of? => true)
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