riakrest 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,242 @@
|
|
1
|
+
module RiakRest
|
2
|
+
|
3
|
+
# Schema for data objects placed in a Riak bucket. Riak performs basic checks
|
4
|
+
# for storing and retrieving data objects in a bucket by ensuring:
|
5
|
+
#
|
6
|
+
# * Only allowed fields are used.
|
7
|
+
# * Required fields are included.
|
8
|
+
# * Only writable fields are stored.
|
9
|
+
# * Only readable fields are retrieved.
|
10
|
+
#
|
11
|
+
# The schema for a bucket can be changed dynamically so this doesn't lock
|
12
|
+
# storage of data objects to a static structure. To store, say, an expanded
|
13
|
+
# data object in an existing bucket, add the new field to the schema and
|
14
|
+
# reset the bucket schema before storing objects of the new structure. Note
|
15
|
+
# that dynamic changes to a bucket schema do not affect the data objects
|
16
|
+
# already stored by Jiak. Schema designations only affect structured Jiak
|
17
|
+
# interaction, not the data itself.
|
18
|
+
#
|
19
|
+
# The fields are kept as symbols or strings in four attribute arrays:
|
20
|
+
# <code>allowed_fields</code>:: Allowed in Jiak interaction.
|
21
|
+
# <code>required_fields</code>:: Required during Jiak interaction.
|
22
|
+
# <code>write_mask</code>:: Allowed to be written during a Jiak store.
|
23
|
+
# <code>read_mask</code>:: Returned by Jiak on a retrieval.
|
24
|
+
#
|
25
|
+
# Since Jiak interaction is JSON, duplicate fields names within an array are
|
26
|
+
# not meaningful, including a symbol that "equals" a string. Duplicates
|
27
|
+
# raise an exception.
|
28
|
+
#
|
29
|
+
# ===Usage
|
30
|
+
# <pre>
|
31
|
+
# schema = JiakSchema.new({:allowed_fields => [:foo,:bar,:baz],
|
32
|
+
# :required_fields => [:foo,:bar],
|
33
|
+
# :read_mask => [:foo,:baz],
|
34
|
+
# :write_mask => [:foo,:bar] })
|
35
|
+
#
|
36
|
+
# schema.required_fields # => [:foo,:bar]
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# schema = JiakSchema.new({:allowed_fields => [:foo,:bar,:baz],
|
40
|
+
# :required_fields => [:foo,:bar]})
|
41
|
+
#
|
42
|
+
# schema.read_mask # => [:foo,:bar,:baz]
|
43
|
+
# schema.required_fields # => [:foo,:bar]
|
44
|
+
# schema.required_fields = [:foo,:bar,:baz]
|
45
|
+
# schema.required_fields # => [:foo,:bar,:baz]
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# schema = JiakSchema.new([:foo,:bar,:baz])
|
49
|
+
#
|
50
|
+
# schema.write_mask # => [:foo,:bar,:baz)
|
51
|
+
#
|
52
|
+
# </pre>
|
53
|
+
class JiakSchema
|
54
|
+
|
55
|
+
attr_accessor :allowed_fields, :required_fields, :read_mask, :write_mask
|
56
|
+
|
57
|
+
# call-seq:
|
58
|
+
# JiakSchema.new(arg) -> JiakSchema
|
59
|
+
#
|
60
|
+
# New schema from either a hash or an single-element array.
|
61
|
+
#
|
62
|
+
# ====Hash structure
|
63
|
+
# <em>required</em>
|
64
|
+
# <code>allowed_fields</code>:: Fields that can be stored.
|
65
|
+
# <em>optional</em>
|
66
|
+
# <code>required_fields</code>:: Fields that must be provided on storage.
|
67
|
+
# <code>read_mask</code>:: Fields returned on retrieval.
|
68
|
+
# <code>write_mask</code>:: Fields that can be changed and stored.
|
69
|
+
# The value for key must be an array.
|
70
|
+
#
|
71
|
+
# =====OR
|
72
|
+
# <code>schema</code>: A hash whose value is the above hash structure.
|
73
|
+
#
|
74
|
+
# Notes
|
75
|
+
# * Keys can either be symbols or strings.
|
76
|
+
# * Array fields must be symbols or strings.
|
77
|
+
# * Required fields defaults to an empty array.
|
78
|
+
# * Masks default to the <code>allowed_fields</code> array.
|
79
|
+
#
|
80
|
+
# ====Array structure
|
81
|
+
# <code>[:f1,...,fn]</code>:: Allowed fields as symbols or strings.
|
82
|
+
#
|
83
|
+
# All other fields take the same value as the <code>allowed_fields</code>
|
84
|
+
# element. The array structure is provided for simplicity but does not
|
85
|
+
# provide the finer-grained control of the hash structure.
|
86
|
+
#
|
87
|
+
# Raise JiakSchemaException if:
|
88
|
+
# * the method argument is not either a hash or array
|
89
|
+
# * The fields are not either symbols or strings
|
90
|
+
# * The fields elements are not unique
|
91
|
+
def initialize(arg)
|
92
|
+
case arg
|
93
|
+
when Hash
|
94
|
+
# Jiak returns a JSON structure with a single key 'schema' whose value
|
95
|
+
# is a hash. If the arg hash has a schema key, set the opts hash to
|
96
|
+
# that; otherwise use the arg as the opts hash.
|
97
|
+
opts = arg[:schema] || arg['schema'] || arg
|
98
|
+
|
99
|
+
opts[:allowed_fields] ||= opts['allowed_fields']
|
100
|
+
check_arr("allowed_fields",opts[:allowed_fields])
|
101
|
+
|
102
|
+
# Use required if provided, otherwise set to empty array
|
103
|
+
opts[:required_fields] ||= opts['required_fields'] || []
|
104
|
+
check_arr("required_fields",opts[:required_fields])
|
105
|
+
|
106
|
+
# Use masks if provided, otherwise set to allowed_fields
|
107
|
+
[:read_mask,:write_mask].each do |key|
|
108
|
+
opts[key] ||= opts[key.to_s] || opts[:allowed_fields]
|
109
|
+
check_arr(key.to_s,opts[key])
|
110
|
+
end
|
111
|
+
when Array
|
112
|
+
# An array arg must be a single-element array of the allowed
|
113
|
+
# fields. Required fields is set to an empty array and the masks are
|
114
|
+
# set to the allowed fields array.
|
115
|
+
check_arr("allowed_fields",arg)
|
116
|
+
opts = {
|
117
|
+
:allowed_fields => arg,
|
118
|
+
:required_fields => [],
|
119
|
+
:read_mask => arg,
|
120
|
+
:write_mask => arg
|
121
|
+
}
|
122
|
+
else
|
123
|
+
raise JiakSchemaException, "Initialize arg must be either hash or array"
|
124
|
+
end
|
125
|
+
|
126
|
+
@allowed_fields = opts[:allowed_fields]
|
127
|
+
@required_fields = opts[:required_fields]
|
128
|
+
@read_mask = opts[:read_mask]
|
129
|
+
@write_mask = opts[:write_mask]
|
130
|
+
end
|
131
|
+
|
132
|
+
# call-seq:
|
133
|
+
# JiakSchema.from_json(json) -> JiakSchema
|
134
|
+
#
|
135
|
+
# Create a JiakSchema from parsed JSON returned by the Jiak server.
|
136
|
+
def self.from_jiak(jiak)
|
137
|
+
new(jiak)
|
138
|
+
end
|
139
|
+
|
140
|
+
# call-seq:
|
141
|
+
# schema.to_jiak -> JSON
|
142
|
+
#
|
143
|
+
# Create a representation suitable for sending to a Jiak server. Called by
|
144
|
+
# JiakClient when transporting a schema to Jiak.
|
145
|
+
def to_jiak
|
146
|
+
{ :schema =>
|
147
|
+
{ :allowed_fields => @allowed_fields,
|
148
|
+
:required_fields => @required_fields,
|
149
|
+
:read_mask => @read_mask,
|
150
|
+
:write_mask => @write_mask
|
151
|
+
}
|
152
|
+
}.to_json
|
153
|
+
end
|
154
|
+
|
155
|
+
def allowed_fields=(arr) # :nodoc:
|
156
|
+
check_arr('allowed_fields',arr)
|
157
|
+
@allowed_fields = arr
|
158
|
+
end
|
159
|
+
def required_fields=(arr) # :nodoc:
|
160
|
+
check_arr('required_fields',arr)
|
161
|
+
@required_fields = arr
|
162
|
+
end
|
163
|
+
def read_mask=(arr) # :nodoc:
|
164
|
+
check_arr('read_mask',arr)
|
165
|
+
@read_mask = arr
|
166
|
+
end
|
167
|
+
def write_mask=(arr) # :nodoc:
|
168
|
+
check_arr('write_mask',arr)
|
169
|
+
@write_mask = arr
|
170
|
+
end
|
171
|
+
|
172
|
+
# :call-seq:
|
173
|
+
# schema.readwrite = [:f1,...,:fn]
|
174
|
+
#
|
175
|
+
# Set the read and write masks for a JiakSchema.
|
176
|
+
def readwrite=(arr) # :nodoc:
|
177
|
+
check_arr('readwrite',arr)
|
178
|
+
@read_mask = arr
|
179
|
+
@write_mask = arr
|
180
|
+
end
|
181
|
+
|
182
|
+
# call-seq:
|
183
|
+
# schema == other -> true or false
|
184
|
+
#
|
185
|
+
# Equality -- Two schemas are equal if they contain the same array elements
|
186
|
+
# for all attributes, irrespective of order.
|
187
|
+
def ==(other)
|
188
|
+
(@allowed_fields.same_fields?(other.allowed_fields) &&
|
189
|
+
@required_fields.same_fields?(other.required_fields) &&
|
190
|
+
@read_mask.same_fields?(other.read_mask) &&
|
191
|
+
@write_mask.same_fields?(other.write_mask)) rescue false
|
192
|
+
end
|
193
|
+
|
194
|
+
# call-seq:
|
195
|
+
# schema.eql?(other) -> true or false
|
196
|
+
#
|
197
|
+
# Returns <code>true</code> if <code>other</code> is a JiakSchema with the
|
198
|
+
# same array elements, irrespective of order.
|
199
|
+
def eql?(other)
|
200
|
+
other.is_a?(JiakSchema) &&
|
201
|
+
@allowed_fields.same_fields?(other.allowed_fields) &&
|
202
|
+
@required_fields.same_fields?(other.required_fields) &&
|
203
|
+
@read_mask.same_fields?(other.read_mask) &&
|
204
|
+
@write_mask.same_fields?(other.write_mask)
|
205
|
+
end
|
206
|
+
|
207
|
+
def hash # :nodoc:
|
208
|
+
@allowed_fields.name.hash + @required_fields.hash +
|
209
|
+
@read_mask.hash + @write_mask.hash
|
210
|
+
end
|
211
|
+
|
212
|
+
# String representation of this schema.
|
213
|
+
def to_s
|
214
|
+
'allowed_fields="'+@allowed_fields.inspect+
|
215
|
+
'",required_fields="'+@required_fields.inspect+
|
216
|
+
'",read_mask="'+@read_mask.inspect+
|
217
|
+
'",write_mask="'+@write_mask.inspect+'"'
|
218
|
+
end
|
219
|
+
|
220
|
+
# Each option must be an array of symbol or string elements.
|
221
|
+
def check_arr(desc,arr)
|
222
|
+
if(arr.eql?("*"))
|
223
|
+
raise(JiakSchemaException,
|
224
|
+
"RiakRest does not support wildcard schemas at this time.")
|
225
|
+
end
|
226
|
+
unless arr.is_a?(Array)
|
227
|
+
raise JiakSchemaException, "#{desc} must be an array"
|
228
|
+
end
|
229
|
+
arr.each do |field|
|
230
|
+
unless(field.is_a?(String) || field.is_a?(Symbol))
|
231
|
+
raise JiakSchemaException, "#{desc} must be strings or symbols"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
unless arr.map{|f| f.to_s}.uniq.size == arr.size
|
235
|
+
raise JiakSchemaException, "#{desc} must have unique elements."
|
236
|
+
end
|
237
|
+
end
|
238
|
+
private :check_arr
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module RiakRest
|
2
|
+
|
3
|
+
# Represents a link used to query linked objects in Jiak. Links are
|
4
|
+
# established using a JiakLink and queried using a QueryLink. The structures
|
5
|
+
# are very similar but significantly different.
|
6
|
+
#
|
7
|
+
# ===Usage
|
8
|
+
# <code>
|
9
|
+
# link = QueryLink.new('people','parent')
|
10
|
+
# link = QueryLink.new(['children','odd','_'])
|
11
|
+
# link = QueryLink.new('blogs',nil,QueryLink::ANY)
|
12
|
+
# </code>
|
13
|
+
class QueryLink
|
14
|
+
|
15
|
+
attr_accessor :bucket, :tag, :acc
|
16
|
+
|
17
|
+
# Jiak (erlang) wildcard character (atom)
|
18
|
+
ANY = '_'
|
19
|
+
|
20
|
+
# :call-seq:
|
21
|
+
# QueryLink.new(*args) -> QueryLink
|
22
|
+
#
|
23
|
+
# Create a link from argument array. Missing, nil, or empty string values
|
24
|
+
# are set to QueryLink::ANY.
|
25
|
+
#
|
26
|
+
# ====Examples
|
27
|
+
# The following create QueryLinks with the shown equivalent array structure:
|
28
|
+
# <code>
|
29
|
+
# QueryLink.new # => ['_','_','_']
|
30
|
+
# QueryLink.new 'b' # => ['b','_','_']
|
31
|
+
# QueryLink.new 'b','t' # => ['b','t','_']
|
32
|
+
# QueryLink.new 'b','t','a' # => ['b','t','a']
|
33
|
+
#
|
34
|
+
# QueryLink.new [] # => ['_','_','_']
|
35
|
+
# QueryLink.new ['b'] # => ['b','_','_']
|
36
|
+
# QueryLink.new ['b','t'] # => ['b','t','_']
|
37
|
+
# QueryLink.new ['b','t','a'] # => ['b','t','a']
|
38
|
+
#
|
39
|
+
# QueryLink.new ['',nil,' '] # => ['_','_','_']
|
40
|
+
# </code>
|
41
|
+
#
|
42
|
+
# Passing another QueryLink as an argument makes a copy of that
|
43
|
+
# link. Passing a JiakBucket in the first (bucket) position uses the name
|
44
|
+
# field of that JiakBucket.
|
45
|
+
def initialize(*args)
|
46
|
+
case args.size
|
47
|
+
when 0
|
48
|
+
bucket = tag = acc = ANY
|
49
|
+
when 1
|
50
|
+
if args[0].is_a? String
|
51
|
+
bucket = args[0]
|
52
|
+
tag = acc = ANY
|
53
|
+
elsif args[0].is_a? QueryLink
|
54
|
+
bucket, tag, acc = args[0].bucket, args[0].tag, args[0].acc
|
55
|
+
elsif args[0].is_a? Array
|
56
|
+
bucket, tag, acc = args[0][0], args[0][1], args[0][2]
|
57
|
+
else
|
58
|
+
raise QueryLinkException, "argument error"
|
59
|
+
end
|
60
|
+
when 2
|
61
|
+
bucket, tag = args[0], args[1]
|
62
|
+
acc = ANY
|
63
|
+
when 3
|
64
|
+
bucket, tag, acc = args[0], args[1], args[2]
|
65
|
+
else
|
66
|
+
raise QueryLinkException, "too many arguments, (#{args.size} for 3)"
|
67
|
+
end
|
68
|
+
|
69
|
+
@bucket, @tag, @acc = transform_args(bucket,tag,acc)
|
70
|
+
end
|
71
|
+
|
72
|
+
# :call-seq
|
73
|
+
# link.bucket = bucket
|
74
|
+
#
|
75
|
+
# Set the bucket field.
|
76
|
+
def bucket=(bucket)
|
77
|
+
bucket = bucket.name if bucket.is_a? JiakBucket
|
78
|
+
@bucket = transform_arg(bucket)
|
79
|
+
end
|
80
|
+
|
81
|
+
# :call-seq:
|
82
|
+
# link.tag = tag
|
83
|
+
#
|
84
|
+
# Set the tag field.
|
85
|
+
def tag=(tag)
|
86
|
+
@tag = transform_arg(tag)
|
87
|
+
end
|
88
|
+
|
89
|
+
# :call-seq:
|
90
|
+
# link.acc = acc
|
91
|
+
#
|
92
|
+
# Set the acc field.
|
93
|
+
def acc=(acc)
|
94
|
+
@acc = transform_arg(acc)
|
95
|
+
end
|
96
|
+
|
97
|
+
# :call-seq:
|
98
|
+
# link.for_uri -> URI encoded string
|
99
|
+
#
|
100
|
+
# URI represent this QueryLink, i.e, a string suitable for inclusion in an
|
101
|
+
# URI.
|
102
|
+
def for_uri
|
103
|
+
URI.encode([@bucket,@tag,@acc].join(','))
|
104
|
+
end
|
105
|
+
|
106
|
+
# :call-seq:
|
107
|
+
# link == other -> true or false
|
108
|
+
#
|
109
|
+
# Equality -- QueryLinks are equal if they contain the same attribute
|
110
|
+
# values.
|
111
|
+
def ==(other)
|
112
|
+
(@bucket == other.bucket &&
|
113
|
+
@tag == other.tag &&
|
114
|
+
@acc == other.acc) rescue false
|
115
|
+
end
|
116
|
+
|
117
|
+
# :call-seq:
|
118
|
+
# link.eql?(other) -> true or false
|
119
|
+
#
|
120
|
+
# Returns <code>true</code> if <code>other</code> is a QueryLink with the
|
121
|
+
# same attribute values.
|
122
|
+
def eql?(other)
|
123
|
+
other.is_a?(QueryLink) &&
|
124
|
+
@bucket.eql?(other.bucket) &&
|
125
|
+
@tag.eql?(other.tag) &&
|
126
|
+
@acc.eql?(other.acc)
|
127
|
+
end
|
128
|
+
|
129
|
+
def hash # :nodoc:
|
130
|
+
@bucket.name.hash + @tag.hash + @acc.hash
|
131
|
+
end
|
132
|
+
|
133
|
+
# String representation of this QueryLink.
|
134
|
+
def to_s
|
135
|
+
'["'+@bucket+'","'+@tag+'","'+@acc+'"]'
|
136
|
+
end
|
137
|
+
|
138
|
+
def transform_args(b,t,a)
|
139
|
+
b = b.name if b.is_a? JiakBucket
|
140
|
+
[transform_arg(b),transform_arg(t),transform_arg(a)]
|
141
|
+
end
|
142
|
+
private :transform_args
|
143
|
+
|
144
|
+
def transform_arg(arg)
|
145
|
+
arg = ANY if arg.nil?
|
146
|
+
unless arg.is_a? String
|
147
|
+
raise QueryLinkException, "Link elements must be Strings."
|
148
|
+
end
|
149
|
+
value = arg.dup
|
150
|
+
value.strip!
|
151
|
+
value.empty? ? ANY : value
|
152
|
+
end
|
153
|
+
private :transform_arg
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module RiakRest
|
2
|
+
# JiakDataHash provides a easy-to-use default JiakData implementation. See
|
3
|
+
# JiakData for a discussion on creating user-defined data classes.
|
4
|
+
#
|
5
|
+
# JiakDataHash creates a JiakData from a list of user-data fields. Note
|
6
|
+
# JiakDataHash, like JiakData, is not used to create instances of user data;
|
7
|
+
# rather it is used to create the class for the user data. That class is then
|
8
|
+
# used to create instances of the user data itself.
|
9
|
+
#
|
10
|
+
# The class created by JiakDataHash is anonymous and takes the name of the
|
11
|
+
# constant to which it is assigned. See the example below.
|
12
|
+
#
|
13
|
+
# Object instances of the class created by JiakDataHash have read and write
|
14
|
+
# accessors for each the fields used in creating the class. Instance values
|
15
|
+
# can also be accessed via [] and []=. Other hash sematics are not
|
16
|
+
# provided. The created class does have a <code>to_hash</code> method that
|
17
|
+
# returns a hash of the instance data fields and values.
|
18
|
+
#
|
19
|
+
# The class created by JiakDataHash includes an initialize method that takes
|
20
|
+
# as argument a hash of the field/value pairs for the instance. The instance
|
21
|
+
# still has all of the field attributes, this simply provides a easy way to
|
22
|
+
# initialize some or all of the values for the fields.
|
23
|
+
#
|
24
|
+
# The class created by JiakDataHash also provides a <code>keygen</code> class
|
25
|
+
# method that allows specifying a list of fields for use in generating the
|
26
|
+
# key for instance data. See JiakDataHash#keygen.
|
27
|
+
#
|
28
|
+
# Note the created class has methods provided by JiakData to inspect or
|
29
|
+
# manipulate the structure Jiak interaction for instances of the class. See
|
30
|
+
# JiakData#ClassMethods for those methods.
|
31
|
+
#
|
32
|
+
# ===Usage
|
33
|
+
# <code>
|
34
|
+
# Dog = JiakDataHash.create(:name,:weight)
|
35
|
+
# Dog.keygen :name
|
36
|
+
#
|
37
|
+
# addie = Dog.new(:name => "Adelaide", :weight => 45)
|
38
|
+
# addie.name # => "Adeliade"
|
39
|
+
# addie.weight # => 45
|
40
|
+
#
|
41
|
+
# addie.weight = 47 # => 47
|
42
|
+
# </code>
|
43
|
+
#
|
44
|
+
class JiakDataHash
|
45
|
+
|
46
|
+
# :call-seq:
|
47
|
+
# JiakDataHash.create(:f1,...,fn) -> JiakDataHash
|
48
|
+
# JiakDataHash.create([:f1,...,fn]) -> JiakDataHash
|
49
|
+
# JiakDataHash.create(schema) -> JiakDataHash
|
50
|
+
#
|
51
|
+
# Creates a JiakDataHash class that can be used to create JiakData objects
|
52
|
+
# containing the specified fields.
|
53
|
+
def self.create(*args)
|
54
|
+
Class.new do
|
55
|
+
include JiakData
|
56
|
+
|
57
|
+
if(args.size == 1)
|
58
|
+
case args[0]
|
59
|
+
when Symbol, Array
|
60
|
+
allowed *args[0]
|
61
|
+
when JiakSchema
|
62
|
+
allowed *args[0].allowed_fields
|
63
|
+
required *args[0].required_fields
|
64
|
+
readable *args[0].read_mask
|
65
|
+
writable *args[0].write_mask
|
66
|
+
end
|
67
|
+
else
|
68
|
+
allowed *args
|
69
|
+
end
|
70
|
+
|
71
|
+
# :call-seq:
|
72
|
+
# DataClass.keygen(*fields)
|
73
|
+
#
|
74
|
+
# The key generation for the data class will be a concatenation of the
|
75
|
+
# to_s result of calling each of the listed data class fields.
|
76
|
+
def self.keygen(*fields)
|
77
|
+
define_method(:keygen) do
|
78
|
+
fields.inject("") {|key,field| key += send("#{field}").to_s}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# :call-seq:
|
83
|
+
# data.new({}) -> JiakDataHash
|
84
|
+
#
|
85
|
+
# Create an instance of the user-defined JiakDataHash using the provide
|
86
|
+
# hash as initial values.
|
87
|
+
def initialize(hsh={})
|
88
|
+
hsh.each {|key,value| send("#{key}=",value)}
|
89
|
+
end
|
90
|
+
|
91
|
+
# :call-seq:
|
92
|
+
# data.jiak_create(jiak) -> JiakDataHash
|
93
|
+
#
|
94
|
+
# Used by RiakRest to create an instance of the user-defined data class
|
95
|
+
# from the values returned by the Jiak server.
|
96
|
+
def self.jiak_create(jiak)
|
97
|
+
new(jiak)
|
98
|
+
end
|
99
|
+
|
100
|
+
# :call-seq:
|
101
|
+
# data[field] -> value
|
102
|
+
#
|
103
|
+
# Get the value of a field.
|
104
|
+
#
|
105
|
+
# Returns <code>nil</code> if <code>field</code> was not declared for
|
106
|
+
# this class. <code>field</code> can be in either string or symbol
|
107
|
+
# form.
|
108
|
+
def [](key)
|
109
|
+
send("#{key}") rescue nil
|
110
|
+
end
|
111
|
+
|
112
|
+
# :call-seq:
|
113
|
+
# data[field] = value
|
114
|
+
#
|
115
|
+
# Set the value of a field.
|
116
|
+
#
|
117
|
+
# Returns the value set, or <code>nil</code> if <code>field</code> was
|
118
|
+
# not declared for this class.
|
119
|
+
def []=(key,value)
|
120
|
+
send("#{key}=",value) rescue nil
|
121
|
+
end
|
122
|
+
|
123
|
+
# :call-seq:
|
124
|
+
# data.for_jiak -> hash
|
125
|
+
#
|
126
|
+
# Return a hash of the writable fields and their values. Used by
|
127
|
+
# RiakRest to prepare the data for transport to the Jiak server.
|
128
|
+
def for_jiak
|
129
|
+
self.class.schema.write_mask.inject({}) do |build,field|
|
130
|
+
val = send("#{field}")
|
131
|
+
build[field] = val unless val.nil?
|
132
|
+
build
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# :call-seq:
|
137
|
+
# data.to_hash
|
138
|
+
#
|
139
|
+
# Return a hash of the allowed fields and their values.
|
140
|
+
def to_hash
|
141
|
+
self.class.schema.allowed_fields.inject({}) do |build,field|
|
142
|
+
val = send("#{field}")
|
143
|
+
build[field] = val
|
144
|
+
build
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# call-seq:
|
150
|
+
# jiak_data == other -> true or false
|
151
|
+
#
|
152
|
+
# Equality -- Two JiakDataHash objects are equal if they contain the
|
153
|
+
# same values for all attributes.
|
154
|
+
def ==(other)
|
155
|
+
self.class.schema.allowed_fields.reduce(true) do |same,field|
|
156
|
+
same && (other.send("#{field}") == (send("#{field}")))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# call-seq:
|
161
|
+
# data.eql?(other) -> true or false
|
162
|
+
#
|
163
|
+
# Returns <code>true</code> if <code>other</code> is a JiakObject with
|
164
|
+
# the same the same attribute values for all allowed fields.
|
165
|
+
def eql?(other)
|
166
|
+
other.is_a?(self.class) &&
|
167
|
+
self.class.schema.allowed_fields.reduce(true) do |same,field|
|
168
|
+
same && other.send("#{field}").eql?(send("#{field}"))
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def hash # :nodoc:
|
173
|
+
self.class.schema.allowed_fields.inject(0) do |hsh,field|
|
174
|
+
hsh += send("#{field}").hash
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|