dm-core 1.1.0 → 1.2.0.rc1

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 (104) hide show
  1. data/Gemfile +13 -11
  2. data/README.rdoc +1 -1
  3. data/Rakefile +1 -2
  4. data/VERSION +1 -1
  5. data/dm-core.gemspec +30 -176
  6. data/lib/dm-core.rb +32 -67
  7. data/lib/dm-core/adapters/abstract_adapter.rb +1 -2
  8. data/lib/dm-core/associations/many_to_many.rb +11 -5
  9. data/lib/dm-core/associations/many_to_one.rb +17 -2
  10. data/lib/dm-core/associations/one_to_many.rb +16 -0
  11. data/lib/dm-core/backwards.rb +13 -0
  12. data/lib/dm-core/collection.rb +1 -1
  13. data/lib/dm-core/model.rb +99 -41
  14. data/lib/dm-core/model/property.rb +24 -27
  15. data/lib/dm-core/model/relationship.rb +22 -28
  16. data/lib/dm-core/property.rb +37 -50
  17. data/lib/dm-core/property/boolean.rb +6 -10
  18. data/lib/dm-core/property/date.rb +0 -2
  19. data/lib/dm-core/property/date_time.rb +0 -2
  20. data/lib/dm-core/property/decimal.rb +5 -1
  21. data/lib/dm-core/property/discriminator.rb +24 -26
  22. data/lib/dm-core/property/float.rb +5 -1
  23. data/lib/dm-core/property/numeric.rb +6 -9
  24. data/lib/dm-core/property/string.rb +2 -1
  25. data/lib/dm-core/property/time.rb +0 -2
  26. data/lib/dm-core/property/typecast/time.rb +7 -2
  27. data/lib/dm-core/property_set.rb +1 -3
  28. data/lib/dm-core/query.rb +3 -10
  29. data/lib/dm-core/query/conditions/comparison.rb +5 -1
  30. data/lib/dm-core/query/conditions/operation.rb +1 -1
  31. data/lib/dm-core/relationship_set.rb +0 -2
  32. data/lib/dm-core/resource.rb +27 -28
  33. data/lib/dm-core/resource/{state.rb → persistence_state.rb} +2 -2
  34. data/lib/dm-core/resource/{state → persistence_state}/clean.rb +4 -4
  35. data/lib/dm-core/resource/{state → persistence_state}/deleted.rb +2 -2
  36. data/lib/dm-core/resource/{state → persistence_state}/dirty.rb +2 -2
  37. data/lib/dm-core/resource/{state → persistence_state}/immutable.rb +3 -3
  38. data/lib/dm-core/resource/{state → persistence_state}/persisted.rb +3 -3
  39. data/lib/dm-core/resource/{state → persistence_state}/transient.rb +3 -3
  40. data/lib/dm-core/spec/lib/adapter_helpers.rb +2 -5
  41. data/lib/dm-core/spec/setup.rb +3 -2
  42. data/lib/dm-core/spec/shared/public/property_spec.rb +8 -0
  43. data/lib/dm-core/spec/shared/resource_spec.rb +14 -0
  44. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +1 -1
  45. data/lib/dm-core/support/descendant_set.rb +0 -2
  46. data/lib/dm-core/support/ext/array.rb +0 -19
  47. data/lib/dm-core/support/ext/blank.rb +1 -0
  48. data/lib/dm-core/support/hook.rb +0 -3
  49. data/lib/dm-core/support/naming_conventions.rb +6 -0
  50. data/lib/dm-core/support/ordered_set.rb +0 -2
  51. data/lib/dm-core/support/subject_set.rb +0 -2
  52. data/lib/dm-core/version.rb +1 -1
  53. data/spec/public/associations/many_to_many_spec.rb +0 -1
  54. data/spec/public/model/property_spec.rb +55 -9
  55. data/spec/public/model/relationship_spec.rb +24 -2
  56. data/spec/public/model_spec.rb +32 -0
  57. data/spec/public/property/binary_spec.rb +14 -6
  58. data/spec/public/property/boolean_spec.rb +14 -6
  59. data/spec/public/property/class_spec.rb +14 -6
  60. data/spec/public/property/date_spec.rb +14 -6
  61. data/spec/public/property/date_time_spec.rb +14 -6
  62. data/spec/public/property/decimal_spec.rb +10 -2
  63. data/spec/public/property/discriminator_spec.rb +15 -1
  64. data/spec/public/property/float_spec.rb +14 -6
  65. data/spec/public/property/integer_spec.rb +14 -6
  66. data/spec/public/property/object_spec.rb +8 -0
  67. data/spec/public/property/serial_spec.rb +14 -6
  68. data/spec/public/property/string_spec.rb +14 -6
  69. data/spec/public/property/text_spec.rb +14 -6
  70. data/spec/public/property/time_spec.rb +14 -6
  71. data/spec/public/resource_spec.rb +58 -0
  72. data/spec/public/shared/finder_shared_spec.rb +8 -4
  73. data/spec/semipublic/associations/many_to_many_spec.rb +2 -0
  74. data/spec/semipublic/associations/many_to_one_spec.rb +2 -0
  75. data/spec/semipublic/associations/one_to_many_spec.rb +2 -0
  76. data/spec/semipublic/associations/one_to_one_spec.rb +2 -0
  77. data/spec/semipublic/property/binary_spec.rb +5 -5
  78. data/spec/semipublic/property/boolean_spec.rb +5 -5
  79. data/spec/semipublic/property/class_spec.rb +5 -5
  80. data/spec/semipublic/property/date_spec.rb +5 -5
  81. data/spec/semipublic/property/date_time_spec.rb +5 -5
  82. data/spec/semipublic/property/decimal_spec.rb +2 -2
  83. data/spec/semipublic/property/discriminator_spec.rb +5 -5
  84. data/spec/semipublic/property/float_spec.rb +5 -5
  85. data/spec/semipublic/property/integer_spec.rb +5 -5
  86. data/spec/semipublic/property/lookup_spec.rb +3 -3
  87. data/spec/semipublic/property/serial_spec.rb +5 -5
  88. data/spec/semipublic/property/string_spec.rb +5 -5
  89. data/spec/semipublic/property/text_spec.rb +5 -5
  90. data/spec/semipublic/property/time_spec.rb +5 -5
  91. data/spec/semipublic/query/conditions/comparison_spec.rb +44 -4
  92. data/spec/semipublic/query_spec.rb +2 -11
  93. data/spec/semipublic/resource/state/clean_spec.rb +6 -6
  94. data/spec/semipublic/resource/state/deleted_spec.rb +4 -4
  95. data/spec/semipublic/resource/state/dirty_spec.rb +8 -8
  96. data/spec/semipublic/resource/state/immutable_spec.rb +6 -6
  97. data/spec/semipublic/resource/state/transient_spec.rb +5 -5
  98. data/spec/semipublic/resource/state_spec.rb +15 -15
  99. data/spec/semipublic/shared/resource_shared_spec.rb +7 -1
  100. data/spec/semipublic/shared/resource_state_shared_spec.rb +8 -8
  101. data/spec/unit/array_spec.rb +0 -14
  102. data/spec/unit/blank_spec.rb +11 -0
  103. metadata +70 -188
  104. data/lib/dm-core/support/inflector.rb +0 -3
