couchpillow 0.4.5 → 0.4.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6c941b4db98918cd72e334fb39d97ce2bb6ea24b
4
- data.tar.gz: 28babdcc130a232e33d10f72c8771291729b45ce
3
+ metadata.gz: c8a125e7eabce1a8d19853040151e38791c57d07
4
+ data.tar.gz: ec143b133ab55a2ec34ec2fd7b4f3c9b84831fad
5
5
  SHA512:
6
- metadata.gz: 5350184abf2713d2385ebb6c810047696fe38dc37a9ec2984777d8099ec342afc363ed0257e75933930dc6269b3a2f049a51a5a1420ce7dbaf6ee453758db808
7
- data.tar.gz: d0428814d6e6811a16c43db27f096a55472f2c82b7fcb1e957f4f654e477033907af5a35bf9f72a30938183ff1e43999de52b1400c96be1a40c16b1091231f03
6
+ metadata.gz: 0d3ce4a39378e5fbe15e642bcee30e97a03506316741c6ee5e3a242398a3b249e79f2ee6e88d08279bb57aabd3f07968f3c1430930921cf8b310efc42f8b4d5c
7
+ data.tar.gz: ddf7c4cc0c9ade106a817bd89d3557248933e167c8faadf3db1fd6855d911accbca5bbea68866c0633c449381099161e7082b79401c1d0485159b8f161632a42
data/README.markdown CHANGED
@@ -22,7 +22,7 @@ methods.
22
22
  gem install couchpillow
23
23
 
24
24
 
25
- ## How To Use
25
+ ## Quick Start
26
26
 
27
27
  require 'couchpillow'
28
28
 
@@ -62,16 +62,47 @@ Specifying custom id:
62
62
  doc.save!
63
63
 
64
64
  # {
65
- # '_id': '123',
65
+ # '_id': 'user::123',
66
66
  # '_type': 'user',
67
67
  # '_created_at': '2014-07-04 00:00:00 UTC'
68
68
  # '_updated_at': '2014-07-04 00:00:00 UTC'
69
69
  # 'email': 'john@email.com',
70
70
  # }
71
71
 
72
+
73
+ ### Document-Level Directives
74
+
75
+ The following are directives that can be used to trigger specific behaviors
76
+ at the Document level.
77
+
78
+ * `type(T)`
79
+
80
+ Set the type of the Document.
81
+
82
+ * `type_prefix(true|false)`
83
+
84
+ Default to `true`. If set to false, it removes prefixing document id with
85
+ the document type. Leaving this to true is the recommended behavior to avoid
86
+ id conflicts between different types of documents, especially when custom
87
+ ids are being used.
88
+
89
+ * `attribute(name, &block)`
90
+
91
+ Declares an attribute for this Document. You can specify additional
92
+ directives for each attribute. See Attributes section.
93
+
94
+ * `db(connection)`
95
+
96
+ Sets the database connections. If set once, it will set that connection as
97
+ the primary connection. Any subsequent calls to this directive will set
98
+ those connections as secondary connections. See Multiple DB Connections
99
+ section.
100
+
101
+
102
+
72
103
  ### Attributes
73
104
 
74
- Using Attribute Directives:
105
+ Using Attribute Directive:
75
106
 
76
107
  class User < CouchPillow::Document
77
108
  type :user
@@ -164,8 +195,8 @@ via the `db` directive. Example:
164
195
 
165
196
  You can also specify multiple `db` directives. The first time the `db`
166
197
  directive is called, it sets that connection as the primary connection, as the
