lorj 1.0.9 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/example/students_1/process/students.rb +1 -1
  4. data/example/students_1/student_v1.md +2 -0
  5. data/example/students_1/students.rb +2 -1
  6. data/example/students_2/process/students.rb +1 -1
  7. data/example/students_2/students.rb +4 -2
  8. data/example/students_3/controller/yaml_students_def.rb +1 -1
  9. data/example/students_3/process/students.rb +1 -1
  10. data/example/students_3/student_v3.md +5 -3
  11. data/example/students_3/students.rb +5 -3
  12. data/example/students_4/controller/yaml_students_def.rb +1 -1
  13. data/example/students_4/process/students/definition/students.rb +1 -1
  14. data/example/students_4/students.rb +5 -3
  15. data/example/students_5/controller/yaml_students.rb +1 -1
  16. data/example/students_5/process/students.rb +1 -1
  17. data/example/students_5/student_v5.md +4 -4
  18. data/example/students_5/students.rb +8 -7
  19. data/example/yaml_students/students.rb +4 -4
  20. data/lib/core/core.rb +110 -64
  21. data/lib/core/core_internal.rb +110 -15
  22. data/lib/core/core_object_data.rb +4 -4
  23. data/lib/core/core_process_setup.rb +3 -30
  24. data/lib/core/lorj_data.rb +1 -1
  25. data/lib/core/lorj_keypath.rb +3 -1
  26. data/lib/core/process.rb +67 -0
  27. data/lib/lorj/version.rb +2 -1
  28. data/lib/lorj.rb +3 -4
  29. data/lib/lorj_account.rb +6 -5
  30. data/lib/lorj_config.rb +3 -2
  31. data/lib/providers/templates/compute.rb +1 -1
  32. data/lorj-spec/controllers/mock/mock.rb +144 -0
  33. data/lorj-spec/data.yaml +0 -0
  34. data/lorj-spec/process/mock2_process.rb +48 -0
  35. data/lorj-spec/process/mock_process.rb +48 -0
  36. data/lorj-spec/providers/mock2/mock2.rb +0 -0
  37. data/lorj.gemspec +2 -4
  38. data/spec/05_lorj_keypath_spec.rb +78 -0
  39. data/spec/20_lorj_meta_spec.rb +1 -1
  40. data/spec/21_lorj_processes_spec.rb +115 -0
  41. metadata +27 -42
  42. data/lib/core_process/cloud/process/common.rb +0 -60
  43. data/lib/core_process/cloud/process/connection.rb +0 -92
  44. data/lib/core_process/cloud/process/external_network.rb +0 -90
  45. data/lib/core_process/cloud/process/flavor.rb +0 -97
  46. data/lib/core_process/cloud/process/images.rb +0 -99
  47. data/lib/core_process/cloud/process/internet_network.rb +0 -33
  48. data/lib/core_process/cloud/process/internet_server.rb +0 -29
  49. data/lib/core_process/cloud/process/keypairs.rb +0 -332
  50. data/lib/core_process/cloud/process/network.rb +0 -107
  51. data/lib/core_process/cloud/process/public_ip.rb +0 -102
  52. data/lib/core_process/cloud/process/router.rb +0 -267
  53. data/lib/core_process/cloud/process/rules.rb +0 -120
  54. data/lib/core_process/cloud/process/security_groups.rb +0 -120
  55. data/lib/core_process/cloud/process/server.rb +0 -126
  56. data/lib/core_process/cloud/process/server_log.rb +0 -34
  57. data/lib/core_process/cloud/process/subnetwork.rb +0 -96
  58. data/lib/core_process/cloud_process.rb +0 -30
  59. data/lib/prc_base_config.rb +0 -300
  60. data/lib/prc_core_config.rb +0 -1258
  61. data/lib/prc_section_config.rb +0 -90
  62. data/lib/providers/hpcloud/compute.rb +0 -105
  63. data/lib/providers/hpcloud/hpcloud.rb +0 -462
  64. data/lib/providers/hpcloud/network.rb +0 -115
  65. data/lib/providers/hpcloud/security_groups.rb +0 -68
  66. data/lib/providers/openstack/openstack.rb +0 -410
  67. data/lib/providers/openstack/openstack_create.rb +0 -205
  68. data/lib/providers/openstack/openstack_delete.rb +0 -28
  69. data/lib/providers/openstack/openstack_get.rb +0 -39
  70. data/lib/providers/openstack/openstack_process.rb +0 -26
  71. data/lib/providers/openstack/openstack_query.rb +0 -96
  72. data/lib/providers/openstack/openstack_update.rb +0 -35
  73. data/lib/rh.rb +0 -426
  74. data/spec/01_hash_rh_spec.rb +0 -282
  75. data/spec/02_prc_base_config_spec.rb +0 -227
  76. data/spec/03_prc_section_config_spec.rb +0 -196
  77. data/spec/04_prc_core_config_spec.rb +0 -325