@@ -24,13 +24,10 @@ module DataMapper
24
24
  @adapter = DataMapper::Spec.adapter(kind)
25
25
  @repository = DataMapper.repository(@adapter.name)
26
26
 
27
+ @repository.scope { DataMapper.finalize }
28
+
27
29
  # create all tables and constraints before each spec
28
30
  if @repository.respond_to?(:auto_migrate!)
29
- # If we are going to auto-migrate, we must also finalize
30
- @repository.scope do
31
- DataMapper.finalize
32
- end
33
-
34
31
  @repository.auto_migrate!
35
32
  end
36
33
  end
@@ -42,11 +42,12 @@ module DataMapper
42
42
  end
43
43
 
44
44
  def require_spec_adapter
45
- if ENV['ADAPTER'] == 'in_memory'
45
+ desired_adapter = ENV['ADAPTER']
46
+ if desired_adapter.nil? || desired_adapter == 'in_memory'
46
47
  ENV['ADAPTER_SUPPORTS'] = 'all'
47
48
  Adapters.use(Adapters::InMemoryAdapter)
48
49
  else
49
- require "dm-#{ENV['ADAPTER']}-adapter/spec/setup"
50
+ require "dm-#{desired_adapter}-adapter/spec/setup"
50
51
  end
51
52
  end
