lorj 0.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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.gitreview +4 -0
  4. data/Gemfile +25 -0
  5. data/Gemfile.lock +34 -0
  6. data/LICENSE.txt +14 -0
  7. data/README.md +652 -0
  8. data/Rakefile +24 -0
  9. data/bin/cloud_test.rb +81 -0
  10. data/example/students_1/process/Students.rb +20 -0
  11. data/example/students_1/students.rb +16 -0
  12. data/example/students_2/process/Students.rb +27 -0
  13. data/example/students_2/students.rb +36 -0
  14. data/example/students_3/controller/yaml_students.rb +94 -0
  15. data/example/students_3/controller/yaml_students_controller.rb +123 -0
  16. data/example/students_3/process/students.rb +118 -0
  17. data/example/students_3/students.rb +93 -0
  18. data/example/students_4/controller/yaml_students.rb +82 -0
  19. data/example/students_4/controller/yaml_students_controller.rb +141 -0
  20. data/example/students_4/process/students.rb +112 -0
  21. data/example/students_4/students.rb +103 -0
  22. data/example/yaml_students/students.rb +78 -0
  23. data/example/yaml_students/yaml_students.rb +115 -0
  24. data/lib/concept.md +111 -0
  25. data/lib/core/core.rb +723 -0
  26. data/lib/core/definition.rb +505 -0
  27. data/lib/core/definition_internal.rb +338 -0
  28. data/lib/core/lorj-basecontroller.rb +90 -0
  29. data/lib/core/lorj-basedefinition.rb +1079 -0
  30. data/lib/core/lorj-baseprocess.rb +231 -0
  31. data/lib/core/lorj-data.rb +567 -0
  32. data/lib/core/lorj-keypath.rb +115 -0
  33. data/lib/core_process/CloudProcess.rb +334 -0
  34. data/lib/core_process/global_process.rb +406 -0
  35. data/lib/core_process/network_process.rb +603 -0
  36. data/lib/img/.directory +4 -0
  37. data/lib/img/account_data_access.png +0 -0
  38. data/lib/img/config_data_access.png +0 -0
  39. data/lib/img/forj-lib-concept.png +0 -0
  40. data/lib/lorj/version.rb +3 -0
  41. data/lib/lorj.rb +51 -0
  42. data/lib/prc-account.rb +339 -0
  43. data/lib/prc-config.rb +1023 -0
  44. data/lib/prc-logging.rb +183 -0
  45. data/lib/prc.rb +108 -0
  46. data/lib/providers/hpcloud/Hpcloud.rb +419 -0
  47. data/lib/providers/hpcloud/compute.rb +108 -0
  48. data/lib/providers/hpcloud/network.rb +117 -0
  49. data/lib/providers/hpcloud/security_groups.rb +67 -0
  50. data/lib/providers/mock/Mock.rb +141 -0
  51. data/lib/providers/openstack/Openstack.rb +47 -0
  52. data/lib/providers/templates/compute.rb +42 -0
  53. data/lib/providers/templates/core.rb +61 -0
  54. data/lib/providers/templates/network.rb +33 -0
  55. data/lorj-spec/defaults.yaml +26 -0
  56. data/lorj.gemspec +39 -0
  57. data/spec/forj-account_spec.rb +75 -0
  58. data/spec/forj-config_spec.rb +196 -0
  59. metadata +164 -0
