dm-types 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.
data/lib/dm-types/yaml.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'yaml'
2
2
  require 'dm-core'
3
+ require 'dm-types/support/dirty_minder'
3
4
 
4
5
  module DataMapper
5
6
  class Property
@@ -15,7 +16,7 @@ module DataMapper
15
16
  elsif value.is_a?(::String)
16
17
  ::YAML.load(value)
17
18
  else
18
- raise ArgumentError.new("+value+ of a property of YAML type must be nil or a String")
19
+ raise ArgumentError, '+value+ of a property of YAML type must be nil or a String'
19
20
  end
20
21
  end
21
22
 
@@ -33,6 +34,8 @@ module DataMapper
33
34
  value
34
35
  end
35
36
 
37
+ include ::DataMapper::Property::DirtyMinder
38
+
36
39
  end # class Yaml
37
40
  end # class Property
38
41
  end # module DataMapper
@@ -0,0 +1,14 @@
1
+ module DataMapper
2
+ module TypesFixtures
3
+ class APIUser
4
+
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+
9
+ property :name, String
10
+
11
+ property :api_key, APIKey
12
+ end
13
+ end
14
+ end
@@ -15,6 +15,7 @@ module DataMapper
15
15
  property :name, String
16
16
  property :positions, Json
17
17
  property :inventions, Yaml
18
+ property :birthday, EpochTime
18
19
 
19
20
  property :interests, CommaSeparatedList