52
53
 
@@ -22,6 +22,14 @@ share_examples_for 'A public Property' do
22
22
  @type.accept_options :foo, :bar
23
23
  end
24
24
 
25
+ before :all do
26
+ @original = @type.accepted_options.dup
27
+ end
28
+
29
+ after :all do
30
+ @type.accepted_options.replace(@original - [ :foo, :bar ])
31
+ end
32
+
25
33
  describe "predefined options" do
26
34
  before :all do
27
35
  class ::ChildSubType < @subtype
@@ -101,6 +101,13 @@ share_examples_for 'A public Resource' do
101
101
  end
102
102
 
103
103
  with_alternate_adapter do
104
+ before :all do
105
+ if @user_model.respond_to?(:auto_migrate!)
106
+ # force the user model to be available in the alternate repository
107
+ @user_model.auto_migrate!(@adapter.name)
108
+ end
109
+ end
110
+
104
111
  describe 'when comparing to a resource with a different repository, but the same properties' do
105
112
  before :all do
106
113
  rescue_if @skip do
@@ -489,6 +496,13 @@ share_examples_for 'A public Resource' do
489
496
  end
490
497
 
491
498
  with_alternate_adapter do
499
+ before :all do
500
+ if @user_model.respond_to?(:auto_migrate!)
501
+ # force the user model to be available in the alternate repository
502
+ @user_model.auto_migrate!(@adapter.name)
503
+ end
504
+ end
505
+
492
506
  describe 'when comparing to a resource with a different repository, but the same properties' do
493
507
  before :all do
494
508
  rescue_if @skip do
@@ -31,7 +31,7 @@ share_examples_for 'A semipublic Property' do
31
31
  end
32
32
 
33
33
  it 'should set the options to the default' do
34
- @property.options.should == @options.merge(@type.options)
34
+ @property.options.should == @type.options.merge(@options)
35
35
  end
36
36
  end
37
37
 
@@ -1,5 +1,3 @@
1
- require 'dm-core/support/subject_set'
2
-
3
1
  module DataMapper
4
2
  class DescendantSet
5
3
  include Enumerable
@@ -1,24 +1,5 @@
1
1
  module DataMapper; module Ext
2
2
  module Array
3
- # Transforms an Array of key/value pairs into a Hash.
4
- #
5
- # This is a better idiom than using Hash[*array.flatten] in Ruby 1.8.6
6
- # because it is not possible to limit the flattening to a single
7
- # level.
8
- #
9
- # @param [Array] array
10
- # The array of key/value pairs to transform.
11
- #
12
- # @return [Hash]
13
- # A Hash where each entry in the Array is turned into a key/value.
14
- #
15
- # @api semipublic
16
- def self.to_hash(array)
17
- h = {}
18
- array.each { |k,v| h[k] = v }
19
- h
20
- end
21
-
22
3
  # Transforms an Array of key/value pairs into a {Mash}.
23
4
  #
24
5
  # This is a better idiom than using Mash[*array.flatten] in Ruby 1.8.6
@@ -7,6 +7,7 @@ module DataMapper
7
7
  #
8
8
  # @api semipublic
9
9
  def self.blank?(value)
10
+ return value.blank? if value.respond_to?(:blank?)
10
11
  case value
