thingtank 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/examples/first_marriage.rb +2 -1
- data/lib/thingtank/character.rb +33 -4
- data/lib/thingtank/instance_methods.rb +13 -0
- data/lib/thingtank/validators.rb +28 -0
- data/test/test_validators.rb +121 -0
- metadata +28 -28
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.6
|
data/examples/first_marriage.rb
CHANGED
@@ -23,13 +23,14 @@ class Spouse < ThingTank::Character
|
|
23
23
|
property :married_state
|
24
24
|
|
25
25
|
validate :spouse_should_be_married
|
26
|
+
validates :married, :character => Married # doc must have "married" character
|
26
27
|
|
27
28
|
def married
|
28
29
|
self["married"]
|
29
30
|
end
|
30
31
|
|
31
32
|
def spouse_should_be_married
|
32
|
-
married["spouse"] == self["_id"]
|
33
|
+
married && married["spouse"] == self["_id"]
|
33
34
|
end
|
34
35
|
|
35
36
|
def name
|
data/lib/thingtank/character.rb
CHANGED
@@ -4,11 +4,36 @@ class ThingTank
|
|
4
4
|
|
5
5
|
class Character < CouchRest::Model::Base
|
6
6
|
|
7
|
-
include ThingTank::ForceUpdate
|
8
7
|
include ThingTank::SharedMethods
|
9
8
|
|
9
|
+
property :update_me
|
10
|
+
|
11
|
+
before_validation do |character|
|
12
|
+
couchrest_attribute_will_change!('update_me') # or update_me_will_change! will also do
|
13
|
+
character.changed_to_character_hash. each do |k,v|
|
14
|
+
if v.is_a?(ThingTank)
|
15
|
+
if v.id
|
16
|
+
self[k] = v.to_sym
|
17
|
+
else
|
18
|
+
self[k] = v.to_character_hash(true)
|
19
|
+
end
|
20
|
+
# only do this for [ThingTank.new, ThingTank.new]
|
21
|
+
# all of them either having an id or not (just the first entry is checked)
|
22
|
+
elsif v && v.is_a?(Array) && !v.empty? && v.first.is_a?(ThingTank)
|
23
|
+
if v.first.id
|
24
|
+
self[k] = v.collect do |tt|
|
25
|
+
tt.to_sym
|
26
|
+
end
|
27
|
+
else
|
28
|
+
self[k] = v.collect do |tt|
|
29
|
+
tt.to_character_hash(true)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
10
36
|
class << self
|
11
|
-
|
12
37
|
# we need this hack with after_inherited and defined or active record is going wild, see: http://stackoverflow.com/questions/790626/ruby-can-i-have-something-like-classinherited-thats-triggered-only-after-the
|
13
38
|
# 'I'm trying to add behavior to activerecord models, but I need all the model customizations to go through before I mess with it. I'm trying to add behavior to activerecord models, but I need all the model customizations to go through before I mess with it. '
|
14
39
|
# exactly my case
|
@@ -99,10 +124,15 @@ class ThingTank
|
|
99
124
|
# use to_doc to put characters changes back to the doc without saving the doc
|
100
125
|
def to_doc
|
101
126
|
if changed?
|
127
|
+
valid = valid?
|
102
128
|
changed_to_character_hash().each do |k,v|
|
103
129
|
_character_doc[k] = v
|
104
130
|
end
|
105
|
-
|
131
|
+
if valid
|
132
|
+
@changed_attributes.clear if @changed_attributes
|
133
|
+
else
|
134
|
+
_doc.errors.add self.class.to_s, self.errors.messages
|
135
|
+
end
|
106
136
|
end
|
107
137
|
end
|
108
138
|
|
@@ -143,5 +173,4 @@ class ThingTank
|
|
143
173
|
_character_doc.add_character(klass, key, &code)
|
144
174
|
end
|
145
175
|
end
|
146
|
-
|
147
176
|
end
|
@@ -15,6 +15,19 @@ class ThingTank
|
|
15
15
|
@dependencies
|
16
16
|
end
|
17
17
|
|
18
|
+
def to_sym
|
19
|
+
if id = self.id
|
20
|
+
"!##{id}"
|
21
|
+
else
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# it is not possible for whatever reason to overwrite valid?, check it out!
|
27
|
+
#def valid?
|
28
|
+
# invalid_characters.empty? && self.errors.messages.empty?
|
29
|
+
#end
|
30
|
+
|
18
31
|
# we don't do this. there is no proper way to update all given characters
|
19
32
|
# one must not rely on a character properties after the doc has been manipulated
|
20
33
|
# use Character#reload to get the latest from the doc object to the character and Character#reload! to reload the doc from the database and reload the character then
|
data/lib/thingtank/validators.rb
CHANGED
@@ -72,3 +72,31 @@ class CharacterValidator < ActiveModel::EachValidator
|
|
72
72
|
end
|
73
73
|
|
74
74
|
end
|
75
|
+
|
76
|
+
|
77
|
+
class DocumentValidator < ActiveModel::EachValidator
|
78
|
+
def validate_single_doc(record, attribute, value, options)
|
79
|
+
if options[:inline]
|
80
|
+
return record.errors.add attribute, "#{value.inspect} should be an inlined doc that is converted to a hash" unless value.is_a? Hash
|
81
|
+
record.errors.add attribute, character.errors.messages unless ThingTank.new(value).valid?
|
82
|
+
else
|
83
|
+
match = (value =~ /^\!\#(.+)$/)
|
84
|
+
doc_id = $1
|
85
|
+
return record.errors.add attribute, "#{value.inspect} does not begin with !# and is therefor no doc id" unless match
|
86
|
+
record.errors.add attribute, "doc with id #{doc_id} does not exist" unless record._doc.class.get(doc_id)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def validate_each(record, attribute, values)
|
91
|
+
case values
|
92
|
+
when NilClass
|
93
|
+
return nil
|
94
|
+
when Array
|
95
|
+
values.each do |value|
|
96
|
+
validate_single_doc(record, attribute, value, options)
|
97
|
+
end
|
98
|
+
else
|
99
|
+
validate_single_doc(record, attribute, values, options)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/test/test_validators.rb
CHANGED
@@ -15,11 +15,16 @@ class TestA < ThingTank::Character
|
|
15
15
|
property :prop2
|
16
16
|
property :foo1
|
17
17
|
property :foo2
|
18
|
+
property :doc
|
19
|
+
property :inline_doc
|
18
20
|
|
19
21
|
validates :prop1, :class => Array
|
20
22
|
validates :prop2, :character => TestB
|
21
23
|
validates :foo1, :class => [Integer, String]
|
22
24
|
validates :foo2, :character => [TestB, TestC]
|
25
|
+
|
26
|
+
validates :doc, :document => true
|
27
|
+
validates :inline_doc, :document => {:inline => true}
|
23
28
|
end
|
24
29
|
|
25
30
|
describe "a classvalidator" do
|
@@ -114,4 +119,120 @@ describe "a charactervalidator and an array of values" do
|
|
114
119
|
end
|
115
120
|
assert_equal false, doc.as(TestA).valid?
|
116
121
|
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "a doc validator" do
|
125
|
+
it "should validate a doc id" do
|
126
|
+
doc1 = ThingTank.create :a => 'b'
|
127
|
+
doc1.save
|
128
|
+
doc2 = ThingTank.create
|
129
|
+
doc2.add_character TestA do |c|
|
130
|
+
c.doc = doc1.to_sym
|
131
|
+
end
|
132
|
+
assert_equal true, doc2.as(TestA).valid?
|
133
|
+
|
134
|
+
doc3 = ThingTank.create
|
135
|
+
doc3.add_character TestA do |c|
|
136
|
+
c.doc = doc1.id
|
137
|
+
end
|
138
|
+
assert_equal false, doc3.as(TestA).valid?
|
139
|
+
|
140
|
+
doc4 = ThingTank.create
|
141
|
+
doc4.add_character TestA do |c|
|
142
|
+
c.doc = "!#3" + doc1.id
|
143
|
+
end
|
144
|
+
assert_equal false, doc4.as(TestA).valid?
|
145
|
+
|
146
|
+
doc5 = ThingTank.create
|
147
|
+
doc5.add_character TestA do |c|
|
148
|
+
c.doc = doc1
|
149
|
+
end
|
150
|
+
assert_equal true, doc5.as(TestA).valid?
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should validate an inline doc" do
|
154
|
+
doc1 = ThingTank.new :a => 'b'
|
155
|
+
|
156
|
+
doc2 = ThingTank.create
|
157
|
+
doc2.add_character TestA do |c|
|
158
|
+
c.inline_doc = doc1.to_character_hash(true)
|
159
|
+
end
|
160
|
+
assert_equal true, doc2.as(TestA).valid?
|
161
|
+
|
162
|
+
doc3 = ThingTank.create
|
163
|
+
doc3.add_character TestA do |c|
|
164
|
+
c.inline_doc = doc1
|
165
|
+
end
|
166
|
+
|
167
|
+
character = doc3.as(TestA)
|
168
|
+
assert_equal true, doc3.as(TestA).valid?
|
169
|
+
|
170
|
+
doc4 = ThingTank.create
|
171
|
+
doc4.add_character TestA do |c|
|
172
|
+
c.inline_doc = "test"
|
173
|
+
end
|
174
|
+
|
175
|
+
character = doc4.as(TestA)
|
176
|
+
assert_equal false, doc4.as(TestA).valid?
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
it "should validate multiple doc ids" do
|
181
|
+
doc0 = ThingTank.create :a => 'b'
|
182
|
+
doc0.save
|
183
|
+
doc1 = ThingTank.create :c => 'd'
|
184
|
+
doc1.save
|
185
|
+
doc2 = ThingTank.create
|
186
|
+
doc2.add_character TestA do |c|
|
187
|
+
c.doc = [doc1.to_sym, doc0.to_sym]
|
188
|
+
end
|
189
|
+
assert_equal true, doc2.as(TestA).valid?
|
190
|
+
|
191
|
+
doc3 = ThingTank.create
|
192
|
+
doc3.add_character TestA do |c|
|
193
|
+
c.doc = [doc1.id, doc0.to_sym]
|
194
|
+
end
|
195
|
+
assert_equal false, doc3.as(TestA).valid?
|
196
|
+
|
197
|
+
doc4 = ThingTank.create
|
198
|
+
doc4.add_character TestA do |c|
|
199
|
+
c.doc = ["!#3" + doc1.id, doc0.to_sym]
|
200
|
+
end
|
201
|
+
assert_equal false, doc4.as(TestA).valid?
|
202
|
+
|
203
|
+
doc5 = ThingTank.create
|
204
|
+
doc5.add_character TestA do |c|
|
205
|
+
c.doc = [doc1, doc0]
|
206
|
+
end
|
207
|
+
assert_equal true, doc5.as(TestA).valid?
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should validate an multiple inline doc" do
|
211
|
+
doc0 = ThingTank.new :a => 'b'
|
212
|
+
doc1 = ThingTank.new :c => 'd'
|
213
|
+
|
214
|
+
doc2 = ThingTank.create
|
215
|
+
doc2.add_character TestA do |c|
|
216
|
+
c.inline_doc = [doc1.to_character_hash(true), doc0.to_character_hash(true)]
|
217
|
+
end
|
218
|
+
assert_equal true, doc2.as(TestA).valid?
|
219
|
+
|
220
|
+
doc3 = ThingTank.create
|
221
|
+
doc3.add_character TestA do |c|
|
222
|
+
c.inline_doc = [doc1, doc0]
|
223
|
+
end
|
224
|
+
|
225
|
+
character = doc3.as(TestA)
|
226
|
+
assert_equal true, doc3.as(TestA).valid?
|
227
|
+
|
228
|
+
doc4 = ThingTank.create
|
229
|
+
doc4.add_character TestA do |c|
|
230
|
+
c.inline_doc = ["test", doc1]
|
231
|
+
end
|
232
|
+
|
233
|
+
character = doc4.as(TestA)
|
234
|
+
assert_equal false, doc4.as(TestA).valid?
|
235
|
+
end
|
236
|
+
|
237
|
+
|
117
238
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thingtank
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-02-28 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
16
|
-
requirement: &
|
16
|
+
requirement: &9750780 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *9750780
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: couchrest
|
27
|
-
requirement: &
|
27
|
+
requirement: &9749340 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *9749340
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: couchrest_model
|
38
|
-
requirement: &
|
38
|
+
requirement: &9748700 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *9748700
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: defined
|
49
|
-
requirement: &
|
49
|
+
requirement: &9747760 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *9747760
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: guard
|
60
|
-
requirement: &
|
60
|
+
requirement: &9717160 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *9717160
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: libnotify
|
71
|
-
requirement: &
|
71
|
+
requirement: &9716460 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *9716460
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rb-inotify
|
82
|
-
requirement: &
|
82
|
+
requirement: &9715280 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *9715280
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: guard-minitest
|
93
|
-
requirement: &
|
93
|
+
requirement: &9714000 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *9714000
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: linecache19
|
104
|
-
requirement: &
|
104
|
+
requirement: &9713360 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *9713360
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: ruby-debug19
|
115
|
-
requirement: &
|
115
|
+
requirement: &9712280 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *9712280
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: yard
|
126
|
-
requirement: &
|
126
|
+
requirement: &9711120 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ~>
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: 0.6.0
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *9711120
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: bundler
|
137
|
-
requirement: &
|
137
|
+
requirement: &9710160 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ~>
|
@@ -142,10 +142,10 @@ dependencies:
|
|
142
142
|
version: 1.0.0
|
143
143
|
type: :development
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *9710160
|
146
146
|
- !ruby/object:Gem::Dependency
|
147
147
|
name: jeweler
|
148
|
-
requirement: &
|
148
|
+
requirement: &9703260 !ruby/object:Gem::Requirement
|
149
149
|
none: false
|
150
150
|
requirements:
|
151
151
|
- - ~>
|
@@ -153,7 +153,7 @@ dependencies:
|
|
153
153
|
version: 1.6.4
|
154
154
|
type: :development
|
155
155
|
prerelease: false
|
156
|
-
version_requirements: *
|
156
|
+
version_requirements: *9703260
|
157
157
|
description:
|
158
158
|
email: ! 'Base64.decode64(bGludXhAbWFyY3JlbmVhcm5zLmRl
|
159
159
|
|
@@ -217,7 +217,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
217
217
|
version: '0'
|
218
218
|
segments:
|
219
219
|
- 0
|
220
|
-
hash:
|
220
|
+
hash: 2476284335551452114
|
221
221
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
222
222
|
none: false
|
223
223
|
requirements:
|