167
- above example shows. Any subsequent calls will insert that DB connection as
168
- secondary connections, which will only be trigger on write (`save!`, `update!`,
198
+ above example shows. Any subsequent calls will insert those DB connection as
199
+ secondary connections, which will only trigger on write (`save!`, `update!`,
169
200
  and `delete!`).
170
201
 
171
202
 
data/lib/couchpillow.rb CHANGED
@@ -1,13 +1,10 @@
1
1
  require 'securerandom'
2
2
  require 'json'
3
3
  require 'time'
4
- require 'celluloid/autostart'
5
4
  require 'couchbase'
6
5
 
7
6
  module CouchPillow
8
7
 
9
- Celluloid.logger = nil
10
-
11
8
  def self.db= driver
12
9
  @db = driver
13
10
  end
@@ -18,8 +15,11 @@ module CouchPillow
18
15
 
19
16
  end
20
17
 
21
- require 'couchpillow/attribute'
22
- require 'couchpillow/attributive'
18
+ require 'couchpillow/directives/type'
19
+ require 'couchpillow/directives/type_prefix'
20
+ require 'couchpillow/directives/attribute'
21
+ require 'couchpillow/directives/multi_db'
22
+
23
23
  require 'couchpillow/errors'
24
24
  require 'couchpillow/boolean'
25
25
  require 'couchpillow/document'
@@ -1,5 +1,36 @@
1
1
  module CouchPillow
2
2
 
3
+ module AttributeDirective
4
+
5
+ # Declares a new Attribute
6
+ #
7
+ def attribute attr, &block
8
+ attr = attr.to_s.to_sym
9
+ new_attr = Attribute.new(attr)
10
+ attributes[attr] = new_attr
11
+
12
+ # Define accessor methods
13
+ define_method(attr) do
14
+ @data[attr]
15
+ end
16
+ define_method("#{attr}=") do |val|
17
+ @data[attr] = val
18
+ end
19
+
20
+ new_attr.instance_eval &block if block
21
+
22
+ new_attr
23
+ end
24
+
25
+
26
+ def attributes
27
+ @attributes ||= {}
28
+ end
29
+
30
+
31
+ end
32
+
33
+
3
34
  class Attribute
4
35
 
5
36
  attr_reader :name
@@ -8,7 +39,6 @@ module CouchPillow
8
39
  @type = nil
9
40
  @auto_convert = false
10
41
  @default_block = nil
11
- @check_value_message = nil
12
42
  @check_value_block = nil
13
43
 
14
44
 
@@ -69,18 +99,16 @@ module CouchPillow
69
99
 
70
100
  # Directive to perform a validation over the value of this Attribute.
71
101
  #
72
- # @param message Message when block passed fails. Optional.
73
102
  # @yield [v] Value of the Attribute.
74
103
  #
75
104
  # @example
76
- # content("Name must be John") { |v| v == "John" }
77
105
  # content { |v| v == "John" }
78
106
  #
79
- def content message = nil, &block
80
- @check_value_message = message
107
+ def content &block
81
108
  @check_value_block = block
82
109
  self
83
110
  end
111
+ alias_method :validate_content, :content
84
112
 
85
113
 
86
114
  # Check the default value.
@@ -96,7 +124,7 @@ module CouchPillow
96
124
  #
97
125
  def trigger_content_directive value
98
126
  if @check_value_block
99
- raise ValidationError, @check_value_message unless
127
+ raise ValidationError, "Content validation error: #{value}" unless
100
128
  @check_value_block.call(value)
101
129
  end
102
130
  value
@@ -110,10 +138,11 @@ module CouchPillow
110
138
  # Run auto-conversion first.
111
139
  value = trigger_auto_convert_directive(value)
112
140
 
141
+ msg = "Type mismatch for attribute #{@name}"
113
142
  if @type == CouchPillow::Boolean
114
- raise ValidationError unless !!value == value
143
+ raise ValidationError, msg unless !!value == value
115
144
  else
116
- raise ValidationError unless value.is_a?(@type)
145
+ raise ValidationError, msg unless value.is_a?(@type)
117
146
  end
118
147
  end
119
148
 
@@ -157,5 +186,3 @@ module CouchPillow
157
186
 
158
187
  end
159
188
  end
160
-
161
-
@@ -0,0 +1,70 @@
1
+ require 'celluloid/autostart'
2
+
3
+ Celluloid.logger = nil
4
+
5
+ module CouchPillow
6
+
7
+ module MultiDBDirective
8
+
9
+ # Set a DB connection. Overrides the default CouchPillow.db connection
10
+ # for the first time this method gets called. Subsequent calls will set
11
+ # secondary connections, which will only be used for write only.
12
+ #
13
+ # Example:
14
+ # db primary_db # use for both read and write
15
+ # db backup_db1 # write only
16
+ # db backup_db2 # write only
17
+ #
18
+ def db conn
19
+ # set the primary db connection
20
+ @primary_db ||= conn
21
+
22
+ # insert as backup db connections
23
+ if conn && @primary_db && conn != @primary_db
24
+ _secondary_dbs << conn
25
+ end
26
+ end
27
+
28
+
29
+ def _default_db
30
+ @default_db ||= (@primary_db || CouchPillow.db)
31
+ end
32
+
33
+
34
+ def _secondary_dbs
35
+ @secondary_dbs ||= []
36
+ end
37
+
38
+
39
+ def _write_to_secondary_dbs &block
40
+ unless _secondary_dbs.empty?
41
+ _futures << Celluloid::Future.new do
42
+ _secondary_dbs.each do |db|
43
+ block.call(db)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+
50
+ def _futures
51
+ @futures ||= []
52
+ end
53
+
54
+
55
+ # Blocks until all pending tasks has completed.
56
+ # Returns the result of those tasks in an array.
57
+ #
58
+ def wait
59
+ result = []
60
+ until _futures.empty?
61
+ f = _futures.shift
62
+ result << f.value
63
+ end
64
+
65
+ result
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,28 @@
1
+ module CouchPillow
2
+
3
+ module TypeDirective
4
+
5
+ # Sets the type of this Document.
6
+ #
7
+ def type value
8
+ @type = value.to_s
9
+ end
10
+
11
+
12
+ def _doc_type
13
+ @type ||= "couchpillow"
14
+ end
15
+
16
+
17
+ # Helper method to sanitize an id string
18
+ #
19
+ def _sanitize_id id
20
+ key = "#{_doc_type}::"
21
+ id = id.to_s
22
+ id.start_with?(key) and
23
+ id = id[key.length..-1] or
24
+ id
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ module CouchPillow
2
+
3
+ module TypePrefixDirective
4
+
5
+
6
+ def type_prefix v
7
+ @type_prefix = v == true
8
+ end
9
+
10
+
11
+ def _is_type_prefixed?
12
+ @type_prefix == true
13
+ end
14
+
15
+ end
16
+ end
@@ -2,19 +2,23 @@ module CouchPillow
2
2
 
3
3
  class Document
4
4
 
5
- extend Attributive
5
+ extend TypeDirective
6
+ extend TypePrefixDirective
7
+ extend AttributeDirective
8
+ extend MultiDBDirective
6
9
 
7
- attr_reader :id
10
+ attr_accessor :id
8
11
 
9
12
  RESERVED_KEYS = %i[_id _type _created_at _updated_at]
10
13
 
11
- DEFAULT_TYPE = "couchpillow".freeze
12
-
13
14
  EVENTS = [ :cas_conflict ].freeze
14
15
 
15
16
  CAS_CONFLICT_RETRY_COUNT = 5
16
17
 
17
18
 
19
+ type_prefix true
20
+
21
+
18
22
  attribute :_created_at do
19
23
  required
20
24
  type Time
@@ -37,19 +41,18 @@ module CouchPillow
37
41
  # @param flags Flags of the document, from the CB client. Optional.
38
42
  #
39
43
  def initialize hash = {},
40
- id = "#{self.class.doc_type}::#{SecureRandom.hex}",
44
+ id = SecureRandom.hex,
41
45
  cas = nil
42
46
 
43
47
  @data = self.class.symbolize(hash)
44
48
  @original = Marshal.load(Marshal.dump(@data))
45
49
 
46
- @id = id
50
+ @id = self.class._is_type_prefixed? ? self.class._sanitize_id(id) : id
51
+
47
52
  time = Time.now.utc
48
53
  @data[:_created_at] ||= time
49
54
  @data[:_updated_at] = time
50
55
 
51
- @futures = []
52
-
53
56
  @cas = cas
54
57
 
55
58
  rename!
@@ -75,19 +78,19 @@ module CouchPillow
75
78
  result = nil
76
79
 
77
80
  # write to the primary db first
78
- result = cas_handler do
81
+ result = _cas_handler do
79
82
  whitelist!
80
83
  sort!
81
- timestamp!
84
+ _timestamp!
82
85
  validate!
83
86
  opts[:cas] = @cas
84
- self.class.default_db.set(@id, to_save, opts)
87
+ self.class._default_db.set(db_id, _to_save, opts)
85
88
  end
86
89
 
87
90
  # write to the secondary only if the primary succeeds
88
91
  # and ignore CAS for secondary DBs.
89
- write_to_secondary_dbs do |db|
90
- db.set @id, to_save
92
+ self.class._write_to_secondary_dbs do |db|
93
+ db.set(db_id, _to_save)
91
94
  end if result
92
95
 
93
96
  result
@@ -97,11 +100,11 @@ module CouchPillow
97
100
  # Delete this document from the server.
98
101
  #
99
102
  def delete!
100
- result = self.class.default_db.delete @id
103
+ result = self.class._default_db.delete(db_id)
101
104
 
102
105
  # write to the secondary only if the primary succeeds
103
- write_to_secondary_dbs do |db|
104
- db.delete @id
106
+ self.class._write_to_secondary_dbs do |db|
107
+ db.delete(db_id)
105
108
  end if result
106
109
 
107
110
  result
@@ -114,20 +117,20 @@ module CouchPillow
114
117
  def update! opts = {}
115
118
 
116
119
  # write to the primary db first
117
- result = cas_handler do
120
+ result = _cas_handler do
118
121
  whitelist!
119
122
  sort!
120
- timestamp!
123
+ _timestamp!
121
124
  validate!
122
125
  opts[:cas] = @cas
123
- result = self.class.default_db.replace(@id, to_save, opts)
126
+ result = self.class._default_db.replace(db_id, _to_save, opts)
124
127
  end
125
128
 
126
129
  # write to the secondary only if the primary succeeds
127
130
  # and ignore CAS for secondary DBs.
128
131
  opts.delete :cas
129
- write_to_secondary_dbs do |db|
130
- db.replace @id, to_save
132
+ self.class._write_to_secondary_dbs do |db|
133
+ db.replace(db_id, _to_save)
131
134
  end if result
132
135
 
133
136
  result
@@ -165,7 +168,7 @@ module CouchPillow
165
168
  # Convert this Document to a Hash
166
169
  #
167
170
  def to_hash
168
- { :_id => @id, :_type => self.class.doc_type }.merge!(@data)
171
+ { :_id => @id, :_type => doc_type }.merge!(@data)
169
172
  end
170
173
 
171
174
 
@@ -173,21 +176,7 @@ module CouchPillow
173
176
  # Can't really name this `type`. Need to avoid name conflict with Ruby's own `type` method.
174
177
  #
175
178
  def doc_type
176
- self.class.doc_type
177
- end
178
-
179
-
180
- # Blocks until all pending tasks has completed.
181
- # Returns the result of those tasks in an array.
182
- #
183
- def wait
184
- result = []
185
- until @futures.empty?
186
- f = @futures.shift
187
- result << f.value
188
- end
189
-
190
- result
179
+ self.class._doc_type
191
180
  end
192
181
 
193
182
 
@@ -256,11 +245,13 @@ module CouchPillow
256
245
  # @return nil if not found or Document is of a different type.
257
246
  #
258
247
  def self.get id
259
- result, _, cas = default_db.get(id, extended: true)
248
+ id = _sanitize_id(id)
249
+ tid = _is_type_prefixed? ? "#{_doc_type}::#{id}" : id
250
+ result, _, cas = _default_db.get(tid, extended: true)
260
251
 
261
252
  result and
262
253
  type = result[:_type] || result["_type"] and
263
- type == doc_type and
254
+ type == _doc_type and
264
255
  new(result, id, cas) or
265
256
  nil
266
257
  end
@@ -277,33 +268,6 @@ module CouchPillow
277
268
  end
278
269
 
279
270
 
280
- # Sets the type of this Document.
281
- #
282
- def self.type value
283
- @type = value.to_s
284
- end
285
-
286
-
287
- # Set a DB connection. Overrides the default CouchPillow.db connection
288
- # for the first time this method gets called. Subsequent calls will set
289
- # secondary connections, which will only be used for write only.
290
- #
291
- # Example:
292
- # db primary_db # use for both read and write
293
- # db backup_db1 # write only
294
- # db backup_db2 # write only
295
- #
296
- def self.db conn
297
- # set the primary db connection
298
- @primary_db ||= conn
299
-
300
- # insert as backup db connections
301
- if conn && @primary_db && conn != @primary_db
302
- secondary_dbs << conn
303
- end
304
- end
305
-
306
-
307
271
  # Registers a listener on a specific event.
308
272
  # See {EVENTS} constant for a list of accepted events.
309
273
  #
@@ -312,28 +276,27 @@ module CouchPillow
312
276
  end
313
277
 
314
278
 
279
+ # Inherit directives
280
+ def self.inherited subclass
281
+ attributes.each do |k, v|
282
+ subclass.attributes[k] = v
283
+ end
284
+ subclass.type_prefix(_is_type_prefixed?)
285
+ subclass.type(_doc_type)
286
+ end
287
+
288
+
315
289
  private
316
290
 
317
291
 
318
292
  # Timestamp this document
319
293
  #
320
- def timestamp!
294
+ def _timestamp!
321
295
  @data[:_updated_at] = Time.now.utc
322
296
  end
323
297
 
324
298
 
325
- def write_to_secondary_dbs &block
326
- unless self.class.secondary_dbs.empty?
327
- @futures << Celluloid::Future.new do
328
- self.class.secondary_dbs.each do |db|
329
- block.call(db)
330
- end
331
- end
332
- end
333
- end
334
-
335
-
336
- def cas_handler &block
299
+ def _cas_handler &block
337
300
  # write to the primary db first
338
301
  rtcount = CAS_CONFLICT_RETRY_COUNT
339
302
  begin
@@ -343,13 +306,13 @@ module CouchPillow
343
306
  raise
344
307
 
345
308
  rescue Couchbase::Error::KeyExists
346
- other_doc, _, newcas = self.class.default_db.get(@id, extended: true)
309
+ other_doc, _, newcas = self.class._default_db.get(db_id, extended: true)
347
310
  raise CASError, "There is a CAS conflict, but DB does not yield a document" unless other_doc
348
311
  raise CASError, "There is a CAS conflict, but no :cas_conflict handler has been defined. See 'on' directive." unless self.class.event_listeners[:cas_conflict]
349
312
 
350
313
  # resolve conflict
351
314
  other_doc = self.class.symbolize(other_doc)
352
- @data = self.class.event_listeners[:cas_conflict].call(@original, other_doc, to_save)
315
+ @data = self.class.event_listeners[:cas_conflict].call(@original, other_doc, _to_save)
353
316
  @cas = newcas
354
317
 
355
318
  rtcount -= 1
@@ -363,20 +326,23 @@ module CouchPillow
363
326
  # Get the final hash that will be saved to the database.
364
327
  # Check if data has been modified.
365
328
  #
366
- def to_save
329
+ def _to_save
367
330
  hash = @data.hash
368
331
  return @tos if @tos && @toshash && @toshash == hash
369
332
 
370
333
  @tos = @data.merge({
371
- :_type => self.class.doc_type
334
+ :_type => doc_type
372
335
  })
373
336
  @toshash = @data.hash
374
337
  @tos
375
338
  end
376
339
 
377
340
 
378
- def self.doc_type
379
- @type ||= DEFAULT_TYPE
341
+ # Get the final id value that will be saved to the database.
342
+ #
343
+ def db_id
344
+ @id = self.class._sanitize_id(@id)
345
+ self.class._is_type_prefixed? ? "#{doc_type}::#{@id}" : @id
380
346
  end
381
347
 
382
348
 
@@ -385,16 +351,6 @@ module CouchPillow
385
351
  end
386
352
 
387
353
 
388
- def self.default_db
389
- @default_db ||= (@primary_db || CouchPillow.db)
390
- end
391
-
392
-
393
- def self.secondary_dbs
394
- @secondary_dbs ||= []
395
- end
396
-
397
-
398
354
  def self.event_listeners
399
355
  @event_listeners ||= {}
400
356
  end
@@ -1,5 +1,5 @@
1
1
  module CouchPillow
2
2
  GEM_NAME = "couchpillow"
3
3
  NAME = "CouchPillow"
4
- VERSION = "0.4.5"
4
+ VERSION = "0.4.6"
5
5
  end
@@ -209,8 +209,8 @@ class TestDocument < Minitest::Test
209
209
 
210
210
 
211
211
  def test_get_returns_nil
212
- CouchPillow.db.expects(:get).with('123', { extended: true }).returns(nil)
213
- Document.expects(:default_db).returns(CouchPillow.db)
212
+ CouchPillow.db.expects(:get).with('couchpillow::123', { extended: true }).returns(nil)
213
+ Document.expects(:_default_db).returns(CouchPillow.db)
214
214
  d = Document.get('123')
215
215
  assert_equal nil, d
216
216
  end
@@ -221,11 +221,6 @@ class TestDocument < Minitest::Test
221
221
  type 'test'
222
222
  end
223
223
 
224
- CouchPillow.db
225
- .expects(:get)
226
- .with('123', { extended: true })
227
- .returns( { '_type' => 'something else', 'stuff' => 'data' } )
228
-
229
224
  d = klass.get('123')
230
225
  assert_equal nil, d
231
226
  end
@@ -417,7 +412,7 @@ class TestDocument < Minitest::Test
417
412
  def test_custom_db_connection
418
413
  conn1 = FakeCouchbaseServer.new
419
414
 
420
- d = Class.new(Document) do
415
+ klass = Class.new(Document) do
421
416
  type 'test'
422
417
 
423
418
  db conn1
@@ -428,20 +423,16 @@ class TestDocument < Minitest::Test
428
423
  required
429
424
  default { "tester" }
430
425
  end
426
+ end
431
427
 
432
-
433
- def initialize doc = {}
434
- super(doc, "1")
435
- end
436
-
437
- end.new
428
+ d = klass.new({}, "1")
438
429
  d.foo = "hello"
439
430
  d.save!
440
431
 
441
- fromdefdb = CouchPillow.db.get("1")
432
+ fromdefdb = CouchPillow.db.get("test::1")
442
433
  assert_nil fromdefdb
443
434
 
444
- fromprimdb = conn1.get("1")
435
+ fromprimdb = conn1.get("test::1")
445
436
  assert_equal "hello", fromprimdb[:foo]
446
437
  end
447
438
 
@@ -451,8 +442,9 @@ class TestDocument < Minitest::Test
451
442
  db2 = FakeCouchbaseServer.new
452
443
  db3 = FakeCouchbaseServer.new
453
444
 
454
- d = Class.new(Document) do
445
+ klass = Class.new(Document) do
455
446
  type 'test'
447
+ type_prefix false
456
448
 
457
449
  db db1
458
450
  db db2
@@ -465,16 +457,13 @@ class TestDocument < Minitest::Test
465
457
  default { "tester" }
466
458
  end
467
459
 
460
+ end
468
461
 
469
- def initialize doc = {}
470
- super(doc, "1")
471
- end
472
-
473
- end.new
462
+ d = klass.new( {}, "1" )
474
463
  d.foo = "hello"
475
464
  d.save!
476
465
 
477
- res = d.wait
466
+ res = klass.wait
478
467
 
479
468
  data = db1.get("1")
480
469
  assert_equal "hello", data[:foo]
@@ -551,4 +540,124 @@ class TestDocument < Minitest::Test
551
540
  end
552
541
 
553
542
 
543
+ def test_type_prefix_directive_default
544
+ assert Document._is_type_prefixed?, "type_prefix default is not true"
545
+ end
546
+
547
+
548
+ def test_type_prefix_directive_false
549
+ klass = Class.new(Document) do
550
+ type 'test'
551
+ type_prefix false
552
+
553
+ attribute :foo do
554
+ type String
555
+ end
556
+ end
557
+
558
+ d = klass.new( { foo: "Hello" } , "10" )
559
+ d.save!
560
+
561
+ dataindb = CouchPillow.db.get("10")
562
+ assert dataindb
563
+ assert_equal "Hello", dataindb[:foo]
564
+ end
565
+
566
+
567
+ def test_type_prefix_directive_true
568
+ klass = Class.new(Document) do
569
+ type 'test'
570
+
571
+ attribute :foo do
572
+ type String
573
+ end
574
+ end
575
+
576
+ d = klass.new( { foo: "Hello" } , "10" )
577
+ assert_equal "10", d.id
578
+ d.save!
579
+
580
+ d1 = klass.get("10")
581
+ assert_equal "Hello", d1.foo
582
+
583
+ dataindb = CouchPillow.db.get("test::10")
584
+ assert dataindb
585
+ assert_equal "Hello", dataindb[:foo]
586
+ end
587
+
588
+
589
+ def test_new_with_type_prefix
590
+ klass = Class.new(Document) do
591
+ type 'test'
592
+
593
+ attribute :foo do
594
+ type String
595
+ end
596
+ end
597
+
598
+ d = klass.new( { foo: "Hello" } , "test::10" )
599
+ assert_equal "10", d.id
600
+
601
+ d = klass.new( { foo: "Hello" } , "wrong::10" )
602
+ assert_equal "wrong::10", d.id
603
+
604
+ klass = Class.new(Document) do
605
+ type 'test'
606
+ type_prefix false
607
+
608
+ attribute :foo do
609
+ type String
610
+ end
611
+ end
612
+
613
+ d = klass.new( { foo: "Hello" } , "test::10" )
614
+ assert_equal "test::10", d.id
615
+
616
+ d = klass.new( { foo: "Hello" } , "wrong::10" )
617
+ assert_equal "wrong::10", d.id
618
+ end
619
+
620
+
621
+ def test_content_directive
622
+ klass = Class.new(Document) do
623
+ type 'test'
624
+
625
+ attribute :foo do
626
+ type String
627
+ content { |v| v == "must" }
628
+ end
629
+ end
630
+
631
+ d = klass.new( foo: "Hello" )
632
+
633
+ assert_raises CouchPillow::ValidationError do
634
+ d.save!
635
+ end
636
+
637
+ d.foo = "must"
638
+ d.save!
639
+ end
640
+
641
+
642
+ def test_validate_content_alias
643
+ klass = Class.new(Document) do
644
+ type 'test'
645
+
646
+ attribute :foo do
647
+ type String
648
+ validate_content { |v| v == "must" }
649
+ end
650
+ end
651
+
652
+ d = klass.new( foo: "Hello" )
653
+
654
+ assert_raises CouchPillow::ValidationError do
655
+ d.save!
656
+ end
657
+
658
+ d.foo = "must"
659
+ d.save!
660
+ end
661
+
662
+
554
663
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchpillow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Albert Tedja
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-14 00:00:00.000000000 Z
11
+ date: 2015-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid
@@ -92,9 +92,11 @@ files:
92
92
  - Rakefile
93
93
  - couchpillow.gemspec
94
94
  - lib/couchpillow.rb
95
- - lib/couchpillow/attribute.rb
96
- - lib/couchpillow/attributive.rb
97
95
  - lib/couchpillow/boolean.rb
96
+ - lib/couchpillow/directives/attribute.rb
97
+ - lib/couchpillow/directives/multi_db.rb
98
+ - lib/couchpillow/directives/type.rb
99
+ - lib/couchpillow/directives/type_prefix.rb
98
100
  - lib/couchpillow/document.rb
99
101
  - lib/couchpillow/errors.rb
100
102
  - lib/couchpillow/version.rb
@@ -1,39 +0,0 @@
1
- module CouchPillow
2
-
3
- module Attributive
4
-
5
- # Declares a new Attribute
6
- #
7
- def attribute attr, &block
8
- attr = attr.to_s.to_sym
9
- new_attr = Attribute.new(attr)
10
- attributes[attr] = new_attr
11
-
12
- # Define accessor methods
13
- define_method(attr) do
14
- @data[attr]
15
- end
16
- define_method("#{attr}=") do |val|
17
- @data[attr] = val
18
- end
19
-
20
- new_attr.instance_eval &block if block
21
-
22
- new_attr
23
- end
24
-
25
-
26
- def attributes
27
- @attributes ||= {}
28
- end
29
-
30
-
31
- def inherited(subclass)
32
- # Copy existing attributes to subclasses
33
- attributes.each do |k, v|
34
- subclass.attributes[k] = v
35
- end
36
- end
37
-
38
- end
39
- end