lorj 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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