11
12
  when ::NilClass, ::FalseClass
12
13
  true
@@ -1,6 +1,3 @@
1
- require 'dm-core/support/assertions'
2
- require 'dm-core/support/local_object_space'
3
-
4
1
  module DataMapper
5
2
  #
6
3
  # TODO: Write more documentation!
@@ -38,6 +38,12 @@ module DataMapper
38
38
  end
39
39
  end # module UnderscoredAndPluralizedWithoutModule
40
40
 
41
+ module UnderscoredAndPluralizedWithoutLeadingModule
42
+ def self.call(name)
43
+ UnderscoredAndPluralized.call(name.to_s.gsub(/^[^:]*::/,''))
44
+ end
45
+ end
46
+
41
47
  module Underscored
42
48
  def self.call(name)
43
49
  DataMapper::Inflector.underscore(name)
@@ -1,5 +1,3 @@
1
- require 'dm-core/support/equalizer'
2
-
3
1
  module DataMapper
4
2
 
5
3
  # An ordered set of things
@@ -1,5 +1,3 @@
1
- require 'dm-core/support/ordered_set'
2
-
3
1
  module DataMapper
4
2
 
5
3
  # An insertion ordered set of named objects
@@ -1,3 +1,3 @@
1
1
  module DataMapper
2
- VERSION = '1.1.0'
2
+ VERSION = '1.2.0.rc1'
3
3
  end
@@ -159,7 +159,6 @@ end
159
159
  @author_model = Blog::Author
160
160
  @article_model = Blog::Article
161
161
  @publication_model = Blog::Publication
162
- DataMapper.finalize
163
162
 
164
163
  @join_model = Blog::Site
165
164
  end
@@ -1,5 +1,19 @@
1
1
  require 'spec_helper'
2
2
 
3
+ shared_examples_for "a correct property declaration" do
4
+ it 'should define a name accessor' do
5
+ @model.should_not be_method_defined(@property_name)
6
+ subject
7
+ @model.should be_method_defined(@property_name)
8
+ end
9
+
10
+ it 'should define a name= mutator' do
11
+ @model.should_not be_method_defined(:"#{@property_name}=")
12
+ subject
13
+ @model.should be_method_defined(:"#{@property_name}=")
14
+ end
15
+ end
16
+
3
17
  describe DataMapper::Model::Property do
4
18
  before do
5
19
  Object.send(:remove_const, :ModelPropertySpecs) if defined?(ModelPropertySpecs)
@@ -12,19 +26,45 @@ describe DataMapper::Model::Property do
12
26
  end
13
27
 
14
28
  describe '#property' do
29
+ context "using default repository" do
30
+ before do
31
+ Object.send(:remove_const, :UserDefault) if defined?(::UserDefault)
32
+
33
+ class ::UserDefault
34
+ include DataMapper::Resource
35
+ property :id, Serial
36
+ end
37
+
38
+ @model = ::UserDefault
39
+ @property_name = :name
40
+ end
15
41
 
16
- subject { ModelPropertySpecs.property(:name, String) }
42
+ subject do
43
+ ::UserDefault.property(:name, String)
44
+ end
17
45
 
18
- it 'should define a name accessor' do
19
- ModelPropertySpecs.should_not be_method_defined(:name)
20
- subject
21
- ModelPropertySpecs.should be_method_defined(:name)
46
+ it_should_behave_like "a correct property declaration"
22
47
  end
23
48
 
24
- it 'should define a name= mutator' do
25
- ModelPropertySpecs.should_not be_method_defined(:name=)
26
- subject
27
- ModelPropertySpecs.should be_method_defined(:name=)
49
+ context "using alternate repository" do
50
+ before do
51
+ Object.send(:remove_const, :UserAlternate) if defined?(::UserAlternate)
52
+
53
+ class ::UserAlternate
54
+ include DataMapper::Resource
55
+ property :id, Serial
56
+ repository(:alternate) { property :age, Integer }
57
+ end
58
+
59
+ @model = UserAlternate
60
+ @property_name = :alt_name
61
+ end
62
+
63
+ subject do
64
+ ::UserAlternate.property(:alt_name, String)
65
+ end
66
+
67
+ it_should_behave_like "a correct property declaration"
28
68
  end