@@ -0,0 +1,567 @@
1
+ # (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Module Lorj which contains several classes.
16
+ #
17
+ # Those classes describes :
18
+ # - processes (BaseProcess) : How to create/delete/edit/query object.
19
+ # - controler (BaseControler) : If a provider is defined, define how will do object creation/etc...
20
+ # - definition(BaseDefinition): Functions to declare objects, query/data mapping and setup
21
+ # this task to make it to work.
22
+ module Lorj
23
+ # This class is the Data object used by lorj object!
24
+ # This is a key component of lorj
25
+ #
26
+ # You find this object in different places.
27
+ #
28
+ # type:
29
+ # - object/data : The Data object contains any kind of data.
30
+ # This data contains 2 elements:
31
+ # - controler object : This is a ruby object managed by the controller.
32
+ # Only the controller has the knowledge to manage this kind of data.
33
+ # - attributes : This is the internal data mapping from the controller object.
34
+ # The controller helped to build this data thanks to the BaseController.get_attr / BaseController.set_attr
35
+ # Attributes are declared by the Data model in BaseDefinition. At least usually, each object has 2 attributes: :id and :name
36
+ #
37
+ # - list : The Data object contains a list of Lorj::Data
38
+ #
39
+ # If the object is of type :list, following functions are usable:
40
+ #
41
+ # - length : return numbers of Lorj::Data
42
+ # - each / each_index : loop on the list, key/value or key_index. yield can return 'remove' to remove the element from the list during loop.
43
+ #
44
+ # If the Data object is of type :data or :object or even :list, following functions are usable.
45
+ #
46
+ # - set/[]=/get/[]/exist? : Basic get/set/exist? feature.
47
+ # - type?/object_type? : Determine the type of this object. ie :data (stands for :object as well) or :list
48
+ # - to_a : Array of Data attributes
49
+ # - empty? nil? : Identify if the object is empty. Avoid to use nil?.
50
+ # - register/unregister : Used by Lorj::BaseDefinition internal @ObjectData.
51
+ # registered? : Determine if this object is stored in the global object cache.
52
+
53
+ class Lorj::Data
54
+
55
+ # Initialize Lorj::Data object
56
+ #
57
+ # * *Args* :
58
+ # - +oType+ : default is :object
59
+ # Support :data/:object for single object data
60
+ # :list for a list of object data
61
+ #
62
+ # * *Returns* :
63
+ # hash - internal data object.
64
+ #
65
+ # * *Raises* :
66
+ # No exceptions
67
+ #
68
+ def initialize(oType = :object)
69
+ oType = :data if not [:list, :object, :data].include?(oType)
70
+ @oType = oType
71
+ case oType
72
+ when :data, :object
73
+ @data = new_object
74
+ when :list
75
+ @data = new_object_list
76
+ end
77
+ end
78
+
79
+ # Return Lorj::Data object type
80
+ #
81
+ # * *Args* :
82
+ # Nothing
83
+ #
84
+ # * *Returns* :
85
+ # - +type+ : Symbol or nil
86
+ # nil if no object.
87
+ # :object for single object data
88
+ # :list for a list of object data
89
+ #
90
+ # * *Raises* :
91
+ # No exceptions
92
+ #
93
+ def type?()
94
+ @oType
95
+ end
96
+
97
+ # Return :object type of the Lorj::Data object.
98
+ #
99
+ # * *Args* :
100
+ # Nothing
101
+ #
102
+ # * *Returns* :
103
+ # - +type+ : Symbol or nil
104
+ # nil if no object.
105
+ # :object type
106
+ #
107
+ # * *Raises* :
108
+ # No exceptions
109
+ #
110
+ def object_type?()
111
+ @data[:object_type]
112
+ end
113
+
114
+ # Set a Lorj::Data object and return itself.
115
+ #
116
+ # There 3 usages:
117
+ # - Set from a Lorj::Data.
118
+ # ex: if data is already a Lorj::Data,
119
+ # copy = Lorj::Data.new()
120
+ # copy.set(data)
121
+ # - Set from an object, not Lorj::Data and not a list.
122
+ # ex:
123
+ # data = { :test => 'toto'}
124
+ # copy = Lorj::Data.new()
125
+ # copy.set(data, :object) { |oObject |
126
+ # oObject
127
+ # }
128
+ # - Set from a list of objects, not Lorj::Data and not a :object.
129
+ # ex:
130
+ # data = [{ :name => 'toto'}, {:name => 'test'}]
131
+ # copy = Lorj::Data.new()
132
+ # copy.set(data, :list, { :name => /^t/ }) { |oObject |
133
+ # oObject
134
+ # }
135
+ #
136
+ # * *Args* :
137
+ # - +data+ : Lorj::Data or any other data.
138
+ # - +ObjType: required only if data is not a Lorj::Data
139
+ # Use :object to store and extract attributes
140
+ # Use :list to extract elements, store them and extract attributes for each of them. data must support each(oObject) loop function
141
+ # - +Query+ : Optional. To store the query object used to get the list objects. It assumes ObjectType = :list
142
+ # - +yield+ : code to extract +data+ attributes from the object (:object or :list). Should return an hash containing attributes data.
143
+ #
144
+ # * *Returns* :
145
+ # - +self+ : Lorj::Data
146
+ #
147
+ # * *Raises* :
148
+ # No exceptions
149
+ #
150
+ def set(oObj, sObjType = nil, hQuery = {})
151
+ if oObj.is_a?(Lorj::Data)
152
+ oType = oObj.type?
153
+ case oType
154
+ when :data, :object
155
+ @data[:object_type] = ((sObjType.nil?)? (oObj.object_type?) : sObjType)
156
+ @data[:object] = oObj.get(:object)
157
+ @data[:attrs] = oObj.get(:attrs)
158
+ when :list
159
+ @data[:object_type] = ((sObjType.nil?)? (oObj.object_type?) : sObjType)
160
+ @data[:object] = oObj.get(:object)
161
+ @data[:list] = oObj.get(:list)
162
+ @data[:query] = oObj.get(:query)
163
+ end
164
+ return self
165
+ end
166
+
167
+ # while saving the object, a mapping work is done?
168
+ case @oType
169
+ when :data, :object
170
+ @data[:object_type] = sObjType
171
+ @data[:object] = oObj
172
+ @data[:attrs] = yield(sObjType, oObj)
173
+ when :list
174
+ @data[:object] = oObj
175
+ @data[:object_type] = sObjType
176
+ @data[:query] = hQuery
177
+ unless oObj.nil?
178
+ begin
179
+ oObj.each { | oObject |
180
+ next if oObject.nil?
181
+ begin
182
+ oDataObject = Lorj::Data.new(:object)
183
+
184
+ oDataObject.set(oObject, sObjType) { |sObjectType, oObject|
185
+ yield(sObjectType, oObject)
186
+ }
187
+ @data[:list] << oDataObject
188
+ rescue => e
189
+ raise Lorj::PrcError.new(), "'%s' Mapping attributes issue.\n%s" % [sObjType, e.message]
190
+ end
191
+ }
192
+ rescue => e
193
+ raise Lorj::PrcError.new(), "each function is not supported by '%s'.\n%s" % [oObj.class, e.message]
194
+ end
195
+ end
196
+ end
197
+ self
198
+ end
199
+
200
+ # Set the :object type
201
+ #
202
+ # * *Args* :
203
+ # - +ObjType: required only if data is not a Lorj::Data
204
+ #
205
+ # * *Returns* :
206
+ # - +self+ : Lorj::Data
207
+ #
208
+ # * *Raises* :
209
+ # No exceptions
210
+ #
211
+ def type=(sObjType)
212
+ return self if self.empty?
213
+ @data[:object_type] = sObjType
214
+ self
215
+ end
216
+
217
+ # Get value from Lorj::data
218
+ #
219
+ # * *Args* :
220
+ # - +keys+: See get function.
221
+ #
222
+ # * *Returns* :
223
+ # - +self+ : Lorj::Data
224
+ #
225
+ # * *Raises* :
226
+ # No exceptions
227
+ #
228
+ def [](*key)
229
+ get(*key)
230
+ end
231
+
232
+ # Set Lorj::data attribute value for an :object
233
+ #
234
+ # * *Args* :
235
+ # - +keys+ : attribute keys
236
+ # - +value+: Value to set
237
+ #
238
+ # * *Returns* :
239
+ # true
240
+ #
241
+ # * *Raises* :
242
+ # No exceptions
243
+ #
244
+ def []=(*key, value)
245
+ return false if @oType == :list
246
+ Lorj::rhSet(@data, value, :attrs, key)
247
+ true
248
+ end
249
+
250
+ # Get value from Lorj::data
251
+ # Depending on Lorj::Data type, you can get:
252
+ # - :object
253
+ # - get internal object data (:object)
254
+ # ex: object = data[:object]
255
+ # - get attribute data
256
+ # ex:
257
+ # data = { :name => 'toto'}
258
+ # copy = Lorj::Data.new()
259
+ # copy.set(data, :object) { |oObject |
260
+ # {:real_name => oObject[:name]}
261
+ # }
262
+ #
263
+ # puts copy[:name] # => nil
264
+ # puts copy[:real_name] # => 'toto'
265
+ # puts copy[:object] # => { :name => 'toto'}
266
+ # puts copy[:attrs] # => { :real_name => 'toto'}
267
+ # - :list
268
+ # - get internal object data (:object)
269
+ # ex: object = data[:object]
270
+ # - get stored query object data (:query)
271
+ # ex: object = data[:query]
272
+ # - get one element attribute or object data
273
+ # ex:
274
+ # data = [{ :name => 'toto'}, {:name => 'test'}]
275
+ # copy = Lorj::Data.new()
276
+ # copy.set(data, :list, { :name => /^t/ }) { |oObject |
277
+ # {:real_name => oObject[:name]}
278
+ # }
279
+ #
280
+ # puts copy[0] # => { :real_name => 'toto'}
281
+ # puts copy[0][:object] # => { :name => 'toto'}
282
+ # puts copy[0][:attrs] # => { :real_name => 'toto'}
283
+ # puts copy[1] # => { :real_name => 'test'}
284
+ # puts copy[1, :real_name] # => 'test'
285
+ # puts copy[1, :test] # => nil
286
+ #
287
+ # * *Args* :
288
+ # - +keys+: See get function.
289
+ #
290
+ # * *Returns* :
291
+ # - +self+ : Lorj::Data
292
+ #
293
+ # * *Raises* :
294
+ # No exceptions
295
+ #
296
+ def get(*key)
297
+ return @data if key.length == 0
298
+ case @oType
299
+ when :data, :object # Return only attrs or the real object.
300
+ return @data[key[0]] if key[0] == :object
301
+ return Lorj::rhGet(@data, key) if key[0] == :attrs
302
+ Lorj::rhGet(@data, :attrs, key)
303
+ when :list
304
+ return @data[key[0]] if [:object, :query].include?(key[0])
305
+ return @data[:list][key[0]] if key.length == 1
306
+ @data[:list][key[0]][key[1..-1]] # can Return only attrs or the real object.
307
+ end
308
+ end
309
+
310
+ # Get the list of elements in an array from Lorj::Data :list type.
311
+ #
312
+ # * *Args* :
313
+ # No parameters
314
+ #
315
+ # * *Returns* :
316
+ # - +Elements+ : Array of elements
317
+ #
318
+ # * *Raises* :
319
+ # No exceptions
320
+ #
321
+ def to_a()
322
+ result = []
323
+ self.each { |elem|
324
+ result<< elem[:attrs]
325
+ }
326
+ result
327
+ end
328
+
329
+ # return true if a data object exist or if an extracted attribute exist.
330
+ #
331
+ # * *Args* :
332
+ # - +keys+ : Keys to verify.
333
+ #
334
+ # * *Returns* :
335
+ # - +exist?+ : true or false.
336
+ #
337
+ # * *Raises* :
338
+ # No exceptions
339
+ #
340
+ # Examples:
341
+ # data = Lorj::Data.new()
342
+ #
343
+ # puts data.exist?(:object) # => false
344
+ #
345
+ # data.set({ :name => 'toto'}, :object) { |oObject |
346
+ # {:real_name => oObject[:name]}
347
+ # }
348
+ # list = Lorj::Data.new()
349
+ #
350
+ # puts data.exist?(:object) # => false
351
+ #
352
+ # list.set([{ :name => 'toto'}, {:name => 'test'}], :list) { |oObject |
353
+ # {:real_name => oObject[:name]}
354
+ # }
355
+ #
356
+ # puts data.exist?(:object) # => true
357
+ # puts data.exist?(:name) # => true
358
+ # puts data.exist?(:test) # => false
359
+ # puts data.exist?(:attrs, :name) # => true
360
+ # puts list.exist?(0) # => true
361
+ # puts list.exist?(0, :object) # => true
362
+ # puts list.exist?(2) # => false
363
+ # puts list.exist?(2, :object) # => false
364
+ # puts list.exist?(0, :name) # => true
365
+ # puts list.exist?(0, :test) # => false
366
+ def exist?(*key)
367
+ case @oType
368
+ when :data, :object
369
+ return true if key[0] == :object and @data.key?(key[0])
370
+ return true if key[0] == :attrs and Lorj::rhExist?(@data, key)
371
+ (Lorj::rhExist?(@data, :attrs, key) == key.length+1)
372
+ when :list
373
+ return true if key[0] == :object and @data.key?(key[0])
374
+ (Lorj::rhExist?(@data[:list][key[0]], :attrs, key[1..-1]) == key.length)
375
+ end
376
+ end
377
+
378
+ # return true if the Lorj::Data object is nil.
379
+ #
380
+ # * *Args* :
381
+ # No parameters
382
+ #
383
+ # * *Returns* :
384
+ # - true/false
385
+ #
386
+ # * *Raises* :
387
+ # No exceptions
388
+ #
389
+ def empty?()
390
+ @data[:object].nil?
391
+ end
392
+
393
+ # Redefine nil? Warning! Can be confused. Cannot see if your object is simply nil or if current object is simply empty.
394
+ # Use empty? instead.
395
+ # A warning will be raised soon to ask developer to update it.
396
+ #
397
+ # * *Args* :
398
+ # No parameters
399
+ #
400
+ # * *Returns* :
401
+ # - true/false
402
+ #
403
+ # * *Raises* :
404
+ # No exceptions
405
+ #
406
+ def nil?()
407
+ # Obsolete Use empty? instead.
408
+ @data[:object].nil?
409
+ end
410
+
411
+ # return 0, 1 or N if the Lorj::Data object is nil.
412
+ # 0 if no objects stored
413
+ # 1 if an object exist even if type :object or :list
414
+ # >1 if a list is stored. It will give the number of elements in the list.
415
+ #
416
+ # * *Args* :
417
+ # No parameters
418
+ #
419
+ # * *Returns* :
420
+ # - >=0 : Number of elements
421
+ #
422
+ # * *Raises* :
423
+ # No exceptions
424
+ #
425
+ def length()
426
+ case @oType
427
+ when :data
428
+ return 0 if self.empty?
429
+ 1
430
+ when :list
431
+ @data[:list].length
432
+ end
433
+ end
434
+
435
+ # yield loop on a list
436
+ #
437
+ # * *Args* :
438
+ # - +yield+ : sAction = yield (elem), where action can :removed to remove the element from the list.
439
+ #
440
+ # * *Returns* :
441
+ # no values
442
+ #
443
+ # * *Raises* :
444
+ # No exceptions
445
+ #
446
+ def each(sData = :list)
447
+ to_remove = []
448
+ return nil if @oType != :list or not [:object, :list].include?(sData)
449
+
450
+ @data[:list].each { |elem|
451
+ sAction = yield (elem)
452
+ case sAction
453
+ when :remove
454
+ to_remove << elem
455
+ end
456
+ }
457
+ if to_remove.length > 0
458
+ to_remove.each { | elem |
459
+ @data[:list].delete(elem)
460
+ }
461
+ end
462
+ end
463
+
464
+ # yield loop on a list
465
+ #
466
+ # * *Args* :
467
+ # - +yield+ : sAction = yield (index), where action can :removed to remove the element from the list.
468
+ #
469
+ # * *Returns* :
470
+ # no values
471
+ #
472
+ # * *Raises* :
473
+ # No exceptions
474
+ #
475
+ def each_index(sData = :list)
476
+ to_remove = []
477
+ return nil if @oType != :list or not [:object, :list].include?(sData)
478
+
479
+ @data[:list].each_index { |iIndex|
480
+ sAction = yield (iIndex)
481
+ case sAction
482
+ when :remove
483
+ to_remove << @data[:list][iIndex]
484
+ end
485
+ }
486
+ if to_remove.length > 0
487
+ to_remove.each { | elem |
488
+ @data[:list].delete(elem)
489
+ }
490
+ end
491
+ end
492
+
493
+ # A Lorj::Data can be cached by Lorj::ObjectData.
494
+ # When adding Lorj::Data to Lorj::ObjectData, Lorj::Data object will be registered.
495
+ # This function will determine if this object is registered or not.
496
+ #
497
+ # * *Args* :
498
+ # none
499
+ #
500
+ # * *Returns* :
501
+ # - registered : true or false if registered or not
502
+ #
503
+ # * *Raises* :
504
+ # No exceptions
505
+ #
506
+ def registered?()
507
+ @bRegister
508
+ end
509
+
510
+ # A Lorj::Data can be cached by Lorj::ObjectData.
511
+ # When adding Lorj::Data to Lorj::ObjectData, Lorj::Data object will be registered.
512
+ # Lorj::ObjectData will call this function to marked it as registered.
513
+ #
514
+ # * *Args* :
515
+ # none
516
+ #
517
+ # * *Returns* :
518
+ # - self
519
+ #
520
+ # * *Raises* :
521
+ # No exceptions
522
+ #
523
+ def register()
524
+ @bRegister = true
525
+ self
526
+ end
527
+
528
+ # A Lorj::Data can be cached by Lorj::ObjectData.
529
+ # When adding Lorj::Data to Lorj::ObjectData, Lorj::Data object will be registered.
530
+ # Lorj::ObjectData will call this function to marked it as unregistered.
531
+ #
532
+ # * *Args* :
533
+ # none
534
+ #
535
+ # * *Returns* :
536
+ # - self
537
+ #
538
+ # * *Raises* :
539
+ # No exceptions
540
+ #
541
+ def unregister()
542
+ @bRegister = false
543
+ self
544
+ end
545
+ private
546
+
547
+ # Define minimal @data structure for a :list object type.
548
+ def new_object_list
549
+ {
550
+ :object => nil,
551
+ :object_type => nil,
552
+ :list => [],
553
+ :query => nil
554
+ }
555
+ end
556
+
557
+ # Define minimal @data structure for a :object object type.
558
+ def new_object
559
+ oCoreObject = {
560
+ :object_type => nil,
561
+ :attrs => {},
562
+ :object => nil,
563
+ }
564
+ end
565
+
566
+ end
567
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: UTF-8
2
+
3
+ # (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # Module Lorj which contains several classes.
18
+ #
19
+ # Those classes describes :
20
+ # - processes (BaseProcess) : How to create/delete/edit/query object.
21
+ # - controler (BaseControler) : If a provider is defined, define how will do object creation/etc...
22
+ # - definition(BaseDefinition): Functions to declare objects, query/data mapping and setup
23
+ # this task to make it to work.
24
+
25
+ module Lorj
26
+
27
+ # Class to handle key or keypath on needs
28
+ # The application configuration can configure a key tree, instead of a key.
29
+ # KeyPath is used to commonly handle key or key tree.
30
+ # Thus, a Keypath can be converted in different format:
31
+ #
32
+ # Ex:
33
+ # oKey = KeyPath(:test)
34
+ # puts oKey.to_s # => 'test'
35
+ # puts oKey.sKey # => :test
36
+ # puts oKey.sKey[0] # => :test
37
+ # puts oKey.sKey[1] # => nil
38
+ # puts oKey.sFullPath # => ':test'
39
+ # puts oKey.aTree # => [:test]
40
+ #
41
+ # oKey = KeyPath([:test,:test2,:test3])
42
+ # puts oKey.to_s # => 'test/test2/test3'
43
+ # puts oKey.sKey # => :test3
44
+ # puts oKey.sKey[0] # => :test
45
+ # puts oKey.sKey[1] # => :test2
46
+ # puts oKey.sFullPath # => ':test/:test2/:ẗest3'
47
+ # puts oKey.aTree # => [:test,:test2,:test3]
48
+ #
49
+ class KeyPath
50
+
51
+ def initialize(sKeyPath = nil)
52
+
53
+ @keypath = []
54
+ self.set sKeyPath
55
+ end
56
+
57
+ def key=(sKeyPath)
58
+ self.set(sKeyPath)
59
+ end
60
+
61
+ def set(sKeyPath)
62
+
63
+ if sKeyPath.is_a?(Symbol)
64
+ @keypath = [ sKeyPath]
65
+ elsif sKeyPath.is_a?(Array)
66
+ @keypath = sKeyPath
67
+ elsif sKeyPath.is_a?(String)
68
+ if /[^\\\/]?\/[^\/]/ =~ sKeyPath or /:[^:\/]/ =~ sKeyPath
69
+ # keypath to interpret
70
+ aResult = sKeyPath.split('/')
71
+ aResult.each_index { | iIndex |
72
+ next if not aResult[iIndex].is_a?(String)
73
+ aResult[iIndex] = aResult[iIndex][1..-1].to_sym if aResult[iIndex][0] == ":"
74
+ }
75
+ @keypath = aResult
76
+ else
77
+ @keypath = [sKeyPath]
78
+ end
79
+ end
80
+ end
81
+
82
+ def aTree()
83
+ @keypath
84
+ end
85
+
86
+ def sFullPath()
87
+ return nil if @keypath.length == 0
88
+ aKeyAccess = @keypath.clone
89
+ aKeyAccess.each_index { |iIndex|
90
+ next if not aKeyAccess[iIndex].is_a?(Symbol)
91
+ aKeyAccess[iIndex] = ":" + aKeyAccess[iIndex].to_s
92
+ }
93
+ aKeyAccess.join('/')
94
+ end
95
+
96
+ def to_s
97
+ return nil if @keypath.length == 0
98
+ aKeyAccess = @keypath.clone
99
+ aKeyAccess.each_index { |iIndex|
100
+ next if not aKeyAccess[iIndex].is_a?(Symbol)
101
+ aKeyAccess[iIndex] = aKeyAccess[iIndex].to_s
102
+ }
103
+ aKeyAccess.join('/')
104
+ end
105
+
106
+ def sKey(iIndex = -1)
107
+ return nil if @keypath.length == 0
108
+ @keypath[iIndex] if self.length >= 1
109
+ end
110
+
111
+ def length()
112
+ @keypath.length
113
+ end
114
+ end
115
+ end