@@ -1,1258 +0,0 @@
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
- require 'yaml'
18
-
19
- module PRC
20
- # Internal CoreConfig functions
21
- class CoreConfig
22
- private
23
-
24
- # Function to initialize a predefined layer
25
- # Used internally by initialize_layers.
26
- def _initialize_layer(layer)
27
- newlayer = { :config => layer[:config], :name => layer[:name] }
28
- newlayer[:set] = layer[:set].boolean? ? layer[:set] : true
29
- newlayer[:load] = layer[:load].boolean? ? layer[:load] : false
30
- newlayer[:save] = layer[:save].boolean? ? layer[:save] : false
31
- newlayer[:file_set] = layer[:file_set].boolean? ? layer[:file_set] : false
32
- newlayer[:init] = true
33
- newlayer
34
- end
35
-
36
- # Check and returns values of options required and optionnal.
37
- #
38
- # * *Args*
39
- # - +options+ : options to extract information.
40
- # - +required+ : Array of required option keys.
41
- # - +optionnal+ : Array of optionnal option keys.
42
- #
43
- # * *Returns*
44
- # - nil if at least one required keys doesn't exist
45
- # - Array of combined required and optionnql values.
46
- #
47
- def _valid_options(options, required, optionnal = [])
48
- return nil unless options.is_a?(Hash)
49
- return nil unless required.is_a?(Array)
50
- optionnal = [] unless optionnal.is_a?(Array)
51
-
52
- result = [[], []]
53
-
54
- required.each do |key|
55
- return nil unless options.key?(key)
56
- result[0] << options[key]
57
- end
58
-
59
- optionnal.each { |key| result[1] << options[key] }
60
-
61
- result
62
- end
63
-
64
- # Internal function to call _common_options_get
65
- # It ensures and cleanup caller setting
66
- # :names and :indexes as those must be single values instead of
67
- # array. ie :name and :index is the only one supported.
68
- #
69
- def _nameindex_common_options_get(options, required = [], optionnal = [])
70
- options = {} if options.nil?
71
-
72
- # ensure :names or :indexes are not set. and clean it up if exists
73
- options.delete(:names) if options.key?(:names)
74
- options.delete(:indexes) if options.key?(:indexes)
75
-
76
- _common_options_get(options, required, optionnal)
77
- end
78
-
79
- # Take care of keys, indexes, names, index and name.
80
- # If names is found, it will replace indexes.
81
- # If name is found, it will replace index.
82
- # If index is found, it will replace indexes.
83
- def _common_options_get(options, required = [], optionnal = [])
84
- return nil unless options.is_a?(Hash)
85
- required = [] unless required.is_a?(Array)
86
- optionnal = [] unless optionnal.is_a?(Array)
87
-
88
- _convert_nameindex_to_arrays(options)
89
-
90
- result = _valid_options(options, required,
91
- [:indexes, :names,
92
- :data_options].concat(optionnal))
93
- return nil if result.nil?
94
- # result Array is structured as:
95
- # required [0] => [...]
96
- # optional [1] => [indexes, names, data_options, ...]
97
-
98
- # Following eliminates the optional :names (1) element
99
- _set_indexes result
100
- # required [0] => [...]
101
- # optional [1] => [indexes, data_options, ...]
102
- return nil if _keys_data_missing(options, required, result)
103
-
104
- # Following eliminates the optional :indexes (0) element
105
- # But add it as required in the Array, at pos 0
106
- _build_layers(result)
107
- # required [0] => [layers, ...]
108
- # optional [1] => [data_options, ...]
109
-
110
- # following eliminates the optional :data_options (0) element
111
- # But data_options is added in required Array, at pos 1.
112
- _set_data_opts(result)
113
- # required [0] => [layers, data_options, ...]
114
- # optional [1] => [...]
115
-
116
- result
117
- end
118
-
119
- # This internal function identify :name and :index
120
- # To replace to respectively to :names and :indexes
121
- def _convert_nameindex_to_arrays(options)
122
- options[:names] = [options.delete(:name)] if options.key?(:name)
123
- options[:indexes] = [options.delete(:index)] if options.key?(:index)
124
- end
125
-
126
- # This internal function checks if the :keys is required, then
127
- # The keys value HAVE to be an Array with at least one element.
128
- # It returns false, if :keys is not the first required field
129
- # or if the keys data (Array not empty) is confirmed.
130
- def _keys_data_missing(options, required, result)
131
- return false unless required[0] == :keys
132
-
133
- return true unless options.key?(:keys)
134
- return true unless result[0][0].is_a?(Array)
135
- return true if result[0][0].length == 0
136
- false
137
- end
138
-
139
- # Setting indexes from names or indexes.
140
- def _set_indexes(result)
141
- names_indexes = layer_indexes(result[1][1])
142
- # replaced indexes by names indexes if exists.
143
- result[1][0] = names_indexes if names_indexes
144
- result[1].delete_at(1)
145
- end
146
-
147
- def _set_data_opts(result)
148
- data_opts = []
149
-
150
- result[0][0].each_index do |layer_index|
151
- data_options = result[1][0][layer_index] if result[1][0].is_a?(Array)
152
- data_options = {} unless data_options.is_a?(Hash)
153
- data_opts << data_options
154
- end
155
- result[0].insert(1, data_opts)
156
-
157
- # And removing the optionnal :data_options
158
- result[1].delete_at(0)
159
- end
160
-
161
- def _build_layers(result)
162
- # Setting layers at required [0]
163
- if result[1][0].nil? || result[1][0].length == 0
164
- config_layers = @config_layers
165
- else
166
- config_layers = []
167
- result[1][0].each do |index|
168
- config_layers << @config_layers[index] if index.is_a?(Fixnum)
169
- end
170
- config_layers = @config_layers if config_layers.length == 0
171
- end
172
- result[0].insert(0, config_layers)
173
-
174
- # And removing the optionnal indexes
175
- result[1].delete_at(0)
176
- result
177
- end
178
-
179
- # Internal function to provide a result for #p_get.
180
- # This function is typically used by a Child Class.
181
- #
182
- # * *Args*
183
- # - +*keys+ : Array of keys.
184
- # - +layers+ : Array of config layers to get data to merge.
185
- # - +data_opts+ : Array of data options per layers
186
- # - +data_options+ : common data options for all layers
187
- # - +merge+ : True if need to get a merge result.
188
- #
189
- # * *Returns*
190
- # - Value, Hash merged or nil.
191
- #
192
- def _get_from_layers(keys, layers, data_opts, data_options, merge)
193
- result = nil
194
-
195
- # In merge case, we need to build from bottom to top
196
- if merge.is_a?(TrueClass)
197
- layers = layers.reverse
198
- data_opts = data_opts.reverse
199
- end
200
-
201
- layers.each_index do |layer_index|
202
- layer = layers[layer_index]
203
-
204
- data_options = data_options.merge(data_opts[layer_index])
205
-
206
- layer[:config].data_options(data_options)
207
-
208
- next unless layer[:config].exist?(*keys)
209
-
210
- return layer[:config][*keys] unless merge.is_a?(TrueClass)
211
-
212
- result = _get_build_merge(result, layer[:config][*keys])
213
- end
214
- result
215
- end
216
-
217
- # Return true if at least the first key value found is of type Hash/Array,
218
- # while be_exclusive is false
219
- # return true if at least one key value is NOT Hash or Array,
220
- # while be_exclusive is true
221
- #
222
- def _check_from_layers(keys, config_layers, data_opts, data_options,
223
- be_exclusive)
224
- found = false
225
- found_class = nil
226
- config_layers.each_index do |layer_index|
227
- layer = config_layers[layer_index]
228
-
229
- data_options = data_options.merge(data_opts[layer_index])
230
-
231
- layer[:config].data_options(data_options)
232
-
233
- next unless layer[:config].exist?(*keys)
234
-
235
- found_class = layer[:config][*keys].class
236
- found = [Hash, Array].include?(found_class)
237
- if be_exclusive
238
- return false unless found
239
- unless found_class && layer[:config][*keys].is_a?(found_class)
240
- return false
241
- end
242
- else
243
- return found
244
- end
245
- end
246
- true
247
- end
248
-
249
- # Internal function to provide a merge result for #_get_from_layers
250
- #
251
- # * *Args*
252
- # - +result+ : Cumulative Hash merged
253
- # - +data+ : data to merge
254
- #
255
- # * *Returns*
256
- # - Cloned Hash merged or simple data updated if possible.
257
- #
258
- def _get_build_merge(result, data)
259
- if [Hash, Array].include?(data.class) &&
260
- [Hash, Array].include?(result.class) && result.is_a?(data.class)
261
- return _do_merge(result, data)
262
- end
263
- _choose_data(result, data)
264
- end
265
-
266
- def _choose_data(result, data)
267
- if result.nil?
268
- return data.rh_clone if [Hash, Array].include?(data.class)
269
- return data
270
- end
271
-
272
- # return result as first one impose the type between Hash/Array.
273
- return result if [Hash, Array].include?(result.class) ||
274
- [Hash, Array].include?(data.class)
275
-
276
- data
277
- end
278
-
279
- # Internal function to do the merge result for #_get_build_merge
280
- #
281
- # * *Args*
282
- # - +result+ : Cumulative Hash merged
283
- # - +data+ : data to merge
284
- #
285
- # * *Returns*
286
- # - Cloned Hash merged.
287
- #
288
- def _do_merge(result, data)
289
- # data and result are of same type. Merge is possible.
290
- return result.merge!(data.rh_clone) if result.is_a?(Hash)
291
-
292
- result.each_index do |index|
293
- result[index] = _get_build_merge(result[index], data[index])
294
- end
295
- result
296
- end
297
- end
298
-
299
- # Internal core functions
300
- class CoreConfig
301
- # *****************************************************
302
-
303
- private
304
-
305
- # Del function called by default by del
306
- # This function is typically used by a Child Class.
307
- #
308
- # * *Args*
309
- # - +options+ : Hash of how to get the data
310
- # - +:keys+ : Array of key path to found
311
- # - +:name+ : layer to get data.
312
- # - +:index+ : layer index to get data.
313
- # If neither :name or :index is set, set will use the
314
- # highest layer
315
- # - +:data_opts+ : Array or Hash. Define data options per layer.
316
- #
317
- # * *Returns*
318
- # - The value attached to the key deleted.
319
- # OR
320
- # - nil can be returned for several reasons:
321
- # - value is nil
322
- # - keys is not an array
323
- # - keys array is empty.
324
- #
325
- # ex:
326
- # value = CoreConfig.New
327
- #
328
- # value[:level1, :level2] = 'value'
329
- # # => {:level1 => {:level2 => 'value'}}
330
- #
331
- # value.del(:keys => [:level1, :level2])
332
- # # => {:level1 => {}}
333
- def p_del(options) #:doc:
334
- parameters = _nameindex_common_options_get(options, [:keys])
335
- return nil if parameters.nil?
336
-
337
- config_layers, data_opts, keys = parameters[0]
338
-
339
- # get data options for level 0
340
- data_options = options.clone.merge!(data_opts[0])
341
-
342
- return nil if keys.length == 0
343
-
344
- data_options.delete_if do |key|
345
- [:keys, :names, :indexes, :name, :index].include?(key)
346
- end
347
-
348
- return nil unless @config_layers[0][:set]
349
-
350
- config_layers[0][:config].data_options(data_options)
351
- config_layers[0][:config].del(keys)
352
- end
353
-
354
- # p_file? Core file function called by default by #file.
355
- # This function is typically used by a Child Class.
356
- #
357
- # This function can be used by child class to set one layer file name
358
- #
359
- # * *Args*
360
- # - +options+ : Hash parameters
361
- # - +:name+ : layer to get data.
362
- # - +:index+ : Array layer indexes to get data.
363
- # If neither :name or :index is set, level 0 is used.
364
- #
365
- # * *Returns*
366
- # - filename : if updated.
367
- # OR
368
- # - false : if not updated.
369
- # OR
370
- # - nil : If something went wrong.
371
- #
372
- # ex:
373
- # { :test => {:titi => 'found'}}
374
- def p_file(filename = nil, options = {}) #:doc:
375
- parameters = _nameindex_common_options_get(options)
376
-
377
- return nil if parameters.nil?
378
-
379
- config_layers = parameters[0][0]
380
-
381
- layer = config_layers[0]
382
-
383
- return layer[:config].filename unless filename.is_a?(String)
384
-
385
- return false if _filename_unsetable(layer)
386
-
387
- layer[:config].filename = filename
388
- filename
389
- end
390
-
391
- def _filename_unsetable(layer)
392
- return true if !layer[:load] && !layer[:save]
393
-
394
- !layer[:config].filename.nil? && !layer[:file_set]
395
- end
396
-
397
- # p_exist? Core exist function called by default by #exist?.
398
- # This function is typically used by a Child Class.
399
- #
400
- # * *Args*
401
- # - +options+ : Hash parameters
402
- # - +:keys+ : key tree to check existence in config layers
403
- # - +:names+ : layer to get data.
404
- # - +:indexes+ : Array layer indexes to get data.
405
- # If neither :name or :index is set, get will search data
406
- # per layers priority.
407
- # - +:data_opts+ : Array or Hash. Define data options per layer.
408
- #
409
- # * *Returns*
410
- # - boolean : true if the key path was found
411
- #
412
- # ex:
413
- # # if one layer data is { :test => {:titi => 'found'}}
414
- # p_exist?(:keys => [:test]) # => true
415
- # p_exist?(:keys => [:test, :titi]) # => true
416
- # p_exist?(:keys => [:test1]) # => false
417
- #
418
- def p_exist?(options) #:doc:
419
- parameters = _common_options_get(options, [:keys])
420
- return nil if parameters.nil?
421
-
422
- config_layers, data_opts, keys = parameters[0]
423
-
424
- return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
425
-
426
- config_layers.each_index do |index|
427
- config = config_layers[index][:config]
428
-
429
- data_options = options.clone
430
- data_options.delete_if do |key|
431
- [:keys, :names, :indexes, :name, :index].include?(key)
432
- end
433
- data_options.merge!(data_opts[index])
434
-
435
- config.data_options(data_options)
436
- return true if config.exist?(*keys)
437
- end
438
- false
439
- end
440
-
441
- # p_where? called by default by #where
442
- # This function is typically used by a Child Class.
443
- #
444
- # * *args*
445
- # - +options+ : Hash parameters
446
- # - +:keys+ : key tree to check existence in config layers
447
- # - +:names+ : layer to get data.
448
- # - +:indexes+ : Array layer indexes to get data.
449
- # If neither :name or :index is set, get will search data
450
- # per layers priority.
451
- # - +:data_opts+ : Array or Hash. Define data options per layer.
452
- #
453
- # * *Returns*
454
- # - array of config name : list of first layers where the key was found.
455
- # OR
456
- # - nil can be returned for several reasons:
457
- # - keys is not an array
458
- # - keys array is empty.
459
- def p_where?(options) #:doc:
460
- parameters = _common_options_get(options, [:keys])
461
- return nil if parameters.nil?
462
-
463
- config_layers, data_opts, keys = parameters[0]
464
-
465
- return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
466
-
467
- _do_where?(config_layers, keys, options, data_opts)
468
- end
469
-
470
- def _do_where?(config_layers, keys, options, data_opts)
471
- layer_indexes = []
472
- config_layers.each_index do |index|
473
- config = config_layers[index][:config]
474
-
475
- data_options = options.clone
476
- data_options.delete_if do |key|
477
- [:keys, :names, :indexes, :name, :index].include?(key)
478
- end
479
- data_options.merge!(data_opts[index]) if data_opts[index].is_a?(Hash)
480
-
481
- config.data_options(data_options)
482
- layer_indexes << config_layers[index][:name] if config.exist?(keys)
483
- end
484
- return layer_indexes if layer_indexes.length > 0
485
- false
486
- end
487
-
488
- # Get function called by default by #[]
489
- # This function is typically used by a Child Class.
490
- #
491
- # * *Args*
492
- # - +options+ : Hash of how to get the data
493
- # - +:keys+ : Array of key path to found
494
- # - +:names+ : layer to get data.
495
- # - +:indexes+ : Array layer indexes to get data.
496
- # If neither :name or :index is set, get will search data
497
- # per layers priority.
498
- # - +:data_opts+ : Array or Hash. Define data options per layer.
499
- # - +:merge+ : Provide a Merged result instead of first found
500
- # returned.
501
- # The merge result depends on deep layer data type found.
502
- #
503
- # Ex:
504
- #
505
- # with 2 config layers, like 'top' and 'bottom', usually a get will
506
- # search in 'top', then 'bottom'. Merge will search in 'bottom'
507
- # first. Then:
508
- # - if 'bottom' value found is of type Hash(or Array),
509
- # p_get will return a Hash(or Array), merged accross upper layers
510
- # So, if 'top' is Hash(or Array), the result is the merge Hash
511
- # (or Array). Otherwise, the 'top' will be ignored.
512
- # - if 'bottom' value found is any kind of other types
513
- # p_get won't merge, but get the highest non Array/Hash data found
514
- # . So with a 'bottom' data of String, and 'top' as 'Fixnum', the
515
- # result will be Fixnum. If there is any Hash/Array in between, it
516
- # will be ignored.
517
- #
518
- # * *Returns*
519
- # value found (or Hash merged) or nil.
520
- #
521
- # nil can be returned for several reasons:
522
- # - keys is not an array
523
- # - keys array is empty.
524
- #
525
- def p_get(options) #:doc:
526
- parameters = _common_options_get(options, [:keys], [:merge])
527
- return nil if parameters.nil?
528
-
529
- # Required options : parameters[0]
530
- config_layers, data_opts, keys = parameters[0]
531
- # Optional options : parameters[1]
532
- merge = parameters[1][0]
533
-
534
- return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
535
-
536
- data_options = options.clone
537
- data_options.delete_if do |key|
538
- [:keys, :names, :indexes, :name, :index, :merge].include?(key)
539
- end
540
-
541
- _get_from_layers(keys,
542
- config_layers, data_opts, data_options,
543
- merge)
544
- end
545
-
546
- # Set function called by default by #[]=
547
- # This function is typically used by a Child Class.
548
- #
549
- # * *Args*
550
- # - +options+ : Hash of how to get the data
551
- # - +:value+: Value to set
552
- # - +:keys+ : Array of key path to found
553
- # - +:name+ : layer to get data.
554
- # - +:index+: layer index to get data.
555
- # If neither :name or :index is set, set will use the highest layer.
556
- # - +:data_opts+ : Array or Hash. Define data options per layer.
557
- #
558
- # * *Returns*
559
- # - The value set.
560
- # OR
561
- # - nil can be returned for several reasons:
562
- # - layer options :set is false
563
- # - options defines a :data_readonly to true.
564
- # - value is nil
565
- # - keys is not an array
566
- # - keys array is empty.
567
- #
568
- # ex:
569
- # value = CoreConfig.New
570
- #
571
- # value[:level1, :level2] = 'value'
572
- # # => {:level1 => {:level2 => 'value'}}
573
- def p_set(options) #:doc:
574
- parameters = _nameindex_common_options_get(options, [:keys, :value])
575
- return nil if parameters.nil?
576
-
577
- config_layers, data_opts, keys, value = parameters[0]
578
-
579
- # get data options for level 0
580
- data_options = options.clone.merge!(data_opts[0])
581
-
582
- return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
583
-
584
- data_options.delete_if do |key|
585
- [:keys, :names, :indexes, :name, :index, :value].include?(key)
586
- end
587
-
588
- return nil unless config_layers[0][:set]
589
-
590
- config_layer = config_layers[0][:config]
591
- config_layer.data_options(data_options)
592
- config_layer[keys] = value
593
- end
594
-
595
- # Load from a file called by default by load.
596
- # This function is typically used by a Child Class.
597
- #
598
- # * *Args* :
599
- # - +options+ : Supported options for load
600
- # - +:name+ : layer name to get data.
601
- # - +:index+ : layer index to get data.
602
- # If neither :name or :index is set, set will use the highest layer.
603
- #
604
- # * *Returns* :
605
- # - true : loaded
606
- # - false: not loaded. There are several possible reasons:
607
- # - input/output issue (normally raised)
608
- # - layer option :load is false.
609
- def p_load(options = {}) #:doc:
610
- options = {} if options.nil?
611
- options[:names] = [options[:name]] if options.key?(:name)
612
- options[:indexes] = [options[:index]] if options.key?(:index)
613
-
614
- parameters = _nameindex_common_options_get(options)
615
- return nil if parameters.nil?
616
-
617
- config_layers = parameters[0][0]
618
-
619
- return nil unless config_layers[0][:load]
620
-
621
- config_layers[0][:config].load
622
- end
623
-
624
- # Save to a file called by default by save
625
- # This function is typically used by a Child Class.
626
- #
627
- # * *Args* :
628
- # - +options+ : Supported options for save
629
- # - +:name+ : layer to get data.
630
- # - +:index+: layer index to get data.
631
- # If neither :name or :index is set, set will use the highest layer
632
- #
633
- # * *Returns* :
634
- # - true : saved
635
- # - false: not saved. There are several possible reasons:
636
- # - options defines a :file_readonly to true.
637
- # - input/output issue (normally raised)
638
- # - layer option :save is false.
639
- def p_save(options = {}) #:doc:
640
- options[:names] = [options[:name]] if options.key?(:name)
641
- options[:indexes] = [options[:index]] if options.key?(:index)
642
-
643
- parameters = _nameindex_common_options_get(options)
644
- return nil if parameters.nil?
645
-
646
- config_layers = parameters[0][0]
647
-
648
- return nil unless config_layers[0][:save]
649
-
650
- config_layers[0][:config].save
651
- end
652
- end
653
-
654
- # private functions usable by child classes
655
- class CoreConfig
656
- # initialize CoreConfig
657
- #
658
- # * *Args*
659
- # - +config_layers+ : Array config layers configuration.
660
- # Each layer options have those options:
661
- # - :config : optional. See `Defining Config layer instance` for
662
- # details
663
- # - :name : required. String. Name of the config layer.
664
- # Warning! unique name on layers is no tested.
665
- # - :set : boolean. True if authorized. Default is True.
666
- # - :load : boolean. True if authorized. Default is False.
667
- # - :save : boolean. True if authorized. Default is False.
668
- # - :file_set : boolean. True if authorized to update a filename.
669
- # Default is False.
670
- #
671
- # each layers can defines some options for the layer to behave differently
672
- # CoreConfig call a layer data_options to set some options, before
673
- # exist?, get or [], set or []=, save and load functions.
674
- # See BaseConfig::data_options for predefined options.
675
- #
676
- # Core config provides some private additionnal functions for
677
- # child class functions:
678
- # - #_set_data_options(layers, options) - To set data_options on one or
679
- # more config layers
680
- # - #p_get(options) - core get function
681
- # - #p_set(options) - core set function
682
- # - #p_save(options) core save function
683
- # - #p_load(options) - core load function
684
- #
685
- # if +config_layers+ is not provided, CoreConfig will instanciate a runtime
686
- # like system:
687
- #
688
- # config = CoreConfig.New
689
- # # is equivalent to :
690
- # config_layers = [{name: 'runtime',
691
- # config: PRC::BaseConfig.new, set: true}]
692
- # config = CoreConfig.New(config_layers)
693
- #
694
- # = Defining Config layer instance:
695
- #
696
- # :config value requires it to be of type 'BaseConfig'
697
- # By default, it uses `:config => PRC::BaseConfig.new`
698
- # Instead, you can set:
699
- # * directly BaseConfig. `:config => PRC::BaseConfig.new`
700
- # * a child based on BaseConfig. `:config => MyConfig.new`
701
- # * some predefined enhanced BaseConfig:
702
- # * PRC::SectionConfig. See prc_section_config.rb.
703
- # `:config => PRC::SectionConfig.new`
704
- #
705
- def initialize(config_layers = nil)
706
- if config_layers.nil?
707
- config_layers = []
708
- config_layers << CoreConfig.define_layer
709
- end
710
- initialize_layers(config_layers)
711
- end
712
-
713
- # This function add a config layer at runtime.
714
- # The new layer added at runtime, can be removed at runtime
715
- # with layer_remove
716
- # The name MUST be different than other existing config layer names
717
- #
718
- # *Args*
719
- # - +options+ : Hash data
720
- # - :name : Required. Name of the layer to add
721
- # - :index : Config position to use. 0 is the default. 0 is the first
722
- # Config layer use by get.
723
- # - :config : A Config instance of class type PRC::BaseConfig
724
- # - :set : Boolean. True if is authorized to set a variable.
725
- # - :load : Boolean. True if is authorized to load from a file.
726
- # - :save : Boolean. True if is authorized to save to a file.
727
- # - :file_set : Boolean. True if is authorized to change the file name.
728
- #
729
- # *returns*
730
- # - true if layer is added.
731
- # OR
732
- # - nil : if layer name already exist
733
- def layer_add(options)
734
- layer = CoreConfig.define_layer(options)
735
-
736
- layer[:init] = false # Runtime layer
737
-
738
- index = 0
739
- index = options[:index] if options[:index].is_a?(Fixnum)
740
- names = []
741
- @config_layers.each { |alayer| names << alayer[:name] }
742
-
743
- return nil if names.include?(layer[:name])
744
- @config_layers.insert(index, layer)
745
- true
746
- end
747
-
748
- # Function to remove a runtime layer.
749
- # You cannot remove a predefined layer, created during CoreConfig
750
- # instanciation.
751
- # *Args*
752
- # - +options+ : Hash data
753
- # - +:name+ : Name of the layer to remove.
754
- # - +:index+: Index of the layer to remove.
755
- #
756
- # At least, :name or :index is required.
757
- # If both; :name and :index are set, :name is used.
758
- # *return*
759
- # - true if layer name is removed.
760
- # OR
761
- # - nil : if not found or invalid.
762
- def layer_remove(options)
763
- index = layer_index(options[:name])
764
- index = options[:index] if index.nil?
765
-
766
- return nil if index.nil?
767
-
768
- layer = @config_layers[index]
769
-
770
- return nil if layer.nil? || layer[:init]
771
-
772
- @config_layers.delete_at(index)
773
- true
774
- end
775
-
776
- # Function to define layer options.
777
- # By default, :set is true and :config is attached to a new PRC::BaseConfig
778
- # instance.
779
- #
780
- # Supported options:
781
- # - :config : optional. See `Defining Config layer instance` for details
782
- # - :name : required. String. Name of the config layer.
783
- # Warning! unique name on layers is no tested.
784
- # - :set : boolean. True if authorized. Default is True.
785
- # - :load : boolean. True if authorized. Default is False.
786
- # - :save : boolean. True if authorized. Default is False.
787
- # - :file_set : boolean. True if authorized to update a filename.
788
- # Default is False.
789
- def self.define_layer(options = {})
790
- attributes = [:name, :config, :set, :load, :save, :file_set]
791
-
792
- layer = {}
793
-
794
- attributes.each do |attribute|
795
- if options.key?(attribute)
796
- layer[attribute] = options[attribute]
797
- else
798
- layer[attribute] = case attribute
799
- when :name
800
- 'runtime'
801
- when :config
802
- PRC::BaseConfig.new
803
- when :set
804
- true
805
- else
806
- false
807
- end
808
- end
809
- end
810
- layer
811
- end
812
-
813
- # layer_indexes function
814
- #
815
- # * *Args*
816
- # - +:name+ : layer to identify.
817
- #
818
- # * *Returns*
819
- # first index found or nil.
820
- #
821
- def layer_indexes(names)
822
- names = [names] if names.is_a?(String)
823
- return nil unless names.is_a?(Array)
824
-
825
- layers = []
826
-
827
- names.each do |name|
828
- index = layer_index(name)
829
- layers << index unless index.nil?
830
- end
831
- return layers if layers.length > 0
832
- nil
833
- end
834
-
835
- # layer_index function
836
- #
837
- # * *Args*
838
- # - +:name+ : layer to identify.
839
- #
840
- # * *Returns*
841
- # first index found or nil.
842
- #
843
- def layer_index(name)
844
- return nil unless name.is_a?(String)
845
- return nil if @config_layers.nil?
846
-
847
- @config_layers.each_index do |index|
848
- return index if @config_layers[index][:name] == name
849
- end
850
- nil
851
- end
852
-
853
- private
854
-
855
- # Function to initialize Config layers.
856
- # This function is typically used by a Child Class.
857
- #
858
- # * *Args*
859
- # - +config_layers+ : Array of config layers.
860
- # First layer is the deepest config object.
861
- # Last layer is the first config object queried.
862
- #
863
- # Ex: If we define 2 config layers:
864
- #
865
- # class Test << PRC::CoreConfig
866
- # def initialize
867
- # local = PRC::BaseConfig.new(:test => :found_local)
868
- # runtime = PRC::BaseConfig.new(:test => :found_runtime)
869
- # layers = []
870
- # layers << PRC::CoreConfig.define_layer(name: 'local',
871
- # config: local )
872
- # layers << PRC::CoreConfig.define_layer(name: 'runtime',
873
- # config: runtime )
874
- # initialize_layers(layers)
875
- # end
876
- # end
877
- #
878
- # config = Test.new
879
- #
880
- # p config[:test] # => :found_runtime
881
- #
882
- # config[:test] = "where?"
883
- # p config.where?(:test) # => ["runtime", "local"]
884
- #
885
- # config.del(:test)
886
- # p config.where?(:test) # => ["local"]
887
- # p config[:test] # => :found_local
888
- #
889
- # config[:test] = "and now?"
890
- # p config.where?(:test) # => ["runtime", "local"]
891
- #
892
- def initialize_layers(config_layers = nil) #:doc:
893
- @config_layers = []
894
-
895
- config_layers.each do |layer|
896
- next unless layer.is_a?(Hash) && layer.key?(:config) &&
897
- layer[:config].is_a?(BaseConfig)
898
- next unless layer[:name].is_a?(String)
899
- @config_layers << _initialize_layer(layer)
900
- end
901
- @config_layers.reverse!
902
- end
903
- end
904
-
905
- # This class implement The CoreConfig system of lorj.
906
- #
907
- # * You can use it directly. See ::new.
908
- # * you can enhance it with class heritage feature.
909
- # See Class child discussion later in this class documentation.
910
- #
911
- # = Public functions implemented:
912
- #
913
- # It implements several layer of CoreConfig object type
914
- # to provide several source of data in layers priorities.
915
- # Ex: RunTime => LocalConfig => AppDefault
916
- #
917
- # It implements config features:
918
- # * #[] - To get a value for a key or tree of keys
919
- # * #[]= - To set a Config value in the highest config.
920
- # * #del - To delete key or simply nil the value in highest config.
921
- # * #exist? - To check the existence of a value in config levels.
922
- # * #where? - To get the name of the level where the value was found.
923
- # * #file - To get or set a filename to a config layer.
924
- # * #save - To save one config data level in a yaml file.
925
- # * #load - To load data from a yaml file to a config data layer.
926
- # * #merge - To merge several layers data values. Values must be Hash.
927
- #
928
- # When the instance is initialized, it defines 3 Config layers (BaseConfig).
929
- #
930
- # If you need to define layers differently, consider to create your child
931
- # class. You will be able to use SectionConfig or even any BaseConfig Child
932
- # class as well.
933
- #
934
- # For details about a Config layers, See BaseConfig or SectionConfig.
935
- #
936
- # = Child Class implementation:
937
- #
938
- # This class can be enhanced with any kind of additional functionality.
939
- #
940
- # You can redefine following functions
941
- # exist?, [], []=, file, save, load, del, merge.
942
- #
943
- # Each public functions calls pendant function, private, prefixed by _, with
944
- # default options
945
- #
946
- # public => private
947
- # * #exist? => #p_exist?
948
- # * #[] => #p_get
949
- # * #[]= => #p_set
950
- # * #file => #p_file
951
- # * #save => #p_save
952
- # * #load => #p_load
953
- # * #del => #p_del
954
- # * #merge => #p_get(:merge => true).
955
- #
956
- # == Examples:
957
- #
958
- # * Your child class can limit or re-organize config layers to query.
959
- # Use :indexes or :names options to select which layer you want to query
960
- # and call the core function.
961
- #
962
- # Ex: If you have 4 config levels and want to limit to 2 top ones
963
- #
964
- # def [](*keys)
965
- # options = { keys: keys}
966
- # options[:indexes] = [0, 1]
967
- # p_get(options)
968
- # end
969
- #
970
- # Ex: If you have 4 config levels and want to limit to 2 names.
971
- #
972
- # def [](*keys)
973
- # options = { keys: keys}
974
- # options[:names] = ['local', 'default_app']
975
- # p_get(options)
976
- # end
977
- #
978
- # * Your child class can force some levels options or define some extra
979
- # options.
980
- #
981
- # Use :data_options to define each of them
982
- #
983
- # # Ex: If your class has 4 levels. /:name is not updatable for level 1.
984
- #
985
- # def [](*keys)
986
- # options = { keys: keys }
987
- # # The following defines data_readonly for the config level 1
988
- # if keys[0] == :name
989
- # options[:data_options] = [nil, {data_readonly: true}]
990
- # end
991
- # p_get(options)
992
- # end
993
- #
994
- # # Ex: if some layer takes care of option :section, and apply to each
995
- # # layers.
996
- # def [](section, *keys)
997
- # options = { keys: keys, section: section }
998
- # p_get(options)
999
- # end
1000
- #
1001
- # # Ex: if some layer takes care of option :section, and to apply to some
1002
- # # layers, like layer 1 and 2. (Assume with 4 layers.)
1003
- #
1004
- # def [](section, *keys)
1005
- # options = { keys: keys }
1006
- # options[:data_options] = [nil, {section: section}, {section: section}]
1007
- # p_get(options)
1008
- # end
1009
- #
1010
- #
1011
- class CoreConfig
1012
- # exist?
1013
- #
1014
- # * *Args*
1015
- # - +keys+ : Array of key path to found
1016
- #
1017
- # * *Returns*
1018
- # - boolean : true if the key path was found
1019
- #
1020
- # Class child:
1021
- # A class child can redefine this function to increase default
1022
- # features.
1023
- #
1024
- def exist?(*keys)
1025
- p_exist?(:keys => keys)
1026
- end
1027
-
1028
- # where?
1029
- #
1030
- # * *Args*
1031
- # - +keys+ : Array of key path to found
1032
- #
1033
- # * *Returns*
1034
- # - boolean : true if the key path was found
1035
- #
1036
- def where?(*keys)
1037
- p_where?(:keys => keys)
1038
- end
1039
-
1040
- # Get function
1041
- #
1042
- # * *Args*
1043
- # - +keys+ : Array of key path to found
1044
- #
1045
- # * *Returns*
1046
- # value found or nil.
1047
- #
1048
- def [](*keys)
1049
- p_get(:keys => keys)
1050
- end
1051
-
1052
- # Merge function
1053
- # Compare to get, merge will extract all values from each layers
1054
- # If those values are found and are type of Hash, merge will merge
1055
- # each layers values from the bottom to the top layer.
1056
- # ie invert of CoreConfig.layers
1057
- #
1058
- # Note that if a layer contains a data, but not Hash, this layer
1059
- # will be ignored.
1060
- #
1061
- # * *Args*
1062
- # - +keys+ : Array of key path to found
1063
- #
1064
- # * *Returns*
1065
- # value found merged or nil.
1066
- #
1067
- def merge(*keys)
1068
- p_get(:keys => keys, :merge => true)
1069
- end
1070
-
1071
- # Set function
1072
- #
1073
- # * *Args*
1074
- # - +keys+ : Array of key path to found
1075
- # * *Returns*
1076
- # - The value set or nil
1077
- #
1078
- # ex:
1079
- # value = CoreConfig.New
1080
- #
1081
- # value[:level1, :level2] = 'value'
1082
- # # => {:level1 => {:level2 => 'value'}}
1083
- def []=(*keys, value)
1084
- p_set(:keys => keys, :value => value)
1085
- end
1086
-
1087
- # Del function
1088
- #
1089
- # * *Args*
1090
- # - +keys+ : Array of key path to found and delete the last element.
1091
- # * *Returns*
1092
- # - The Hash updated.
1093
- #
1094
- # ex:
1095
- # value = CoreConfig.New
1096
- #
1097
- # value[:level1, :level2] = 'value'
1098
- # # => {:level1 => {:level2 => 'value'}}
1099
- # {:level1 => {:level2 => 'value'}}.del(:level1, :level2)
1100
- # # => {:level1 => {}}
1101
- def del(*keys)
1102
- p_del(:keys => keys)
1103
- end
1104
-
1105
- # Load from a file to the highest layer or a specific layer.
1106
- #
1107
- # * *Args* :
1108
- # - +options+ : Supported options for load
1109
- # - +:name+ : layer to get data.
1110
- # - +:index+: layer index to get data.
1111
- # If neither :name or :index is set, set will use the highest
1112
- # layer
1113
- #
1114
- # * *Returns* :
1115
- # -
1116
- # * *Raises* :
1117
- # - ++ ->
1118
- def load(options = {})
1119
- p_load(options)
1120
- end
1121
-
1122
- # Save to a file
1123
- #
1124
- # * *Args* :
1125
- # - +options+ : Supported options for save
1126
- # - +:name+ : layer to get data.
1127
- # - +:index+: layer index to get data.
1128
- # If neither :name or :index is set, set will use the highest
1129
- # layer
1130
- #
1131
- # * *Returns* :
1132
- # -
1133
- def save(options = {})
1134
- p_save(options)
1135
- end
1136
-
1137
- # Get/Set the file name.
1138
- #
1139
- # * *Args*
1140
- # - +:file+ : file name for the layer identified.
1141
- # - +options+ : Supported options for save
1142
- # - +:index+: layer index to get data.
1143
- # - +:name+ : layer to get data.
1144
- # If neither :name or :index is set, nil is returned.
1145
- #
1146
- # * *Returns*
1147
- # - The file name.
1148
- def file(filename = nil, options = {})
1149
- p_file(filename, options)
1150
- end
1151
-
1152
- # Function to check if merge can be used on a key.
1153
- # merge can return data only if at least one key value accross layers
1154
- # are of type Hash or Array.
1155
- # * *Args*
1156
- # - +options+ : Hash of how to get the data
1157
- # - +:value+ : Value to set
1158
- # - +:keys+ : Array of key path to found
1159
- # - +:name+ : layer to get data.
1160
- # - +:index+ : layer index to get data.
1161
- # If neither :name or :index is set, set will use the highest layer.
1162
- # - +:data_opts+ : Array or Hash. Define data options per layer.
1163
- # - +:exclusive+ : true to ensure values found are exclusively Hash or
1164
- # Array
1165
- #
1166
- def mergeable?(options)
1167
- parameters = _common_options_get(options, [:keys], [:exclusive])
1168
- return nil if parameters.nil?
1169
-
1170
- # Required options : parameters[0]
1171
- config_layers, data_opts, keys = parameters[0]
1172
- # Optional options : parameters[1]
1173
- be_exclusive = parameters[1][0]
1174
-
1175
- # Merge is done in the reverse order. ie from deepest to top.
1176
- config_layers = config_layers.reverse
1177
-
1178
- return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
1179
-
1180
- data_options = options.clone
1181
- data_options.delete_if do |key|
1182
- [:keys, :names, :indexes, :name, :index, :merge].include?(key)
1183
- end
1184
-
1185
- _check_from_layers(keys, config_layers, data_opts, data_options,
1186
- be_exclusive)
1187
- end
1188
-
1189
- # Function to get the version of a config layer name.
1190
- # * *Args*
1191
- # - +:name+ : layer to get data.
1192
- #
1193
- def version(name)
1194
- return nil unless name.is_a?(String)
1195
-
1196
- index = layer_index(name)
1197
- return nil if index.nil?
1198
-
1199
- @config_layers[index][:config].version
1200
- end
1201
-
1202
- # Function to set the version of a config layer name.
1203
- # * *Args*
1204
- # - +:name+ : layer to set data version.
1205
- #
1206
- def version_set(name, version)
1207
- return nil unless name.is_a?(String) && version.is_a?(String)
1208
-
1209
- index = layer_index(name)
1210
- return nil if index.nil?
1211
-
1212
- @config_layers[index][:config].version = version
1213
- end
1214
-
1215
- # List all config layers defined in this instance.
1216
- def layers
1217
- result = []
1218
- @config_layers.each { |layer| result << layer[:name] }
1219
- result
1220
- end
1221
-
1222
- # Display in human format.
1223
- def to_s
1224
- data = "Configs list ordered:\n"
1225
- @config_layers.each do |layer|
1226
- data += format("---- Config : %s ----\noptions: ", layer[:name])
1227
-
1228
- data += 'predefined, ' if layer[:init].is_a?(TrueClass)
1229
- if layer[:set]
1230
- data += 'data RW '
1231
- else
1232
- data += 'data RO '
1233
- end
1234
- data += format(", %s\n", to_s_file_opts(layer))
1235
-
1236
- data += format("%s\n", layer[:config].to_s)
1237
- end
1238
- data
1239
- end
1240
-
1241
- private
1242
-
1243
- def to_s_file_opts(layer)
1244
- data = 'File '
1245
- if layer[:load] &&
1246
- if layer[:save]
1247
- data += 'RW'
1248
- else
1249
- data += 'RO'
1250
- end
1251
- data += ', filename updatable' if layer[:file_set]
1252
- else
1253
- data += 'None'
1254
- end
1255
- data
1256
- end
1257
- end
1258
- end