configliere 0.3.4 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +3 -0
- data/.watchr +20 -0
- data/CHANGELOG.textile +99 -3
- data/Gemfile +26 -0
- data/Gemfile.lock +54 -0
- data/README.textile +162 -138
- data/Rakefile +30 -21
- data/VERSION +1 -1
- data/bin/configliere +77 -77
- data/bin/configliere-decrypt +85 -0
- data/bin/configliere-delete +85 -0
- data/bin/configliere-dump +85 -0
- data/bin/configliere-encrypt +85 -0
- data/bin/configliere-list +85 -0
- data/bin/configliere-set +85 -0
- data/configliere.gemspec +53 -23
- data/examples/config_block_script.rb +9 -2
- data/examples/encrypted_script.rb +28 -16
- data/examples/env_var_script.rb +2 -2
- data/examples/help_message_demo.rb +16 -0
- data/examples/independent_config.rb +28 -0
- data/examples/prompt.rb +23 -0
- data/examples/simple_script.rb +28 -15
- data/examples/simple_script.yaml +1 -1
- data/lib/configliere.rb +22 -24
- data/lib/configliere/commandline.rb +135 -116
- data/lib/configliere/commands.rb +38 -54
- data/lib/configliere/config_block.rb +4 -2
- data/lib/configliere/config_file.rb +30 -52
- data/lib/configliere/crypter.rb +8 -5
- data/lib/configliere/deep_hash.rb +368 -0
- data/lib/configliere/define.rb +83 -89
- data/lib/configliere/encrypted.rb +17 -18
- data/lib/configliere/env_var.rb +5 -7
- data/lib/configliere/param.rb +37 -64
- data/lib/configliere/prompt.rb +23 -0
- data/spec/configliere/commandline_spec.rb +156 -57
- data/spec/configliere/commands_spec.rb +75 -30
- data/spec/configliere/config_block_spec.rb +10 -1
- data/spec/configliere/config_file_spec.rb +83 -55
- data/spec/configliere/crypter_spec.rb +3 -2
- data/spec/configliere/deep_hash_spec.rb +401 -0
- data/spec/configliere/define_spec.rb +121 -42
- data/spec/configliere/encrypted_spec.rb +53 -20
- data/spec/configliere/env_var_spec.rb +24 -4
- data/spec/configliere/param_spec.rb +25 -27
- data/spec/configliere/prompt_spec.rb +50 -0
- data/spec/configliere_spec.rb +3 -9
- data/spec/spec_helper.rb +17 -6
- metadata +110 -35
- data/lib/configliere/core_ext.rb +0 -2
- data/lib/configliere/core_ext/blank.rb +0 -93
- data/lib/configliere/core_ext/hash.rb +0 -108
- data/lib/configliere/core_ext/sash.rb +0 -170
- data/spec/configliere/core_ext/hash_spec.rb +0 -78
- data/spec/configliere/core_ext/sash_spec.rb +0 -312
data/.document
CHANGED
data/.watchr
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
def run_spec(file)
|
4
|
+
unless File.exist?(file)
|
5
|
+
puts "#{file} does not exist"
|
6
|
+
return
|
7
|
+
end
|
8
|
+
|
9
|
+
puts "Running #{file}"
|
10
|
+
system "bundle exec rspec #{file}"
|
11
|
+
puts
|
12
|
+
end
|
13
|
+
|
14
|
+
watch("spec/.*/*_spec\.rb") do |match|
|
15
|
+
run_spec match[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
watch("lib/(.*)\.rb") do |match|
|
19
|
+
run_spec %{spec/#{match[1]}_spec.rb}
|
20
|
+
end
|
data/CHANGELOG.textile
CHANGED
@@ -1,3 +1,98 @@
|
|
1
|
+
h2. Version 0.4.0 2011-05-13: MANY BREAKING CHANGES
|
2
|
+
|
3
|
+
Killed many features for great justice. Configliere should now be much more predictable and lightweight, and has a much stricter API. Unfortunately, this will break backwards compatibility in some ways.
|
4
|
+
|
5
|
+
h4. Cleanup of the Configliere::Params "Magic Hash" class
|
6
|
+
|
7
|
+
* Configliere no longer modifies any core classes
|
8
|
+
* All the hash gymnastics have been relocated to DeepHash.
|
9
|
+
* DeepHash now converts *all* keys to symbols, and transparently handles deep keys:
|
10
|
+
|
11
|
+
<pre>
|
12
|
+
Settings['foo.bar'] = 1
|
13
|
+
Settings.merge! 'foo.bar' => 1
|
14
|
+
Settings[ [:foo, :bar] ] = 1
|
15
|
+
# => all give { :foo => { :bar => 1 } }
|
16
|
+
</pre>
|
17
|
+
|
18
|
+
* DeepHash typeconverts objects of type Hash to DeepHash when merged or added.
|
19
|
+
* DeepHash added several convenience methods -- @slice/slice!@, @compact/compact!@, @extract/extract!@, @reverse_merge/reverse_merge!@, @assert_valid_keys@.
|
20
|
+
|
21
|
+
* Configliere::Params @#defaults@, @#resolve!@, @#validate!@ and @#use@ all return self, so you can say
|
22
|
+
|
23
|
+
<pre>Settings.defaults(:hi => :mom).use(:commandline).resolve!.validate!</pre>
|
24
|
+
|
25
|
+
* Configliere::Params.use now adds middleware only to the *instance* -- you don't get commandline params in your settings object just becaus some other class use'd it.
|
26
|
+
* Configliere::Params middlewares should supply a block to Configliere::Params.on_use to #extend the object, #use related middlewares, etc.
|
27
|
+
|
28
|
+
h4. Cleanup of Configliere::Define.
|
29
|
+
|
30
|
+
* The prepositional soup of accessor sugar is gone, replaced by three public methods:
|
31
|
+
- @definition_of(param, aspect=nil)@ (without arg, gives the definition hash; with arg, gives that value);
|
32
|
+
- @params_with(aspect)@ (hash of param => aspect_definition)
|
33
|
+
- has_definition?(param) (has #define been called for that param?)
|
34
|
+
see below for what's gone.
|
35
|
+
* Specs for the magical getter/setter given when you define a param, and for deep key handling.
|
36
|
+
|
37
|
+
* Commandline now tracks commandline arguments that haven't been define'd in @unknown_argvs@. It adopts them all the same, but if you don't like what you see there you're free to raise a warning or error.
|
38
|
+
* Single-character flags now take an argument: @-a=hello@ or @-a hello@
|
39
|
+
|
40
|
+
h4. Misc
|
41
|
+
|
42
|
+
* :encrypted keys are now stored as base64-encoded
|
43
|
+
* cleaned up handling of encrypt_pass -- it's no longer publicly readable; set it as a member (Settings[:encrypt_pass]) or through the ENCRYPT_PASS environment variable and it will be adopted in the course of action (and, if a member, deleted). Because of the #use method refactoring, you can have independent settings bundles use encrypted independently.
|
44
|
+
* Prompt is now its own middleware:
|
45
|
+
|
46
|
+
<pre>
|
47
|
+
Settings.use :prompt
|
48
|
+
pwd = Settings.prompt_for(:password)
|
49
|
+
</pre>
|
50
|
+
|
51
|
+
* bin/configliere shows off the git-style-binaries aspect, and helps you set encrypted params.
|
52
|
+
* Specs documentation is now quite readable
|
53
|
+
* Cleaned up the STDERR-capturing part of the specs
|
54
|
+
* Added spork and watchr support to the specs.
|
55
|
+
|
56
|
+
h4. Killing features for great justice:
|
57
|
+
|
58
|
+
* No modifications to core classes. Scripts that were secretly depending on Configliere for blank? etc might now break. deep_merge, deep_set and deep_delete have been moved to a DeepHash class, and the Sash class is gone.
|
59
|
+
|
60
|
+
* dashed commandline params are accepted but cause a warning -- they do *not* serve as deep keys. By default Configliere happily accepts them. To change that, make a middleware to either convert --foo-bar to --foo.bar, or convert --foo-bar to --foo_bar.
|
61
|
+
|
62
|
+
* config_file now just takes a filename: Instead of a magic handle, scope a segment of the file with the :env option:
|
63
|
+
|
64
|
+
<pre>Settings.read('./config/foo.yaml', :env => ENV['RACK_ENV'])</pre>
|
65
|
+
|
66
|
+
Stripped out a whole raft of oversweet sugar:
|
67
|
+
|
68
|
+
* Settings.argv Settings.rest
|
69
|
+
* Settings.commands? Settings.params_with(:command).empty?
|
70
|
+
* Configliere.new Configliere::Param.new
|
71
|
+
* param_or_ask Settings.prompt_for (with Settings.use(:prompt))
|
72
|
+
* param_definitions Not publicly accessible, use definition_of(param)
|
73
|
+
* described_params Settings.params_with(:description)
|
74
|
+
* type_for Settings.definition_of(param, :type)
|
75
|
+
* typed_params Settings.params_with(:type)
|
76
|
+
* required_params Settings.params_with(:required)
|
77
|
+
* define with :no_help and :no_env_help (instead say @:internal@)
|
78
|
+
|
79
|
+
* Removed the long-deprecated :git_style_binaries synonym for :commands
|
80
|
+
|
81
|
+
h2. Version 0.3.4
|
82
|
+
|
83
|
+
The jump in minor version number was unintentional.
|
84
|
+
|
85
|
+
* handle case wehre file is empty on environment merge
|
86
|
+
* read returns self, so can chain
|
87
|
+
|
88
|
+
h2. Version 0.2.3
|
89
|
+
|
90
|
+
* Added a feature to load only production/development/etc subhash from a config file, so:
|
91
|
+
|
92
|
+
<pre>
|
93
|
+
Settings.read(root_path('config/foo.yaml'), :env => ENV['RACK_ENV'])
|
94
|
+
</pre>
|
95
|
+
|
1
96
|
h2. Version 0.2.1 2011-01-28
|
2
97
|
|
3
98
|
* Missing required params include their definition in error message
|
@@ -13,10 +108,10 @@ h2. Version 0.1.0 2010-07-24
|
|
13
108
|
* Single-letter option flags
|
14
109
|
* Can give a ':finally' proc (or hand a block to) Settings.define. Example:
|
15
110
|
|
16
|
-
<pre
|
111
|
+
<pre>
|
17
112
|
Settings.define :key_pair_file, :description => 'AWS Key pair file', :finally => lambda{ Settings.key_pair_file = File.expand_path(Settings.key_pair_file.to_s) if Settings.key_pair_file }
|
18
113
|
Settings.define :key_pair, :description => "AWS Key pair name. If not specified, it's taken from key_pair_file's basename", :finally => lambda{ Settings.key_pair ||= File.basename(Settings.key_pair_file.to_s, '.pem') if Settings.key_pair_file }
|
19
|
-
</
|
114
|
+
</pre>
|
20
115
|
|
21
116
|
h2. Version 0.0.8 2010-05-02
|
22
117
|
|
@@ -39,10 +134,11 @@ h2. Version 0.0.4 2010-01-16
|
|
39
134
|
h2. Version 0.0.3 2010-01-15
|
40
135
|
|
41
136
|
* @Settings.param@ now only works for params that have been @#define@'d :
|
137
|
+
|
42
138
|
<pre>
|
43
139
|
Settings :no_yuo => 'oops'
|
44
140
|
Settings.no_yuo
|
45
|
-
#=> NoMethodError: undefined method `no_yuo' for {:no_yuo=>"oops"}:Configliere::Param
|
141
|
+
#=> NoMethodError: undefined method `no_yuo' for { :no_yuo => "oops" } :Configliere::Param
|
46
142
|
Settings.define :happy_param, :default => 'yay'
|
47
143
|
Settings.happy_param
|
48
144
|
#=> "yay"
|
data/Gemfile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Add dependencies to develop your gem here.
|
4
|
+
# Include everything needed to run rake, tests, features, etc.
|
5
|
+
group :development do
|
6
|
+
gem 'bundler', "~> 1.0.12"
|
7
|
+
gem 'yard', "~> 0.6.7"
|
8
|
+
gem 'jeweler', "~> 1.5.2"
|
9
|
+
gem 'rspec', "~> 2.5.0"
|
10
|
+
gem 'spork', "~> 0.9.0.rc5"
|
11
|
+
gem 'RedCloth' # for yard
|
12
|
+
end
|
13
|
+
|
14
|
+
group :development do
|
15
|
+
# purely optional, used in the sample scripts
|
16
|
+
gem 'gorillib', ">= 0.0.4"
|
17
|
+
gem 'highline', ">= 1.5.2"
|
18
|
+
end
|
19
|
+
|
20
|
+
group :optional do
|
21
|
+
# only interesting for coverage testing
|
22
|
+
gem 'rcov', ">= 0.9.9"
|
23
|
+
gem 'reek'
|
24
|
+
gem 'roodi'
|
25
|
+
gem 'watchr'
|
26
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
RedCloth (4.2.7)
|
5
|
+
diff-lcs (1.1.2)
|
6
|
+
git (1.2.5)
|
7
|
+
gorillib (0.0.7)
|
8
|
+
highline (1.6.1)
|
9
|
+
jeweler (1.5.2)
|
10
|
+
bundler (~> 1.0.0)
|
11
|
+
git (>= 1.2.5)
|
12
|
+
rake
|
13
|
+
rake (0.8.7)
|
14
|
+
rcov (0.9.9)
|
15
|
+
reek (1.2.8)
|
16
|
+
ruby2ruby (~> 1.2)
|
17
|
+
ruby_parser (~> 2.0)
|
18
|
+
sexp_processor (~> 3.0)
|
19
|
+
roodi (2.1.0)
|
20
|
+
ruby_parser
|
21
|
+
rspec (2.5.0)
|
22
|
+
rspec-core (~> 2.5.0)
|
23
|
+
rspec-expectations (~> 2.5.0)
|
24
|
+
rspec-mocks (~> 2.5.0)
|
25
|
+
rspec-core (2.5.2)
|
26
|
+
rspec-expectations (2.5.0)
|
27
|
+
diff-lcs (~> 1.1.2)
|
28
|
+
rspec-mocks (2.5.0)
|
29
|
+
ruby2ruby (1.2.5)
|
30
|
+
ruby_parser (~> 2.0)
|
31
|
+
sexp_processor (~> 3.0)
|
32
|
+
ruby_parser (2.0.6)
|
33
|
+
sexp_processor (~> 3.0)
|
34
|
+
sexp_processor (3.0.5)
|
35
|
+
spork (0.9.0.rc7)
|
36
|
+
watchr (0.7)
|
37
|
+
yard (0.6.8)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
RedCloth
|
44
|
+
bundler (~> 1.0.12)
|
45
|
+
gorillib (>= 0.0.4)
|
46
|
+
highline (>= 1.5.2)
|
47
|
+
jeweler (~> 1.5.2)
|
48
|
+
rcov (>= 0.9.9)
|
49
|
+
reek
|
50
|
+
roodi
|
51
|
+
rspec (~> 2.5.0)
|
52
|
+
spork (~> 0.9.0.rc5)
|
53
|
+
watchr
|
54
|
+
yard (~> 0.6.7)
|
data/README.textile
CHANGED
@@ -6,34 +6,45 @@ bq. So, Consigliere of mine, I think you should tell your Don what everyone know
|
|
6
6
|
|
7
7
|
You've got a script. It's got some settings. Some settings are for this module, some are for that module. Most of them don't change. Except on your laptop, where the paths are different. Or when you're in production mode. Or when you're testing from the command line.
|
8
8
|
|
9
|
-
Configliere manages settings from many sources: static constants, simple config files, environment variables, commandline options, straight ruby. You don't have to predefine anything, but you can ask configliere to type-convert, require, document or password-obscure any of its fields.
|
9
|
+
Configliere manages settings from many sources: static constants, simple config files, environment variables, commandline options, straight ruby. You don't have to predefine anything, but you can ask configliere to type-convert, require, document or password-obscure any of its fields. Basically: *Settings go in, the right thing happens*.
|
10
10
|
|
11
|
-
|
11
|
+
h2. Example
|
12
12
|
|
13
13
|
Here's a simple example, using params from a config file and the command line. In the script:
|
14
14
|
|
15
15
|
<pre>
|
16
16
|
#/usr/bin/env ruby
|
17
17
|
require 'configliere'
|
18
|
-
Settings.use :commandline
|
18
|
+
Settings.use :commandline
|
19
19
|
|
20
|
+
# Supply defaults inline.
|
20
21
|
Settings({
|
21
|
-
:dest_time => '
|
22
|
+
:dest_time => '11-05-1955',
|
22
23
|
:delorean => {
|
23
24
|
:power_source => 'plutonium',
|
24
25
|
:roads_needed => true,
|
25
26
|
},
|
26
27
|
:username => 'marty',
|
27
28
|
})
|
28
|
-
|
29
|
+
|
30
|
+
# Pre-defining params isn't required, but it's easy and expressive to do so:
|
31
|
+
Settings.define :dest_time, :type => DateTime, :description => "Target date"
|
32
|
+
# This defines a 'deep key': it controls Settings[:delorean][:roads_needed]
|
33
|
+
Settings.define 'delorean.roads_needed', :type => :boolean
|
34
|
+
|
35
|
+
# The settings in this file will be merged with the above
|
36
|
+
Settings.read './examples/simple_script.yaml'
|
37
|
+
|
38
|
+
# resolve! the settings: load the commandline, do type conversion, etc.
|
29
39
|
Settings.resolve!
|
30
|
-
p Settings
|
40
|
+
p Settings
|
41
|
+
</pre>
|
31
42
|
|
32
|
-
We'll override some of the defaults with a config file, in this case
|
43
|
+
We'll override some of the defaults with a config file, in this case ./examples/simple_script.yaml
|
33
44
|
|
34
45
|
<pre>
|
35
46
|
# Settings for return
|
36
|
-
:dest_time:
|
47
|
+
:dest_time: 11-05-1985
|
37
48
|
:delorean:
|
38
49
|
:power_source: 1.21 jiggawatts
|
39
50
|
</pre>
|
@@ -42,35 +53,72 @@ Output, when run with commandline parameters as shown:
|
|
42
53
|
|
43
54
|
<pre>
|
44
55
|
./time_machine.rb --username=doc_brown --delorean.roads_needed="" --delorean.power_source="Mr. Fusion"
|
45
|
-
|
56
|
+
|
57
|
+
{:delorean => {:power_source=>"Mr. Fusion", :roads_needed=>nil}, :username=>"doc_brown", :dest_time=>#<DateTime: 1985-05-11T00:00:00+00:00>}
|
46
58
|
</pre>
|
47
59
|
|
48
60
|
For an extensive usage in production, see the "wukong gem.":http://github.com/mrflip/wukong
|
49
61
|
|
50
|
-
|
62
|
+
h2. Notice
|
63
|
+
|
64
|
+
Configliere 4.x now has 100% spec coverage, more powerful commandline handling, zero required dependencies. However, it also strips out several obscure features and much magical code, which breaks said obscure features and magic-dependent code. See the "CHANGELOG.":CHANGELOG.textile for details as you upgrade.
|
65
|
+
|
66
|
+
h2. Design goals:
|
67
|
+
|
68
|
+
* *Omerta (Code of Silence)*. Most commandline parsers force you to pre-define all your parameters in a centralized and wordy syntax. In configliere, you don't have to pre-define anything -- commandline parameters map directly to values in the Configliere hash. Here's all you need to have full-fledged commandline params:
|
69
|
+
|
70
|
+
<pre>
|
71
|
+
$ cat ./shorty.rb
|
72
|
+
require 'configliere'
|
73
|
+
Settings.use(:commandline).resolve!
|
74
|
+
p [Settings, Settings.rest]
|
75
|
+
|
76
|
+
$ ./shorty.rb --foo=bar go
|
77
|
+
[{:foo=>"bar"}, ["go"]]
|
78
|
+
</pre>
|
51
79
|
|
52
|
-
* *Don't go outside the family*. Requires almost no external resources and almost no code in your script.
|
53
|
-
* *Don't mess with my crew*. Settings for a model over here can be done independently of settings for a model over there, and don't require asking the boss to set something up.
|
54
80
|
* *Be willing to sit down with the Five Families*. Takes settings from (at your option):
|
55
81
|
** Pre-defined defaults from constants
|
56
|
-
** Simple config files
|
82
|
+
** Simple config files
|
57
83
|
** Environment variables
|
58
|
-
** Commandline options
|
59
|
-
** Ruby block called when all other options are in place
|
60
|
-
|
84
|
+
** Commandline options and git-style command runners
|
85
|
+
** Ruby block (called when all other options are in place)
|
86
|
+
|
87
|
+
* *Don't go outside the family*. Has no dependencies and requires almost no code in your script. Configliere makes no changes to standard ruby classes.
|
88
|
+
|
89
|
+
* *Offer discreet counsel*. Configliere offers many features, but only loads the code you request explicitly by calling @use@.
|
90
|
+
|
91
|
+
* *Don't mess with my crew*. Settings for a model over here can be done independently of settings for a model over there, and don't require asking the boss to set something up. You centralize configuration _values_ while distributing configuration _definition_:
|
92
|
+
|
93
|
+
<pre>
|
94
|
+
# In lib/handler/mysql.rb
|
95
|
+
Settings.define :mysql_host, :type => String, :description => "MySQL db hostname", :default => 'localhost'
|
96
|
+
|
97
|
+
# In app/routes/homepage.rb
|
98
|
+
Settings.define :background_color, :description => "Homepage background color"
|
99
|
+
|
100
|
+
# In config/app.yaml
|
101
|
+
---
|
102
|
+
:background_color: '#eee'
|
103
|
+
:mysql_host: 'brains.infochimps.com'
|
104
|
+
</pre>
|
105
|
+
|
106
|
+
You can decentralize even more by giving modules their own config files or separate Configliere::Param objects.
|
107
|
+
|
61
108
|
* *Can hide your assets*. Rather than storing passwords and API keys in plain sight, configliere has a protection racket that can obscure values when stored to disk.
|
62
109
|
|
63
110
|
fuhgeddaboudit.
|
64
111
|
|
112
|
+
|
65
113
|
h2. Settings structure
|
66
114
|
|
67
|
-
Configliere settings
|
115
|
+
A Configliere settings object is just a (mostly-)normal hash.
|
68
116
|
|
69
117
|
You can define static defaults in your module
|
70
118
|
|
71
119
|
<pre>
|
72
120
|
Settings({
|
73
|
-
:dest_time => '
|
121
|
+
:dest_time => '11-05-1955',
|
74
122
|
:fluxcapacitor => {
|
75
123
|
:speed => 88,
|
76
124
|
},
|
@@ -83,11 +131,11 @@ You can define static defaults in your module
|
|
83
131
|
})
|
84
132
|
</pre>
|
85
133
|
|
86
|
-
|
134
|
+
All simple keys should be symbols. Retrieve the settings as:
|
87
135
|
|
88
136
|
<pre>
|
89
137
|
# hash keys
|
90
|
-
Settings[:dest_time] #=> '
|
138
|
+
Settings[:dest_time] #=> '11-05-1955'
|
91
139
|
# deep keys
|
92
140
|
Settings[:delorean][:power_source] #=> 'plutonium'
|
93
141
|
Settings[:delorean][:missing] #=> nil
|
@@ -97,199 +145,150 @@ You can define static defaults in your module
|
|
97
145
|
Settings['delorean.missing'] #=> nil
|
98
146
|
Settings['delorean.missing.fail'] #=> nil
|
99
147
|
# method-like (no deep keys tho, and you have to #define the param; see below)
|
100
|
-
Settings.dest_time #=> '
|
101
|
-
</pre>
|
102
|
-
|
103
|
-
h3. Shortcut syntax for deep keys
|
104
|
-
|
105
|
-
You can use a 'dotted key' like 'delorean.power_source' as simple notation for a deep key: @Settings['delorean.power_source']@ is equivalent to @Settings[:delorean][:power_source]@. You can use a dotted key in any simple reference:
|
106
|
-
|
107
|
-
<pre>
|
108
|
-
Settings['delorean.power_source'] = "Mr. Fusion"
|
109
|
-
Settings[:delorean][:power_source]
|
110
|
-
#=> "Mr. Fusion"
|
111
|
-
Settings.delete('delorean.power_source')
|
112
|
-
#=> "Mr. Fusion"
|
113
|
-
Settings
|
114
|
-
#=> { :delorean => {} }
|
115
|
-
</pre>
|
116
|
-
|
117
|
-
Intermediate keys "auto-vivify" (automatically create any intervening hashes):
|
118
|
-
|
119
|
-
<pre>
|
120
|
-
Settings['one.two.three'] = "To tha Fo'"
|
121
|
-
# Settings is { :one => { :two => { :three => "To tha Fo'" } }, :delorean => { :power_source => "Mr. Fusion" }
|
122
|
-
</pre>
|
123
|
-
|
124
|
-
Do *not* use a dotted key except as a simple reference. You'll ruin Christmas:
|
125
|
-
|
126
|
-
<pre>
|
127
|
-
Settings.defaults :this => "that", "made.of.fail" => "oops"
|
128
|
-
#=> { :this => "that", :"made.of.fail" => "oops" } # !!! BROKEN !!!
|
129
|
-
</pre>
|
130
|
-
|
131
|
-
This may change once we figure out how to handle it all more cleanly, and how to balance "Keep it Simple, Stupid" with "Keep it Convenient, Kilroy".
|
132
|
-
|
133
|
-
h3. Only basic functionality loaded by default
|
134
|
-
|
135
|
-
Configliere doesn't load any other functionality by default -- you may not want to load config files, or environment variable handling, and so forth. You can require each file directly, or call @Configliere.use@ with a list of mixins (:all to load all functionality).
|
136
|
-
|
137
|
-
<pre>
|
138
|
-
Configliere.use :config_file, :define # Load config files and pre-define
|
139
|
-
Configliere.use :all # all of them
|
148
|
+
Settings.dest_time #=> '11-05-1955'
|
140
149
|
</pre>
|
141
150
|
|
142
151
|
h2. Configuration files
|
143
152
|
|
144
|
-
Call @Settings.read(
|
153
|
+
Call @Settings.read(filename)@ to read a YAML config file.
|
145
154
|
|
146
155
|
<pre>
|
147
156
|
# Settings for version II.
|
148
|
-
:
|
149
|
-
:dest_time: 2015-11-05
|
150
|
-
:delorean:
|
151
|
-
:power_source: Mr. Fusion
|
152
|
-
:roads_needed: ~
|
153
|
-
</pre>
|
154
|
-
|
155
|
-
You can instead supply a path to a config file. If a bare filename (no '/') is given, configliere looks for the file in @Configliere::DEFAULT_CONFIG_DIR@ (normally ~/.configliere). Otherwise it loads the given file.
|
156
|
-
|
157
|
-
<pre>
|
158
|
-
Settings.read(:time_machine) # looks in ~/.configliere.yaml, and extracts the :time_machine group
|
159
|
-
Settings.read('/etc/time_machine.yaml') # looks in /etc/time_machine.yaml
|
160
|
-
Settings.read('time_machine.yaml') # looks in ~/.configliere/time_machine.yaml
|
161
|
-
</pre>
|
162
|
-
|
163
|
-
When you read directly from a file you should leave off the top-level settings group:
|
164
|
-
|
165
|
-
<pre>
|
166
|
-
# Settings for version II.
|
167
|
-
:dest_time: 2015-11-05
|
157
|
+
:dest_time: 11-05-2015
|
168
158
|
:delorean:
|
169
159
|
:power_source: Mr. Fusion
|
170
160
|
:roads_needed: ~
|
171
161
|
</pre>
|
172
162
|
|
173
|
-
|
163
|
+
If a bare filename (no '/') is given, configliere looks for the file in @Configliere::DEFAULT_CONFIG_DIR@ (normally ~/.configliere). Otherwise it loads the given file.
|
174
164
|
|
175
165
|
<pre>
|
176
|
-
Settings.
|
177
|
-
Settings.
|
178
|
-
Settings.save('time_machine.yaml') # overwrites ~/.configliere/time_machine.yaml
|
166
|
+
Settings.read('/etc/time_machine.yaml') # looks in /etc/time_machine.yaml
|
167
|
+
Settings.read('time_machine.yaml') # looks in ~/.configliere/time_machine.yaml
|
179
168
|
</pre>
|
180
169
|
|
181
|
-
|
170
|
+
As you can see, you're free to use as many config files as you like. Loading a config file sets values immediately, so later-loaded files win out over earlier-loaded ones.
|
182
171
|
|
183
|
-
|
184
|
-
Settings.read('time_machine_global.yaml')
|
185
|
-
Settings.read('time_machine_site.yaml')
|
186
|
-
</pre>
|
187
|
-
|
188
|
-
h2. Environment Variables
|
172
|
+
You can save configuration too:
|
189
173
|
|
190
174
|
<pre>
|
191
|
-
Settings.
|
175
|
+
Settings.save!('/etc/time_machine.yaml') # overwrites /etc/time_machine.yaml
|
176
|
+
Settings.save!('time_machine.yaml') # overwrites ~/.configliere/time_machine.yaml
|
192
177
|
</pre>
|
193
178
|
|
194
|
-
As usual, dotted keys set the corresponeding nested key (@'delorean.power_source'@ sets @Settings[:delorean][:power_source]@). As shown below, you may also use #define to set up environment variables: @define 'delorean.power_source', :environment => 'POWER_SOURCE'@.
|
195
|
-
|
196
|
-
Environment variables are demonstrated in "examples/simple_script.rb":http://github.com/mrflip/configliere/tree/master/examples/simple_script.rb and "examples/env_var_script.rb":http://github.com/mrflip/configliere/tree/master/examples/env_var_script.rb
|
197
|
-
|
198
|
-
**NOTE**: The interface to #env_vars has changed since v0.2, see "CHANGELOG.textile":CHANGELOG.textile
|
199
|
-
|
200
179
|
h2. Command-line parameters
|
201
180
|
|
202
181
|
<pre>
|
203
182
|
# Head back
|
204
|
-
time_machine --delorean.power_source='1.21 gigawatt lightning strike' --dest_time=
|
183
|
+
time_machine --delorean.power_source='1.21 gigawatt lightning strike' --dest_time=11-05-1985
|
205
184
|
# (in the time_machine script:)
|
206
|
-
Settings.use
|
185
|
+
Settings.use(:commandline)
|
207
186
|
Settings.resolve!
|
208
187
|
</pre>
|
209
188
|
|
210
189
|
Interpretation of command-line parameters:
|
211
|
-
|
190
|
+
|
191
|
+
* *name-val params*: @--param=val@ sets @Configliere[:param]@ to val. You _must_ use the '=' in there: <code>./my_cmd --filename=bar</code> good, <code>./my_cmd --filename bar</code> bad.
|
212
192
|
* *boolean params*: @--param@ sets @Configliere[:param]@ to be true. @--param=""@ sets @Configliere[:param]@ to be nil.
|
213
|
-
* *
|
214
|
-
|
215
|
-
** Only @[\w
|
193
|
+
* *single-char flags*: Define a flag for a variable: <code>Settings.define :filename, :flag => "f"</code> allows you to say <code>./my_cmd -f=bar</code>.
|
194
|
+
* *scoped params*: A dot within a parameter name scopes that parameter: @--group.sub_group.param=val@ sets @Configliere[:group][:subgroup][:param]@ to val (and similarly for boolean parameters).
|
195
|
+
** Only @[\w\.]+@ are accepted in parameter names. '-' is currently accepted but causes a warning.
|
216
196
|
* *Settings.rest*: anything else is stored, in order, in @Settings.rest@.
|
217
197
|
* *stop marker*: a @--@ alone stops parameter processing and tosses all remaining params (not including the @--@) into Settings.rest.
|
218
198
|
|
219
199
|
Here are some things you don't get:
|
220
|
-
* There are no short parameters (-r, etc).
|
221
|
-
* Apart from converting @''@ (an explicit blank string) to @nil@, no type coercion is performed on parameters unless requested explicitly (see below).
|
222
|
-
* No validation is performed on parameters.
|
223
|
-
* No ordering or multiplicity is preserved (you can't say @--file=this --file=that@).
|
224
200
|
|
225
|
-
|
201
|
+
* Configliere doesn't complain about un-@define@'d commandline argvs. However, it does store each undefine'd argv (when resolve! is called) into @unknown_argvs@, so you can decide what to do about it.
|
202
|
+
* Apart from converting @''@ (an explicit blank string) to @nil@, no type coercion is performed on parameters unless requested explicitly (see below).
|
203
|
+
* No validation is performed on parameters, but you can insert a middleware with a @validate!()@ method, or use a @:finally@ block.
|
204
|
+
* No ordering or multiplicity is preserved: you can't say @--file=this --file=that@. Instead, define the param as an array <code>Settings.define :file, :type => Array</code> and give a simple comma-separated list.
|
226
205
|
|
227
|
-
Commandline parameters are demonstrated in "examples/simple_script.rb":http://github.com/mrflip/configliere/tree/master/examples/simple_script.rb and examples/env_var_script.rb":http://github.com/mrflip/configliere/tree/master/examples/env_var_script.rb
|
206
|
+
Commandline parameters are demonstrated in "examples/simple_script.rb":http://github.com/mrflip/configliere/tree/master/examples/simple_script.rb and "examples/env_var_script.rb":http://github.com/mrflip/configliere/tree/master/examples/env_var_script.rb
|
228
207
|
|
229
|
-
h2.
|
208
|
+
h2. Defined Parameters
|
230
209
|
|
231
210
|
You don't have to pre-define parameters, but you can:
|
232
211
|
|
233
212
|
<pre>
|
234
|
-
Settings.use :define
|
235
213
|
Settings.define :dest_time, :type => DateTime, :description => 'Arrival time'
|
236
214
|
Settings.define 'delorean.power_source', :env_var => 'POWER_SOURCE', :description => 'Delorean subsytem supplying power to the Flux Capacitor.'
|
237
215
|
Settings.define :password, :required => true, :encrypted => true
|
238
216
|
</pre>
|
239
217
|
|
240
|
-
*
|
241
|
-
*
|
242
|
-
*
|
243
|
-
*
|
244
|
-
*
|
218
|
+
* @:description@: documents a param.
|
219
|
+
* @:type@: converts params to a desired form.
|
220
|
+
* @:required@: marks params required.
|
221
|
+
* @:encrypted@: marks params to be obscured when saved to disk. See [#Encrypted Parameters] below for caveats.
|
222
|
+
* @:env_var@: take param from given environment variable if set.
|
245
223
|
|
246
224
|
Defined parameters are demonstrated in most of the "example scripts":http://github.com/mrflip/configliere/tree/master/examples
|
247
225
|
|
226
|
+
h3. Description
|
227
|
+
|
228
|
+
If you define a param's description, besides nicely documenting it within your code the description will be stuffed into the output when the --help commandline option is invoked.
|
229
|
+
|
230
|
+
<pre>
|
231
|
+
$ ./examples/simple_script
|
232
|
+
usage: simple_script.rb [...--param=val...]
|
233
|
+
|
234
|
+
Params:
|
235
|
+
--delorean.roads_needed delorean.roads_needed
|
236
|
+
--dest_time=DateTime Date to travel to [Default: 11-05-1955]
|
237
|
+
</pre>
|
238
|
+
|
248
239
|
h3. Type Conversion
|
249
240
|
|
241
|
+
Parameters defined with a @:type@ and will be type-converted when you call @Settings.resolve!@.
|
242
|
+
|
250
243
|
<pre>
|
251
244
|
Settings.define :dest_time, :type => DateTime
|
252
245
|
Settings.define :fugeddaboudit, :type => Array
|
253
|
-
Settings :fugeddaboudit => 'badabing,badaboom,hey', :dest_time => '
|
246
|
+
Settings :fugeddaboudit => 'badabing,badaboom,hey', :dest_time => '11-05-1955'
|
254
247
|
Settings.resolve!
|
255
248
|
Settings[:fugeddaboudit] #=> ['badabing', 'badaboom', 'hey']
|
256
249
|
Settings[:dest_time] #=> #<DateTime: 4870833/2,0,2299161>
|
257
250
|
</pre>
|
258
251
|
|
259
|
-
Configliere can coerce parameter values to Integer, Float, :boolean, Symbol, Array, Date and DateTime.
|
252
|
+
Configliere can coerce parameter values to Integer, Float, :boolean, Symbol, Array, Date and DateTime.
|
260
253
|
|
261
254
|
* :boolean converts nil to nil ; false, 'false', 0, '0' and '' to false; and everything else to true.
|
262
255
|
* Array just does a simple split on ",". It doesn't do any escaping or quoting.
|
263
256
|
* Date and DateTime convert unparseable inputs to nil.
|
257
|
+
* :filename calls File.expand_path() on the param.
|
264
258
|
|
265
|
-
h3.
|
259
|
+
h3. Required Parameters
|
266
260
|
|
267
|
-
|
261
|
+
Any required parameter found to be nil raise an error (listing all missing params) when you call Settings.resolve! (See "examples/env_var_script.rb":http://github.com/mrflip/configliere/tree/master/examples/env_var_script.rb)
|
268
262
|
|
269
|
-
h3.
|
263
|
+
h3. Environment Variables
|
270
264
|
|
271
|
-
|
265
|
+
<pre>
|
266
|
+
Settings.define :dest_time, :env_var => 'DEST_TIME'
|
267
|
+
Settings.define :environment, :env_var => 'RACK_ENV'
|
268
|
+
</pre>
|
272
269
|
|
273
270
|
h3. Encrypted Parameters
|
274
271
|
|
275
|
-
Define a param to be encrypted and invoke Settings.save
|
272
|
+
Define a param to be encrypted and invoke Settings.save!. It will use Settings.encrypt_pass (or the ENCRYPT_PASS environment variable) to encrypt the data when it is saved to disk. (see "examples/encrypted_script.rb":http://github.com/mrflip/configliere/tree/master/examples/encrypted_script.rb)
|
276
273
|
|
277
274
|
<pre>
|
278
|
-
|
279
|
-
|
275
|
+
Settings.use :encrypted
|
276
|
+
Settings.define 'amazon.api.key', :encrypted => true
|
277
|
+
Settings 'amazon.api.key' => 'fnord'
|
280
278
|
</pre>
|
281
279
|
|
282
|
-
In this example, the hash saved to disk will contain @{ :amazon => { :api => { :encrypted_key => "...encrypted val..." } } }@. After reading from disk, #resolve! will recover its original value: @{ :amazon => { :api => { :key => "fnord" } } }@.
|
280
|
+
In this example, the hash saved to disk will contain @{ :amazon => { :api => { :encrypted_key => "...encrypted val..." } } }@. After reading from disk, #resolve! will recover its original value: @{ :amazon => { :api => { :key => "fnord" } } }@.
|
283
281
|
|
284
282
|
bq. There are two kinds of cryptography in this world: cryptography that will stop your kid sister from reading your files, and cryptography that will stop major governments from reading your files. This book is about the latter. -- Preface to Applied Cryptography by Bruce Schneier
|
285
283
|
|
286
|
-
Configliere provides the
|
284
|
+
Configliere provides the former.
|
287
285
|
|
288
|
-
|
286
|
+
Anyone with access to the script, its config files and its normal launch environment can recover the plaintext password; but it at least doesn't appear when you cat the file while giving a presentation.
|
289
287
|
|
290
288
|
h2. Ruby Block
|
291
289
|
|
292
290
|
<pre>
|
291
|
+
Settings.use :config_block
|
293
292
|
Settings.finally do |c|
|
294
293
|
c.dest_time = (Time.now + 60) if c.username == 'einstein'
|
295
294
|
# you can use hash syntax too
|
@@ -301,24 +300,49 @@ h2. Ruby Block
|
|
301
300
|
Settings.resolve! # the finally blocks will be called in order
|
302
301
|
</pre>
|
303
302
|
|
304
|
-
Configliere 'finally' blocks are invoked when you call
|
303
|
+
Configliere 'finally' blocks are invoked when you call @resolve!@. They're guaranteed to be called at the end of the resolve chain, and before the validate chain.
|
305
304
|
|
306
305
|
Config blocks are demonstrated in "examples/config_block.rb":http://github.com/mrflip/configliere/tree/master/examples/config_block.rb
|
307
306
|
|
307
|
+
h2. Shortcut syntax for deep keys
|
308
|
+
|
309
|
+
You can use a 'dotted key' like 'delorean.power_source' as simple notation for a deep key: @Settings['delorean.power_source']@ is equivalent to @Settings[:delorean][:power_source]@. You can use a dotted key in any simple reference:
|
310
|
+
|
311
|
+
<pre>
|
312
|
+
Settings['delorean.power_source'] = "Mr. Fusion"
|
313
|
+
Settings[:delorean][:power_source]
|
314
|
+
#=> "Mr. Fusion"
|
315
|
+
Settings.delete('delorean.power_source')
|
316
|
+
#=> "Mr. Fusion"
|
317
|
+
Settings
|
318
|
+
#=> { :delorean => {} }
|
319
|
+
</pre>
|
320
|
+
|
321
|
+
Intermediate keys "auto-vivify" (automatically create any intervening hashes):
|
322
|
+
|
323
|
+
<pre>
|
324
|
+
Settings['one.two.three'] = "To tha Fo'"
|
325
|
+
# Settings is { :one => { :two => { :three => "To tha Fo'" } }, :delorean => { :power_source => "Mr. Fusion" }
|
326
|
+
</pre>
|
327
|
+
|
308
328
|
h2. Independent Settings
|
309
329
|
|
310
|
-
All of the above examples use the global variable @Settings@, defined in configliere.rb. You're free to define your own settings universe though:
|
330
|
+
All of the above examples use the global variable @Settings@, defined in configliere.rb. It really works fine in practice, even where several systems intersect. You're free to define your own settings universe though:
|
311
331
|
|
312
332
|
<pre>
|
313
333
|
class Wolfman
|
314
|
-
|
315
|
-
self.config
|
316
|
-
|
317
|
-
|
318
|
-
|
334
|
+
attr_reader :config
|
335
|
+
def self.config() @@config ; end
|
336
|
+
self.config = Configliere::Param.new({
|
337
|
+
:moon => 'full',
|
338
|
+
:nards => true,
|
339
|
+
})
|
319
340
|
end
|
320
|
-
|
341
|
+
Wolfman.use :commandline
|
342
|
+
|
343
|
+
teen_wolf = Wolfman.new
|
321
344
|
teen_wolf.config.defaults(:give_me => 'keg of beer')
|
345
|
+
|
322
346
|
teen_wolf.config #=> {:moon=>"full", :nards=>true, :give_me=>"keg of beer" }
|
323
347
|
Settings #=> {}
|
324
348
|
</pre>
|