dm-core 1.1.0 → 1.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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