20
21
 
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ try_spec do
4
+ require './spec/fixtures/api_user'
5
+
6
+ describe DataMapper::TypesFixtures::APIUser do
7
+ supported_by :all do
8
+ subject { described_class.new(:name => 'alice') }
9
+
10
+ let(:original_api_key) { subject.api_key }
11
+
12
+ it "should have a default value" do
13
+ original_api_key.should_not be_nil
14
+ end
15
+
16
+ it "should preserve the default value" do
17
+ subject.api_key.should == original_api_key
18
+ end
19
+
20
+ it "should generate unique API Keys for each resource" do
21
+ other_resource = described_class.new(:name => 'eve')
22
+
23
+ other_resource.api_key.should_not == original_api_key
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,197 @@
1
+ require 'spec_helper'
2
+
3
+ try_spec do
4
+
5
+ # FIXME: DirtyMinder is currently unsupported on RBX, because unlike the other
6
+ # supported Rubies, RBX core class (e.g. Array, Hash) methods use #send(). In
7
+ # other words, the other Rubies don't use #send() (they map directly to their
8
+ # C functions).
9
+ #
10
+ # The current methodology takes advantage of this by using #send() to forward
11
+ # method invocations we've hooked. Supporting RBX will require finding
12
+ # another way, possibly for all Rubies. In the meantime, something is better
13
+ # than nothing.
14
+ next if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'rbx'
15
+
16
+ require './spec/fixtures/person'
17
+
18
+ describe DataMapper::TypesFixtures::Person do
19
+ supported_by :all do
20
+ before :all do
21
+ @resource = DataMapper::TypesFixtures::Person.new(:name => 'Thomas Edison')
22
+ end
23
+
24
+ describe 'with positions indirectly mutated as a hash' do
25
+ before :all do
26
+ @resource.positions = {
27
+ 'company' => "Soon To Be Dirty, LLC",
28
+ 'title' => "Layperson",
29
+ 'details' => { 'awesome' => true },
30
+ }
31
+ @resource.save
32
+ @resource.reload
33
+ @resource.positions['title'].should == 'Layperson'
34
+ end
35
+
36
+ describe "when I change positions" do
37
+ before :all do
38
+ @resource.clean?.should == true
39
+ @resource.positions['title'] = 'Chief Layer of People'
40
+ @resource.save
41
+ @resource.reload
42
+ end
43
+
44
+ it "should remember the new position" do
45
+ @resource.positions['title'].should == 'Chief Layer of People'
46
+ end
47
+ end
48
+
49
+ describe "when I add a new attribute of the position" do
50
+ before :all do
51
+ @resource.clean?.should == true
52
+ @resource.positions['pays_buttloads_of_money'] = true
53
+ @resource.save
54
+ @resource.reload
55
+ end
56
+
57
+ it "should remember the new attribute" do
58
+ @resource.positions['pays_buttloads_of_money'].should be(true)
59
+ end
60
+ end
61
+
62
+ describe "when I change the details of the position" do
63
+ before :all do
64
+ @resource.clean?.should == true
65
+ @resource.positions['details'].merge!('awesome' => "VERY TRUE")
66
+ @resource.save
67
+ @resource.reload
68
+ end
69
+
70
+ it "should remember the changed detail" do
71
+ pending "not supported (YET)" do
72
+ # TODO: Not supported (yet?) -- this is a much harder problem to
73
+ # solve: using mutating accessors of nested objects. We could
74
+ # detect it from #dirty? (using the #hash method), but #dirty?
75
+ # only returns the status of known-mutated properties (not full,
76
+ # on-demand scan of object dirty-ness).
77
+ @resource.positions['details']['awesome'].should == 'VERY TRUE'
78
+ end
79
+ end
80
+ end
81
+
82
+ describe "when I reload the resource while the property is dirty" do
83
+ before :all do
84
+ @resource.positions['title'] = 'Chief Layer of People'
85
+ @resource.reload
86
+ end
87
+
88
+ it "should reflect the previously set/persisted value" do
89
+ @resource.positions.should_not be_nil
90
+ @resource.positions['title'].should == 'Layperson'
91
+ end
92
+ end
93
+
94
+ end # positions indirectly mutated as a hash
95
+
96
+ describe 'with positions indirectly mutated as an array' do
97
+ before :all do
98
+ @resource.positions = [
99
+ { 'company' => "Soon To Be Dirty, LLC",
100
+ 'title' => "Layperson",
101
+ 'details' => { 'awesome' => true },
102
+ },
103
+ ]
104
+ @resource.save
105
+ @resource.reload
106
+ @resource.positions.first['title'].should == 'Layperson'
107
+ end
108
+
109
+ describe "when I remove the position" do
110
+ before :all do
111
+ @resource.clean?.should == true
112
+ @resource.positions.pop
113
+ @resource.save
114
+ @resource.reload
115
+ end
116
+
117
+ it "should know there aren't any positions" do
118
+ @resource.positions.should == []
119
+ end
120
+ end
121
+
122
+ describe "when I add a new position" do
123
+ before :all do
124
+ @resource.clean?.should == true
125
+ @resource.positions << {
126
+ 'company' => "Down and Dirty, LP",
127
+ 'title' => "Porn Star",
128
+ 'details' => { 'awesome' => "also true" },
129
+ }
130
+ @resource.save
131
+ @resource.reload
132
+ end
133
+
134
+ it "should know there's two positions" do
135
+ @resource.positions.length.should == 2
136
+ end
137
+
138
+ it "should know which position is which" do
139
+ @resource.positions.first['title'].should == "Layperson"
140
+ @resource.positions.last['title'].should == "Porn Star"
141
+ end
142
+
143
+ describe "when I change the details of one of the positions" do
144
+ before :all do
145
+ @resource.positions.last['details'].merge!('high_risk' => true)
146
+ @resource.save
147
+ @resource.reload
148
+ end
149
+
150
+ it "should remember the changed detail" do
151
+ pending "not supported (YET)" do
152
+ # TODO: Not supported (yet?) -- this is a much harder problem to
153
+ # solve: using mutating accessors of nested objects. We could
154
+ # detect it from #dirty? (using the #hash method), but #dirty?
155
+ # only returns the status of known-mutated properties (not full,
156
+ # on-demand scan of object dirty-ness).
157
+ @resource.positions.last['details']['high_risk'].should == true
158
+ end
159
+ end
160
+ end
161
+ end # when I add a new position
162
+
163
+ describe "when I remove the position with a block-based mutator" do
164
+ before :all do
165
+ @resource.clean?.should == true
166
+ @resource.positions.reject! { |_| true }
167
+ @resource.save
168
+ @resource.reload
169
+ end
170
+
171
+ it "should know there aren't any positions" do
172
+ @resource.positions.should == []
173
+ end
174
+ end
175
+
176
+ describe "when I mutate positions through a reference" do
177
+ before :all do
178
+ @resource.clean?.should == true
179
+ @positions = @resource.positions
180
+ @positions << {
181
+ 'company' => "Ooga Booga, Inc",
182
+ 'title' => "Rocker",
183
+ }
184
+ end
185
+
186
+ it "should reflect the change in both the property and the reference" do
187
+ @resource.positions.length.should == 2
188
+ @resource.positions.last['title'].should == 'Rocker'
189
+ @positions.last['title'].should == 'Rocker'
190
+ end
191
+ end
192
+
193
+ end # positions indirectly mutated as an array
194
+
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ try_spec do
4
+
5
+ require './spec/fixtures/person'
6
+
7
+ describe DataMapper::TypesFixtures::Person do
8
+ supported_by :all do
9
+ before :all do
10
+ @resource = DataMapper::TypesFixtures::Person.new(:name => '')
11
+ end
12
+
13
+ describe 'with a birthday' do
14
+ before :all do
15
+ @resource.birthday = '1983-05-03'
16
+ end
17
+
18
+ describe 'after typecasting string input' do
19
+ it 'has a valid birthday' do
20
+ @resource.birthday.should == ::Time.parse('1983-05-03')
21
+ end
22
+ end
23
+
24
+ describe 'when dumped and loaded again' do
25
+ before :all do
26
+ @resource.save.should be(true)
27
+ @resource.reload
28
+ end
29
+
30
+ it 'has a valid birthday' do
31
+ @resource.birthday.should == ::Time.parse('1983-05-03')
32
+ end
33
+ end
34
+ end
35
+
36
+ describe 'without a birthday' do
37
+ before :all do
38
+ @resource.birthday = nil
39
+ end
40
+
41
+ describe 'after typecasting nil' do
42
+ it 'has a nil value for birthday' do
43
+ @resource.birthday.should be_nil
44
+ end
45
+ end
46
+
47
+ describe 'when dumped and loaded again' do
48
+ before :all do
49
+ @resource.save.should be(true)
50
+ @resource.reload
51
+ end
52
+
53
+ it 'has a nil value for birthday' do
54
+ @resource.birthday.should be_nil
55
+ end
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -1,15 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
- Spec::Matchers.define :run_ipv4 do |model|
4
- match do |model|
5
- model.runs_ipv4?
6
- end
3
+ Spec::Matchers.define :run_ipv4 do
4
+ match { |model| model.runs_ipv4? }
7
5
  end
