couchbase 1.2.1-x86-mingw32 → 1.2.2-x86-mingw32
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/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 +24 -49
- 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
|