xeme 0.3.1 → 1.0
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.
- checksums.yaml +4 -4
- data/README.md +352 -260
- data/lib/xeme.rb +422 -450
- metadata +24 -11
data/lib/xeme.rb
CHANGED
@@ -1,37 +1,37 @@
|
|
1
|
-
require 'date'
|
2
|
-
require 'json'
|
3
1
|
require 'forwardable'
|
2
|
+
require 'declutter'
|
3
|
+
|
4
4
|
|
5
5
|
#===============================================================================
|
6
6
|
# Xeme
|
7
7
|
#
|
8
|
-
|
9
|
-
# Objects of this class represent a set of results. See the README file for
|
10
|
-
# more details.
|
11
|
-
|
12
8
|
class Xeme
|
13
|
-
#
|
14
|
-
|
9
|
+
# Returns the underlying hash that the xeme manages.
|
10
|
+
attr_reader :hsh
|
15
11
|
|
16
|
-
|
17
|
-
#
|
18
|
-
|
12
|
+
#---------------------------------------------------------------------------
|
13
|
+
# delegate
|
14
|
+
#
|
15
|
+
extend Forwardable
|
16
|
+
delegate %w([] []= each length clear delete to_json) => :hsh
|
17
|
+
#
|
18
|
+
# delegate
|
19
|
+
#---------------------------------------------------------------------------
|
19
20
|
|
20
|
-
# A hash of any miscellaneous details you want to include.
|
21
|
-
attr_reader :misc
|
22
21
|
|
23
22
|
#---------------------------------------------------------------------------
|
24
23
|
# initialize
|
25
24
|
#
|
26
25
|
|
27
|
-
# new
|
26
|
+
# Creates a new Xeme object. Optionally takes a single strin parameter which
|
27
|
+
# is set as the id for the xeme.
|
28
28
|
|
29
|
-
def initialize
|
30
|
-
@
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
def initialize(id=nil)
|
30
|
+
@hsh = {}
|
31
|
+
|
32
|
+
if id
|
33
|
+
meta id
|
34
|
+
end
|
35
35
|
end
|
36
36
|
#
|
37
37
|
# initialize
|
@@ -39,627 +39,599 @@ class Xeme
|
|
39
39
|
|
40
40
|
|
41
41
|
#---------------------------------------------------------------------------
|
42
|
-
#
|
42
|
+
# meta
|
43
43
|
#
|
44
44
|
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
|
45
|
+
# Returns the meta hash, creating it if necessary. The meta hash
|
46
|
+
# contains at least a timestamp and a UUID.
|
47
|
+
|
48
|
+
def meta(id=nil)
|
49
|
+
require 'securerandom'
|
50
|
+
|
51
|
+
# initialize meta element if necessary
|
52
|
+
@hsh['meta'] ||= {}
|
53
|
+
|
54
|
+
# populate meta
|
55
|
+
@hsh['meta']['uuid'] ||= SecureRandom.uuid().to_s
|
56
|
+
@hsh['meta']['timestamp'] ||= Time.now
|
57
|
+
|
58
|
+
# give child id if given
|
59
|
+
if id
|
60
|
+
meta['id'] = id
|
61
|
+
end
|
62
|
+
|
63
|
+
# return
|
64
|
+
return @hsh['meta']
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the UUID in the meta hash.
|
68
|
+
def uuid
|
69
|
+
return meta['uuid']
|
49
70
|
end
|
50
71
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
72
|
+
# Returns the timestamp in the meta hash.
|
73
|
+
def timestamp
|
74
|
+
return meta['timestamp']
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the id element of the meta hash if there is one.
|
78
|
+
def id
|
79
|
+
if @hsh['meta']
|
80
|
+
return @hsh['meta']['id']
|
81
|
+
else
|
82
|
+
return nil
|
83
|
+
end
|
55
84
|
end
|
56
85
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
return @messages['notes']
|
86
|
+
# Sets id element of the meta.
|
87
|
+
def id=(v)
|
88
|
+
return meta['id'] = v
|
61
89
|
end
|
62
90
|
#
|
63
|
-
#
|
91
|
+
# meta
|
64
92
|
#---------------------------------------------------------------------------
|
65
93
|
|
66
94
|
|
67
95
|
#---------------------------------------------------------------------------
|
68
|
-
#
|
96
|
+
# flatten
|
69
97
|
#
|
70
98
|
|
71
|
-
|
72
|
-
#
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
99
|
+
# Folds all nested messages into the outermost xeme, and deletes nested
|
100
|
+
# xemes. Only the messages are folded in, not any metainformation or other
|
101
|
+
# information that might be in the nested xemes.
|
102
|
+
|
103
|
+
def flatten
|
104
|
+
resolve()
|
105
|
+
|
106
|
+
as_arr('nested').each do |child|
|
107
|
+
child.flatten
|
108
|
+
|
109
|
+
%w{errors warnings notes promises}.each do |msg_key|
|
110
|
+
if child[msg_key]
|
111
|
+
@hsh[msg_key] ||= []
|
112
|
+
@hsh[msg_key] += child[msg_key]
|
113
|
+
child.delete(msg_key)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
@hsh.delete('nested')
|
119
|
+
end
|
77
120
|
#
|
78
|
-
#
|
121
|
+
# flatten
|
122
|
+
#---------------------------------------------------------------------------
|
123
|
+
|
124
|
+
|
125
|
+
#---------------------------------------------------------------------------
|
126
|
+
# to_h
|
79
127
|
#
|
80
|
-
#
|
128
|
+
# def to_h
|
129
|
+
# rv = @hsh.to_h
|
130
|
+
#
|
131
|
+
# # loop through nested xemes
|
132
|
+
# if rv['nested']
|
133
|
+
# rv['nested'] = rv['nested'].map do |child|
|
134
|
+
# child.to_h
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# # return
|
139
|
+
# return rv
|
140
|
+
# end
|
81
141
|
#
|
82
|
-
#
|
83
|
-
|
84
|
-
|
142
|
+
# to_h
|
143
|
+
#---------------------------------------------------------------------------
|
144
|
+
|
145
|
+
|
146
|
+
#---------------------------------------------------------------------------
|
147
|
+
# succeed
|
85
148
|
#
|
86
|
-
# xeme.transaction.request = request.id
|
87
149
|
|
88
|
-
|
89
|
-
|
90
|
-
|
150
|
+
# Attempt to set success to true. Raises an exception if there are any
|
151
|
+
# errors or promises in this or any nested Xeme.
|
152
|
+
|
153
|
+
def succeed
|
154
|
+
# if any errors, don't succeed
|
155
|
+
if errors.any?
|
156
|
+
raise 'cannot-set-to-success: errors'
|
157
|
+
end
|
158
|
+
|
159
|
+
# if any promises, don't succeed
|
160
|
+
if promises.any?
|
161
|
+
raise 'cannot-set-to-success: promises'
|
162
|
+
end
|
163
|
+
|
164
|
+
# set to success
|
165
|
+
return @hsh['success'] = true
|
91
166
|
end
|
167
|
+
|
92
168
|
#
|
93
|
-
#
|
169
|
+
# succeed
|
94
170
|
#---------------------------------------------------------------------------
|
95
171
|
|
96
172
|
|
97
173
|
#---------------------------------------------------------------------------
|
98
|
-
#
|
174
|
+
# try_succeed
|
99
175
|
#
|
100
176
|
|
101
|
-
|
102
|
-
#
|
103
|
-
# object. Empty arrays, such as if there are no warnings, are not included.
|
177
|
+
# Attempt to set success to true. Does not raise an exception if there are
|
178
|
+
# errors or promises, but in those cases will not set success to true.
|
104
179
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
# initialize return value
|
109
|
-
rv = {}
|
180
|
+
def try_succeed(resolve_self=true)
|
181
|
+
enforce_nil = false
|
110
182
|
|
111
|
-
#
|
112
|
-
|
183
|
+
# resolve self and descendents
|
184
|
+
if resolve_self
|
185
|
+
resolve()
|
186
|
+
end
|
113
187
|
|
114
|
-
#
|
115
|
-
if
|
116
|
-
|
188
|
+
# if any promises
|
189
|
+
if as_arr('promises').any?
|
190
|
+
@hsh.delete 'success'
|
191
|
+
enforce_nil = true
|
117
192
|
end
|
118
193
|
|
119
|
-
#
|
120
|
-
|
121
|
-
|
194
|
+
# try_succeed for descendents
|
195
|
+
as_arr('nested').each do |child|
|
196
|
+
child.try_succeed false
|
122
197
|
|
123
|
-
@
|
124
|
-
if
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
msgs[key].push msg.to_h
|
129
|
-
end
|
198
|
+
if @hsh['success'].nil?
|
199
|
+
if child['success'].nil?
|
200
|
+
enforce_nil = true
|
201
|
+
elsif not child['success']
|
202
|
+
@hsh['success'] = false
|
130
203
|
end
|
131
204
|
end
|
132
205
|
end
|
133
206
|
|
134
|
-
#
|
135
|
-
if @
|
136
|
-
|
207
|
+
# set to success if success is nil and no promises
|
208
|
+
if @hsh['success'].nil? and (! enforce_nil)
|
209
|
+
@hsh['success'] = true
|
137
210
|
end
|
138
211
|
|
139
212
|
# return
|
140
|
-
return
|
213
|
+
return @hsh['success']
|
141
214
|
end
|
215
|
+
|
142
216
|
#
|
143
|
-
#
|
217
|
+
# try_succeed
|
144
218
|
#---------------------------------------------------------------------------
|
145
219
|
|
146
220
|
|
147
221
|
#---------------------------------------------------------------------------
|
148
|
-
#
|
222
|
+
# fail
|
149
223
|
#
|
150
224
|
|
151
|
-
|
152
|
-
|
153
|
-
def
|
154
|
-
|
155
|
-
|
156
|
-
else
|
157
|
-
return JSON.generate(self.to_h)
|
158
|
-
end
|
225
|
+
# Explicitly set success to false. Does not add an error.
|
226
|
+
|
227
|
+
def fail
|
228
|
+
@hsh['success'] = false
|
229
|
+
resolve()
|
159
230
|
end
|
231
|
+
|
160
232
|
#
|
161
|
-
#
|
233
|
+
# fail
|
162
234
|
#---------------------------------------------------------------------------
|
163
235
|
|
164
236
|
|
165
237
|
#---------------------------------------------------------------------------
|
166
|
-
# success
|
238
|
+
# success?
|
167
239
|
#
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
def success
|
173
|
-
return @messages['errors'].empty?
|
240
|
+
def success?
|
241
|
+
resolve()
|
242
|
+
return @hsh['success']
|
174
243
|
end
|
175
|
-
|
176
|
-
##
|
177
|
-
# Returns the opposite of <tt>success()</tt>.
|
178
|
-
def failure
|
179
|
-
return success ? false : true
|
180
|
-
end
|
181
|
-
|
182
244
|
#
|
183
|
-
# success
|
245
|
+
# success?
|
184
246
|
#---------------------------------------------------------------------------
|
185
247
|
|
186
248
|
|
187
249
|
#---------------------------------------------------------------------------
|
188
|
-
#
|
250
|
+
# messages
|
189
251
|
#
|
190
252
|
|
191
|
-
#
|
192
|
-
#
|
253
|
+
# Returns a locked array of all errors, including errors in nested xemes.
|
254
|
+
# If the optional id param is sent, returns only errors with that id.
|
255
|
+
def errors(id=nil)
|
256
|
+
return all_messages('errors', id)
|
257
|
+
end
|
258
|
+
|
259
|
+
# Returns a locked array of all warnings, including warnings in nested xemes.
|
260
|
+
# If the optional id param is sent, returns only warnings with that id.
|
261
|
+
def warnings(id=nil)
|
262
|
+
return all_messages('warnings', id)
|
263
|
+
end
|
264
|
+
|
265
|
+
# Returns a locked array of all notes, including notes in nested xemes.
|
266
|
+
# If the optional id param is sent, returns only notes with that id.
|
267
|
+
def notes(id=nil)
|
268
|
+
return all_messages('notes', id)
|
269
|
+
end
|
193
270
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
271
|
+
# Returns a locked array of all promises, including promises in nested xemes.
|
272
|
+
# If the optional id param is sent, returns only promises with that id.
|
273
|
+
def promises(id=nil)
|
274
|
+
return all_messages('promises', id)
|
198
275
|
end
|
276
|
+
|
199
277
|
#
|
200
|
-
#
|
278
|
+
# messages
|
201
279
|
#---------------------------------------------------------------------------
|
202
280
|
|
203
281
|
|
204
282
|
#---------------------------------------------------------------------------
|
205
|
-
#
|
283
|
+
# message hashes
|
206
284
|
#
|
207
285
|
|
208
|
-
|
209
|
-
#
|
210
|
-
#
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
# xeme.error '/virginia/angle'
|
215
|
-
# xeme.error '/virginia/departure'
|
216
|
-
#
|
217
|
-
# That works, but the redundancy can get confusing (and annoying). With
|
218
|
-
# <tt>prefix</tt> you can avoid the redundancy like this:
|
219
|
-
#
|
220
|
-
# xeme.prefix('virginia') do
|
221
|
-
# xeme.error 'slope'
|
222
|
-
# xeme.error 'angle'
|
223
|
-
# xeme.error 'departure'
|
224
|
-
# end
|
225
|
-
#
|
226
|
-
# puts xeme.errors[0].id # /virginia/slope
|
227
|
-
# puts xeme.errors[1].id # /virginia/angle
|
228
|
-
# puts xeme.errors[2].id # /virginia/departure
|
229
|
-
#
|
230
|
-
# Prefixes can also be nested, like this:
|
231
|
-
#
|
232
|
-
# xeme.prefix('virginia') do
|
233
|
-
# xeme.prefix('fairfax') do
|
234
|
-
# xeme.error 'slope'
|
235
|
-
# end
|
236
|
-
# end
|
237
|
-
#
|
238
|
-
# puts xeme.errors[0].id # /virginia/fairfax/slope
|
286
|
+
# Returns a hash of all errors, including nested errors. The key for each
|
287
|
+
# element is the id of the error(s). Does not return errors that don't have
|
288
|
+
# ids.
|
289
|
+
def errors_hash()
|
290
|
+
return messages_hash('errors')
|
291
|
+
end
|
239
292
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
293
|
+
# Returns a hash of all warnings, including nested warnings. The key for
|
294
|
+
# each element is the id of the warnings(s). Does not return warnings that
|
295
|
+
# don't have ids.
|
296
|
+
def warnings_hash(id=nil)
|
297
|
+
return messages_hash('warnings')
|
298
|
+
end
|
299
|
+
|
300
|
+
# Returns a hash of all notes, including nested notes. The key for each
|
301
|
+
# element is the id of the notes(s). Does not return notes that don't have
|
302
|
+
# ids.
|
303
|
+
def notes_hash(id=nil)
|
304
|
+
return messages_hash('notes')
|
305
|
+
end
|
306
|
+
|
307
|
+
# Returns a hash of all promises, including nested promises. The key for
|
308
|
+
# each element is the id of the promise(s). Does not return promises that
|
309
|
+
# don't have ids.
|
310
|
+
def promises_hash(id=nil)
|
311
|
+
return messages_hash('promises')
|
251
312
|
end
|
313
|
+
|
252
314
|
#
|
253
|
-
#
|
315
|
+
# message hashes
|
254
316
|
#---------------------------------------------------------------------------
|
255
317
|
|
256
318
|
|
257
319
|
#---------------------------------------------------------------------------
|
258
|
-
#
|
320
|
+
# add message
|
259
321
|
#
|
260
322
|
|
261
|
-
|
262
|
-
#
|
263
|
-
#
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
# with the message object in its Xeme::Message#details property.
|
268
|
-
#
|
269
|
-
# xeme.error('error-0', 'choice'=>'a')
|
270
|
-
#
|
271
|
-
# This method returns the message object, which can be used as another
|
272
|
-
# way to store details.
|
273
|
-
#
|
274
|
-
# msg = xeme.error('error-1').
|
275
|
-
# msg['location'] = 1
|
276
|
-
#
|
277
|
-
# If a block is given, the block is called with the error object as the
|
278
|
-
# single param.
|
279
|
-
#
|
280
|
-
# xeme.error('error-2') do |error|
|
281
|
-
# error['location'] = 2
|
282
|
-
# end
|
283
|
-
def error(id, details={}, &block)
|
284
|
-
return add_comment(Xeme::Message, 'errors', id, details={}, &block)
|
323
|
+
# Creates and returns an error message. Accepts a do block which yields the
|
324
|
+
# new message. If given the opional id param, sets that value as the id for
|
325
|
+
# the message.
|
326
|
+
def error(id, &block)
|
327
|
+
@hsh['success'] = false
|
328
|
+
return message('errors', id, &block)
|
285
329
|
end
|
286
330
|
|
287
|
-
|
288
|
-
#
|
289
|
-
|
290
|
-
|
331
|
+
# Creates and returns a warning message. Accepts a do block which yields
|
332
|
+
# the new message. If given the opional id param, sets that value as the id
|
333
|
+
# for the new message.
|
334
|
+
def warning(id, &block)
|
335
|
+
return message('warnings', id, &block)
|
291
336
|
end
|
292
337
|
|
293
|
-
|
294
|
-
#
|
295
|
-
|
296
|
-
|
338
|
+
# Creates and returns a note message. Accepts a do block which yields
|
339
|
+
# the new message. If given the opional id param, sets that value as the id
|
340
|
+
# for the new message.
|
341
|
+
def note(id, &block)
|
342
|
+
return message('notes', id, &block)
|
297
343
|
end
|
344
|
+
|
345
|
+
# Creates and returns a promise message. Accepts a do block which yields
|
346
|
+
# the new message. If given the opional id param, sets that value as the id
|
347
|
+
# for the new message.
|
348
|
+
def promise(id, &block)
|
349
|
+
unless @hsh['success'].is_a?(FalseClass)
|
350
|
+
@hsh.delete 'success'
|
351
|
+
end
|
352
|
+
|
353
|
+
return message('promises', id, &block)
|
354
|
+
end
|
355
|
+
|
298
356
|
#
|
299
|
-
#
|
357
|
+
# add message
|
300
358
|
#---------------------------------------------------------------------------
|
301
359
|
|
302
360
|
|
303
361
|
#---------------------------------------------------------------------------
|
304
|
-
#
|
362
|
+
# nest
|
305
363
|
#
|
306
364
|
|
307
|
-
# Creates a new
|
365
|
+
# Creates a new xeme and nests it in the current xeme. Yields to a do block
|
366
|
+
# if one is sent. Returns the new child xeme.
|
308
367
|
|
309
|
-
def
|
310
|
-
|
311
|
-
|
312
|
-
|
368
|
+
def nest(id=nil)
|
369
|
+
@hsh['nested'] ||= []
|
370
|
+
child = self.class.new()
|
371
|
+
@hsh['nested'].push child
|
313
372
|
|
314
|
-
#
|
315
|
-
if
|
316
|
-
|
317
|
-
rv.messages[msg_type] ||= []
|
318
|
-
rv.messages[msg_type] += arr
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
# misc
|
323
|
-
if misc = hsh['misc']
|
324
|
-
misc.each do |key, val|
|
325
|
-
rv.misc[key] = val
|
326
|
-
end
|
373
|
+
# give id
|
374
|
+
if id
|
375
|
+
child.meta['id'] = id
|
327
376
|
end
|
328
377
|
|
329
|
-
#
|
330
|
-
if
|
331
|
-
|
332
|
-
rv.transaction.timestamp = DateTime.parse(transaction['timestamp'])
|
333
|
-
end
|
334
|
-
|
335
|
-
if transaction['request']
|
336
|
-
rv.transaction.request = transaction['request']
|
337
|
-
end
|
338
|
-
|
339
|
-
if transaction['response']
|
340
|
-
rv.transaction.response = transaction['response']
|
341
|
-
end
|
378
|
+
# yield in block
|
379
|
+
if block_given?
|
380
|
+
yield child
|
342
381
|
end
|
343
382
|
|
344
383
|
# return
|
345
|
-
return
|
384
|
+
return child
|
346
385
|
end
|
386
|
+
|
347
387
|
#
|
348
|
-
#
|
388
|
+
# nest
|
349
389
|
#---------------------------------------------------------------------------
|
350
390
|
|
351
391
|
|
352
392
|
#---------------------------------------------------------------------------
|
353
|
-
#
|
393
|
+
# nested
|
354
394
|
#
|
355
|
-
|
356
|
-
#
|
357
|
-
#
|
358
|
-
|
359
|
-
def new_exception(error_id)
|
360
|
-
return Xeme::Exception.new(error_id, self)
|
361
|
-
end
|
395
|
+
# def nested()
|
396
|
+
# @hsh['nested'] ||= []
|
397
|
+
# return @hsh['nested']
|
398
|
+
# end
|
362
399
|
#
|
363
|
-
#
|
400
|
+
# nested
|
364
401
|
#---------------------------------------------------------------------------
|
365
402
|
|
366
403
|
|
367
|
-
# private methods
|
368
|
-
private
|
369
|
-
|
370
|
-
|
371
404
|
#---------------------------------------------------------------------------
|
372
|
-
#
|
405
|
+
# resolve
|
373
406
|
#
|
374
|
-
def messages_to_h(arr)
|
375
|
-
rv = []
|
376
|
-
|
377
|
-
# messages
|
378
|
-
arr.each do |msg|
|
379
|
-
rv.push msg.to_h
|
380
|
-
end
|
381
|
-
|
382
|
-
# return
|
383
|
-
return rv
|
384
|
-
end
|
385
|
-
#
|
386
|
-
# messages_to_h
|
387
|
-
#---------------------------------------------------------------------------
|
388
407
|
|
408
|
+
# Resolves conflicts between errors, promises, and success. See README.md
|
409
|
+
# for details. You generally don't need to call this method yourself.
|
389
410
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
# build message
|
397
|
-
msg = cls.new(prefix_id(id), details)
|
411
|
+
def resolve
|
412
|
+
# resolve descendents
|
413
|
+
as_arr('nested').each do |child|
|
414
|
+
child.resolve
|
415
|
+
end
|
398
416
|
|
399
|
-
#
|
400
|
-
|
417
|
+
# if own errors, fail
|
418
|
+
if as_arr('errors').any?
|
419
|
+
@hsh['success'] = false
|
420
|
+
return
|
421
|
+
end
|
401
422
|
|
402
|
-
#
|
403
|
-
@
|
423
|
+
# if explicitly set to false, return
|
424
|
+
if @hsh['success'].is_a?(FalseClass)
|
425
|
+
return
|
426
|
+
end
|
404
427
|
|
405
|
-
#
|
406
|
-
if
|
407
|
-
|
428
|
+
# if any promises, set success to nil
|
429
|
+
if as_arr('promises').any?
|
430
|
+
@hsh.delete 'success'
|
408
431
|
end
|
409
432
|
|
410
|
-
#
|
411
|
-
return
|
433
|
+
# if any child is set to nil, set self to nil
|
434
|
+
# if any child set to false, set self to false and return
|
435
|
+
as_arr('nested').each do |child|
|
436
|
+
if child['success'].nil?
|
437
|
+
@hsh.delete 'success'
|
438
|
+
elsif not child['success']
|
439
|
+
@hsh['success'] = false
|
440
|
+
return
|
441
|
+
end
|
442
|
+
end
|
412
443
|
end
|
413
444
|
#
|
414
|
-
#
|
445
|
+
# resolve
|
415
446
|
#---------------------------------------------------------------------------
|
416
447
|
|
417
448
|
|
418
449
|
#---------------------------------------------------------------------------
|
419
|
-
#
|
450
|
+
# declutter
|
420
451
|
#
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
452
|
+
|
453
|
+
# Removes empty arrays and hahes.
|
454
|
+
|
455
|
+
def declutter
|
456
|
+
resolve()
|
457
|
+
Declutter.process @hsh
|
458
|
+
return true
|
427
459
|
end
|
428
460
|
#
|
429
|
-
#
|
461
|
+
# declutter
|
430
462
|
#---------------------------------------------------------------------------
|
431
|
-
end
|
432
|
-
#
|
433
|
-
# Xeme
|
434
|
-
#===============================================================================
|
435
|
-
|
436
|
-
|
437
|
-
#===============================================================================
|
438
|
-
# Xeme::Message
|
439
|
-
#
|
440
|
-
|
441
|
-
# A Xeme::Message object represents a single error, warning, or note.
|
442
|
-
# It is the base class for Xeme::Message::Error,
|
443
|
-
# Xeme::Message::Warning, and
|
444
|
-
# Xeme::Message::Note. Don't instantiate Xeme::Message
|
445
|
-
# directly, use Xeme#error, Xeme#warning, or Xeme#note.
|
446
|
-
#
|
447
|
-
# Each message contains at least an id. It can also have an options details
|
448
|
-
# hash which can be used to store misc information about the message.
|
449
|
-
#
|
450
|
-
# The message itself can be treated like a hash to give details:
|
451
|
-
#
|
452
|
-
# msg = xeme.error('my-error')
|
453
|
-
# msg['location'] = 1
|
454
|
-
|
455
|
-
class Xeme::Message
|
456
|
-
# The id of the message.
|
457
|
-
attr_reader :id
|
458
|
-
|
459
|
-
# Details about the message.
|
460
|
-
attr_reader :details
|
461
|
-
|
462
|
-
# delegate to hsh
|
463
|
-
extend Forwardable
|
464
|
-
delegate %w([] []= each length clear delete) => :@details
|
465
463
|
|
466
464
|
|
467
465
|
#---------------------------------------------------------------------------
|
468
|
-
#
|
466
|
+
# all
|
469
467
|
#
|
470
468
|
|
471
|
-
#
|
472
|
-
# be any string. The optional <tt>details</tt> hash will be stored with the
|
473
|
-
# message.
|
469
|
+
# Returns an array consisting of the xeme and all nested xemes.
|
474
470
|
|
475
|
-
def
|
476
|
-
|
471
|
+
def all(seek_id=nil)
|
472
|
+
rv = []
|
473
|
+
|
474
|
+
# add self
|
475
|
+
if seek_id
|
476
|
+
if id == seek_id
|
477
|
+
rv.push self
|
478
|
+
end
|
479
|
+
else
|
480
|
+
rv.push self
|
481
|
+
end
|
482
|
+
|
483
|
+
# loop through nested children
|
484
|
+
as_arr('nested').each do |child|
|
485
|
+
rv += child.all(seek_id)
|
486
|
+
end
|
477
487
|
|
478
|
-
#
|
479
|
-
|
488
|
+
# freeze return value
|
489
|
+
rv.freeze
|
480
490
|
|
481
|
-
#
|
482
|
-
|
491
|
+
# return
|
492
|
+
return rv
|
483
493
|
end
|
484
494
|
#
|
485
|
-
#
|
495
|
+
# all
|
486
496
|
#---------------------------------------------------------------------------
|
487
497
|
|
488
498
|
|
489
499
|
#---------------------------------------------------------------------------
|
490
|
-
#
|
500
|
+
# misc
|
491
501
|
#
|
492
502
|
|
493
|
-
|
494
|
-
# Returns a hash structure of the message. This structure is used by
|
495
|
-
# Xeme#to_h.
|
503
|
+
# A handy place to puts miscellaneous information.
|
496
504
|
|
497
|
-
def
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
if @details.any?
|
502
|
-
rv['details'] = @details
|
503
|
-
end
|
504
|
-
|
505
|
-
return rv
|
505
|
+
def misc
|
506
|
+
@hsh['misc'] ||= {}
|
507
|
+
return @hsh['misc']
|
506
508
|
end
|
509
|
+
|
507
510
|
#
|
508
|
-
#
|
511
|
+
# misc
|
509
512
|
#---------------------------------------------------------------------------
|
510
|
-
|
511
|
-
|
512
|
-
#
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
#===============================================================================
|
517
|
-
# Xeme::Messages
|
518
|
-
#
|
519
|
-
|
520
|
-
##
|
521
|
-
# This object holds the arrays of errors, warnings, and notes. It can mostly be
|
522
|
-
# treated like a hash. The main difference between a Xeme::Messages object and
|
523
|
-
# a hash is that any? returns true or false based on if there are any messages,
|
524
|
-
# not if there are any elements in the hash.
|
525
|
-
|
526
|
-
class Xeme::Messages
|
527
|
-
# delegate to hsh
|
528
|
-
extend Forwardable
|
529
|
-
delegate %w([] []= each length keys has_key?) => :@hsh
|
513
|
+
|
514
|
+
|
515
|
+
# private
|
516
|
+
private
|
517
|
+
|
530
518
|
|
531
519
|
#---------------------------------------------------------------------------
|
532
|
-
#
|
520
|
+
# as_arr
|
533
521
|
#
|
534
522
|
|
535
|
-
|
536
|
-
#
|
523
|
+
# Convenience function for reading messages as arrays even if they don't
|
524
|
+
# exist.
|
537
525
|
|
538
|
-
def
|
539
|
-
@hsh
|
540
|
-
@hsh['errors'] = []
|
541
|
-
@hsh['warnings'] = []
|
542
|
-
@hsh['notes'] = []
|
526
|
+
def as_arr(key)
|
527
|
+
return @hsh[key] || []
|
543
528
|
end
|
544
529
|
#
|
545
|
-
#
|
530
|
+
# as_arr
|
546
531
|
#---------------------------------------------------------------------------
|
547
532
|
|
548
533
|
|
549
534
|
#---------------------------------------------------------------------------
|
550
|
-
#
|
535
|
+
# message
|
551
536
|
#
|
552
537
|
|
553
|
-
|
554
|
-
# Returns if there are any messages in any of the errors, warnings, or
|
555
|
-
# notes arrays.
|
538
|
+
# Creates a message object of the given type.
|
556
539
|
|
557
|
-
def
|
558
|
-
|
559
|
-
|
540
|
+
def message(type, id, &block)
|
541
|
+
# build message
|
542
|
+
msg = {}
|
543
|
+
id and msg['id'] = id
|
544
|
+
|
545
|
+
# add to array
|
546
|
+
@hsh[type] ||= []
|
547
|
+
@hsh[type].push msg
|
548
|
+
|
549
|
+
# yield if necessary
|
550
|
+
if block_given?
|
551
|
+
yield msg
|
560
552
|
end
|
561
553
|
|
562
|
-
return
|
554
|
+
# return
|
555
|
+
return msg
|
563
556
|
end
|
564
557
|
#
|
565
|
-
#
|
558
|
+
# message
|
566
559
|
#---------------------------------------------------------------------------
|
567
|
-
end
|
568
|
-
#
|
569
|
-
# Xeme::Messages
|
570
|
-
#===============================================================================
|
571
|
-
|
572
|
-
|
573
|
-
#===============================================================================
|
574
|
-
# Xeme::Transaction
|
575
|
-
#
|
576
|
-
|
577
|
-
# An object of this class provides meta information about the request and
|
578
|
-
# results. It always provides a timestamp and a unique ID for the results. It
|
579
|
-
# may also optionally include a request ID that was provided by the process
|
580
|
-
# that made the request, such as a call to a REST application. Do not directly
|
581
|
-
# instantiate this class; use Xeme#transaction.
|
582
|
-
|
583
|
-
class Xeme::Transaction
|
584
|
-
|
585
|
-
# Optional. An ID for the request that was sent by the calling process. Do
|
586
|
-
# not generate this value yourself; use the ID that was sent with the
|
587
|
-
# request (if one was sent).
|
588
|
-
attr_accessor :request
|
589
560
|
|
590
|
-
# Gives a unique ID for these results.
|
591
|
-
attr_accessor :response
|
592
|
-
|
593
|
-
# Gives a timestamp for when these results were generated.
|
594
|
-
attr_accessor :timestamp
|
595
561
|
|
596
562
|
#---------------------------------------------------------------------------
|
597
|
-
#
|
563
|
+
# all_messages
|
598
564
|
#
|
599
565
|
|
600
|
-
#
|
566
|
+
# Returns a locked array of all messages (including nested) or the given
|
567
|
+
# type.
|
601
568
|
|
602
|
-
def
|
603
|
-
|
604
|
-
|
605
|
-
|
569
|
+
def all_messages(plural, id)
|
570
|
+
rv = []
|
571
|
+
|
572
|
+
# add own messages
|
573
|
+
if @hsh[plural]
|
574
|
+
if id
|
575
|
+
@hsh[plural].each do |m|
|
576
|
+
if m['id'] == id
|
577
|
+
rv.push m
|
578
|
+
end
|
579
|
+
end
|
580
|
+
else
|
581
|
+
rv += @hsh[plural]
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
# recurse
|
586
|
+
as_arr('nested').each do |child|
|
587
|
+
rv += child.send(plural, id)
|
588
|
+
end
|
589
|
+
|
590
|
+
# freeze return value
|
591
|
+
rv.freeze
|
592
|
+
|
593
|
+
# return
|
594
|
+
return rv
|
606
595
|
end
|
607
596
|
#
|
608
|
-
#
|
597
|
+
# all_messages
|
609
598
|
#---------------------------------------------------------------------------
|
610
599
|
|
611
600
|
|
612
601
|
#---------------------------------------------------------------------------
|
613
|
-
#
|
602
|
+
# messages_hash
|
614
603
|
#
|
615
|
-
|
604
|
+
|
605
|
+
# Returns a hash of the messages (including nested) of the given type. The
|
606
|
+
# keys to the hash are the message ids. Does not return messages that don't
|
607
|
+
# have ids.
|
608
|
+
|
609
|
+
def messages_hash(type)
|
616
610
|
rv = {}
|
617
611
|
|
618
|
-
#
|
619
|
-
|
620
|
-
|
612
|
+
# add own messages
|
613
|
+
as_arr(type).each do |msg|
|
614
|
+
if msg['id']
|
615
|
+
rv[msg['id']] ||= []
|
616
|
+
rv[msg['id']].push msg
|
617
|
+
end
|
621
618
|
end
|
622
619
|
|
623
|
-
#
|
624
|
-
|
625
|
-
|
620
|
+
# loop through nested children
|
621
|
+
as_arr('nested').each do |child|
|
622
|
+
child.send("#{type}_hash").each do |k, msgs|
|
623
|
+
rv[k] ||= []
|
624
|
+
rv[k] += msgs
|
625
|
+
end
|
626
|
+
end
|
626
627
|
|
627
628
|
# return
|
628
629
|
return rv
|
629
630
|
end
|
630
631
|
#
|
631
|
-
#
|
632
|
+
# messages_hash
|
632
633
|
#---------------------------------------------------------------------------
|
633
634
|
end
|
634
635
|
#
|
635
|
-
# Xeme
|
636
|
-
#===============================================================================
|
637
|
-
|
638
|
-
|
639
|
-
#===============================================================================
|
640
|
-
# Xeme::Exception
|
641
|
-
#
|
642
|
-
|
643
|
-
# Xeme::Exception is a subclass of StandardError and can be used exactly like a
|
644
|
-
# StandardError object. The one addition to StandardError is the `xeme` property
|
645
|
-
# which holds a Xeme object. Don't instantiate this class directly; use
|
646
|
-
# Xeme#new_exception.
|
647
|
-
|
648
|
-
class Xeme::Exception < StandardError
|
649
|
-
attr_reader :xeme # a xeme object
|
650
|
-
|
651
|
-
#---------------------------------------------------------------------------
|
652
|
-
# initialize
|
653
|
-
#
|
654
|
-
def initialize(error_code, xeme)
|
655
|
-
@error_code = error_code
|
656
|
-
@xeme = xeme
|
657
|
-
super @error_code
|
658
|
-
end
|
659
|
-
#
|
660
|
-
# initialize
|
661
|
-
#---------------------------------------------------------------------------
|
662
|
-
end
|
663
|
-
#
|
664
|
-
# Xeme::Exception
|
665
|
-
#===============================================================================
|
636
|
+
# Xeme
|
637
|
+
#===============================================================================
|