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