lorj 0.2.0 → 1.0.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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +46 -0
  4. data/Gemfile +15 -15
  5. data/README.md +22 -17
  6. data/Rakefile +12 -2
  7. data/bin/cloud_test.rb +13 -65
  8. data/example/students_1/process/students.rb +39 -0
  9. data/example/students_1/students.rb +22 -5
  10. data/example/students_2/process/students.rb +48 -0
  11. data/example/students_2/students.rb +39 -16
  12. data/example/students_3/controller/yaml_students.rb +50 -43
  13. data/example/students_3/controller/yaml_students_controller.rb +100 -87
  14. data/example/students_3/process/students.rb +161 -97
  15. data/example/students_3/students.rb +85 -56
  16. data/example/yaml_students/students.rb +40 -40
  17. data/example/yaml_students/yaml_students.rb +103 -90
  18. data/lib/core/core.rb +356 -696
  19. data/lib/core/core_controller.rb +227 -0
  20. data/lib/core/core_internal.rb +339 -0
  21. data/lib/core/core_model.rb +328 -0
  22. data/lib/core/core_object_data.rb +330 -0
  23. data/lib/core/core_object_params.rb +230 -0
  24. data/lib/core/core_process.rb +391 -0
  25. data/lib/core/core_process_setup.rb +353 -0
  26. data/lib/core/core_setup_ask.rb +241 -0
  27. data/lib/core/core_setup_encrypt.rb +146 -0
  28. data/lib/core/core_setup_init.rb +229 -0
  29. data/lib/core/core_setup_list.rb +160 -0
  30. data/lib/core/definition.rb +647 -469
  31. data/lib/core/definition_internal.rb +264 -308
  32. data/lib/core/lorj_basecontroller.rb +95 -0
  33. data/lib/core/lorj_basedefinition.rb +307 -0
  34. data/lib/core/lorj_baseprocess.rb +265 -0
  35. data/lib/core/lorj_data.rb +583 -0
  36. data/lib/core/lorj_keypath.rb +119 -0
  37. data/lib/core_process/cloud/process/common.rb +63 -0
  38. data/lib/core_process/cloud/process/connection.rb +93 -0
  39. data/lib/core_process/cloud/process/external_network.rb +94 -0
  40. data/lib/core_process/cloud/process/flavor.rb +99 -0
  41. data/lib/core_process/cloud/process/images.rb +87 -0
  42. data/lib/core_process/cloud/process/internet_network.rb +34 -0
  43. data/lib/core_process/cloud/process/internet_server.rb +30 -0
  44. data/lib/core_process/cloud/process/keypairs.rb +276 -0
  45. data/lib/core_process/cloud/process/network.rb +108 -0
  46. data/lib/core_process/cloud/process/public_ip.rb +100 -0
  47. data/lib/core_process/cloud/process/router.rb +260 -0
  48. data/lib/core_process/cloud/process/rules.rb +120 -0
  49. data/lib/core_process/cloud/process/security_groups.rb +121 -0
  50. data/lib/core_process/cloud/process/server.rb +127 -0
  51. data/lib/core_process/cloud/process/server_log.rb +35 -0
  52. data/lib/core_process/cloud/process/subnetwork.rb +108 -0
  53. data/lib/core_process/cloud_process.rb +30 -0
  54. data/lib/logging.rb +298 -0
  55. data/lib/lorj/version.rb +18 -1
  56. data/lib/lorj.rb +58 -18
  57. data/lib/lorj_account.rb +556 -0
  58. data/lib/lorj_config.rb +468 -0
  59. data/lib/lorj_defaults.rb +278 -0
  60. data/lib/prc.rb +136 -104
  61. data/lib/prc_base_config.rb +285 -0
  62. data/lib/prc_core_config.rb +878 -0
  63. data/lib/prc_section_config.rb +57 -0
  64. data/lib/providers/hpcloud/compute.rb +81 -93
  65. data/lib/providers/hpcloud/hpcloud.rb +462 -0
  66. data/lib/providers/hpcloud/network.rb +96 -98
  67. data/lib/providers/hpcloud/security_groups.rb +41 -40
  68. data/lib/providers/mock/mock.rb +144 -0
  69. data/lib/providers/openstack/openstack.rb +45 -0
  70. data/lib/providers/templates/compute.rb +21 -23
  71. data/lib/providers/templates/mycloud.rb +72 -0
  72. data/lib/providers/templates/network.rb +11 -12
  73. data/lib/rh.rb +339 -0
  74. data/lorj-spec/defaults.yaml +4 -0
  75. data/lorj.gemspec +6 -0
  76. data/spec/00_lorj_log_spec.rb +53 -0
  77. data/spec/01_hash_rh_spec.rb +243 -0
  78. data/spec/02_prc_base_config_spec.rb +216 -0
  79. data/spec/04_prc_core_config_spec.rb +83 -0
  80. data/spec/11_lorj_config_spec.rb +263 -0
  81. data/spec/12_lorj_account_spec.rb +181 -0
  82. metadata +76 -28
  83. data/Gemfile.lock +0 -37
  84. data/example/students_1/process/Students.rb +0 -20
  85. data/example/students_2/process/Students.rb +0 -27
  86. data/example/students_4/controller/yaml_students.rb +0 -82
  87. data/example/students_4/controller/yaml_students_controller.rb +0 -141
  88. data/example/students_4/process/students.rb +0 -112
  89. data/example/students_4/students.rb +0 -103
  90. data/lib/core/lorj-basecontroller.rb +0 -90
  91. data/lib/core/lorj-basedefinition.rb +0 -1139
  92. data/lib/core/lorj-baseprocess.rb +0 -236
  93. data/lib/core/lorj-data.rb +0 -567
  94. data/lib/core/lorj-keypath.rb +0 -115
  95. data/lib/core_process/CloudProcess.rb +0 -337
  96. data/lib/core_process/global_process.rb +0 -502
  97. data/lib/core_process/network_process.rb +0 -605
  98. data/lib/prc-account.rb +0 -339
  99. data/lib/prc-config.rb +0 -1030
  100. data/lib/prc-logging.rb +0 -261
  101. data/lib/providers/hpcloud/Hpcloud.rb +0 -426
  102. data/lib/providers/mock/Mock.rb +0 -141
  103. data/lib/providers/openstack/Openstack.rb +0 -47
  104. data/lib/providers/templates/core.rb +0 -61
  105. data/spec/forj-account_spec.rb +0 -75
  106. data/spec/forj-config_spec.rb +0 -196
