riakrest 0.0.1
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/History.txt +4 -0
- data/Manifest.txt +41 -0
- data/PostInstall.txt +2 -0
- data/README.rdoc +51 -0
- data/Rakefile +24 -0
- data/examples/auto_update_data.rb +50 -0
- data/examples/auto_update_links.rb +48 -0
- data/examples/basic_client.rb +33 -0
- data/examples/basic_resource.rb +34 -0
- data/examples/json_data_resource.rb +32 -0
- data/examples/linked_resource.rb +113 -0
- data/examples/multiple_resources.rb +43 -0
- data/lib/riakrest/core/exceptions.rb +73 -0
- data/lib/riakrest/core/jiak_bucket.rb +146 -0
- data/lib/riakrest/core/jiak_client.rb +316 -0
- data/lib/riakrest/core/jiak_data.rb +265 -0
- data/lib/riakrest/core/jiak_link.rb +131 -0
- data/lib/riakrest/core/jiak_object.rb +233 -0
- data/lib/riakrest/core/jiak_schema.rb +242 -0
- data/lib/riakrest/core/query_link.rb +156 -0
- data/lib/riakrest/data/jiak_data_hash.rb +182 -0
- data/lib/riakrest/resource/jiak_resource.rb +628 -0
- data/lib/riakrest/version.rb +7 -0
- data/lib/riakrest.rb +164 -0
- data/riakrest.gemspec +38 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/core/exceptions_spec.rb +18 -0
- data/spec/core/jiak_bucket_spec.rb +103 -0
- data/spec/core/jiak_client_spec.rb +358 -0
- data/spec/core/jiak_link_spec.rb +77 -0
- data/spec/core/jiak_object_spec.rb +210 -0
- data/spec/core/jiak_schema_spec.rb +184 -0
- data/spec/core/query_link_spec.rb +128 -0
- data/spec/data/jiak_data_hash_spec.rb +14 -0
- data/spec/resource/jiak_resource_spec.rb +128 -0
- data/spec/riakrest_spec.rb +17 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +12 -0
- data/tasks/rspec.rake +21 -0
- metadata +113 -0
@@ -0,0 +1,265 @@
|
|
1
|
+
module RiakRest
|
2
|
+
|
3
|
+
# All end-user data stored via RiakRest is contained in user-defined data
|
4
|
+
# objects. To make a user-defined data object, include module JiakData into
|
5
|
+
# your class definition. This allows creating a class that can be used to
|
6
|
+
# create instances of your user-defined data. Note JiakData does create
|
7
|
+
# user-data instances, rather it facilitates creating the class you use to
|
8
|
+
# create user-data instances.
|
9
|
+
#
|
10
|
+
# The four class methods <code>allowed, required, readable, writable</code>
|
11
|
+
# defined in JiakData#ClassMethods are used to declare the schema for
|
12
|
+
# structured Jiak interaction with user-defined data. The <code>allowed</code>
|
13
|
+
# method is mandatory; the other methods take the defaults as described in
|
14
|
+
# JiakSchema. See JiakSchema for discussion on structured data interaction.
|
15
|
+
#
|
16
|
+
# User-defined data classes must override JiakData#ClassMethods#jiak_create
|
17
|
+
# (creating your user-defined data from the information returned by Jiak) and
|
18
|
+
# JiakData#for_jiak (providing the information to be sent to Jiak). The
|
19
|
+
# default implementations of these methods throw JiakDataException to
|
20
|
+
# enforce this override.
|
21
|
+
#
|
22
|
+
# JiakData provides a default data key generator that returns nil, which
|
23
|
+
# instructs the Jiak server to generate a random key on first data
|
24
|
+
# storage. To explicitly set the key override JiakData#keygen to return
|
25
|
+
# whatever string you want to use for the key. Keys need to be unique within
|
26
|
+
# each bucket on the Jiak server but can be the same across distinct buckets.
|
27
|
+
#
|
28
|
+
# ===Example
|
29
|
+
# <code>
|
30
|
+
# class FooBarBaz
|
31
|
+
# include JiakData
|
32
|
+
#
|
33
|
+
# allowed :foo, :bar, :baz
|
34
|
+
# required :foo
|
35
|
+
# readable :foo, :bar
|
36
|
+
# writable :foo, :baz
|
37
|
+
#
|
38
|
+
# def initialize(foo,bar,baz)
|
39
|
+
# @foo = foo
|
40
|
+
# @bar = bar
|
41
|
+
# @baz = baz
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# def self.jiak_create(jiak)
|
45
|
+
# new(jiak['foo'],jiak['bar'])
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# def for_jiak
|
49
|
+
# { :foo => @foo,
|
50
|
+
# :baz => @baz
|
51
|
+
# }
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# def keygen
|
55
|
+
# "#{foo}"
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
# </code>
|
59
|
+
#
|
60
|
+
# Note that FooBarBaz <code>bar</code> is readable but not writable and
|
61
|
+
# <code>baz</code> is writable but not readable. Also note
|
62
|
+
# <code>for_jiak</code> only provides the <code>writable</code> fields for
|
63
|
+
# writing to the Jiak server and <code>jiak_create</code> only initializes
|
64
|
+
# from the <code>readable</code> fields returned by the Jiak server. The
|
65
|
+
# above definition means a user of FooBarBaz could change <code>baz</code>
|
66
|
+
# but not see that change and could access <code>bar</code> but not change
|
67
|
+
# it. This could be useful if either another JiakData class (with a different
|
68
|
+
# schema) created access into the same data, allowing <code>bar</code> writes
|
69
|
+
# and <code>baz</code> reads, or if Riak server-side manipulation affected
|
70
|
+
# those fields. The constraints declared in FooBarBaz simply provide
|
71
|
+
# a particular structured interaction of data on a Jiak server.
|
72
|
+
#
|
73
|
+
# If only one JiakData will be used for a particular type of data on the Jiak
|
74
|
+
# server it is desirable to have the <code>readable</code> and
|
75
|
+
# <code>writable</code> fields be the same as <code>allowed</code>. Setting
|
76
|
+
# only <code>allowed</code> fields provide this reasonable default, hence only
|
77
|
+
# that call is mandatory.
|
78
|
+
module JiakData
|
79
|
+
|
80
|
+
# ----------------------------------------------------------------------
|
81
|
+
# Class methods
|
82
|
+
# ----------------------------------------------------------------------
|
83
|
+
|
84
|
+
# Class methods for use in creating a user-defined JiakData. The methods
|
85
|
+
# <code>allowed, required, readable, writable</code> define the JiakSchema
|
86
|
+
# for this JiakData. See JiakSchema for discussion on the use of schemas in
|
87
|
+
# Riak.
|
88
|
+
module ClassMethods
|
89
|
+
|
90
|
+
# :call-seq:
|
91
|
+
# allowed :f1, ..., :fn -> array
|
92
|
+
#
|
93
|
+
# Fields allowed in Jiak interactions. Returns an array of the allowed
|
94
|
+
# fields.
|
95
|
+
#
|
96
|
+
def allowed(*fields)
|
97
|
+
arr_fields = create_array(fields)
|
98
|
+
fields.each {|field| attr_accessor field}
|
99
|
+
@schema = JiakSchema.new(arr_fields)
|
100
|
+
arr_fields
|
101
|
+
end
|
102
|
+
|
103
|
+
# :call-seq:
|
104
|
+
# required :f1, ..., :fn -> array
|
105
|
+
#
|
106
|
+
# Fields required during in Jiak interactions. Returns an array of the
|
107
|
+
# required fields.
|
108
|
+
#
|
109
|
+
def required(*fields)
|
110
|
+
set_fields('required_fields',*fields)
|
111
|
+
end
|
112
|
+
|
113
|
+
# :call-seq:
|
114
|
+
# readable :f1, ..., :fn -> array
|
115
|
+
#
|
116
|
+
# Fields returned by Jiak on retrieval. Returns an array of the fields in
|
117
|
+
# the read mask.
|
118
|
+
#
|
119
|
+
def readable(*fields)
|
120
|
+
set_fields('read_mask',*fields)
|
121
|
+
end
|
122
|
+
|
123
|
+
# :call-seq:
|
124
|
+
# writable :f1, ..., :fn -> arry
|
125
|
+
#
|
126
|
+
# Fields that can be written during Jiak interaction. Returns an array of
|
127
|
+
# the fields in the write mask.
|
128
|
+
#
|
129
|
+
def writable(*fields)
|
130
|
+
set_fields('write_mask',*fields)
|
131
|
+
end
|
132
|
+
|
133
|
+
# :call-seq:
|
134
|
+
# readwrite :f1, ..., :fn -> array
|
135
|
+
#
|
136
|
+
# Set the read and write masks to the same fields. Returns an array of
|
137
|
+
# the fields in the masks.
|
138
|
+
def readwrite(*fields)
|
139
|
+
arr_fields = set_fields('readwrite',*fields)
|
140
|
+
arr_fields
|
141
|
+
end
|
142
|
+
|
143
|
+
def set_fields(which,*fields)
|
144
|
+
arr_fields = create_array(fields)
|
145
|
+
check_allowed(arr_fields)
|
146
|
+
@schema.send("#{which}=",arr_fields)
|
147
|
+
arr_fields
|
148
|
+
end
|
149
|
+
private :set_fields
|
150
|
+
|
151
|
+
# :call-seq:
|
152
|
+
# JiakData.schema -> JiakSchema
|
153
|
+
#
|
154
|
+
# Get a JiakSchema representation determined by
|
155
|
+
# <code>allowed, required, readable, writable</code>.
|
156
|
+
#
|
157
|
+
def schema
|
158
|
+
@schema
|
159
|
+
end
|
160
|
+
|
161
|
+
# :call-seq:
|
162
|
+
# JiakData.jiak_create(jiak) -> JiakData
|
163
|
+
#
|
164
|
+
# Create an instance of user-defined data object from the fields read
|
165
|
+
# by Jiak. These fields are determined by the read mask of the
|
166
|
+
# structured Jiak interaction. See JiakSchema for read mask discussion.
|
167
|
+
#
|
168
|
+
# User-defined data classes must override this method. The method is
|
169
|
+
# called during the creation of a JiakObject from information returned by
|
170
|
+
# Jiak. The JiakObject contains the user-defined data itself. You do not
|
171
|
+
# call this method explicitly.
|
172
|
+
#
|
173
|
+
# ====Example
|
174
|
+
# <code>
|
175
|
+
# def initialize(f1,f2)
|
176
|
+
# @f1 = f1
|
177
|
+
# @f2 = f2
|
178
|
+
# end
|
179
|
+
# def jiak_create(jiak)
|
180
|
+
# new(jiak['f1'], jiak['f2'])
|
181
|
+
# end
|
182
|
+
# </code>
|
183
|
+
#
|
184
|
+
# Raise JiakDataException if not explicitly defined by user-defined data class.
|
185
|
+
def jiak_create(json)
|
186
|
+
raise JiakDataException, "#{self} must define jiak_create"
|
187
|
+
end
|
188
|
+
|
189
|
+
def create_array(*fields)
|
190
|
+
if(fields.size == 1 && fields[0].is_a?(Array))
|
191
|
+
array = fields[0]
|
192
|
+
else
|
193
|
+
array = fields
|
194
|
+
end
|
195
|
+
array.map {|field| field}
|
196
|
+
array
|
197
|
+
end
|
198
|
+
private :create_array
|
199
|
+
|
200
|
+
def check_allowed(fields)
|
201
|
+
allowed_fields = @schema.allowed_fields
|
202
|
+
fields.each do |field|
|
203
|
+
unless allowed_fields.include?(field)
|
204
|
+
raise JiakDataException, "field '#{field}' not allowed"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
private :check_allowed
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.included(including_class) # :nodoc:
|
212
|
+
including_class.extend(ClassMethods)
|
213
|
+
end
|
214
|
+
|
215
|
+
# ----------------------------------------------------------------------
|
216
|
+
# Instance methods
|
217
|
+
# ----------------------------------------------------------------------
|
218
|
+
|
219
|
+
# :call-seq:
|
220
|
+
# for_jiak -> hash
|
221
|
+
#
|
222
|
+
# Provide a hash structure of the data to write to Jiak. The fields for
|
223
|
+
# this structure should come from the write mask of the structured Jiak
|
224
|
+
# interaction. See JiakSchema for write mask discussion.
|
225
|
+
#
|
226
|
+
# User-defined data classes must override this method. The method is called
|
227
|
+
# during the creation of a JiakObject to send information to Jiak. The
|
228
|
+
# JiakObject contains the user-defined data itself. You do not call this
|
229
|
+
# method explicitly.
|
230
|
+
#
|
231
|
+
# ====Example
|
232
|
+
# <code>
|
233
|
+
# def for_jiak
|
234
|
+
# { :writable_f1 => @writable_f1,
|
235
|
+
# :writable_f2 => @writable_f2
|
236
|
+
# }
|
237
|
+
# end
|
238
|
+
# </code>
|
239
|
+
#
|
240
|
+
# Raise JiakDataException if not explicitly defined by user-defined data class.
|
241
|
+
def for_jiak
|
242
|
+
raise JiakDataException, "#{self} must define for_jiak"
|
243
|
+
end
|
244
|
+
|
245
|
+
# :call-seq:
|
246
|
+
# keygen -> string
|
247
|
+
#
|
248
|
+
# Generate Jiak key for data. Default implementation returns
|
249
|
+
# <code>nil</code> which instructs the Jiak server to generate a random
|
250
|
+
# key. Override for user-defined data behaviour.
|
251
|
+
#
|
252
|
+
# ====Example
|
253
|
+
# A simple implementation would look like:
|
254
|
+
# <code>
|
255
|
+
# def keygen
|
256
|
+
# f1.to_s
|
257
|
+
# end
|
258
|
+
# </code>
|
259
|
+
def keygen
|
260
|
+
nil
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module RiakRest
|
2
|
+
|
3
|
+
# Represents a link between object in Jiak. JiakLinks are used to link a
|
4
|
+
# JiakObject to another JiakObject at a bucket/key. The tag allows the link
|
5
|
+
# to be traversed later using a QueryLink.
|
6
|
+
#
|
7
|
+
# ===Usage
|
8
|
+
# <code>
|
9
|
+
# link = JiakLink.new('people','callie','sister')
|
10
|
+
# </code>
|
11
|
+
# If the above link were added to a JiakObject in the same bucket and keyed
|
12
|
+
# by the string 'remy', the link from remy to the sister callie would be
|
13
|
+
# retrieve using JiakClient#walk and the query link
|
14
|
+
# <code>QueryLink.new('people','sister')</code>
|
15
|
+
#
|
16
|
+
class JiakLink
|
17
|
+
|
18
|
+
attr_accessor :bucket, :key, :tag
|
19
|
+
|
20
|
+
# :call-seq:
|
21
|
+
# JiakLink.new(bucket,key,tag) -> JiakLink
|
22
|
+
# JiakLink.new([bucket,key,tag]) -> JiakLink
|
23
|
+
#
|
24
|
+
# Create a link (designated by tag) to an object at bucket/key. Bucket can
|
25
|
+
# be either a JiakBucket or a string bucket name; key and tag must both be
|
26
|
+
# strings.
|
27
|
+
#
|
28
|
+
def initialize(*args)
|
29
|
+
case args.size
|
30
|
+
when 1
|
31
|
+
if args[0].is_a? Array
|
32
|
+
bucket, key, tag = args[0][0], args[0][1], args[0][2]
|
33
|
+
elsif args[0].is_a? JiakLink
|
34
|
+
bucket, key, tag = args[0].bucket, args[0].key, args[0].tag
|
35
|
+
else
|
36
|
+
raise JiakLinkException, "argument error"
|
37
|
+
end
|
38
|
+
when 3
|
39
|
+
bucket, key, tag = args[0], args[1], args[2]
|
40
|
+
else
|
41
|
+
raise JiakLinkException, "argument error"
|
42
|
+
end
|
43
|
+
|
44
|
+
@bucket, @key, @tag = transform_args(bucket,key,tag)
|
45
|
+
end
|
46
|
+
|
47
|
+
# :call-seq:
|
48
|
+
# link.bucket = bucket
|
49
|
+
#
|
50
|
+
# Set the bucket field.
|
51
|
+
def bucket=(bucket)
|
52
|
+
bucket = bucket.name if bucket.is_a? JiakBucket
|
53
|
+
@bucket = transform_arg(bucket)
|
54
|
+
end
|
55
|
+
|
56
|
+
# :call-seq:
|
57
|
+
# link.key = key
|
58
|
+
#
|
59
|
+
# Set the key field.
|
60
|
+
def key=(key)
|
61
|
+
@key = transform_arg(key)
|
62
|
+
end
|
63
|
+
|
64
|
+
# :call-seq:
|
65
|
+
# link.tag = tag
|
66
|
+
#
|
67
|
+
# Set the tag field.
|
68
|
+
def tag=(tag)
|
69
|
+
@tag = transform_arg(tag)
|
70
|
+
end
|
71
|
+
|
72
|
+
# :call-seq:
|
73
|
+
# link.for_jiak -> JSON
|
74
|
+
#
|
75
|
+
# Representation of this JiakLink for transport to Jiak.
|
76
|
+
def for_jiak
|
77
|
+
[@bucket, @key, @tag]
|
78
|
+
end
|
79
|
+
|
80
|
+
# :call-seq:
|
81
|
+
# link == other -> true or false
|
82
|
+
#
|
83
|
+
# Equality -- JiakLinks are equal if they contain the same attribute values.
|
84
|
+
def ==(other)
|
85
|
+
(@bucket == other.bucket &&
|
86
|
+
@key == other.key &&
|
87
|
+
@tag == other.tag) rescue false
|
88
|
+
end
|
89
|
+
|
90
|
+
# :call-seq:
|
91
|
+
# eql?(other) -> true or false
|
92
|
+
#
|
93
|
+
# Returns <code>true</code> if <code>other</code> is a JiakLink with the
|
94
|
+
# same attribute values.
|
95
|
+
def eql?(other)
|
96
|
+
other.is_a?(JiakLink) &&
|
97
|
+
@bucket.eql?(other.bucket) &&
|
98
|
+
@key.eql?(other.key) &&
|
99
|
+
@tag.eql?(other.tag)
|
100
|
+
end
|
101
|
+
|
102
|
+
def hash # :nodoc:
|
103
|
+
@bucket.hash + @key.hash + @tag.hash
|
104
|
+
end
|
105
|
+
|
106
|
+
# String representation of this JiakLink.
|
107
|
+
def to_s
|
108
|
+
"[#{bucket},#{key},#{tag}]"
|
109
|
+
end
|
110
|
+
|
111
|
+
def transform_args(b,k,t)
|
112
|
+
b = b.name if b.is_a? JiakBucket
|
113
|
+
[transform_arg(b),transform_arg(k),transform_arg(t)]
|
114
|
+
end
|
115
|
+
private :transform_args
|
116
|
+
|
117
|
+
def transform_arg(arg)
|
118
|
+
unless arg.is_a? String
|
119
|
+
raise JiakLinkException, "Link elements must be Strings."
|
120
|
+
end
|
121
|
+
value = arg.dup
|
122
|
+
value.strip!
|
123
|
+
if value.empty?
|
124
|
+
raise JiakLinkException, "Link elements can't be empty."
|
125
|
+
end
|
126
|
+
value
|
127
|
+
end
|
128
|
+
private :transform_arg
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
module RiakRest
|
2
|
+
|
3
|
+
# Wrapper for JiakData.
|
4
|
+
class JiakObject
|
5
|
+
|
6
|
+
attr_accessor :bucket, :key, :data, :links, :riak
|
7
|
+
|
8
|
+
# :call-seq:
|
9
|
+
# JiakObject.new(opts) -> JiakObject
|
10
|
+
#
|
11
|
+
# Create a object for Jiak storage. Valid options:
|
12
|
+
# <code>:bucket</code> :: JiakBucket for storage.
|
13
|
+
# <code>:data</code> :: Object JiakData to be stored.
|
14
|
+
# <code>:key</code> :: Object key.
|
15
|
+
# <code>:links</code> :: Object JiakLink array.
|
16
|
+
#
|
17
|
+
# The bucket and data options are required.
|
18
|
+
#
|
19
|
+
# The key and links options are optional. If no key is provided, the
|
20
|
+
# <code>keygen</code> method of <code>data</code> is used to provide the
|
21
|
+
# key. The default implementation of JiakData#keygen is an empty string,
|
22
|
+
# which instructs the Jiak server to generate a random key. If no links are
|
23
|
+
# provided, the default uses an empty array.
|
24
|
+
#
|
25
|
+
# There are other options used by the system to maintain the context of the
|
26
|
+
# JiakObject on the Riak cluster. These options should not be manually
|
27
|
+
# altered and are purposely not described here.
|
28
|
+
def initialize(opts)
|
29
|
+
opts[:links] ||= []
|
30
|
+
check_opts(opts)
|
31
|
+
|
32
|
+
@bucket = check_bucket(opts[:bucket])
|
33
|
+
@data = check_data(opts[:data])
|
34
|
+
@key = transform_key(opts[:key] || @data.keygen)
|
35
|
+
@links = check_links(opts[:links])
|
36
|
+
|
37
|
+
# The Riak context for the object if provided.
|
38
|
+
if opts[:vclock]
|
39
|
+
@riak = opts.select {|k,v| [:vclock,:vtag,:lastmod].include?(k)}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# :call-seq:
|
44
|
+
# JiakObject.from_jiak(jiak) -> JiakObject
|
45
|
+
#
|
46
|
+
# Create a JiakObject from parsed JSON returned by the Jiak server. Calls
|
47
|
+
# the <code>jiak_create</code> of the JiakData class passed as the second
|
48
|
+
# argument to inflate the data into the user-defined data class.
|
49
|
+
def self.from_jiak(jiak,klass)
|
50
|
+
jiak[:bucket] = JiakBucket.new(jiak.delete('bucket'),klass)
|
51
|
+
jiak[:data] = klass.jiak_create(jiak.delete('object'))
|
52
|
+
jiak[:links] = jiak.delete('links').map {|link| JiakLink.new(link)}
|
53
|
+
|
54
|
+
new(jiak.inject({}) do |build, (key, value)|
|
55
|
+
build[key.to_sym] = value
|
56
|
+
build
|
57
|
+
end)
|
58
|
+
end
|
59
|
+
|
60
|
+
# :call-seq:
|
61
|
+
# jiak_object.to_jiak -> JSON
|
62
|
+
#
|
63
|
+
# Create a representation suitable for sending to a Jiak server. Calls the
|
64
|
+
# <code>for_jiak</code> method of the wrapped JiakData. Called by
|
65
|
+
# JiakClient when transporting an object to Jiak.
|
66
|
+
def to_jiak
|
67
|
+
jiak = {
|
68
|
+
:bucket => @bucket.name,
|
69
|
+
:key => @key,
|
70
|
+
:object => @data.for_jiak,
|
71
|
+
:links => @links.map {|link| link.for_jiak}
|
72
|
+
}
|
73
|
+
if(@riak)
|
74
|
+
jiak[:vclock] = @riak[:vclock]
|
75
|
+
jiak[:vtag] = @riak[:vtag]
|
76
|
+
jiak[:lastmod] = @riak[:lastmod]
|
77
|
+
end
|
78
|
+
jiak.to_json
|
79
|
+
end
|
80
|
+
|
81
|
+
# :call-seq:
|
82
|
+
# jiak_object.bucket = bucket
|
83
|
+
#
|
84
|
+
# Set the bucket for a JiakObject. Bucket must be a JiakBucket.
|
85
|
+
def bucket=(bucket)
|
86
|
+
@bucket = check_bucket(bucket)
|
87
|
+
end
|
88
|
+
|
89
|
+
# :call-seq:
|
90
|
+
# jiak_object.key = string or nil
|
91
|
+
#
|
92
|
+
# Set the key for a JiakObject. Key string is stripped of leading and
|
93
|
+
# trailing blanks. A nil key is interpreted as an empty string.
|
94
|
+
def key=(key)
|
95
|
+
@key = transform_key(key)
|
96
|
+
end
|
97
|
+
|
98
|
+
# :call-seq:
|
99
|
+
# jiak_object.data = {}
|
100
|
+
#
|
101
|
+
# Set the data wrapped by a JiakObject. The data must be a JiakData object.
|
102
|
+
def data=(data)
|
103
|
+
@data = check_data(data)
|
104
|
+
end
|
105
|
+
|
106
|
+
# :call-seq:
|
107
|
+
# jiak_object.links = []
|
108
|
+
#
|
109
|
+
# Set the links array for JiakObject. Each array element must be a
|
110
|
+
# JiakLink.
|
111
|
+
def links=(links)
|
112
|
+
@links = check_links(links)
|
113
|
+
end
|
114
|
+
|
115
|
+
# :call-seq:
|
116
|
+
# jiak_object << JiakLink -> JiakObject
|
117
|
+
#
|
118
|
+
# Convenience method for adding a JiakLink to the links for a
|
119
|
+
# JiakObject. Duplicate links are ignored. Returns the JiakObject for
|
120
|
+
# chaining.
|
121
|
+
def <<(link)
|
122
|
+
link = check_link(link)
|
123
|
+
@links << link unless @links.include?(link)
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
127
|
+
# :call-seq:
|
128
|
+
# jiak_object.riak = riak
|
129
|
+
#
|
130
|
+
# Set the Riak context for a JiakObject.
|
131
|
+
def riak=(riak)
|
132
|
+
@riak = check_riak(riak)
|
133
|
+
end
|
134
|
+
|
135
|
+
# :call-seq:
|
136
|
+
# jiak_object == other -> true or false
|
137
|
+
#
|
138
|
+
# Equality -- Two JiakObjects are equal if they contain the same values
|
139
|
+
# for all attributes.
|
140
|
+
def ==(other)
|
141
|
+
(@bucket == other.bucket &&
|
142
|
+
@key == other.key &&
|
143
|
+
@data == other.data &&
|
144
|
+
@links == other.links
|
145
|
+
) rescue false
|
146
|
+
end
|
147
|
+
|
148
|
+
# :call-seq:
|
149
|
+
# jiak_object.eql?(other) -> true or false
|
150
|
+
#
|
151
|
+
# Returns <code>true</code> if <code>other</code> is a JiakObject with the
|
152
|
+
# same the same attribute values.
|
153
|
+
def eql?(other)
|
154
|
+
other.is_a?(JiakObject) &&
|
155
|
+
@bucket.eql?(other.bucket) &&
|
156
|
+
@key.eql?(other.key) &&
|
157
|
+
@data.eql?(other.data) &&
|
158
|
+
@links.eql?(other.links)
|
159
|
+
end
|
160
|
+
|
161
|
+
def hash # :nodoc:
|
162
|
+
@bucket.name.hash + @key.hash + @data.hash + @links.hash + @riak.hash
|
163
|
+
end
|
164
|
+
|
165
|
+
def check_opts(opts)
|
166
|
+
err = opts.select {|k,v| !VALID_OPTS.include?(k)}
|
167
|
+
unless err.empty?
|
168
|
+
raise JiakObjectException, "unrecognized options: #{err.keys}"
|
169
|
+
end
|
170
|
+
opts
|
171
|
+
end
|
172
|
+
private :check_opts
|
173
|
+
|
174
|
+
def check_bucket(bucket)
|
175
|
+
unless bucket.is_a?(JiakBucket)
|
176
|
+
raise JiakObjectException, "Bucket must be a JiakBucket."
|
177
|
+
end
|
178
|
+
bucket
|
179
|
+
end
|
180
|
+
private :check_bucket
|
181
|
+
|
182
|
+
def transform_key(key)
|
183
|
+
# Change nil key to empty
|
184
|
+
o_key = key.nil? ? '' : key.dup
|
185
|
+
unless o_key.is_a?(String)
|
186
|
+
raise JiakObjectException, "Key must be a String"
|
187
|
+
end
|
188
|
+
o_key.strip!
|
189
|
+
o_key
|
190
|
+
end
|
191
|
+
private :transform_key
|
192
|
+
|
193
|
+
def check_data(data)
|
194
|
+
unless data.is_a?(JiakData)
|
195
|
+
raise JiakObjectException, "Data must be a JiakData."
|
196
|
+
end
|
197
|
+
data
|
198
|
+
end
|
199
|
+
private :check_data
|
200
|
+
|
201
|
+
def check_links(links)
|
202
|
+
unless links.is_a? Array
|
203
|
+
raise JiakObjectException, "Links must be an array"
|
204
|
+
end
|
205
|
+
links.each do |link|
|
206
|
+
check_link(link)
|
207
|
+
end
|
208
|
+
links
|
209
|
+
end
|
210
|
+
private :check_links
|
211
|
+
|
212
|
+
def check_link(link)
|
213
|
+
unless link.is_a? JiakLink
|
214
|
+
raise JiakObjectException, "Each link must be a JiakLink"
|
215
|
+
end
|
216
|
+
link
|
217
|
+
end
|
218
|
+
private :check_link
|
219
|
+
|
220
|
+
def check_riak(riak)
|
221
|
+
err = riak.select {|k,v| !VALID_RIAK.include?(k)}
|
222
|
+
unless err.empty?
|
223
|
+
raise JiakObjectException, "unrecognized options: #{err.keys}"
|
224
|
+
end
|
225
|
+
riak
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
VALID_RIAK = [:vclock,:vtag,:lastmod]
|
230
|
+
VALID_OPTS = [:bucket,:key,:data,:links] + VALID_RIAK
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|