configliere 0.3.4 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.document +3 -0
  2. data/.watchr +20 -0
  3. data/CHANGELOG.textile +99 -3
  4. data/Gemfile +26 -0
  5. data/Gemfile.lock +54 -0
  6. data/README.textile +162 -138
  7. data/Rakefile +30 -21
  8. data/VERSION +1 -1
  9. data/bin/configliere +77 -77
  10. data/bin/configliere-decrypt +85 -0
  11. data/bin/configliere-delete +85 -0
  12. data/bin/configliere-dump +85 -0
  13. data/bin/configliere-encrypt +85 -0
  14. data/bin/configliere-list +85 -0
  15. data/bin/configliere-set +85 -0
  16. data/configliere.gemspec +53 -23
  17. data/examples/config_block_script.rb +9 -2
  18. data/examples/encrypted_script.rb +28 -16
  19. data/examples/env_var_script.rb +2 -2
  20. data/examples/help_message_demo.rb +16 -0
  21. data/examples/independent_config.rb +28 -0
  22. data/examples/prompt.rb +23 -0
  23. data/examples/simple_script.rb +28 -15
  24. data/examples/simple_script.yaml +1 -1
  25. data/lib/configliere.rb +22 -24
  26. data/lib/configliere/commandline.rb +135 -116
  27. data/lib/configliere/commands.rb +38 -54
  28. data/lib/configliere/config_block.rb +4 -2
  29. data/lib/configliere/config_file.rb +30 -52
  30. data/lib/configliere/crypter.rb +8 -5
  31. data/lib/configliere/deep_hash.rb +368 -0
  32. data/lib/configliere/define.rb +83 -89
  33. data/lib/configliere/encrypted.rb +17 -18
  34. data/lib/configliere/env_var.rb +5 -7
  35. data/lib/configliere/param.rb +37 -64
  36. data/lib/configliere/prompt.rb +23 -0
  37. data/spec/configliere/commandline_spec.rb +156 -57
  38. data/spec/configliere/commands_spec.rb +75 -30
  39. data/spec/configliere/config_block_spec.rb +10 -1
  40. data/spec/configliere/config_file_spec.rb +83 -55
  41. data/spec/configliere/crypter_spec.rb +3 -2
  42. data/spec/configliere/deep_hash_spec.rb +401 -0
  43. data/spec/configliere/define_spec.rb +121 -42
  44. data/spec/configliere/encrypted_spec.rb +53 -20
  45. data/spec/configliere/env_var_spec.rb +24 -4
  46. data/spec/configliere/param_spec.rb +25 -27
  47. data/spec/configliere/prompt_spec.rb +50 -0
  48. data/spec/configliere_spec.rb +3 -9
  49. data/spec/spec_helper.rb +17 -6
  50. metadata +110 -35
  51. data/lib/configliere/core_ext.rb +0 -2
  52. data/lib/configliere/core_ext/blank.rb +0 -93
  53. data/lib/configliere/core_ext/hash.rb +0 -108
  54. data/lib/configliere/core_ext/sash.rb +0 -170
  55. data/spec/configliere/core_ext/hash_spec.rb +0 -78
  56. data/spec/configliere/core_ext/sash_spec.rb +0 -312
data/.document CHANGED
@@ -1,4 +1,7 @@
1
1
  README.textile
2
2
  lib/**/*.rb
