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,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
|