stacked_config 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 396a51271ebfbb2aee0f6a8d3d03674f46b7a398
4
- data.tar.gz: d4215b4890198baf73cb42ea690ff46b000e9ea3
3
+ metadata.gz: bbaae6cc93a17d8d15943af382d2683addc479c2
4
+ data.tar.gz: 3949626e5a158e99d7cdcf1bcdf6a32852966bb8
5
5
  SHA512:
6
- metadata.gz: 35cc07767ab94e5891230097e9a83ecaac1202c4325af0d2e8e6fc82ff555d4b760e855bb8e41d8014e66135b52833608ff78e60a30df7e8750c67d48fb408e9
7
- data.tar.gz: d114a476a6684535ffabc7a777fe4eff2175a11cd58cca4644ba9657b513e0fc4d3bad0850907425f12ce8c0074ad404d2c21c69da5f991cbc2c64410c5de3cd
6
+ metadata.gz: 8a9e072826b8bccf78c16d30479ebfda5f92408c3fa4bf92661bcf11a48efc7c1c0ce7f715dcafad384917ef8f54f6787160af5d6369336e6f3a5a2760e1e926
7
+ data.tar.gz: bcb3241c7a790dce29df30c1a219cb3589d9a0ec9f4e859842bc5e4ea63c515e27c47d08582fdc1d1d9fd1763c1ba70f2376ddab0677f321570915b036dfa7e6
data/README.md CHANGED
@@ -2,18 +2,22 @@
2
2
  [![Build Status](https://travis-ci.org/lbriais/stacked_config.svg)](https://travis-ci.org/lbriais/stacked_config)
3
3
  [![Gem Version](https://badge.fury.io/rb/stacked_config.svg)](http://badge.fury.io/rb/stacked_config)
4
4
 
5
+ If you need to manage config files accross the system, some of them belonging to the administrator some to the user
6
+ running the application, some coming from the command line and more, __[This Gem]
7
+ (http://rubygems.org/gems/stacked_config) is made for you__ !
8
+
5
9
  The purpose of this gem is to provide a __simple__ way to handle the __inheritance__ of __config files__ for a ruby
6
10
  script. By default, it will handle already few config layers:
7
11
 
8
12
  * The __system layer__, which is a level common to all applications using this gem.
9
13
  * The __global layer__, which is the level to declare options for all users that use the ruby script using this gem.
10
14
  * The __user layer__, which is the level, where a user can set options for the ruby script using this gem.
11
- * The __extra layer__, which provides the possibility to specify a config file from the command line.
15
+ * The __extra layer__, which provides the possibility to specify another config file from the command line.
12
16
  * The __command-line layer__, which provides the ability to specify options from the command line.
13
17
  * The __override layer__, which will contain all modifications done to the config at run time.
14
18
 
15
19
  The different layers are evaluated by default in that order using the [super_stack gem][SS] (Please read for more
16
- detail).
20
+ detail). The `StackedConfig::Orchestrator` will expose a merged view of all its layers without modifying them.
17
21
 
18
22
  All the config files are following the [YAML] syntax.
19
23
 
@@ -54,9 +58,25 @@ if config[:help]
54
58
  end
55
59
  ```
56
60
 
57
- Try this little script and then create some config files to test how it is handled (see next section to know where to
58
- create the config files).
61
+ Try this little script and then create some config files to test how it is handled (see [next section]
62
+ (#where-are-my-config-files-) to know where to create the config files).
63
+
64
+ You are supposed to access the merged config through the `[]` method of the orchestrator (`config[]` in the previous
65
+ example). Still you can directly modify any of the layers automatically created, you are not supposed to, and if you
66
+ modify or add any new property (a so called "runtime property"), it will actually set the property in the `override`
67
+ layer.
68
+
69
+ That's why you can always come back to the initial state by calling `reset` on the orchestrator. This actually just
70
+ clears the override layer.
59
71
 
72
+ Every layer is accessible through the following orchestrator properties:
73
+
74
+ * `system_layer`
75
+ * `global_layer`
76
+ * `user_layer`
77
+ * `provided_config_file_layer`
78
+ * `command_line_layer`
79
+ * `write_layer`
60
80
 
61
81
  ### Where are my config files ?
62
82
 
@@ -72,14 +92,15 @@ As you can see in the sources, paths are expressed using kind of 'templates', wh
72
92
 
73
93
  * `##SYSTEM_CONFIG_ROOT##` is where the system config is stored. On Unix systems, it should be `/etc`.
74
94
  * `##PROGRAM_NAME##` is by default the name of the script you are running (with no extension). You can if you want
75
- change this name at runtime. Changing it will trigger a re-search and reload of all the config files.
95
+ change this name at runtime. __Changing it (using the `executable_name` orchestrator property ) will trigger a
96
+ re-search and reload of all the config files__.
76
97
  * `##USER_CONFIG_ROOT##` is where the user config is stored. On Unix systems, it should be your `$HOME` directory.
77
98
  * `##EXTENSION##` is one of the following extensions : `conf CONF cfg CFG yml YML yaml YAML`.
78
99
 
79
100
  The search of the config files is done according to the order defined in sources just above and then extensions
80
101
  are tried according to the extensions just above in that exact order.
81
102
 
82
- __The first file matching for a particular level is used !__ And there can be only one per level.
103
+ __The first file matching for a particular level is used ! And there can be only one per level.__
83
104
 
84
105
  Thus according to the rules above, and assuming my script is named `my_script.rb` if the two following files exists at
85
106
  user config level, only the first is taken in account:
@@ -90,11 +111,98 @@ user config level, only the first is taken in account:
90
111
 
91
112
  ### Script command line options
92
113
 
93
- `stacked_config` uses internally the fantastic [Slop] gem to manage options coming from
94
- the command line.
114
+ `stacked_config` uses internally the fantastic [Slop] gem to manage options coming from the command line within the
115
+ command line layer. This layer will be simply part of the complete config that the orchestrator exposes.
116
+
117
+ #### Command line help
118
+
119
+ You can easily display a help using the orchestrator `command_line_help` method.
120
+
121
+ To even have a better command line help displayed you can provide optional information:
122
+
123
+ * The __application name__ through the `app_name` orchestrator property.
124
+ * The __application version__ through the `app_version` orchestrator property.
125
+ * The __application description__ through the `app_description` orchestrator property.
126
+
127
+ You could as well do this with the `describes_application` method (see [complete example]()).
128
+
129
+ ```ruby
130
+ require 'stacked_config'
131
+
132
+ config = StackedConfig::Orchestrator.new
133
+
134
+ config.app_name = 'My super Application'
135
+ config.app_version = '1.0.0'
136
+ config.app_description = <<EOD
137
+ You can have a multiline description of your application.
138
+ This may help a lot having a consistent command-line help.
139
+ EOD
140
+ puts config.command_line_help
141
+ ```
142
+
143
+ This would issue:
144
+
145
+ ```
146
+ Usage: myscript [options]
147
+ My super Application Version: 1.0.0
148
+
149
+ You can have a multiline description of your application.
150
+ This may help a lot having a consistent command-line help.
151
+
152
+ -- Generic options -------------------------------------------------------------
153
+ --auto Auto mode. Bypasses questions to user.
154
+ --simulate Do not perform the actual underlying actions.
155
+ -v, --verbose Enable verbose mode.
156
+ -h, --help Displays this help.
157
+ -- Configuration options -------------------------------------------------------
158
+ --config-file Specify a config file.
159
+ --config-override If specified override all other config.
160
+ ```
161
+
162
+ Which are the default options available.
163
+
164
+
165
+ #### Default command line options
166
+
167
+ By default the following command line options are available:
168
+
169
+ * __auto__ Auto mode. Bypasses questions to user. Just provided for convenience. Not used anywhere in the
170
+ code.
171
+ * __simulate__ Do not perform the actual underlying actions. Just provided for convenience. Not used anywhere
172
+ in the code.
173
+ * __verbose__ Enable verbose mode. Just provided for convenience. Not used anywhere in the code.
174
+ * __help__ Displays this help. Just provided for convenience. Not used anywhere in the code.
175
+ * __config-file__ Specify a config file for the extra layer.
176
+ * __config-override__ If specified, means that the config file specified will override all other config (actually
177
+ changes the merge policy [see below] (#changing-the-way-things-are-merged)) of the extra layer.
178
+
179
+ Flags that are said "Just provided for convenience. Not used anywhere in the code." are just there because they are
180
+ standard options and thus you can easily test in your code.
181
+
182
+ ```ruby
183
+ puts "Something very important" if config[:verbose]
184
+ ```
185
+
186
+ `stacked_config` provides a convenient method to display the command line help every user expects from a decent script:
187
+
188
+ ```ruby
189
+ require 'stacked_config'
190
+
191
+ config = StackedConfig::Orchestrator.new
192
+
193
+ if config[:help]
194
+ # command_line_help will provide a formatted help to display on the command line
195
+ puts config.command_line_help
196
+ exit 0
197
+ end
198
+
199
+ # ... do something else
200
+ ```
201
+
202
+ #### Adding new command line options
95
203
 
96
- To define your options the command-line layer exposes a `slop_definition` method that enables
97
- to directly configure slop.
204
+ To define your options the command-line layer exposes a `slop_definition` method that enables to directly configure
205
+ slop.
98
206
 
99
207
  For most usages you can use the higher level method `add_command_line_section` from the orchestrator.
100
208
 
@@ -110,20 +218,23 @@ end
110
218
 
111
219
  The `add_command_line_section` method supports a parameter to define the name of the section.
112
220
 
221
+ __Of course adding new command line options will adapt the display of the `command_line_help` method of the
222
+ orchestrator__.
113
223
 
114
- ### Advanced usage
115
224
 
116
- #### Re-ordering layers
225
+ ## Advanced usage
226
+
227
+ ### Re-ordering layers
117
228
 
118
229
  The way layers are processed is done according to their priority. By default the existing layers have the following
119
230
  priorities:
120
231
 
121
- * The system layer has a priority of 10
122
- * The global layer has a priority of 20
123
- * The user layer has a priority of 30
124
- * The extra layer has a priority of 40
125
- * The command-line layer has a priority of 100
126
- * The override layer has a priority of 1000
232
+ * The system layer has a priority of __10__
233
+ * The global layer has a priority of __20__
234
+ * The user layer has a priority of __30__
235
+ * The extra layer has a priority of __40__
236
+ * The command-line layer has a priority of __100__
237
+ * The override layer has a priority of __1000__
127
238
 
128
239
  But imagine you want to say that no-one could override properties defined at the system and global layer even from the
129
240
  command-line, then you just have to change the priorities of those 2 layers.
@@ -137,10 +248,10 @@ config.global_layer.priority = 1600
137
248
  ```
138
249
 
139
250
  By doing such the system and global layers will be evaluated after the command line layer and therefore properties set
140
- in those files cannot be overridden even at command line level.
251
+ in those files cannot be overridden even at command line level thanks to [super_stack][SS] mechanisms.
141
252
 
142
253
 
143
- #### Adding extra layers
254
+ ### Adding extra layers
144
255
 
145
256
  Imagine you want to add a specific layer in your config, coming from let's say a web-service or a database, you may
146
257
  create your own layers for this purpose. Have a look at [super_stack gem][SS] for further info about how to create
@@ -148,14 +259,165 @@ layers.
148
259
 
149
260
  But basically just create your new layer, gives it a priority and add it to the orchestrator.
150
261
 
262
+ ### Changing the way things are merged
263
+
264
+ The [super_stack gem][SS] defines some different merge policies. By default `stacked_config` will use the
265
+ `SuperStack::MergePolicies::FullMergePolicy` that merges hashes and arrays at all levels. But you can choose to completely
266
+ change the merge behaviour by changing the merge policy. See [super_stack gem][SS] documentation for other merge
267
+ policies.
268
+
269
+ Merge policies can be changed either at orchestrator level or at layer level by setting the merge_policy property.
270
+
271
+ This is actually exactly what happens when the `config-override` flag is passed on the command line. It triggers the
272
+ change of the merge policy of the extra layer from `SuperStack::MergePolicies::FullMergePolicy` to
273
+ `SuperStack::MergePolicies::OverridePolicy`.
274
+
275
+ ## A complete example of a program using `stacked_config`
276
+
277
+ Save the following file somewhere as `example.rb`.
278
+
279
+ You can use this as a template for your own scripts:
280
+
281
+ ```ruby
282
+ #!/usr/bin/env ruby
283
+
284
+ require 'stacked_config'
285
+
286
+ class MyApp
287
+
288
+ VERSION = '0.0.1'
289
+ NAME = 'My brand new Application'
290
+ DESCRIPTION = 'Best app ever'
291
+
292
+ attr_reader :config
293
+
294
+ def initialize
295
+ @config = StackedConfig::Orchestrator.new
296
+ config.describes_application app_name: NAME, app_version: VERSION, app_description: DESCRIPTION
297
+ add_script_options
298
+ end
299
+
300
+
301
+ def add_script_options
302
+ config.add_command_line_section('Options for the script') do |slop|
303
+ slop.on :u, :useless, 'Stupid option', :argument => false
304
+ slop.on :an_int, 'Stupid option with integer argument', :argument => true, :as => Integer
305
+ end
306
+ end
307
+
308
+ def run
309
+ if config[:help]
310
+ puts config.command_line_help
311
+ exit 0
312
+ end
313
+ do_some_processing
314
+ end
315
+
316
+ def do_some_processing
317
+ # Here you would really start your process
318
+ config[:something] = 'Added something...'
319
+
320
+ if config[:verbose]
321
+ puts ' ## Here is a display of the config sources and contents'
322
+ puts config.detailed_layers_info
323
+ puts ' ## This the resulting merged config'
324
+ puts config[].to_yaml
325
+ end
326
+
327
+ puts ' ## Bye...'
328
+ end
329
+
330
+ end
331
+
332
+ MyApp.new.run
333
+ ```
334
+
335
+ If you run
336
+
337
+ $ ./example.rb
338
+
339
+ You would get
340
+
341
+ ```
342
+ ## Bye...
343
+ ```
344
+
345
+ If you run
346
+
347
+ $ ./example.rb --help
348
+
349
+ You would get
350
+
351
+ ```
352
+ Usage: example [options]
353
+ My brand new Application Version: 0.0.1
354
+
355
+ Best app ever
356
+ -- Generic options -------------------------------------------------------------
357
+ --auto Auto mode. Bypasses questions to user.
358
+ --simulate Do not perform the actual underlying actions.
359
+ -v, --verbose Enable verbose mode.
360
+ -h, --help Displays this help.
361
+ -- Configuration options -------------------------------------------------------
362
+ --config-file Specify a config file.
363
+ --config-override If specified override all other config.
364
+ -- Options for the script ------------------------------------------------------
365
+ -u, --useless Stupid option
366
+ --an_int Stupid option with integer argument
367
+ ```
368
+
369
+ If you run
370
+
371
+ $ ./example.rb --verbose
372
+
373
+ You would get
374
+ ```
375
+ ## Here is a display of the config sources and contents
376
+ --------------------------------------------------------------------------------
377
+ System-wide configuration level
378
+ There is no file attached to this level.
379
+ There is no data in this layer
380
+ --------------------------------------------------------------------------------
381
+ Global configuration level
382
+ There is no file attached to this level.
383
+ There is no data in this layer
384
+ --------------------------------------------------------------------------------
385
+ User configuration level
386
+ There is no file attached to this level.
387
+ There is no data in this layer
388
+ --------------------------------------------------------------------------------
389
+ Specific config file configuration level
390
+ There is no file attached to this level.
391
+ There is no data in this layer
392
+ --------------------------------------------------------------------------------
393
+ Command line configuration level
394
+ There is no file attached to this level.
395
+ This layer contains the following data:
396
+ --- !ruby/hash:StackedConfig::Layers::CommandLineLayer
397
+ :verbose: true
398
+
399
+ --------------------------------------------------------------------------------
400
+ Overridden configuration level
401
+ There is no file attached to this level.
402
+ This layer contains the following data:
403
+ --- !ruby/hash:SuperStack::Layer
404
+ :something: Added something...
405
+
406
+ --------------------------------------------------------------------------------
407
+ ## This the resulting merged config
408
+ ---
409
+ :verbose: true
410
+ :something: Added something...
411
+ ## Bye...
412
+ ```
151
413
 
152
414
  ## Contributing
153
415
 
154
- 1. [Fork it] ( https://github.com/lbriais/stacked_config/fork )
155
- 2. Create your feature branch (`git checkout -b my-new-feature`)
156
- 3. Commit your changes (`git commit -am 'Add some feature'`)
157
- 4. Push to the branch (`git push origin my-new-feature`)
158
- 5. Create new Pull Request
416
+ 1. [Fork it] ( https://github.com/lbriais/stacked_config/fork ), clone your fork.
417
+ 2. Create your feature branch (`git checkout -b my-new-feature`) and develop your super extra feature.
418
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
419
+ 4. Push to the branch (`git push origin my-new-feature`).
420
+ 5. Create a Pull Request.
159
421
 
160
422
  [SS]: https://github.com/lbriais/super_stack "Super Stack gem"
161
423
  [SystemLayer]: https://github.com/lbriais/stacked_config/blob/master/lib/stacked_config/layers/system_layer.rb "the system layer places where config files are searched"
@@ -14,30 +14,6 @@ module StackedConfig
14
14
  describes_application executable_name: default_name, app_name: default_name
15
15
  end
16
16
 
17
- def detailed_layers_info
18
- info, sep = [], '-' * 80
19
- info << sep
20
- layers.values.sort {|a, b| a.priority <=> b.priority}.each do |layer|
21
- info << layer.name
22
- if layer.file_name.nil?
23
- info << 'There is no file attached to this level.'
24
- else
25
- info << "Using '#{layer.file_name}' as config file for this layer."
26
- end
27
- if layer.empty?
28
- info << 'There is no data in this layer'
29
- else
30
- info << 'This layer contains the following data:'
31
- info << layer.to_yaml
32
- end
33
- info << sep
34
- end
35
- info.join "\n"
36
- end
37
-
38
- def command_line_help
39
- command_line_layer.help
40
- end
41
17
 
42
18
  def self.default_executable_name
43
19
  File.basename($PROGRAM_NAME).gsub /\.[^\.]+$/, ''
@@ -42,6 +42,32 @@ module StackedConfig
42
42
 
43
43
  end
44
44
 
45
+
46
+ def detailed_layers_info
47
+ info, sep = [], '-' * 80
48
+ info << sep
49
+ layers.values.sort {|a, b| a.priority <=> b.priority}.each do |layer|
50
+ info << layer.name
51
+ if layer.file_name.nil?
52
+ info << 'There is no file attached to this level.'
53
+ else
54
+ info << "Using '#{layer.file_name}' as config file for this layer."
55
+ end
56
+ if layer.empty?
57
+ info << 'There is no data in this layer'
58
+ else
59
+ info << 'This layer contains the following data:'
60
+ info << layer.to_yaml
61
+ end
62
+ info << sep
63
+ end
64
+ info.join "\n"
65
+ end
66
+
67
+ def command_line_help
68
+ command_line_layer.help
69
+ end
70
+
45
71
  def describes_application(options = {})
46
72
  self.app_name = options.fetch(:app_name, nil)
47
73
  self.app_version = options.fetch(:app_version, nil)
@@ -1,3 +1,3 @@
1
1
  module StackedConfig
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stacked_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent B.