3
3
  bin/*
4
+ -
4
5
  LICENSE
6
+ CHANGELOG.textile
7
+ VERSION
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><code>
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
- </code></pre>
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. Modules can define config settings independently of each other and the main program.
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
- h3. Example
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, :config_file
18
+ Settings.use :commandline
19
19
 
20
+ # Supply defaults inline.
20
21
  Settings({
21
- :dest_time => '1955-11-05',
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
- Settings.read 'my_script.yaml' # reads ~/.configliere/my_script.yaml
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</pre>
40
+ p Settings
41
+ </pre>
31
42
 
32
- We'll override some of the defaults with a config file, in this case ~/.configliere/simple_script.yaml
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: 1985-11-05
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
- {:dest_time=>"1985-11-05", :username=>"doc_brown", :delorean=>{:power_source=>"Mr. Fusion", :roads_needed=>nil}}
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
- h3. Design goals:
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
- * *Code of Silence*. Most commandline parsers force you to pre-define all your parameters in a centralized and wordy syntax. In configliere, you pre-define nothing -- commandline parameters map directly to values in the Configliere hash.
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 are just a plain old normal hash.
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 => '1955-11-05',
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
- (Note that all simple keys should be symbols, with an exception you're about to see.) Retrieve the settings as:
134
+ All simple keys should be symbols. Retrieve the settings as:
87
135
 
88
136
  <pre>
89
137
  # hash keys
90
- Settings[:dest_time] #=> '1955-11-05'
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 #=> '1955-11-05'
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(:my_settings_group)@ to read a param group from the YAML global config file (@Configliere::DEFAULT_CONFIG_FILE@ -- normally ~/.configliere.yaml)
153
+ Call @Settings.read(filename)@ to read a YAML config file.
145
154
 
146
155
  <pre>
147
156
  # Settings for version II.
148
- :time_machine:
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
- Save defaults by inserting a line like:
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.save(:time_machine) # merges into ~/.configliere.yaml, under :time_machine
177
- Settings.save('/etc/time_machine.yaml') # overwrites /etc/time_machine.yaml
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
- 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:
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
- <pre>
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.env_vars 'DEST_TIME', :password => 'TM_PASS', 'delorean.power_source' => 'POWER_SOURCE'
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=1985-11-05
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 :commandline
185
+ Settings.use(:commandline)
207
186
  Settings.resolve!
208
187
  </pre>
209
188
 
210
189
  Interpretation of command-line parameters:
211
- * *name-val params*: @--param=val@ sets @Configliere[:param]@ to val.
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
- * *scoped params*: @--group-sub_group-param=val@ sets @Configliere[:group][:subgroup][:param]@ to val (and similarly for boolean parameters).
214
- ** A dash or dot within a parameter name scopes that parameter: @--group.sub_group.param=val@ and @--group-sub_group-param=val@ do the same thing. A _ within a parameter name is left as part of the segment.
215
- ** Only @[\w\.\-]+@ are accepted in parameter names.
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
- If you want more, you might like the Trollop gem. If you enjoy wordy nightmares, use "getoptlog":http://linuxdevcenter.com/pub/a/linux/2003/09/18/ruby_csv.html?page=2 from the ruby standard library.
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. Fancy Parameters
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
- * *:type*: converts params to a desired form.
241
- * *:description*: documents a param.
242
- * *:required*: marks params required.
243
- * *:encrypted*: marks params to be obscured when saved to disk. See [#Encrypted Parameters] below for caveats.
244
- * *:env_var*: take param from given environment variable if set.
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 => '1955-11-05'
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. (Make sure to call Settings.resolve! in your script.)
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. Description
259
+ h3. Required Parameters
266
260
 
267
- 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.
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. Required Parameters
263
+ h3. Environment Variables
270
264
 
271
- Any required parameter found to be nil raises an error (listing all missing params). (Make sure to call Settings.resolve! in your script.)
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
- define 'amazon.api.key', :encrypted => true
279
- Settings 'amazon.api.key' => 'fnord'
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" } } }@. The code currently doesn't look for a collision between a :param and :encrypted_param, so be careful; you can preemptively call resolve_encrypted! to enforce order.
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 latter. Anyone with access to the script, its config files and the config file passphrase can recover the plaintext password. Still, there's a difference between immediate access and having to find a paperclip and jimmy open your annoying older brother's stupid journal.
284
+ Configliere provides the former.
287
285
 
288
- Encrypted parameters are demonstrated in "examples/encrypted_script.rb":http://github.com/mrflip/configliere/tree/master/examples/encrypted_script.rb
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 @#resolve!@. They're guaranteed to be called at the end of the resolve chain, and before the validate chain.
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
- cattr_accessor :config
315
- self.config = Configliere.new({
316
- :moon => 'full',
317
- :nards => true,
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
- teen_wolf = proj.new
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>