couchbase 1.2.1 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +50 -5
- data/RELEASE_NOTES.markdown +256 -145
- data/couchbase.gemspec +2 -4
- data/examples/chat-em/Gemfile +7 -0
- data/examples/chat-em/README.markdown +45 -0
- data/examples/chat-em/server.rb +82 -0
- data/ext/couchbase_ext/arguments.c +18 -17
- data/ext/couchbase_ext/arithmetic.c +17 -25
- data/ext/couchbase_ext/bucket.c +227 -32
- data/ext/couchbase_ext/context.c +64 -0
- data/ext/couchbase_ext/couchbase_ext.c +106 -14
- data/ext/couchbase_ext/couchbase_ext.h +81 -12
- data/ext/couchbase_ext/delete.c +18 -25
- data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
- data/ext/couchbase_ext/extconf.rb +2 -0
- data/ext/couchbase_ext/get.c +18 -31
- data/ext/couchbase_ext/http.c +40 -31
- data/ext/couchbase_ext/multithread_plugin.c +38 -201
- data/ext/couchbase_ext/observe.c +17 -25
- data/ext/couchbase_ext/plugin_common.c +171 -0
- data/ext/couchbase_ext/result.c +18 -12
- data/ext/couchbase_ext/stats.c +17 -25
- data/ext/couchbase_ext/store.c +43 -47
- data/ext/couchbase_ext/touch.c +18 -25
- data/ext/couchbase_ext/unlock.c +18 -25
- data/ext/couchbase_ext/utils.c +23 -8
- data/ext/couchbase_ext/version.c +16 -24
- data/lib/couchbase.rb +1 -0
- data/lib/couchbase/bucket.rb +1 -1
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view.rb +210 -60
- data/lib/couchbase/view_row.rb +103 -61
- data/tasks/compile.rake +1 -1
- data/test/test_async.rb +63 -0
- data/test/test_eventmachine.rb +70 -0
- metadata +143 -174
- data/tasks/doc.rake +0 -27
data/lib/couchbase.rb
CHANGED
data/lib/couchbase/bucket.rb
CHANGED
@@ -109,7 +109,7 @@ module Couchbase
|
|
109
109
|
if obj['doc']
|
110
110
|
obj['doc']['value'] = obj['doc'].delete('json')
|
111
111
|
end
|
112
|
-
doc =
|
112
|
+
doc = DesignDoc.wrap(self, obj)
|
113
113
|
key = doc.id.sub(/^_design\//, '')
|
114
114
|
next if self.environment == :production && key =~ /dev_/
|
115
115
|
docmap[key] = doc
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Couchbase
|
2
|
+
module Constants # :nodoc:
|
3
|
+
S_ID = 'id'.freeze
|
4
|
+
S_DOC = 'doc'.freeze
|
5
|
+
S_VALUE = 'value'.freeze
|
6
|
+
S_META = 'meta'.freeze
|
7
|
+
S_FLAGS = 'flags'.freeze
|
8
|
+
S_CAS = 'cas'.freeze
|
9
|
+
S_KEY = 'key'.freeze
|
10
|
+
S_IS_LAST = Object.new.freeze
|
11
|
+
end
|
12
|
+
end
|
data/lib/couchbase/version.rb
CHANGED
data/lib/couchbase/view.rb
CHANGED
@@ -47,8 +47,9 @@ module Couchbase
|
|
47
47
|
str = super
|
48
48
|
if @type || @reason
|
49
49
|
str.sub(/ \(/, ": #{[@type, @reason].compact.join(": ")} (")
|
50
|
+
else
|
51
|
+
str
|
50
52
|
end
|
51
|
-
str
|
52
53
|
end
|
53
54
|
end
|
54
55
|
end
|
@@ -58,6 +59,88 @@ module Couchbase
|
|
58
59
|
# @see http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views.html
|
59
60
|
class View
|
60
61
|
include Enumerable
|
62
|
+
include Constants
|
63
|
+
|
64
|
+
class ArrayWithTotalRows < Array # :nodoc:
|
65
|
+
attr_accessor :total_rows
|
66
|
+
alias total_entries total_rows
|
67
|
+
end
|
68
|
+
|
69
|
+
class AsyncHelper # :nodoc:
|
70
|
+
include Constants
|
71
|
+
EMPTY = []
|
72
|
+
|
73
|
+
def initialize(wrapper_class, bucket, include_docs, quiet, block)
|
74
|
+
@wrapper_class = wrapper_class
|
75
|
+
@bucket = bucket
|
76
|
+
@block = block
|
77
|
+
@quiet = quiet
|
78
|
+
@include_docs = include_docs
|
79
|
+
@queue = []
|
80
|
+
@first = @shift = 0
|
81
|
+
@completed = false
|
82
|
+
end
|
83
|
+
|
84
|
+
# Register object in the emitter.
|
85
|
+
def push(obj)
|
86
|
+
if @include_docs
|
87
|
+
@queue << obj
|
88
|
+
@bucket.get(obj[S_ID], :extended => true, :quiet => @quiet) do |res|
|
89
|
+
obj[S_DOC] = {
|
90
|
+
S_VALUE => res.value,
|
91
|
+
S_META => {
|
92
|
+
S_ID => obj[S_ID],
|
93
|
+
S_FLAGS => res.flags,
|
94
|
+
S_CAS => res.cas
|
95
|
+
}
|
96
|
+
}
|
97
|
+
check_for_ready_documents
|
98
|
+
end
|
99
|
+
else
|
100
|
+
old_obj = @queue.shift
|
101
|
+
@queue << obj
|
102
|
+
block_call(old_obj) if old_obj
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def complete!
|
107
|
+
if @include_docs
|
108
|
+
@completed = true
|
109
|
+
check_for_ready_documents
|
110
|
+
elsif !@queue.empty?
|
111
|
+
obj = @queue.shift
|
112
|
+
obj[S_IS_LAST] = true
|
113
|
+
block_call obj
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def block_call(obj)
|
120
|
+
@block.call @wrapper_class.wrap(@bucket, obj)
|
121
|
+
end
|
122
|
+
|
123
|
+
def check_for_ready_documents
|
124
|
+
shift = @shift
|
125
|
+
queue = @queue
|
126
|
+
save_last = @completed ? 0 : 1
|
127
|
+
while @first < queue.size + shift - save_last
|
128
|
+
obj = queue[@first - shift]
|
129
|
+
break unless obj[S_DOC]
|
130
|
+
queue[@first - shift] = nil
|
131
|
+
@first += 1
|
132
|
+
if @completed && @first == queue.size + shift
|
133
|
+
obj[S_IS_LAST] = true
|
134
|
+
end
|
135
|
+
block_call obj
|
136
|
+
end
|
137
|
+
if @first - shift > queue.size / 2
|
138
|
+
queue[0, @first - shift] = EMPTY
|
139
|
+
@shift = @first
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
61
144
|
|
62
145
|
attr_reader :params
|
63
146
|
|
@@ -112,6 +195,16 @@ module Couchbase
|
|
112
195
|
fetch(params) {|doc| yield(doc)}
|
113
196
|
end
|
114
197
|
|
198
|
+
def first(params = {})
|
199
|
+
params = params.merge(:limit => 1)
|
200
|
+
fetch(params).first
|
201
|
+
end
|
202
|
+
|
203
|
+
def take(n, params = {})
|
204
|
+
params = params.merge(:limit => n)
|
205
|
+
fetch(params)
|
206
|
+
end
|
207
|
+
|
115
208
|
# Registers callback function for handling error objects in view
|
116
209
|
# results stream.
|
117
210
|
#
|
@@ -259,93 +352,150 @@ module Couchbase
|
|
259
352
|
# doc.recent_posts_with_comments(:start_key => [post_id, 0],
|
260
353
|
# :end_key => [post_id, 1],
|
261
354
|
# :include_docs => true)
|
262
|
-
def fetch(params = {})
|
355
|
+
def fetch(params = {}, &block)
|
263
356
|
params = @params.merge(params)
|
357
|
+
include_docs = params.delete(:include_docs)
|
358
|
+
quiet = params.delete(:quiet){ true }
|
359
|
+
|
264
360
|
options = {:chunked => true, :extended => true, :type => :view}
|
265
361
|
if body = params.delete(:body)
|
266
362
|
body = MultiJson.dump(body) unless body.is_a?(String)
|
267
363
|
options.update(:body => body, :method => params.delete(:method) || :post)
|
268
364
|
end
|
269
|
-
include_docs = params.delete(:include_docs)
|
270
|
-
quiet = true
|
271
|
-
if params.has_key?(:quiet)
|
272
|
-
quiet = params.delete(:quiet)
|
273
|
-
end
|
274
365
|
path = Utils.build_query(@endpoint, params)
|
275
366
|
request = @bucket.make_http_request(path, options)
|
276
|
-
|
367
|
+
|
368
|
+
if @bucket.async?
|
369
|
+
if block
|
370
|
+
fetch_async(request, include_docs, quiet, block)
|
371
|
+
end
|
372
|
+
else
|
373
|
+
fetch_sync(request, include_docs, quiet, block)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Method for fetching asynchronously all rows and passing array to callback
|
378
|
+
#
|
379
|
+
# Parameters are same as for {View#fetch} method, but callback is called for whole set for
|
380
|
+
# rows instead of one by each.
|
381
|
+
#
|
382
|
+
# @example
|
383
|
+
# con.run do
|
384
|
+
# doc.recent_posts.fetch_all do |posts|
|
385
|
+
# do_something_with_all_posts(posts)
|
386
|
+
# end
|
387
|
+
# end
|
388
|
+
def fetch_all(params = {}, &block)
|
389
|
+
return fetch(params) unless @bucket.async?
|
390
|
+
raise ArgumentError, "Block needed for fetch_all in async mode" unless block
|
391
|
+
|
392
|
+
all = []
|
393
|
+
fetch(params) do |row|
|
394
|
+
all << row
|
395
|
+
if row.last?
|
396
|
+
@bucket.create_timer(0) { block.call(all) }
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
|
402
|
+
# Returns a string containing a human-readable representation of the {View}
|
403
|
+
#
|
404
|
+
# @return [String]
|
405
|
+
def inspect
|
406
|
+
%(#<#{self.class.name}:#{self.object_id} @endpoint=#{@endpoint.inspect} @params=#{@params.inspect}>)
|
407
|
+
end
|
408
|
+
|
409
|
+
private
|
410
|
+
|
411
|
+
def send_error(*args)
|
412
|
+
if @on_error
|
413
|
+
@on_error.call(*args.take(2))
|
414
|
+
else
|
415
|
+
raise Error::View.new(*args)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
def fetch_async(request, include_docs, quiet, block)
|
420
|
+
filter = ["/rows/", "/errors/"]
|
421
|
+
parser = YAJI::Parser.new(:filter => filter, :with_path => true)
|
422
|
+
helper = AsyncHelper.new(@wrapper_class, @bucket, include_docs, quiet, block)
|
423
|
+
|
277
424
|
request.on_body do |chunk|
|
278
|
-
|
279
|
-
|
425
|
+
if chunk.success?
|
426
|
+
parser << chunk.value if chunk.value
|
427
|
+
helper.complete! if chunk.completed?
|
428
|
+
else
|
429
|
+
send_error("http_error", chunk.error)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
parser.on_object do |path, obj|
|
434
|
+
case path
|
435
|
+
when "/errors/"
|
436
|
+
from, reason = obj["from"], obj["reason"]
|
437
|
+
send_error(from, reason)
|
438
|
+
else
|
439
|
+
helper.push(obj)
|
440
|
+
end
|
280
441
|
end
|
442
|
+
|
443
|
+
request.perform
|
444
|
+
nil
|
445
|
+
end
|
446
|
+
|
447
|
+
def fetch_sync(request, include_docs, quiet, block)
|
448
|
+
res = []
|
281
449
|
filter = ["/rows/", "/errors/"]
|
282
|
-
|
450
|
+
unless block
|
451
|
+
filter << "/total_rows"
|
452
|
+
docs = ArrayWithTotalRows.new
|
453
|
+
end
|
283
454
|
parser = YAJI::Parser.new(:filter => filter, :with_path => true)
|
284
|
-
|
455
|
+
last_chunk = nil
|
456
|
+
|
457
|
+
request.on_body do |chunk|
|
458
|
+
last_chunk = chunk
|
459
|
+
res << chunk.value if chunk.success?
|
460
|
+
end
|
461
|
+
|
285
462
|
parser.on_object do |path, obj|
|
286
463
|
case path
|
287
464
|
when "/total_rows"
|
288
465
|
# if total_rows key present, save it and take next object
|
289
|
-
docs.
|
466
|
+
docs.total_rows = obj
|
290
467
|
when "/errors/"
|
291
468
|
from, reason = obj["from"], obj["reason"]
|
292
|
-
|
293
|
-
@on_error.call(from, reason)
|
294
|
-
else
|
295
|
-
raise Error::View.new(from, reason)
|
296
|
-
end
|
469
|
+
send_error(from, reason)
|
297
470
|
else
|
298
471
|
if include_docs
|
299
|
-
val, flags, cas = @bucket.get(obj[
|
300
|
-
obj[
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
472
|
+
val, flags, cas = @bucket.get(obj[S_ID], :extended => true, :quiet => quiet)
|
473
|
+
obj[S_DOC] = {
|
474
|
+
S_VALUE => val,
|
475
|
+
S_META => {
|
476
|
+
S_ID => obj[S_ID],
|
477
|
+
S_FLAGS => flags,
|
478
|
+
S_CAS => cas
|
306
479
|
}
|
307
480
|
}
|
308
481
|
end
|
309
|
-
|
310
|
-
|
311
|
-
else
|
312
|
-
docs << @wrapper_class.wrap(@bucket, obj)
|
313
|
-
end
|
482
|
+
doc = @wrapper_class.wrap(@bucket, obj)
|
483
|
+
block ? block.call(doc) : docs << doc
|
314
484
|
end
|
315
485
|
end
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
if r.error
|
323
|
-
if @on_error
|
324
|
-
@on_error.call("http_error", r.error)
|
325
|
-
break
|
326
|
-
else
|
327
|
-
raise Error::View.new("http_error", r.error, nil)
|
328
|
-
end
|
329
|
-
end
|
330
|
-
last_res = r
|
331
|
-
parser << r.value
|
332
|
-
end
|
333
|
-
if last_res.nil? || !last_res.completed? # shall we run the event loop?
|
334
|
-
request.continue
|
335
|
-
else
|
336
|
-
break
|
486
|
+
|
487
|
+
request.continue
|
488
|
+
|
489
|
+
if last_chunk.success?
|
490
|
+
while value = res.shift
|
491
|
+
parser << value
|
337
492
|
end
|
493
|
+
else
|
494
|
+
send_error("http_error", last_chunk.error, nil)
|
338
495
|
end
|
339
|
-
# return nil for call with block
|
340
|
-
block_given? ? nil : docs
|
341
|
-
end
|
342
|
-
|
343
496
|
|
344
|
-
|
345
|
-
|
346
|
-
# @return [String]
|
347
|
-
def inspect
|
348
|
-
%(#<#{self.class.name}:#{self.object_id} @endpoint=#{@endpoint.inspect} @params=#{@params.inspect}>)
|
497
|
+
# return nil for call with block
|
498
|
+
docs
|
349
499
|
end
|
350
500
|
end
|
351
501
|
end
|
data/lib/couchbase/view_row.rb
CHANGED
@@ -20,11 +20,11 @@ module Couchbase
|
|
20
20
|
#
|
21
21
|
# @since 1.2.0
|
22
22
|
#
|
23
|
-
# It behaves like Hash,
|
24
|
-
# the documnent considered as Design document.
|
23
|
+
# It behaves like Hash for document included into row, and has access methods to row data as well.
|
25
24
|
#
|
26
25
|
# @see http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-datastore.html
|
27
26
|
class ViewRow
|
27
|
+
include Constants
|
28
28
|
|
29
29
|
# Undefine as much methods as we can to free names for views
|
30
30
|
instance_methods.each do |m|
|
@@ -84,26 +84,11 @@ module Couchbase
|
|
84
84
|
# @return [Hash]
|
85
85
|
attr_accessor :meta
|
86
86
|
|
87
|
-
# The list of views defined or empty array
|
88
|
-
#
|
89
|
-
# @since 1.2.0
|
90
|
-
#
|
91
|
-
# @return [Array<View>]
|
92
|
-
attr_accessor :views
|
93
|
-
|
94
|
-
# The list of spatial views defined or empty array
|
95
|
-
#
|
96
|
-
# @since 1.2.0
|
97
|
-
#
|
98
|
-
# @return [Array<View>]
|
99
|
-
attr_accessor :spatial
|
100
|
-
|
101
87
|
# Initialize the document instance
|
102
88
|
#
|
103
89
|
# @since 1.2.0
|
104
90
|
#
|
105
|
-
# It takes reference to the bucket, data hash.
|
106
|
-
# methods if the data object looks like design document.
|
91
|
+
# It takes reference to the bucket, data hash.
|
107
92
|
#
|
108
93
|
# @param [Couchbase::Bucket] bucket the reference to connection
|
109
94
|
# @param [Hash] data the data hash, which was built from JSON document
|
@@ -111,37 +96,14 @@ module Couchbase
|
|
111
96
|
def initialize(bucket, data)
|
112
97
|
@bucket = bucket
|
113
98
|
@data = data
|
114
|
-
@key = data[
|
115
|
-
@value = data[
|
116
|
-
if data[
|
117
|
-
@meta = data[
|
118
|
-
@doc = data[
|
119
|
-
end
|
120
|
-
@id = data['id'] || @meta && @meta['id']
|
121
|
-
@views = []
|
122
|
-
@spatial = []
|
123
|
-
if design_doc?
|
124
|
-
if @doc.has_key?('views')
|
125
|
-
@doc['views'].each do |name, _|
|
126
|
-
@views << name
|
127
|
-
self.instance_eval <<-EOV, __FILE__, __LINE__ + 1
|
128
|
-
def #{name}(params = {})
|
129
|
-
View.new(@bucket, "\#{@id}/_view/#{name}", params)
|
130
|
-
end
|
131
|
-
EOV
|
132
|
-
end
|
133
|
-
end
|
134
|
-
if @doc.has_key?('spatial')
|
135
|
-
@doc['spatial'].each do |name, _|
|
136
|
-
@spatial << name
|
137
|
-
self.instance_eval <<-EOV, __FILE__, __LINE__ + 1
|
138
|
-
def #{name}(params = {})
|
139
|
-
View.new(@bucket, "\#{@id}/_spatial/#{name}", params)
|
140
|
-
end
|
141
|
-
EOV
|
142
|
-
end
|
143
|
-
end
|
99
|
+
@key = data[S_KEY]
|
100
|
+
@value = data[S_VALUE]
|
101
|
+
if data[S_DOC]
|
102
|
+
@meta = data[S_DOC][S_META]
|
103
|
+
@doc = data[S_DOC][S_VALUE]
|
144
104
|
end
|
105
|
+
@id = data[S_ID] || @meta && @meta[S_ID]
|
106
|
+
@last = data.delete(S_IS_LAST) || false
|
145
107
|
end
|
146
108
|
|
147
109
|
# Wraps data hash into ViewRow instance
|
@@ -156,7 +118,7 @@ module Couchbase
|
|
156
118
|
#
|
157
119
|
# @return [ViewRow]
|
158
120
|
def self.wrap(bucket, data)
|
159
|
-
|
121
|
+
self.new(bucket, data)
|
160
122
|
end
|
161
123
|
|
162
124
|
# Get attribute of the document
|
@@ -198,33 +160,113 @@ module Couchbase
|
|
198
160
|
@doc[key] = value
|
199
161
|
end
|
200
162
|
|
201
|
-
#
|
163
|
+
# Signals if this row is last in a stream
|
202
164
|
#
|
203
|
-
# @since 1.2.
|
165
|
+
# @since 1.2.1
|
204
166
|
#
|
205
|
-
# @return [true, false]
|
206
|
-
def
|
207
|
-
|
167
|
+
# @return [true, false] +true+ if this row is last in a stream
|
168
|
+
def last?
|
169
|
+
@last
|
170
|
+
end
|
171
|
+
|
172
|
+
def inspect
|
173
|
+
desc = "#<#{self.class.name}:#{self.object_id}"
|
174
|
+
[:@id, :@key, :@value, :@doc, :@meta].each do |iv|
|
175
|
+
desc << " #{iv}=#{instance_variable_get(iv).inspect}"
|
176
|
+
end
|
177
|
+
desc << ">"
|
178
|
+
desc
|
208
179
|
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# This class encapsulates information about design docs
|
183
|
+
#
|
184
|
+
# @since 1.2.1
|
185
|
+
#
|
186
|
+
# It is subclass of ViewRow, but also gives access to view creation through method_missing
|
187
|
+
#
|
188
|
+
# @see http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-datastore.html
|
189
|
+
class DesignDoc < ViewRow
|
190
|
+
# It isn't allowed to change design document ID after
|
191
|
+
# initialization
|
192
|
+
undef id=
|
193
|
+
|
194
|
+
# Initialize the design doc instance
|
195
|
+
#
|
196
|
+
# @since 1.2.1
|
197
|
+
#
|
198
|
+
# It takes reference to the bucket, data hash. It will define view
|
199
|
+
# methods if the data object looks like design document.
|
200
|
+
#
|
201
|
+
# @param [Couchbase::Bucket] bucket the reference to connection
|
202
|
+
# @param [Hash] data the data hash, which was built from JSON document
|
203
|
+
# representation
|
204
|
+
def initialize(bucket, data)
|
205
|
+
super
|
206
|
+
@all_views = {}
|
207
|
+
@views = @doc.has_key?('views') ? @doc['views'].keys : []
|
208
|
+
@spatial = @doc.has_key?('spatial') ? @doc['spatial'].keys : []
|
209
|
+
@views.each{|name| @all_views[name] = "#{@id}/_view/#{name}"}
|
210
|
+
@spatial.each{|name| @all_views[name] = "#{@id}/_spatial/#{name}"}
|
211
|
+
end
|
212
|
+
|
213
|
+
def method_missing(meth, *args)
|
214
|
+
if path = @all_views[meth.to_s]
|
215
|
+
View.new(@bucket, path, *args)
|
216
|
+
else
|
217
|
+
super
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def respond_to?(meth, *args)
|
222
|
+
if @all_views[meth.to_s]
|
223
|
+
true
|
224
|
+
else
|
225
|
+
super
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def method(meth, *args)
|
230
|
+
if path = @all_views[meth.to_s]
|
231
|
+
lambda{|*p| View.new(@bucket, path, *p)}
|
232
|
+
else
|
233
|
+
super
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# The list of views defined or empty array
|
238
|
+
#
|
239
|
+
# @since 1.2.1
|
240
|
+
#
|
241
|
+
# @return [Array<View>]
|
242
|
+
attr_accessor :views
|
243
|
+
|
244
|
+
# The list of spatial views defined or empty array
|
245
|
+
#
|
246
|
+
# @since 1.2.1
|
247
|
+
#
|
248
|
+
# @return [Array<View>]
|
249
|
+
attr_accessor :spatial
|
209
250
|
|
210
251
|
# Check if the document has views defines
|
211
252
|
#
|
212
|
-
# @since 1.2.
|
253
|
+
# @since 1.2.1
|
213
254
|
#
|
214
|
-
# @see
|
255
|
+
# @see DesignDoc#views
|
215
256
|
#
|
216
257
|
# @return [true, false] +true+ if the document have views
|
217
258
|
def has_views?
|
218
|
-
|
259
|
+
!@views.empty?
|
219
260
|
end
|
220
261
|
|
221
262
|
def inspect
|
222
|
-
desc = "#<#{self.class.name}:#{self.object_id}
|
223
|
-
|
224
|
-
"#{iv}=#{instance_variable_get(iv).inspect}"
|
225
|
-
end
|
263
|
+
desc = "#<#{self.class.name}:#{self.object_id}"
|
264
|
+
[:@id, :@views, :@spatial].each do |iv|
|
265
|
+
desc << " #{iv}=#{instance_variable_get(iv).inspect}"
|
266
|
+
end
|
226
267
|
desc << ">"
|
227
268
|
desc
|
228
269
|
end
|
270
|
+
|
229
271
|
end
|
230
272
|
end
|