@@ -0,0 +1,878 @@
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
+ # This class implement The CoreConfig system of lorj.
21
+ #
22
+ # * You can use it directly. See PRC::CoreConfig.initialize.
23
+ # * you can enhance it with class heritage feature.
24
+ # See Class child discussion later in this class documentation.
25
+ #
26
+ # It implements several layer of CoreConfig object type
27
+ # to provide several source of data in layers priorities.
28
+ # Ex: RunTime => LocalConfig => AppDefault
29
+ #
30
+ # It implements config features:
31
+ # * [] - To get a value for a key or tree of keys
32
+ # * []= - To set a Config value in the highest config.
33
+ # * del - To delete key or simply nil the value in highest config.
34
+ # * exist? - To check the existence of a value in config levels.
35
+ # * where? - To get the name of the level where the value was found.
36
+ # * file - To get or set a filename to a config layer.
37
+ # * save - To save one config data level in a yaml file.
38
+ # * load - To load data from a yaml file to a config data layer.
39
+ #
40
+ # It implements Config Layer settings at init time.
41
+ # See initialize(config_layers)
42
+ #
43
+ # For details about Config data management, See BaseConfig.
44
+ #
45
+ # Child Class:
46
+ # ------------
47
+ #
48
+ # This class can be enhanced with any kind of additional functionality.
49
+ #
50
+ # You can redefine following functions:
51
+ # exist?, [], []=, file, save, load, del.
52
+ #
53
+ # * Your child class can limit or re-organize config layers to query.
54
+ # Use :indexes or :names options to select which layer you want to query
55
+ # and call the core function.
56
+ #
57
+ # Ex: If you have 4 config levels and want to limit to 2 top ones
58
+ #
59
+ # def [](*keys)
60
+ # options = { keys: keys}
61
+ # options[:indexes] = [0, 1]
62
+ # _get(options)
63
+ # end
64
+ #
65
+ # Ex: If you have 4 config levels and want to limit to 2 names.
66
+ #
67
+ # def [](*keys)
68
+ # options = { keys: keys}
69
+ # options[:names] = ['local', 'default_app']
70
+ # _get(options)
71
+ # end
72
+ #
73
+ # * Your child class can force some levels options.
74
+ # Use :data_options to define each of them
75
+ #
76
+ # Ex: If your class has 4 levels. /:name is not updatable for level 1.
77
+ #
78
+ # def [](*keys)
79
+ # options = { keys: keys }
80
+ # # The following defines data_readonly for the config level 1
81
+ # if keys[0] == :name
82
+ # options[:data_options] = [nil, {data_readonly: true}]
83
+ # end
84
+ # _get(options)
85
+ # end
86
+ #
87
+ #
88
+ #
89
+ #
90
+ #
91
+ class CoreConfig
92
+ # exist?
93
+ #
94
+ # * *Args*
95
+ # - +keys+ : Array of key path to found
96
+ #
97
+ # * *Returns*
98
+ # - boolean : true if the key path was found
99
+ #
100
+ # Class child:
101
+ # A class child can redefine this function to increase default
102
+ # features.
103
+ #
104
+ def exist?(*keys)
105
+ _exist?(:keys => keys)
106
+ end
107
+
108
+ # where?
109
+ #
110
+ # * *Args*
111
+ # - +keys+ : Array of key path to found
112
+ #
113
+ # * *Returns*
114
+ # - boolean : true if the key path was found
115
+ #
116
+ def where?(*keys)
117
+ _where?(:keys => keys)
118
+ end
119
+
120
+ # Get function
121
+ #
122
+ # * *Args*
123
+ # - +keys+ : Array of key path to found
124
+ #
125
+ # * *Returns*
126
+ # value found or nil.
127
+ #
128
+ def [](*keys)
129
+ _get(:keys => keys)
130
+ end
131
+
132
+ # Set function
133
+ #
134
+ # * *Args*
135
+ # - +keys+ : Array of key path to found
136
+ # * *Returns*
137
+ # - The value set or nil
138
+ #
139
+ # ex:
140
+ # value = CoreConfig.New
141
+ #
142
+ # value[:level1, :level2] = 'value'
143
+ # # => {:level1 => {:level2 => 'value'}}
144
+ def []=(*keys, value)
145
+ _set(:keys => keys, :value => value)
146
+ end
147
+
148
+ # Del function
149
+ #
150
+ # * *Args*
151
+ # - +keys+ : Array of key path to found and delete the last element.
152
+ # * *Returns*
153
+ # - The Hash updated.
154
+ #
155
+ # ex:
156
+ # value = CoreConfig.New
157
+ #
158
+ # value[:level1, :level2] = 'value'
159
+ # # => {:level1 => {:level2 => 'value'}}
160
+ # {:level1 => {:level2 => 'value'}}.del(:level1, :level2)
161
+ # # => {:level1 => {}}
162
+ def del(*keys)
163
+ _del(:keys => keys)
164
+ end
165
+
166
+ # Load from a file to the highest layer or a specific layer.
167
+ #
168
+ # * *Args* :
169
+ # - +options+ : Supported options for load
170
+ # - +:name+ : layer to get data.
171
+ # - +:index+: layer index to get data.
172
+ # If neither :name or :index is set, set will use the highest
173
+ # layer
174
+ #
175
+ # * *Returns* :
176
+ # -
177
+ # * *Raises* :
178
+ # - ++ ->
179
+ def load(options = {})
180
+ _load(options)
181
+ end
182
+
183
+ # Save to a file
184
+ #
185
+ # * *Args* :
186
+ # - +options+ : Supported options for save
187
+ # - +:name+ : layer to get data.
188
+ # - +:index+: layer index to get data.
189
+ # If neither :name or :index is set, set will use the highest
190
+ # layer
191
+ #
192
+ # * *Returns* :
193
+ # -
194
+ def save(options = {})
195
+ _save(options)
196
+ end
197
+
198
+ # Get/Set the file name.
199
+ #
200
+ # * *Args*
201
+ # - +:file+ : file name for the layer identified.
202
+ # - +options+ : Supported options for save
203
+ # - +:index+: layer index to get data.
204
+ # - +:name+ : layer to get data.
205
+ # If neither :name or :index is set, nil is returned.
206
+ #
207
+ # * *Returns*
208
+ # - The file name.
209
+ def file(filename = nil, options = {})
210
+ _file(filename, options)
211
+ end
212
+
213
+ def layers
214
+ result = []
215
+ @config_layers.each { | layer | result << layer[:name] }
216
+ result
217
+ end
218
+
219
+ def to_s
220
+ data = "Configs list ordered:\n"
221
+ @config_layers.each do | layer |
222
+ data += format("---- Config : %s ----\noptions: ", layer[:name])
223
+
224
+ if layer[:set]
225
+ data += 'data RW '
226
+ else
227
+ data += 'data RO '
228
+ end
229
+ data += format(", %s\n", to_s_file_opts(layer))
230
+
231
+ data += format("%s\n", layer[:config].to_s)
232
+ end
233
+ data
234
+ end
235
+
236
+ private
237
+
238
+ def to_s_file_opts(layer)
239
+ data = 'File '
240
+ if layer[:load] &&
241
+ if layer[:save]
242
+ data += 'RW'
243
+ else
244
+ data += 'RO'
245
+ end
246
+ data += ', filename updatable' if layer[:file_set]
247
+ else
248
+ data += 'None'
249
+ end
250
+ data
251
+ end
252
+
253
+ def _file_common_options_get(options)
254
+ options = {} if options.nil?
255
+ options[:names] = [options[:name]] if options.key?(:name)
256
+ options[:indexes] = [options[:index]] if options.key?(:index)
257
+
258
+ _common_options_get(options)
259
+ end
260
+ end
261
+
262
+ # Internal core functions
263
+ class CoreConfig
264
+ # *****************************************************
265
+
266
+ private
267
+
268
+ # *****************************************************
269
+
270
+ # _file? Core file function called by default by file.
271
+ #
272
+ # This function can be used by child class to set one layer file name
273
+ #
274
+ # * *Args*
275
+ # - +options+ : Hash parameters
276
+ # - +:name+ : layer to get data.
277
+ # - +:index+ : Array layer indexes to get data.
278
+ # If neither :name or :index is set, level 0 is used.
279
+ #
280
+ # * *Returns*
281
+ # - filename : if updated.
282
+ # OR
283
+ # - false : if not updated.
284
+ # OR
285
+ # - nil : If something went wrong.
286
+ #
287
+ # ex:
288
+ # { :test => {:titi => 'found'}}
289
+ def _file(filename = nil, options = {})
290
+ parameters = _file_common_options_get(options)
291
+
292
+ return nil if parameters.nil?
293
+
294
+ config_layers = parameters[0][0]
295
+
296
+ layer = config_layers[0]
297
+
298
+ return layer[:config].filename unless filename.is_a?(String)
299
+
300
+ return false if _filename_unsetable(layer)
301
+
302
+ layer[:config].filename = filename
303
+ filename
304
+ end
305
+
306
+ def _filename_unsetable(layer)
307
+ return true if !layer[:load] && !layer[:save]
308
+
309
+ !layer[:config].filename.nil? && !layer[:file_set]
310
+ end
311
+
312
+ # _exist? Core exist function called by default by exist?.
313
+ #
314
+ # * *Args*
315
+ # - +options+ : Hash parameters
316
+ # - +:keys+ : key tree to check existence in config layers
317
+ # - +:names+ : layer to get data.
318
+ # - +:indexes+ : Array layer indexes to get data.
319
+ # If neither :name or :index is set, get will search data
320
+ # per layers priority.
321
+ # - +:data_opts+ : Array or Hash. Define data options per layer.
322
+ #
323
+ # * *Returns*
324
+ # - boolean : true if the key path was found
325
+ #
326
+ # ex:
327
+ # { :test => {:titi => 'found'}}
328
+ def _exist?(options)
329
+ parameters = _common_options_get(options, [:keys])
330
+ return nil if parameters.nil?
331
+
332
+ config_layers, data_opts, keys = parameters[0]
333
+
334
+ return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
335
+
336
+ config_layers.each_index do | index |
337
+ config = @config_layers[index][:config]
338
+
339
+ data_options = options.clone
340
+ data_options.delete_if do |key|
341
+ [:keys, :names, :indexes, :name, :index].include?(key)
342
+ end
343
+ data_options.merge!(data_opts[index])
344
+
345
+ config.data_options(data_options)
346
+ return true if config.exist?(*keys)
347
+ end
348
+ false
349
+ end
350
+
351
+ # _where? called by default by where
352
+ #
353
+ # - +options+ : Hash parameters
354
+ # - +:keys+ : key tree to check existence in config layers
355
+ # - +:names+ : layer to get data.
356
+ # - +:indexes+ : Array layer indexes to get data.
357
+ # If neither :name or :index is set, get will search data
358
+ # per layers priority.
359
+ # - +:data_opts+ : Array or Hash. Define data options per layer.
360
+ #
361
+ # * *Returns*
362
+ # - array of config name : list of first layers where the key was found.
363
+ # OR
364
+ # - nil can be returned for several reasons:
365
+ # - keys is not an array
366
+ # - keys array is empty.
367
+
368
+ #
369
+ # ex:
370
+ # { :test => {:titi => 'found'}}
371
+ def _where?(options)
372
+ parameters = _common_options_get(options, [:keys])
373
+ return nil if parameters.nil?
374
+
375
+ config_layers, data_opts, keys = parameters[0]
376
+
377
+ return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
378
+
379
+ _do_where?(config_layers, keys, options, data_opts)
380
+ end
381
+
382
+ def _do_where?(config_layers, keys, options, data_opts)
383
+ layer_indexes = []
384
+ config_layers.each_index do | index |
385
+ config = @config_layers[index][:config]
386
+
387
+ data_options = options.clone
388
+ data_options.delete_if do |key|
389
+ [:keys, :names, :indexes, :name, :index].include?(key)
390
+ end
391
+ data_options.merge!(data_opts[index]) if data_opts[index].is_a?(Hash)
392
+
393
+ config.data_options(data_options)
394
+ layer_indexes << @config_layers[index][:name] if config.exist?(keys)
395
+ end
396
+ return layer_indexes if layer_indexes.length > 0
397
+ false
398
+ end
399
+ # Get function called by default by []
400
+ #
401
+ # * *Args*
402
+ # - +options+ : Hash of how to get the data
403
+ # - +:keys+ : Array of key path to found
404
+ # - +:names+ : layer to get data.
405
+ # - +:indexes+ : Array layer indexes to get data.
406
+ # If neither :name or :index is set, get will search data
407
+ # per layers priority.
408
+ # - +:data_opts+ : Array or Hash. Define data options per layer.
409
+ #
410
+ # * *Returns*
411
+ # value found or nil.
412
+ # nil can be returned for several reasons:
413
+ # - keys is not an array
414
+ # - keys array is empty.
415
+ #
416
+ def _get(options)
417
+ parameters = _common_options_get(options, [:keys])
418
+ return nil if parameters.nil?
419
+
420
+ config_layers, data_opts, keys = parameters[0]
421
+
422
+ return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
423
+
424
+ config_layers.each_index do | layer_index |
425
+ layer = config_layers[layer_index]
426
+
427
+ data_options = options.clone
428
+ data_options.delete_if do |key|
429
+ [:keys, :names, :indexes, :name, :index].include?(key)
430
+ end
431
+ data_options = data_options.merge!(data_opts[layer_index])
432
+
433
+ layer[:config].data_options(data_options)
434
+ return layer[:config][*keys] if layer[:config].exist?(*keys)
435
+ end
436
+ nil
437
+ end
438
+
439
+ # Set function called by default by []=
440
+ #
441
+ # * *Args*
442
+ # - +options+ : Hash of how to get the data
443
+ # - +:value+: Value to set
444
+ # - +:keys+ : Array of key path to found
445
+ # - +:name+ : layer to get data.
446
+ # - +:index+: layer index to get data.
447
+ # If neither :name or :index is set, set will use the highest
448
+ # layer
449
+ # - +:data_opts+ : Array or Hash. Define data options per layer.
450
+ #
451
+ # * *Returns*
452
+ # - The value set.
453
+ # OR
454
+ # - nil can be returned for several reasons:
455
+ # - layer options :set is false
456
+ # - options defines a :data_readonly to true.
457
+ # - value is nil
458
+ # - keys is not an array
459
+ # - keys array is empty.
460
+ #
461
+ # ex:
462
+ # value = CoreConfig.New
463
+ #
464
+ # value[:level1, :level2] = 'value'
465
+ # # => {:level1 => {:level2 => 'value'}}
466
+ def _set(options)
467
+ parameters = _common_options_get(options, [:keys, :value])
468
+ return nil if parameters.nil?
469
+
470
+ config_layers, data_opts, keys, value = parameters[0]
471
+
472
+ # get data options for level 0
473
+ data_options = options.clone.merge!(data_opts[0])
474
+
475
+ return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
476
+
477
+ data_options.delete_if do |key|
478
+ [:keys, :names, :indexes, :name, :index, :value].include?(key)
479
+ end
480
+
481
+ return nil unless @config_layers[0][:set]
482
+
483
+ config_layer = config_layers[0][:config]
484
+ config_layer.data_options(data_options)
485
+ config_layer[keys] = value
486
+ end
487
+
488
+ # Del function called by default by del
489
+ #
490
+ # * *Args*
491
+ # - +options+ : Hash of how to get the data
492
+ # - +:keys+ : Array of key path to found
493
+ # - +:name+ : layer to get data.
494
+ # - +:index+ : layer index to get data.
495
+ # If neither :name or :index is set, set will use the
496
+ # highest layer
497
+ # - +:data_opts+ : Array or Hash. Define data options per layer.
498
+ #
499
+ # * *Returns*
500
+ # - The value attached to the key deleted.
501
+ # OR
502
+ # - nil can be returned for several reasons:
503
+ # - value is nil
504
+ # - keys is not an array
505
+ # - keys array is empty.
506
+ #
507
+ # ex:
508
+ # value = CoreConfig.New
509
+ #
510
+ # value[:level1, :level2] = 'value'
511
+ # # => {:level1 => {:level2 => 'value'}}
512
+ #
513
+ # value.del(:keys => [:level1, :level2])
514
+ # # => {:level1 => {}}
515
+ def _del(options)
516
+ parameters = _common_options_get(options, [:keys])
517
+ return nil if parameters.nil?
518
+
519
+ config_layers, data_opts, keys = parameters[0]
520
+
521
+ # get data options for level 0
522
+ data_options = options.clone.merge!(data_opts[0])
523
+
524
+ return nil if keys.length == 0
525
+
526
+ data_options.delete_if do |key|
527
+ [:keys, :names, :indexes, :name, :index].include?(key)
528
+ end
529
+
530
+ return nil unless @config_layers[0][:set]
531
+
532
+ config_layers[0][:config].data_options(data_options)
533
+ config_layers[0][:config].del(keys)
534
+ end
535
+
536
+ # Load from a file called by default by load.
537
+ #
538
+ # * *Args* :
539
+ # - +options+ : Supported options for load
540
+ # - +:name+ : layer name to get data.
541
+ # - +:index+ : layer index to get data.
542
+ # If neither :name or :index is set, set will use the highest
543
+ # layer.
544
+ #
545
+ # * *Returns* :
546
+ # - true : loaded
547
+ # - false: not loaded. There are several possible reasons:
548
+ # - input/output issue (normally raised)
549
+ # - layer option :load is false.
550
+ def _load(options = {})
551
+ options = {} if options.nil?
552
+ options[:names] = [options[:name]] if options.key?(:name)
553
+ options[:indexes] = [options[:index]] if options.key?(:index)
554
+
555
+ parameters = _file_common_options_get(options)
556
+ return nil if parameters.nil?
557
+
558
+ config_layers = parameters[0][0]
559
+
560
+ return nil unless config_layers[0][:load]
561
+
562
+ config_layers[0][:config].load
563
+ end
564
+
565
+ # Save to a file called by default by save
566
+ #
567
+ # * *Args* :
568
+ # - +options+ : Supported options for save
569
+ # - +:name+ : layer to get data.
570
+ # - +:index+: layer index to get data.
571
+ # If neither :name or :index is set, set will use the highest
572
+ # layer
573
+ #
574
+ # * *Returns* :
575
+ # - true : saved
576
+ # - false: not saved. There are several possible reasons:
577
+ # - options defines a :file_readonly to true.
578
+ # - input/output issue (normally raised)
579
+ # - layer option :save is false.
580
+ def _save(options = {})
581
+ options[:names] = [options[:name]] if options.key?(:name)
582
+ options[:indexes] = [options[:index]] if options.key?(:index)
583
+
584
+ parameters = _file_common_options_get(options)
585
+ return nil if parameters.nil?
586
+
587
+ config_layers = parameters[0][0]
588
+
589
+ return nil unless config_layers[0][:save]
590
+
591
+ config_layers[0][:config].save
592
+ end
593
+ end
594
+
595
+ # Internal functions
596
+ class CoreConfig
597
+ # initialize CoreConfig
598
+ #
599
+ # * *Args*
600
+ # - +config_layers+ : Array config layers configuration.
601
+ # Each layer options have those options:
602
+ # - :config : optional. See `Defining Config layer instance` for details
603
+ # - :name : required. String. Name of the config layer.
604
+ # Warning! unique name on layers is no tested.
605
+ # - :set : boolean. True if authorized. Default is True.
606
+ # - :load : boolean. True if authorized. Default is False.
607
+ # - :save : boolean. True if authorized. Default is False.
608
+ # - :file_set : boolean. True if authorized to update a filename.
609
+ # Default is False.
610
+ #
611
+ # each layers can defines some options for the layer to behave differently
612
+ # CoreConfig call a layer data_options to set some options, before
613
+ # exist?, get or [], set or []=, save and load functions.
614
+ # See BaseConfig::data_options for predefined options.
615
+ #
616
+ # Core config provides some private additionnal functions for
617
+ # child class functions:
618
+ # - _set_data_options(layers, options) - To set data_options on one or
619
+ # more config layers
620
+ # - _get(options) - core get function
621
+ # - _set(options) - core set function
622
+ # - _save(options) - core save function
623
+ # - _load(options) - core load function
624
+ #
625
+ # if +config_layers+ is not provided, CoreConfig will instanciate a runtime
626
+ # like system:
627
+ # config = CoreConfig.New
628
+ # # is equivalent as :
629
+ # config_layers = [{name: 'runtime',
630
+ # config: PRC::BaseConfig.new, set: true}]
631
+ # config = CoreConfig.New(config_layers)
632
+ #
633
+ # Defining Config layer instance:
634
+ # -------------------------------
635
+ #
636
+ # :config value requires it to be of type 'BaseConfig'
637
+ # By default, it uses `:config => PRC::BaseConfig.new`
638
+ # Instead, you can set:
639
+ # * directly BaseConfig. `:config => PRC::BaseConfig.new`
640
+ # * a child based on BaseConfig. `:config => MyConfig.new`
641
+ # * some predefined enhanced BaseConfig:
642
+ # * PRC::SectionConfig. See prc_section_config.rb.
643
+ # `:config => PRC::SectionConfig.new`
644
+ #
645
+ def initialize(config_layers = nil)
646
+ if config_layers.nil?
647
+ config_layers = []
648
+ config_layers << CoreConfig.define_layer
649
+ end
650
+ initialize_layers(config_layers)
651
+ end
652
+
653
+ def self.define_layer(options = {})
654
+ attributes = [:name, :config, :set, :load, :save, :file_set]
655
+
656
+ layer = {}
657
+
658
+ attributes.each do | attribute |
659
+ if options.key?(attribute)
660
+ layer[attribute] = options[attribute]
661
+ else
662
+ layer[attribute] = case attribute
663
+ when :name
664
+ 'runtime'
665
+ when :config
666
+ PRC::BaseConfig.new
667
+ when :set
668
+ true
669
+ else
670
+ false
671
+ end
672
+ end
673
+ end
674
+ layer
675
+ end
676
+
677
+ # Function to initialize Config layers.
678
+ #
679
+ # *Args*
680
+ # - +config_layers+ : Array of config layers.
681
+ # First layer is the deepest config object.
682
+ # last layer is the first config object queried.
683
+ #
684
+ # Ex: If we define 2 config layer:
685
+ # local = PRC::BaseConfig.new(:test => :found_local)
686
+ # runtime = PRC::BaseConfig.new(:test => :found_runtime)
687
+ # layers = []
688
+ # layers << CoreConfig.define_layer(name: 'local', config: local )
689
+ # layers << CoreConfig.define_layer(name: 'runtime', config: runtime )
690
+ # config = PRC::CoreConfig.new
691
+ # config.initialize_layers(layers)
692
+ #
693
+ # p config[:test] # => :found_runtime
694
+ #
695
+ # config[:test] = "where?"
696
+ # p config.where?(:test) # => ["runtime", "local"]
697
+ #
698
+ # config.del(:test)
699
+ # p config.where?(:test) # => ["local"]
700
+ # p config[:test] # => :found_local
701
+ #
702
+ # config[:test] = "and now?"
703
+ # p config.where?(:test) # => ["runtime", "local"]
704
+ #
705
+ def initialize_layers(config_layers = nil)
706
+ @config_layers = []
707
+
708
+ config_layers.each do | layer |
709
+ next unless layer.is_a?(Hash) && layer.key?(:config) &&
710
+ layer[:config].is_a?(BaseConfig)
711
+ next unless layer[:name].is_a?(String)
712
+ @config_layers << initialize_layer(layer)
713
+ end
714
+ @config_layers.reverse!
715
+ end
716
+
717
+ def initialize_layer(layer)
718
+ newlayer = { :config => layer[:config], :name => layer[:name] }
719
+ newlayer[:set] = layer[:set].boolean? ? layer[:set] : true
720
+ newlayer[:load] = layer[:load].boolean? ? layer[:load] : false
721
+ newlayer[:save] = layer[:save].boolean? ? layer[:save] : false
722
+ newlayer[:file_set] = layer[:file_set].boolean? ? layer[:file_set] : false
723
+ newlayer
724
+ end
725
+
726
+ # layer_indexes function
727
+ #
728
+ # * *Args*
729
+ # - +:name+ : layer to identify.
730
+ #
731
+ # * *Returns*
732
+ # first index found or nil.
733
+ #
734
+ def _layer_indexes(names)
735
+ names = [names] if names.is_a?(String)
736
+ return nil unless names.is_a?(Array)
737
+
738
+ layers = []
739
+
740
+ names.each do | name |
741
+ index = layer_index(name)
742
+ layers << index unless index.nil?
743
+ end
744
+ return layers if layers.length > 0
745
+ nil
746
+ end
747
+
748
+ # layer_index function
749
+ #
750
+ # * *Args*
751
+ # - +:name+ : layer to identify.
752
+ #
753
+ # * *Returns*
754
+ # first index found or nil.
755
+ #
756
+ def layer_index(name)
757
+ return nil unless name.is_a?(String)
758
+ return nil if @config_layers.nil?
759
+
760
+ @config_layers.each_index do | index |
761
+ return index if @config_layers[index][:name] == name
762
+ end
763
+ nil
764
+ end
765
+
766
+ # Check and returns values of options required and optionnal.
767
+ #
768
+ # * *Args*
769
+ # - +options+ : options to extract information.
770
+ # - +required+ : Array of required option keys.
771
+ # - +optionnal+ : Array of optionnal option keys.
772
+ #
773
+ # * *Returns*
774
+ # - nil if at least one required keys doesn't exist
775
+ # - Array of combined required and optionnql values.
776
+ #
777
+ def _valid_options(options, required, optionnal = [])
778
+ return nil unless options.is_a?(Hash)
779
+ return nil unless required.is_a?(Array)
780
+ optionnal = [] unless optionnal.is_a?(Array)
781
+
782
+ result = [[], []]
783
+
784
+ required.each do | key |
785
+ return nil unless options.key?(key)
786
+ result[0] << options[key]
787
+ end
788
+
789
+ optionnal.each { | key | result[1] << options[key] }
790
+
791
+ result
792
+ end
793
+
794
+ # Take care of keys, indexes and names.
795
+ # if names if found, it will replace indexes.
796
+ def _common_options_get(options, required = [], optionnal = [])
797
+ return nil unless options.is_a?(Hash)
798
+ required = [] unless required.is_a?(Array)
799
+ optionnal = [] unless optionnal.is_a?(Array)
800
+
801
+ result = _valid_options(options, required,
802
+ [:indexes, :names,
803
+ :data_options].concat(optionnal))
804
+ # result Array is structured as:
805
+ # required [0] => [...]
806
+ # optional [1] => [indexes, names, data_options, ...]
807
+
808
+ # Following eliminates the optional :names (1) element
809
+ _set_indexes result
810
+ # required [0] => [...]
811
+ # optional [1] => [indexes, data_options, ...]
812
+ return nil if _keys_data_missing(options, required, result)
813
+
814
+ # Following eliminates the optional :indexes (0) element
815
+ # But add it as required in the Array, at pos 0
816
+ _build_layers(result)
817
+ # required [0] => [layers, ...]
818
+ # optional [1] => [data_options, ...]
819
+
820
+ # following eliminates the optional :data_options (0) element
821
+ # But data_options is added in required Array, at pos 1.
822
+ _set_data_opts(result)
823
+ # required [0] => [layers, data_options, ...]
824
+ # optional [1] => [...]
825
+
826
+ result
827
+ end
828
+
829
+ def _keys_data_missing(options, required, result)
830
+ return false unless required[0] == :keys
831
+
832
+ return true unless options.key?(:keys)
833
+ return true unless result[0][0].is_a?(Array)
834
+ return true if result[0][0].length == 0
835
+ false
836
+ end
837
+
838
+ # Setting indexes from names or indexes.
839
+ def _set_indexes(result)
840
+ names_indexes = _layer_indexes(result[1][1])
841
+ # replaced indexes by names indexes if exists.
842
+ result[1][0] = names_indexes if names_indexes
843
+ result[1].delete_at(1)
844
+ end
845
+
846
+ def _set_data_opts(result)
847
+ data_opts = []
848
+
849
+ result[0][0].each_index do | layer_index |
850
+ data_options = result[1][0][layer_index] if result[1][0].is_a?(Array)
851
+ data_options = {} unless data_options.is_a?(Hash)
852
+ data_opts << data_options
853
+ end
854
+ result[0].insert(1, data_opts)
855
+
856
+ # And removing the optionnal :data_options
857
+ result[1].delete_at(0)
858
+ end
859
+
860
+ def _build_layers(result)
861
+ # Setting layers at required [0]
862
+ if result[1][0].nil? || result[1][0].length == 0
863
+ config_layers = @config_layers
864
+ else
865
+ config_layers = []
866
+ result[1][0].each do | index |
867
+ config_layers << @config_layers[index] if index.is_a?(Fixnum)
868
+ end
869
+ config_layers = @config_layers if config_layers.length == 0
870
+ end
871
+ result[0].insert(0, config_layers)
872
+
873
+ # And removing the optionnal indexes
874
+ result[1].delete_at(0)
875
+ result
876
+ end
877
+ end
878
+ end