8
6
 
9
- Spec::Matchers.define :run_ipv6 do |model|
10
- match do |model|
11
- model.runs_ipv6?
12
- end
7
+ Spec::Matchers.define :run_ipv6 do
8
+ match { |model| model.runs_ipv6? }
13
9
  end
14
10
 
15
11
  try_spec do
@@ -66,6 +66,7 @@ try_spec do
66
66
  end
67
67
  end
68
68
  end
69
+
69
70
  end
70
71
  end
71
72
  end
@@ -25,35 +25,39 @@ try_spec do
25
25
  end
26
26
  end
27
27
 
28
- [
29
- ['Iñtërnâtiônàlizætiøn', 'internationalizaetion' ],
30
- ["This is Dan's Blog", 'this-is-dans-blog'],
31
- ['This is My Site, and Blog', 'this-is-my-site-and-blog'],
32
- ['Google searches for holy grail of Python performance', 'google-searches-for-holy-grail-of-python-performance'],
33
- ['iPhone dev: Creating length-controlled data sources', 'iphone-dev-creating-length-controlled-data-sources'],
34
- ["Review: Nintendo's New DSi -- A Quantum Leap Forward", 'review-nintendos-new-dsi-a-quantum-leap-forward'],
35
- ["Arriva BraiVe, è l'auto-robot che si 'guida' da sola'", 'arriva-braive-e-lauto-robot-che-si-guida-da-sola'],
36
- ["La ley antipiratería reduce un 33% el tráfico online en Suecia", 'la-ley-antipirateria-reduce-un-33-percent-el-trafico-online-en-suecia'],
37
- ["L'Etat américain du Texas s'apprête à interdire Windows Vista", 'letat-americain-du-texas-sapprete-a-interdire-windows-vista']
38
- ].each do |title, slug|
39
- describe "set with title '#{title}'" do
40
- before :all do
41
- @resource = DataMapper::TypesFixtures::Article.new(:title => title)
42
- @resource.valid?.should be(true)
43
- end
44
-
45
- it "has slug equal to '#{slug}'" do
46
- @resource.slug.should == slug
47
- end
48
-
49
- describe "and persisted" do
28
+ # FIXME: when stringex fixes the problems it has with it's YAML
29
+ # files not being parsable by psych remove this conditional.
30
+ unless RUBY_PLATFORM =~ /java/ && JRUBY_VERSION >= '1.6' && RUBY_VERSION >= '1.9.2'
31
+ [
32
+ [ 'Iñtërnâtiônàlizætiøn', 'internationalizaetion' ],
33
+ [ "This is Dan's Blog", 'this-is-dans-blog' ],
34
+ [ 'This is My Site, and Blog', 'this-is-my-site-and-blog' ],
35
+ [ 'Google searches for holy grail of Python performance', 'google-searches-for-holy-grail-of-python-performance' ],
36
+ [ 'iPhone dev: Creating length-controlled data sources', 'iphone-dev-creating-length-controlled-data-sources' ],
37
+ [ "Review: Nintendo's New DSi -- A Quantum Leap Forward", 'review-nintendos-new-dsi-a-quantum-leap-forward' ],
38
+ [ "Arriva BraiVe, è l'auto-robot che si 'guida' da sola'", 'arriva-braive-e-lauto-robot-che-si-guida-da-sola' ],
39
+ [ "La ley antipiratería reduce un 33% el tráfico online en Suecia", 'la-ley-antipirateria-reduce-un-33-percent-el-trafico-online-en-suecia' ],
40
+ [ "L'Etat américain du Texas s'apprête à interdire Windows Vista", 'letat-americain-du-texas-sapprete-a-interdire-windows-vista' ],
41
+ ].each do |title, slug|
42
+ describe "set with title '#{title}'" do
50
43
  before :all do
