lorj 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/example/students_1/students.rb +5 -6
- data/example/students_2/students.rb +4 -5
- data/example/students_3/students.rb +4 -5
- data/example/students_4/students.rb +4 -5
- data/example/students_5/students.rb +5 -5
- data/lib/core/core.rb +6 -1
- data/lib/core/core_controller.rb +1 -9
- data/lib/core/core_internal.rb +2 -1
- data/lib/core/core_model.rb +2 -10
- data/lib/core/core_object_data.rb +18 -0
- data/lib/core/core_object_params.rb +43 -4
- data/lib/core/core_process.rb +1 -9
- data/lib/core/core_process_setup.rb +32 -6
- data/lib/core/core_setup_ask.rb +41 -33
- data/lib/core/core_setup_encrypt.rb +29 -6
- data/lib/core/core_setup_init.rb +2 -2
- data/lib/core/definition.rb +33 -10
- data/lib/core/definition_internal.rb +10 -14
- data/lib/core/lorj_basedefinition.rb +16 -24
- data/lib/core/lorj_baseprocess.rb +113 -44
- data/lib/core/lorj_data.rb +2 -9
- data/lib/core/lorj_keypath.rb +5 -2
- data/lib/core_process/cloud/process/common.rb +4 -7
- data/lib/core_process/cloud/process/connection.rb +44 -45
- data/lib/core_process/cloud/process/external_network.rb +24 -28
- data/lib/core_process/cloud/process/flavor.rb +31 -34
- data/lib/core_process/cloud/process/images.rb +12 -15
- data/lib/core_process/cloud/process/internet_network.rb +13 -14
- data/lib/core_process/cloud/process/internet_server.rb +9 -10
- data/lib/core_process/cloud/process/keypairs.rb +34 -27
- data/lib/core_process/cloud/process/network.rb +21 -23
- data/lib/core_process/cloud/process/public_ip.rb +17 -18
- data/lib/core_process/cloud/process/router.rb +86 -92
- data/lib/core_process/cloud/process/rules.rb +30 -31
- data/lib/core_process/cloud/process/security_groups.rb +21 -22
- data/lib/core_process/cloud/process/server.rb +30 -31
- data/lib/core_process/cloud/process/server_log.rb +13 -14
- data/lib/core_process/cloud/process/subnetwork.rb +25 -40
- data/lib/logging.rb +4 -17
- data/lib/lorj/version.rb +1 -1
- data/lib/lorj.rb +2 -1
- data/lib/lorj_account.rb +137 -90
- data/lib/lorj_config.rb +13 -19
- data/lib/lorj_defaults.rb +46 -292
- data/lib/lorj_meta.rb +729 -0
- data/lib/prc.rb +119 -30
- data/lib/prc_base_config.rb +53 -47
- data/lib/prc_core_config.rb +837 -565
- data/lib/prc_section_config.rb +44 -16
- data/lib/providers/hpcloud/hpcloud.rb +1 -1
- data/lib/providers/openstack/openstack.rb +278 -21
- data/lib/providers/openstack/openstack_create.rb +205 -0
- data/lib/providers/openstack/openstack_delete.rb +28 -0
- data/lib/providers/openstack/openstack_get.rb +39 -0
- data/lib/providers/openstack/openstack_process.rb +26 -0
- data/lib/providers/openstack/openstack_query.rb +96 -0
- data/lib/providers/openstack/openstack_update.rb +35 -0
- data/lib/rh.rb +91 -6
- data/lorj-spec/defaults.yaml +18 -12
- data/lorj.gemspec +1 -0
- data/spec/01_hash_rh_spec.rb +41 -2
- data/spec/02_prc_base_config_spec.rb +1 -1
- data/spec/03_prc_section_config_spec.rb +1 -1
- data/spec/04_prc_core_config_spec.rb +148 -4
- data/spec/09_prc_spec.rb +104 -0
- data/spec/{00_lorj_log_spec.rb → 10_lorj_log_spec.rb} +23 -2
- data/spec/11_lorj_config_spec.rb +9 -27
- data/spec/12_lorj_account_spec.rb +36 -20
- data/spec/20_lorj_meta_spec.rb +271 -0
- data/spec/21_lorj_defaults_spec.rb +85 -0
- metadata +31 -4
data/lib/prc_core_config.rb
CHANGED
@@ -17,266 +17,350 @@
|
|
17
17
|
require 'yaml'
|
18
18
|
|
19
19
|
module PRC
|
20
|
-
#
|
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
|
-
#
|
20
|
+
# Internal CoreConfig functions
|
91
21
|
class CoreConfig
|
92
|
-
|
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.
|
93
37
|
#
|
94
38
|
# * *Args*
|
95
|
-
#
|
39
|
+
# - +options+ : options to extract information.
|
40
|
+
# - +required+ : Array of required option keys.
|
41
|
+
# - +optionnal+ : Array of optionnal option keys.
|
96
42
|
#
|
97
43
|
# * *Returns*
|
98
|
-
#
|
99
|
-
#
|
100
|
-
# Class child:
|
101
|
-
# A class child can redefine this function to increase default
|
102
|
-
# features.
|
44
|
+
# - nil if at least one required keys doesn't exist
|
45
|
+
# - Array of combined required and optionnql values.
|
103
46
|
#
|
104
|
-
def
|
105
|
-
|
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
|
106
62
|
end
|
107
63
|
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
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.
|
112
68
|
#
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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)
|
118
77
|
end
|
119
78
|
|
120
|
-
#
|
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.
|
121
181
|
#
|
122
182
|
# * *Args*
|
123
|
-
# -
|
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.
|
124
188
|
#
|
125
189
|
# * *Returns*
|
126
|
-
#
|
190
|
+
# - Value, Hash merged or nil.
|
127
191
|
#
|
128
|
-
def
|
129
|
-
|
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
|
130
215
|
end
|
131
216
|
|
132
|
-
#
|
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
|
133
221
|
#
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|
146
247
|
end
|
147
248
|
|
148
|
-
#
|
249
|
+
# Internal function to provide a merge result for #_get_from_layers
|
149
250
|
#
|
150
251
|
# * *Args*
|
151
|
-
# - +
|
152
|
-
#
|
153
|
-
# - The Hash updated.
|
252
|
+
# - +result+ : Cumulative Hash merged
|
253
|
+
# - +data+ : data to merge
|
154
254
|
#
|
155
|
-
#
|
156
|
-
#
|
255
|
+
# * *Returns*
|
256
|
+
# - Cloned Hash merged or simple data updated if possible.
|
157
257
|
#
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
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)
|
164
264
|
end
|
165
265
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
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
|
182
271
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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)
|
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
|
196
277
|
end
|
197
278
|
|
198
|
-
#
|
279
|
+
# Internal function to do the merge result for #_get_build_merge
|
199
280
|
#
|
200
281
|
# * *Args*
|
201
|
-
#
|
202
|
-
#
|
203
|
-
# - +:index+: layer index to get data.
|
204
|
-
# - +:name+ : layer to get data.
|
205
|
-
# If neither :name or :index is set, nil is returned.
|
282
|
+
# - +result+ : Cumulative Hash merged
|
283
|
+
# - +data+ : data to merge
|
206
284
|
#
|
207
285
|
# * *Returns*
|
208
|
-
#
|
209
|
-
|
210
|
-
|
211
|
-
|
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)
|
212
291
|
|
213
|
-
|
214
|
-
|
215
|
-
|
292
|
+
result.each_index do |index|
|
293
|
+
result[index] = _get_build_merge(result[index], data[index])
|
294
|
+
end
|
216
295
|
result
|
217
296
|
end
|
297
|
+
end
|
218
298
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
data += format("---- Config : %s ----\noptions: ", layer[:name])
|
299
|
+
# Internal core functions
|
300
|
+
class CoreConfig
|
301
|
+
# *****************************************************
|
223
302
|
|
224
|
-
|
225
|
-
if layer[:set]
|
226
|
-
data += 'data RW '
|
227
|
-
else
|
228
|
-
data += 'data RO '
|
229
|
-
end
|
230
|
-
data += format(", %s\n", to_s_file_opts(layer))
|
303
|
+
private
|
231
304
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
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])
|
236
341
|
|
237
|
-
|
342
|
+
return nil if keys.length == 0
|
238
343
|
|
239
|
-
|
240
|
-
|
241
|
-
if layer[:load] &&
|
242
|
-
if layer[:save]
|
243
|
-
data += 'RW'
|
244
|
-
else
|
245
|
-
data += 'RO'
|
246
|
-
end
|
247
|
-
data += ', filename updatable' if layer[:file_set]
|
248
|
-
else
|
249
|
-
data += 'None'
|
344
|
+
data_options.delete_if do |key|
|
345
|
+
[:keys, :names, :indexes, :name, :index].include?(key)
|
250
346
|
end
|
251
|
-
data
|
252
|
-
end
|
253
347
|
|
254
|
-
|
255
|
-
options = {} if options.nil?
|
256
|
-
options[:names] = [options[:name]] if options.key?(:name)
|
257
|
-
options[:indexes] = [options[:index]] if options.key?(:index)
|
348
|
+
return nil unless @config_layers[0][:set]
|
258
349
|
|
259
|
-
|
350
|
+
config_layers[0][:config].data_options(data_options)
|
351
|
+
config_layers[0][:config].del(keys)
|
260
352
|
end
|
261
|
-
end
|
262
|
-
|
263
|
-
# Internal core functions
|
264
|
-
class CoreConfig
|
265
|
-
# *****************************************************
|
266
|
-
|
267
|
-
private
|
268
|
-
|
269
|
-
# *****************************************************
|
270
353
|
|
271
|
-
#
|
354
|
+
# p_file? Core file function called by default by #file.
|
355
|
+
# This function is typically used by a Child Class.
|
272
356
|
#
|
273
357
|
# This function can be used by child class to set one layer file name
|
274
358
|
#
|
275
359
|
# * *Args*
|
276
|
-
#
|
277
|
-
#
|
278
|
-
#
|
279
|
-
#
|
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.
|
280
364
|
#
|
281
365
|
# * *Returns*
|
282
366
|
# - filename : if updated.
|
@@ -287,8 +371,8 @@ module PRC
|
|
287
371
|
#
|
288
372
|
# ex:
|
289
373
|
# { :test => {:titi => 'found'}}
|
290
|
-
def
|
291
|
-
parameters =
|
374
|
+
def p_file(filename = nil, options = {}) #:doc:
|
375
|
+
parameters = _nameindex_common_options_get(options)
|
292
376
|
|
293
377
|
return nil if parameters.nil?
|
294
378
|
|
@@ -310,23 +394,28 @@ module PRC
|
|
310
394
|
!layer[:config].filename.nil? && !layer[:file_set]
|
311
395
|
end
|
312
396
|
|
313
|
-
#
|
397
|
+
# p_exist? Core exist function called by default by #exist?.
|
398
|
+
# This function is typically used by a Child Class.
|
314
399
|
#
|
315
400
|
# * *Args*
|
316
|
-
#
|
317
|
-
#
|
318
|
-
#
|
319
|
-
#
|
320
|
-
#
|
321
|
-
#
|
322
|
-
#
|
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.
|
323
408
|
#
|
324
409
|
# * *Returns*
|
325
410
|
# - boolean : true if the key path was found
|
326
411
|
#
|
327
412
|
# ex:
|
328
|
-
# { :test => {:titi => 'found'}}
|
329
|
-
|
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:
|
330
419
|
parameters = _common_options_get(options, [:keys])
|
331
420
|
return nil if parameters.nil?
|
332
421
|
|
@@ -349,15 +438,17 @@ module PRC
|
|
349
438
|
false
|
350
439
|
end
|
351
440
|
|
352
|
-
#
|
441
|
+
# p_where? called by default by #where
|
442
|
+
# This function is typically used by a Child Class.
|
353
443
|
#
|
354
|
-
#
|
355
|
-
# -
|
356
|
-
#
|
357
|
-
#
|
358
|
-
#
|
359
|
-
#
|
360
|
-
#
|
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.
|
361
452
|
#
|
362
453
|
# * *Returns*
|
363
454
|
# - array of config name : list of first layers where the key was found.
|
@@ -365,11 +456,7 @@ module PRC
|
|
365
456
|
# - nil can be returned for several reasons:
|
366
457
|
# - keys is not an array
|
367
458
|
# - keys array is empty.
|
368
|
-
|
369
|
-
#
|
370
|
-
# ex:
|
371
|
-
# { :test => {:titi => 'found'}}
|
372
|
-
def _where?(options)
|
459
|
+
def p_where?(options) #:doc:
|
373
460
|
parameters = _common_options_get(options, [:keys])
|
374
461
|
return nil if parameters.nil?
|
375
462
|
|
@@ -397,57 +484,76 @@ module PRC
|
|
397
484
|
return layer_indexes if layer_indexes.length > 0
|
398
485
|
false
|
399
486
|
end
|
400
|
-
|
487
|
+
|
488
|
+
# Get function called by default by #[]
|
489
|
+
# This function is typically used by a Child Class.
|
401
490
|
#
|
402
491
|
# * *Args*
|
403
|
-
#
|
404
|
-
#
|
405
|
-
#
|
406
|
-
#
|
407
|
-
#
|
408
|
-
#
|
409
|
-
#
|
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.
|
410
517
|
#
|
411
518
|
# * *Returns*
|
412
|
-
# value found or nil.
|
413
|
-
#
|
519
|
+
# value found (or Hash merged) or nil.
|
520
|
+
#
|
521
|
+
# nil can be returned for several reasons:
|
414
522
|
# - keys is not an array
|
415
523
|
# - keys array is empty.
|
416
524
|
#
|
417
|
-
def
|
418
|
-
parameters = _common_options_get(options, [:keys])
|
525
|
+
def p_get(options) #:doc:
|
526
|
+
parameters = _common_options_get(options, [:keys], [:merge])
|
419
527
|
return nil if parameters.nil?
|
420
528
|
|
529
|
+
# Required options : parameters[0]
|
421
530
|
config_layers, data_opts, keys = parameters[0]
|
531
|
+
# Optional options : parameters[1]
|
532
|
+
merge = parameters[1][0]
|
422
533
|
|
423
534
|
return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
|
424
535
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
data_options = options.clone
|
429
|
-
data_options.delete_if do |key|
|
430
|
-
[:keys, :names, :indexes, :name, :index].include?(key)
|
431
|
-
end
|
432
|
-
data_options = data_options.merge!(data_opts[layer_index])
|
433
|
-
|
434
|
-
layer[:config].data_options(data_options)
|
435
|
-
return layer[:config][*keys] if layer[:config].exist?(*keys)
|
536
|
+
data_options = options.clone
|
537
|
+
data_options.delete_if do |key|
|
538
|
+
[:keys, :names, :indexes, :name, :index, :merge].include?(key)
|
436
539
|
end
|
437
|
-
|
540
|
+
|
541
|
+
_get_from_layers(keys,
|
542
|
+
config_layers, data_opts, data_options,
|
543
|
+
merge)
|
438
544
|
end
|
439
545
|
|
440
|
-
# Set function called by default by []=
|
546
|
+
# Set function called by default by #[]=
|
547
|
+
# This function is typically used by a Child Class.
|
441
548
|
#
|
442
549
|
# * *Args*
|
443
|
-
#
|
444
|
-
#
|
445
|
-
#
|
446
|
-
#
|
447
|
-
#
|
448
|
-
#
|
449
|
-
#
|
450
|
-
# - +:data_opts+ : Array or Hash. Define data options per layer.
|
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.
|
451
557
|
#
|
452
558
|
# * *Returns*
|
453
559
|
# - The value set.
|
@@ -464,8 +570,8 @@ module PRC
|
|
464
570
|
#
|
465
571
|
# value[:level1, :level2] = 'value'
|
466
572
|
# # => {:level1 => {:level2 => 'value'}}
|
467
|
-
def
|
468
|
-
parameters =
|
573
|
+
def p_set(options) #:doc:
|
574
|
+
parameters = _nameindex_common_options_get(options, [:keys, :value])
|
469
575
|
return nil if parameters.nil?
|
470
576
|
|
471
577
|
config_layers, data_opts, keys, value = parameters[0]
|
@@ -479,81 +585,33 @@ module PRC
|
|
479
585
|
[:keys, :names, :indexes, :name, :index, :value].include?(key)
|
480
586
|
end
|
481
587
|
|
482
|
-
return nil unless
|
588
|
+
return nil unless config_layers[0][:set]
|
483
589
|
|
484
590
|
config_layer = config_layers[0][:config]
|
485
591
|
config_layer.data_options(data_options)
|
486
592
|
config_layer[keys] = value
|
487
593
|
end
|
488
594
|
|
489
|
-
# Del function called by default by del
|
490
|
-
#
|
491
|
-
# * *Args*
|
492
|
-
# - +options+ : Hash of how to get the data
|
493
|
-
# - +:keys+ : Array of key path to found
|
494
|
-
# - +:name+ : layer to get data.
|
495
|
-
# - +:index+ : layer index to get data.
|
496
|
-
# If neither :name or :index is set, set will use the
|
497
|
-
# highest layer
|
498
|
-
# - +:data_opts+ : Array or Hash. Define data options per layer.
|
499
|
-
#
|
500
|
-
# * *Returns*
|
501
|
-
# - The value attached to the key deleted.
|
502
|
-
# OR
|
503
|
-
# - nil can be returned for several reasons:
|
504
|
-
# - value is nil
|
505
|
-
# - keys is not an array
|
506
|
-
# - keys array is empty.
|
507
|
-
#
|
508
|
-
# ex:
|
509
|
-
# value = CoreConfig.New
|
510
|
-
#
|
511
|
-
# value[:level1, :level2] = 'value'
|
512
|
-
# # => {:level1 => {:level2 => 'value'}}
|
513
|
-
#
|
514
|
-
# value.del(:keys => [:level1, :level2])
|
515
|
-
# # => {:level1 => {}}
|
516
|
-
def _del(options)
|
517
|
-
parameters = _common_options_get(options, [:keys])
|
518
|
-
return nil if parameters.nil?
|
519
|
-
|
520
|
-
config_layers, data_opts, keys = parameters[0]
|
521
|
-
|
522
|
-
# get data options for level 0
|
523
|
-
data_options = options.clone.merge!(data_opts[0])
|
524
|
-
|
525
|
-
return nil if keys.length == 0
|
526
|
-
|
527
|
-
data_options.delete_if do |key|
|
528
|
-
[:keys, :names, :indexes, :name, :index].include?(key)
|
529
|
-
end
|
530
|
-
|
531
|
-
return nil unless @config_layers[0][:set]
|
532
|
-
|
533
|
-
config_layers[0][:config].data_options(data_options)
|
534
|
-
config_layers[0][:config].del(keys)
|
535
|
-
end
|
536
|
-
|
537
595
|
# Load from a file called by default by load.
|
596
|
+
# This function is typically used by a Child Class.
|
538
597
|
#
|
539
598
|
# * *Args* :
|
540
|
-
#
|
541
|
-
#
|
542
|
-
#
|
543
|
-
#
|
544
|
-
# layer.
|
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.
|
545
603
|
#
|
546
604
|
# * *Returns* :
|
547
605
|
# - true : loaded
|
548
606
|
# - false: not loaded. There are several possible reasons:
|
549
607
|
# - input/output issue (normally raised)
|
550
608
|
# - layer option :load is false.
|
551
|
-
def
|
609
|
+
def p_load(options = {}) #:doc:
|
552
610
|
options = {} if options.nil?
|
553
611
|
options[:names] = [options[:name]] if options.key?(:name)
|
554
612
|
options[:indexes] = [options[:index]] if options.key?(:index)
|
555
613
|
|
556
|
-
parameters =
|
614
|
+
parameters = _nameindex_common_options_get(options)
|
557
615
|
return nil if parameters.nil?
|
558
616
|
|
559
617
|
config_layers = parameters[0][0]
|
@@ -564,13 +622,13 @@ module PRC
|
|
564
622
|
end
|
565
623
|
|
566
624
|
# Save to a file called by default by save
|
625
|
+
# This function is typically used by a Child Class.
|
567
626
|
#
|
568
627
|
# * *Args* :
|
569
|
-
#
|
570
|
-
#
|
571
|
-
#
|
572
|
-
#
|
573
|
-
# layer
|
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
|
574
632
|
#
|
575
633
|
# * *Returns* :
|
576
634
|
# - true : saved
|
@@ -578,11 +636,11 @@ module PRC
|
|
578
636
|
# - options defines a :file_readonly to true.
|
579
637
|
# - input/output issue (normally raised)
|
580
638
|
# - layer option :save is false.
|
581
|
-
def
|
639
|
+
def p_save(options = {}) #:doc:
|
582
640
|
options[:names] = [options[:name]] if options.key?(:name)
|
583
641
|
options[:indexes] = [options[:index]] if options.key?(:index)
|
584
642
|
|
585
|
-
parameters =
|
643
|
+
parameters = _nameindex_common_options_get(options)
|
586
644
|
return nil if parameters.nil?
|
587
645
|
|
588
646
|
config_layers = parameters[0][0]
|
@@ -593,21 +651,22 @@ module PRC
|
|
593
651
|
end
|
594
652
|
end
|
595
653
|
|
596
|
-
#
|
654
|
+
# private functions usable by child classes
|
597
655
|
class CoreConfig
|
598
656
|
# initialize CoreConfig
|
599
657
|
#
|
600
658
|
# * *Args*
|
601
|
-
#
|
602
|
-
#
|
603
|
-
#
|
604
|
-
#
|
605
|
-
#
|
606
|
-
#
|
607
|
-
#
|
608
|
-
#
|
609
|
-
#
|
610
|
-
#
|
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.
|
611
670
|
#
|
612
671
|
# each layers can defines some options for the layer to behave differently
|
613
672
|
# CoreConfig call a layer data_options to set some options, before
|
@@ -616,23 +675,23 @@ module PRC
|
|
616
675
|
#
|
617
676
|
# Core config provides some private additionnal functions for
|
618
677
|
# child class functions:
|
619
|
-
#
|
620
|
-
#
|
621
|
-
#
|
622
|
-
#
|
623
|
-
#
|
624
|
-
#
|
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
|
625
684
|
#
|
626
685
|
# if +config_layers+ is not provided, CoreConfig will instanciate a runtime
|
627
686
|
# like system:
|
628
|
-
# config = CoreConfig.New
|
629
|
-
# # is equivalent as :
|
630
|
-
# config_layers = [{name: 'runtime',
|
631
|
-
# config: PRC::BaseConfig.new, set: true}]
|
632
|
-
# config = CoreConfig.New(config_layers)
|
633
687
|
#
|
634
|
-
#
|
635
|
-
#
|
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:
|
636
695
|
#
|
637
696
|
# :config value requires it to be of type 'BaseConfig'
|
638
697
|
# By default, it uses `:config => PRC::BaseConfig.new`
|
@@ -657,20 +716,20 @@ module PRC
|
|
657
716
|
# The name MUST be different than other existing config layer names
|
658
717
|
#
|
659
718
|
# *Args*
|
660
|
-
#
|
661
|
-
#
|
662
|
-
#
|
663
|
-
#
|
664
|
-
#
|
665
|
-
#
|
666
|
-
#
|
667
|
-
#
|
668
|
-
#
|
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.
|
669
728
|
#
|
670
729
|
# *returns*
|
671
|
-
#
|
672
|
-
#
|
673
|
-
#
|
730
|
+
# - true if layer is added.
|
731
|
+
# OR
|
732
|
+
# - nil : if layer name already exist
|
674
733
|
def layer_add(options)
|
675
734
|
layer = CoreConfig.define_layer(options)
|
676
735
|
|
@@ -690,16 +749,16 @@ module PRC
|
|
690
749
|
# You cannot remove a predefined layer, created during CoreConfig
|
691
750
|
# instanciation.
|
692
751
|
# *Args*
|
693
|
-
#
|
694
|
-
#
|
695
|
-
#
|
752
|
+
# - +options+ : Hash data
|
753
|
+
# - +:name+ : Name of the layer to remove.
|
754
|
+
# - +:index+: Index of the layer to remove.
|
696
755
|
#
|
697
756
|
# At least, :name or :index is required.
|
698
757
|
# If both; :name and :index are set, :name is used.
|
699
758
|
# *return*
|
700
|
-
#
|
701
|
-
#
|
702
|
-
#
|
759
|
+
# - true if layer name is removed.
|
760
|
+
# OR
|
761
|
+
# - nil : if not found or invalid.
|
703
762
|
def layer_remove(options)
|
704
763
|
index = layer_index(options[:name])
|
705
764
|
index = options[:index] if index.nil?
|
@@ -714,247 +773,460 @@ module PRC
|
|
714
773
|
true
|
715
774
|
end
|
716
775
|
|
717
|
-
# Function to define layer options.
|
718
|
-
# By default, :set is true and :config is attached to a new PRC::BaseConfig
|
719
|
-
# instance.
|
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?
|
720
1029
|
#
|
721
|
-
#
|
722
|
-
# - :
|
723
|
-
#
|
724
|
-
#
|
725
|
-
# - :
|
726
|
-
#
|
727
|
-
|
728
|
-
|
729
|
-
# Default is False.
|
730
|
-
def self.define_layer(options = {})
|
731
|
-
attributes = [:name, :config, :set, :load, :save, :file_set]
|
732
|
-
|
733
|
-
layer = {}
|
734
|
-
|
735
|
-
attributes.each do |attribute|
|
736
|
-
if options.key?(attribute)
|
737
|
-
layer[attribute] = options[attribute]
|
738
|
-
else
|
739
|
-
layer[attribute] = case attribute
|
740
|
-
when :name
|
741
|
-
'runtime'
|
742
|
-
when :config
|
743
|
-
PRC::BaseConfig.new
|
744
|
-
when :set
|
745
|
-
true
|
746
|
-
else
|
747
|
-
false
|
748
|
-
end
|
749
|
-
end
|
750
|
-
end
|
751
|
-
layer
|
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)
|
752
1038
|
end
|
753
1039
|
|
754
|
-
#
|
1040
|
+
# Get function
|
755
1041
|
#
|
756
1042
|
# * *Args*
|
757
|
-
#
|
1043
|
+
# - +keys+ : Array of key path to found
|
758
1044
|
#
|
759
1045
|
# * *Returns*
|
760
|
-
#
|
1046
|
+
# value found or nil.
|
761
1047
|
#
|
762
|
-
def
|
763
|
-
|
764
|
-
return nil unless names.is_a?(Array)
|
765
|
-
|
766
|
-
layers = []
|
767
|
-
|
768
|
-
names.each do |name|
|
769
|
-
index = layer_index(name)
|
770
|
-
layers << index unless index.nil?
|
771
|
-
end
|
772
|
-
return layers if layers.length > 0
|
773
|
-
nil
|
1048
|
+
def [](*keys)
|
1049
|
+
p_get(:keys => keys)
|
774
1050
|
end
|
775
1051
|
|
776
|
-
#
|
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.
|
777
1060
|
#
|
778
1061
|
# * *Args*
|
779
|
-
#
|
1062
|
+
# - +keys+ : Array of key path to found
|
780
1063
|
#
|
781
1064
|
# * *Returns*
|
782
|
-
#
|
1065
|
+
# value found merged or nil.
|
783
1066
|
#
|
784
|
-
def
|
785
|
-
|
786
|
-
return nil if @config_layers.nil?
|
787
|
-
|
788
|
-
@config_layers.each_index do |index|
|
789
|
-
return index if @config_layers[index][:name] == name
|
790
|
-
end
|
791
|
-
nil
|
1067
|
+
def merge(*keys)
|
1068
|
+
p_get(:keys => keys, :merge => true)
|
792
1069
|
end
|
793
1070
|
|
794
|
-
|
795
|
-
|
796
|
-
# Function to initialize Config layers.
|
797
|
-
#
|
798
|
-
# *Args*
|
799
|
-
# - +config_layers+ : Array of config layers.
|
800
|
-
# First layer is the deepest config object.
|
801
|
-
# last layer is the first config object queried.
|
1071
|
+
# Set function
|
802
1072
|
#
|
803
|
-
#
|
804
|
-
#
|
805
|
-
#
|
806
|
-
#
|
807
|
-
# layers << CoreConfig.define_layer(name: 'local', config: local )
|
808
|
-
# layers << CoreConfig.define_layer(name: 'runtime', config: runtime )
|
809
|
-
# config = PRC::CoreConfig.new
|
810
|
-
# config.initialize_layers(layers)
|
1073
|
+
# * *Args*
|
1074
|
+
# - +keys+ : Array of key path to found
|
1075
|
+
# * *Returns*
|
1076
|
+
# - The value set or nil
|
811
1077
|
#
|
812
|
-
#
|
1078
|
+
# ex:
|
1079
|
+
# value = CoreConfig.New
|
813
1080
|
#
|
814
|
-
#
|
815
|
-
#
|
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
|
816
1088
|
#
|
817
|
-
#
|
818
|
-
#
|
819
|
-
#
|
1089
|
+
# * *Args*
|
1090
|
+
# - +keys+ : Array of key path to found and delete the last element.
|
1091
|
+
# * *Returns*
|
1092
|
+
# - The Hash updated.
|
820
1093
|
#
|
821
|
-
#
|
822
|
-
#
|
1094
|
+
# ex:
|
1095
|
+
# value = CoreConfig.New
|
823
1096
|
#
|
824
|
-
|
825
|
-
|
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
|
826
1104
|
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
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)
|
834
1120
|
end
|
835
1121
|
|
836
|
-
#
|
837
|
-
#
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
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)
|
846
1135
|
end
|
847
1136
|
|
848
|
-
#
|
1137
|
+
# Get/Set the file name.
|
849
1138
|
#
|
850
1139
|
# * *Args*
|
851
|
-
#
|
852
|
-
#
|
853
|
-
#
|
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.
|
854
1145
|
#
|
855
1146
|
# * *Returns*
|
856
|
-
#
|
857
|
-
|
858
|
-
|
859
|
-
def _valid_options(options, required, optionnal = [])
|
860
|
-
return nil unless options.is_a?(Hash)
|
861
|
-
return nil unless required.is_a?(Array)
|
862
|
-
optionnal = [] unless optionnal.is_a?(Array)
|
863
|
-
|
864
|
-
result = [[], []]
|
865
|
-
|
866
|
-
required.each do |key|
|
867
|
-
return nil unless options.key?(key)
|
868
|
-
result[0] << options[key]
|
869
|
-
end
|
870
|
-
|
871
|
-
optionnal.each { |key| result[1] << options[key] }
|
872
|
-
|
873
|
-
result
|
1147
|
+
# - The file name.
|
1148
|
+
def file(filename = nil, options = {})
|
1149
|
+
p_file(filename, options)
|
874
1150
|
end
|
875
1151
|
|
876
|
-
#
|
877
|
-
#
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
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?
|
882
1169
|
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
# required [0] => [...]
|
888
|
-
# optional [1] => [indexes, names, data_options, ...]
|
1170
|
+
# Required options : parameters[0]
|
1171
|
+
config_layers, data_opts, keys = parameters[0]
|
1172
|
+
# Optional options : parameters[1]
|
1173
|
+
be_exclusive = parameters[1][0]
|
889
1174
|
|
890
|
-
#
|
891
|
-
|
892
|
-
# required [0] => [...]
|
893
|
-
# optional [1] => [indexes, data_options, ...]
|
894
|
-
return nil if _keys_data_missing(options, required, result)
|
1175
|
+
# Merge is done in the reverse order. ie from deepest to top.
|
1176
|
+
config_layers = config_layers.reverse
|
895
1177
|
|
896
|
-
|
897
|
-
# But add it as required in the Array, at pos 0
|
898
|
-
_build_layers(result)
|
899
|
-
# required [0] => [layers, ...]
|
900
|
-
# optional [1] => [data_options, ...]
|
1178
|
+
return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
|
901
1179
|
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
# optional [1] => [...]
|
1180
|
+
data_options = options.clone
|
1181
|
+
data_options.delete_if do |key|
|
1182
|
+
[:keys, :names, :indexes, :name, :index, :merge].include?(key)
|
1183
|
+
end
|
907
1184
|
|
908
|
-
|
1185
|
+
_check_from_layers(keys, config_layers, data_opts, data_options,
|
1186
|
+
be_exclusive)
|
909
1187
|
end
|
910
1188
|
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
return true if result[0][0].length == 0
|
917
|
-
false
|
1189
|
+
# List all config layers defined in this instance.
|
1190
|
+
def layers
|
1191
|
+
result = []
|
1192
|
+
@config_layers.each { |layer| result << layer[:name] }
|
1193
|
+
result
|
918
1194
|
end
|
919
1195
|
|
920
|
-
#
|
921
|
-
def
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
result[1].delete_at(1)
|
926
|
-
end
|
1196
|
+
# Display in human format.
|
1197
|
+
def to_s
|
1198
|
+
data = "Configs list ordered:\n"
|
1199
|
+
@config_layers.each do |layer|
|
1200
|
+
data += format("---- Config : %s ----\noptions: ", layer[:name])
|
927
1201
|
|
928
|
-
|
929
|
-
|
1202
|
+
data += 'predefined, ' if layer[:init].is_a?(TrueClass)
|
1203
|
+
if layer[:set]
|
1204
|
+
data += 'data RW '
|
1205
|
+
else
|
1206
|
+
data += 'data RO '
|
1207
|
+
end
|
1208
|
+
data += format(", %s\n", to_s_file_opts(layer))
|
930
1209
|
|
931
|
-
|
932
|
-
data_options = result[1][0][layer_index] if result[1][0].is_a?(Array)
|
933
|
-
data_options = {} unless data_options.is_a?(Hash)
|
934
|
-
data_opts << data_options
|
1210
|
+
data += format("%s\n", layer[:config].to_s)
|
935
1211
|
end
|
936
|
-
|
937
|
-
|
938
|
-
# And removing the optionnal :data_options
|
939
|
-
result[1].delete_at(0)
|
1212
|
+
data
|
940
1213
|
end
|
941
1214
|
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
1215
|
+
private
|
1216
|
+
|
1217
|
+
def to_s_file_opts(layer)
|
1218
|
+
data = 'File '
|
1219
|
+
if layer[:load] &&
|
1220
|
+
if layer[:save]
|
1221
|
+
data += 'RW'
|
1222
|
+
else
|
1223
|
+
data += 'RO'
|
1224
|
+
end
|
1225
|
+
data += ', filename updatable' if layer[:file_set]
|
946
1226
|
else
|
947
|
-
|
948
|
-
result[1][0].each do |index|
|
949
|
-
config_layers << @config_layers[index] if index.is_a?(Fixnum)
|
950
|
-
end
|
951
|
-
config_layers = @config_layers if config_layers.length == 0
|
1227
|
+
data += 'None'
|
952
1228
|
end
|
953
|
-
|
954
|
-
|
955
|
-
# And removing the optionnal indexes
|
956
|
-
result[1].delete_at(0)
|
957
|
-
result
|
1229
|
+
data
|
958
1230
|
end
|
959
1231
|
end
|
960
1232
|
end
|