29
69
 
30
70
  it 'should raise an exception if the method exists' do
@@ -33,6 +73,12 @@ describe DataMapper::Model::Property do
33
73
  }.should raise_error(ArgumentError, '+name+ was :key, which cannot be used as a property name since it collides with an existing method or a query option')
34
74
  end
35
75
 
76
+ it 'should raise an exception if the property is boolean and method with question mark already exists' do
77
+ lambda {
78
+ ModelPropertySpecs.property(:destroyed, DataMapper::Property::Boolean)
79
+ }.should raise_error(ArgumentError, '+name+ was :destroyed, which cannot be used as a property name since it collides with an existing method or a query option')
80
+ end
81
+
36
82
  it 'should raise an exception if the name is the same as one of the query options' do
37
83
  lambda {
38
84
  ModelPropertySpecs.property(:order, String)
@@ -282,7 +282,8 @@ share_examples_for 'it creates a many accessor' do
282
282
 
283
283
  # set the model scope to only return the first record
284
284
  @model.default_scope.update(
285
- DataMapper::Ext::Array.to_hash(@model.key(@repository.name).zip(@expected.key)))
285
+ Hash[ @model.key(@repository.name).zip(@expected.key) ]
286
+ )
286
287
 
287
288
  @return = @car.model.get(*@car.key).__send__(@name)
288
289
  end
@@ -433,7 +434,7 @@ describe DataMapper::Associations do
433
434
  class ::Car
434
435
  include DataMapper::Resource
435
436
 
436
- property :id, Serial
437
+ property :id, Serial
437
438
  property :name, String
438
439
  end
439
440
 
@@ -497,6 +498,27 @@ describe DataMapper::Associations do
497
498
  end
498
499
  end
499
500
  end
501
+
502
+ describe 'with a :unique option' do
503
+ let(:unique) { [ :one, :two, :three ] }
504
+
505
+ before :all do
506
+ @relationship = Car.belongs_to("#{@name}_with_unique".to_sym, @model, :unique => unique)
507
+ DataMapper.finalize
508
+ end
509
+
510
+ it 'should create a foreign key that is unique' do
511
+ @relationship.child_key.each do |property|
512
+ property.should be_unique
513
+ end
514
+ end
515
+
516
+ it 'should create a foreign key that has a unique index' do
517
+ @relationship.child_key.each do |property|
518
+ property.unique_index.should equal(unique)
519
+ end
520
+ end
521
+ end
500
522
  end
501
523
 
502
524
  # TODO: refactor these specs into above structure once they pass
@@ -36,6 +36,13 @@ describe DataMapper::Model do
36
36
 
37
37
  describe '#copy' do
38
38
  with_alternate_adapter do
39
+ before :all do
40
+ if @article_model.respond_to?(:auto_migrate!)
41
+ # force the article model to be available in the alternate repository
42
+ @article_model.auto_migrate!(@adapter.name)
43
+ end
44
+ end
45
+
39
46
  describe 'between identical models' do
40
47
  before :all do
41
48
  @return = @resources = @article_model.copy(@repository.name, @adapter.name)
@@ -422,5 +429,30 @@ describe DataMapper::Model do
422
429
  end
423
430
  end
424
431
  end