51
- @resource.save.should be(true)
52
- @resource.reload
44
+ @resource = DataMapper::TypesFixtures::Article.new(:title => title)
45
+ @resource.valid?.should be(true)
53
46
  end
54
47
 
55
- it 'can be found by slug' do
56
- DataMapper::TypesFixtures::Article.first(:slug => slug).should == @resource
48
+ it "has slug equal to '#{slug}'" do
49
+ @resource.slug.should == slug
50
+ end
51
+
52
+ describe "and persisted" do
53
+ before :all do
54
+ @resource.save.should be(true)
55
+ @resource.reload
56
+ end
57
+
58
+ it 'can be found by slug' do
59
+ DataMapper::TypesFixtures::Article.first(:slug => slug).should == @resource
60
+ end
57
61
  end
58
62
  end
59
63
  end
@@ -21,22 +21,38 @@ describe DataMapper::Property::EpochTime do
21
21
  it { should == value.to_i }
22
22
  end
23
23
 
24
+ describe 'with nil' do
25
+ let(:value) { nil }
26
+
27
+ it { should == value }
28
+ end
29
+ end
30
+
31
+ describe '#typecast' do
32
+ subject { @property.typecast(value) }
33
+
24
34
  describe 'with a DateTime instance' do
25
35
  let(:value) { DateTime.now }
26
36
 
27
- it { should == Time.parse(value.to_s).to_i }
37
+ it { should == Time.parse(value.to_s) }
28
38
  end
29
39
 
30
40
  describe 'with a number' do
31
41
  let(:value) { Time.now.to_i }
32
42
 
33
- it { should == value }
43
+ it { should == ::Time.at(value) }
34
44
  end
35
45
 
36
- describe 'with nil' do
37
- let(:value) { nil }
46
+ describe 'with a numeric string' do
47
+ let(:value) { Time.now.to_i.to_s }
38
48
 
39
- it { should == value }
49
+ it { should == ::Time.at(value.to_i) }
50
+ end
51
+
52
+ describe 'with a DateTime string' do
53
+ let(:value) { '2011-07-11 15:00:04 UTC' }
54
+
55
+ it { should == ::Time.parse(value) }
40
56
  end
41
57
  end
42
58