432
+
433
+ it 'A model should respond to allowed_writer_methods' do
434
+ @article_model.should respond_to(:allowed_writer_methods)
435
+ end
436
+
437
+ describe '#allowed_writer_methods' do
438
+ subject { @article_model.allowed_writer_methods }
439
+
440
+ let(:expected_writer_methods) do
441
+ %w[ original= revisions= previous= publications= article_publications=
442
+ id= title= content= subtitle= original_id= persisted_state= ].to_set
443
+ end
444
+
445
+ it { should be_kind_of(Set) }
446
+
447
+ it { should be_all { |method| method.kind_of?(String) } }
448
+
449
+ it { should be_frozen }
450
+
451
+ it 'is idempotent' do
452
+ should equal(instance_eval(&self.class.subject))
453
+ end
454
+
455
+ it { should eql(expected_writer_methods) }
456
+ end
425
457
  end
426
458
  end
@@ -2,13 +2,21 @@ require 'spec_helper'
2
2
 
3
3
  describe DataMapper::Property::Binary do
4
4
  before :all do
5
- @name = :title
6
- @type = DataMapper::Property::Binary
7
- @primitive = String
8
- @value = 'value'
9
- @other_value = 'return value'
5
+ @name = :title
6
+ @type = described_class
7
+ @primitive = String
8
+ @value = 'value'
9
+ @other_value = 'return value'
10
10
  @invalid_value = 1
11
11
  end
12
12
 
13
- it_should_behave_like "A public Property"
13
+ it_should_behave_like 'A public Property'
14
+
15
+ describe '.options' do
16
+ subject { described_class.options }
17
+
18
+ it { should be_kind_of(Hash) }
19
+
20
+ it { should eql(:primitive => @primitive, :length => 50) }
21
+ end
14
22
  end
@@ -2,13 +2,21 @@ require 'spec_helper'
2
2
 
3
3
  describe DataMapper::Property::Boolean do
4
4
  before :all do
5
- @name = :active
6
- @type = DataMapper::Property::Boolean
7
- @primitive = TrueClass
8
- @value = true
9
- @other_value = false
5
+ @name = :active
6
+ @type = described_class
7
+ @primitive = TrueClass
8
+ @value = true
9
+ @other_value = false
10
10
  @invalid_value = 1
11
11
  end
12
12
 
13
- it_should_behave_like "A public Property"
13
+ it_should_behave_like 'A public Property'
14
+
15
+ describe '.options' do
16
+ subject { described_class.options }
17
+
18
+ it { should be_kind_of(Hash) }
19
+
20
+ it { should eql(:primitive => @primitive) }
21
+ end
14
22
  end
@@ -8,13 +8,21 @@ describe DataMapper::Property::Class do
8
8
  class ::Foo; end
9
9
  class ::Bar; end
10
10
 
11
- @name = :type
12
- @type = DataMapper::Property::Class
13
- @primitive = Class
14
- @value = Foo
15
- @other_value = Bar
11
+ @name = :type
12
+ @type = described_class
13
+ @primitive = Class
14
+ @value = Foo
15
+ @other_value = Bar
16
16
  @invalid_value = 1
17
17
  end
18
18
 
19
- it_should_behave_like "A public Property"
19
+ it_should_behave_like 'A public Property'
20
+
21
+ describe '.options' do
22
+ subject { described_class.options }
23
+
24
+ it { should be_kind_of(Hash) }
25
+
26
+ it { should eql(:primitive => @primitive) }
27
+ end
20
28
  end
@@ -2,13 +2,21 @@ require 'spec_helper'
2
2
 
3
3
  describe DataMapper::Property::Date do
4
4
  before :all do
5
- @name = :created_on
6
- @type = DataMapper::Property::Date
7
- @primitive = Date
8
- @value = Date.today
9
- @other_value = Date.today+1
5
+ @name = :created_on
6
+ @type = described_class
7
+ @primitive = Date
8
+ @value = Date.today
9
+ @other_value = Date.today + 1
10
10
  @invalid_value = 1
11
11
  end
12
12
 
13
- it_should_behave_like "A public Property"
13
+ it_should_behave_like 'A public Property'
14
+
15
+ describe '.options' do
16
+ subject { described_class.options }
17
+
18
+ it { should be_kind_of(Hash) }
19
+
20
+ it { should eql(:primitive => @primitive) }
21
+ end
14
22
  end