configliere 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +119 -36
- data/Rakefile +2 -17
- data/VERSION +1 -1
- data/configliere.gemspec +10 -31
- data/examples/simple_script.rb +6 -8
- data/examples/simple_script.yaml +4 -4
- data/lib/configliere.rb +1 -1
- data/lib/configliere/commandline.rb +2 -2
- data/lib/configliere/{config_blocks.rb → config_block.rb} +2 -2
- data/lib/configliere/{param_store.rb → config_file.rb} +7 -7
- data/lib/configliere/core_ext.rb +1 -0
- data/lib/configliere/core_ext/blank.rb +89 -0
- data/lib/configliere/core_ext/hash.rb +12 -2
- data/lib/configliere/crypter.rb +1 -1
- data/lib/configliere/define.rb +41 -29
- data/lib/configliere/encrypted.rb +20 -20
- data/lib/configliere/environment.rb +8 -7
- data/lib/configliere/param.rb +2 -0
- data/spec/configliere/{config_blocks_spec.rb → config_block_spec.rb} +3 -3
- data/spec/configliere/{param_store_spec.rb → config_file_spec.rb} +4 -4
- data/spec/configliere/define_spec.rb +19 -9
- data/spec/configliere/encrypted_spec.rb +1 -1
- data/spec/configliere/param_spec.rb +2 -1
- data/spec/spec_helper.rb +0 -6
- metadata +10 -50
data/README.textile
CHANGED
@@ -6,7 +6,38 @@ 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
|
9
|
+
Configliere manage 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.
|
10
|
+
|
11
|
+
h3. Example
|
12
|
+
|
13
|
+
Here's a simple example, using params from a config file and the command line. A config file, in ~/.configliere/simple_script.yaml
|
14
|
+
|
15
|
+
<pre>
|
16
|
+
:cat: hat
|
17
|
+
:spider: tuffet
|
18
|
+
:sprats:
|
19
|
+
:jack: lean</pre>
|
20
|
+
|
21
|
+
A simple script:
|
22
|
+
|
23
|
+
<pre>
|
24
|
+
#/usr/bin/env ruby
|
25
|
+
require 'configliere'
|
26
|
+
|
27
|
+
Settings.use(:commandline, :config_file,
|
28
|
+
:dish => 'spoon', :cow => 'moon')
|
29
|
+
Settings.read 'my_script.yaml'
|
30
|
+
Settings.resolve!
|
31
|
+
|
32
|
+
p Settings</pre>
|
33
|
+
|
34
|
+
Output:
|
35
|
+
|
36
|
+
<pre>
|
37
|
+
./simple_script.rb --sprats.wife=fat --spider=drainspout
|
38
|
+
{:spider=>"drainspout", :cat=>"hat", :sprats=>{:wife=>"fat", :jack=>"lean"}, :cow=>"moon"} </pre>
|
39
|
+
|
40
|
+
h3. Design goals:
|
10
41
|
|
11
42
|
* *Don't go outside the family*. Requires almost no external resources and almost no code in your script.
|
12
43
|
* *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.
|
@@ -27,6 +58,7 @@ Configliere settings are just a plain old normal hash.
|
|
27
58
|
|
28
59
|
You can define static defaults in your module
|
29
60
|
|
61
|
+
<pre>
|
30
62
|
Settings.defaults({
|
31
63
|
:dest_time => '1955-11-05',
|
32
64
|
:fluxcapacitor => {
|
@@ -39,70 +71,87 @@ You can define static defaults in your module
|
|
39
71
|
:username => 'marty',
|
40
72
|
:password => '',
|
41
73
|
})
|
74
|
+
</pre>
|
42
75
|
|
43
76
|
Retrieve them as:
|
44
77
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
78
|
+
<pre>
|
79
|
+
# hash keys
|
80
|
+
Config[:dest_time] #=> '1955-11-05'
|
81
|
+
# deep keys
|
82
|
+
Config[:delorean][:power_source] #=> 'plutonium'
|
83
|
+
Config[:delorean][:missing] #=> nil
|
84
|
+
Config[:delorean][:missing][:fail] #=> raises an error
|
85
|
+
# dotted keys resolve to deep keys
|
86
|
+
Config['delorean.power_source'] #=> 'plutonium'
|
87
|
+
Config['delorean.missing'] #=> nil
|
88
|
+
Config['delorean.missing.fail'] #=> nil
|
89
|
+
# method-like (no deep keys tho)
|
90
|
+
Settings.dest_time #=> '1955-11-05'
|
91
|
+
</pre>
|
92
|
+
|
93
|
+
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).
|
94
|
+
|
95
|
+
<pre>
|
96
|
+
Configliere.use :config_file, :define # Load config files and pre-define
|
61
97
|
Configliere.use :all # all of them
|
98
|
+
</pre>
|
62
99
|
|
63
100
|
h2. Configuration files
|
64
101
|
|
65
|
-
Call Settings.read(:my_settings_group) to read a param group from the YAML global config file (Configliere::DEFAULT_CONFIG_FILE
|
102
|
+
Call @Settings.read(:my_settings_group)@ to read a param group from the YAML global config file (@Configliere::DEFAULT_CONFIG_FILE@ -- normally ~/.configliere.yaml)
|
66
103
|
|
104
|
+
<pre>
|
67
105
|
# Settings for version II.
|
68
106
|
:time_machine:
|
69
107
|
:dest_time: 2015-11-05
|
70
108
|
:delorean:
|
71
109
|
:power_source: Mr. Fusion
|
72
110
|
:roads_needed: ~
|
111
|
+
</pre>
|
73
112
|
|
74
|
-
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.
|
113
|
+
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.
|
75
114
|
|
115
|
+
<pre>
|
76
116
|
Settings.read(:time_machine) # looks in ~/.configliere.yaml, and extracts the :time_machine group
|
77
117
|
Settings.read('/etc/time_machine.yaml') # looks in /etc/time_machine.yaml
|
78
118
|
Settings.read('time_machine.yaml') # looks in ~/.configliere/time_machine.yaml
|
119
|
+
</pre>
|
79
120
|
|
80
121
|
When you read directly from a file you should leave off the top-level settings group:
|
81
122
|
|
123
|
+
<pre>
|
82
124
|
# Settings for version II.
|
83
125
|
:dest_time: 2015-11-05
|
84
126
|
:delorean:
|
85
127
|
:power_source: Mr. Fusion
|
86
128
|
:roads_needed: ~
|
129
|
+
</pre>
|
87
130
|
|
88
131
|
You can save defaults with
|
89
132
|
|
133
|
+
<pre>
|
90
134
|
Settings.save(:time_machine) # merges into ~/.configliere.yaml, under :time_machine
|
91
135
|
Settings.save('/etc/time_machine.yaml') # overwrites /etc/time_machine.yaml
|
92
136
|
Settings.save('time_machine.yaml') # overwrites ~/.configliere/time_machine.yaml
|
137
|
+
</pre>
|
93
138
|
|
94
139
|
h2. Environment Variables
|
95
140
|
|
141
|
+
<pre>
|
96
142
|
Settings.use_environment 'DEST_TIME', 'TM_PASS' => 'password', 'POWER_SOURCE' => 'delorean.power_source'
|
143
|
+
</pre>
|
97
144
|
|
98
|
-
As usual, dotted keys set the corresponeding nested key ('delorean.power_source' sets Config[:delorean][:power_source])
|
145
|
+
As usual, dotted keys set the corresponeding nested key ('delorean.power_source' sets Config[:delorean][:power_source]). You can alternatively set up environment variables with @define 'delorean.power_source', :environment => 'POWER_SOURCE'@ - see below.
|
99
146
|
|
100
147
|
h2. Command-line parameters
|
101
148
|
|
149
|
+
<pre>
|
102
150
|
# Head back
|
103
151
|
time_machine --delorean-power_source='1.21 gigawatt lightning strike' --dest_time=1985-11-05
|
104
152
|
# (in the time_machine script:)
|
105
153
|
Settings.use :commandline
|
154
|
+
</pre>
|
106
155
|
|
107
156
|
Interpretation of command-line parameters:
|
108
157
|
* *name-val params*: @--param=val@ sets @Configliere[:param]@ to val.
|
@@ -115,7 +164,7 @@ Interpretation of command-line parameters:
|
|
115
164
|
|
116
165
|
Here are some things you don't get:
|
117
166
|
* There are no short parameters (-r, etc).
|
118
|
-
* Apart from converting @''@ (an explicit blank string) to nil
|
167
|
+
* Apart from converting @''@ (an explicit blank string) to @nil@, no type coercion is performed on parameters unless requested explicitly (see below).
|
119
168
|
* No validation is performed on parameters.
|
120
169
|
* No ordering or multiplicity is preserved (you can't say @--file=this --file=that@).
|
121
170
|
|
@@ -125,15 +174,39 @@ h2. Fancy Parameters
|
|
125
174
|
|
126
175
|
You don't have to pre-define parameters, but you can:
|
127
176
|
|
177
|
+
<pre>
|
128
178
|
Settings.use :define
|
129
|
-
Settings.define :dest_time, :type => Date, :description => 'Arrival time
|
130
|
-
Settings.define 'delorean.power_source', :description => 'Delorean subsytem supplying power to the Flux Capacitor.'
|
131
|
-
Settings.define :password, :required => true, :
|
179
|
+
Settings.define :dest_time, :type => Date, :description => 'Arrival time'
|
180
|
+
Settings.define 'delorean.power_source', :environment => 'POWER_SOURCE', :description => 'Delorean subsytem supplying power to the Flux Capacitor.'
|
181
|
+
Settings.define :password, :required => true, :encrypted => true
|
182
|
+
</pre>
|
132
183
|
|
133
|
-
* *:type*: converts params to a desired form.
|
134
|
-
* *:description
|
135
|
-
* *:required
|
136
|
-
* *:encrypted
|
184
|
+
* *:type*: converts params to a desired form.
|
185
|
+
* *:description*: documents a param.
|
186
|
+
* *:required*: marks params required.
|
187
|
+
* *:encrypted*: marks params to be obscured when saved to disk. See [#Encrypted Parameters] below for caveats.
|
188
|
+
* *:environment*: take param from given environment variable if set.
|
189
|
+
|
190
|
+
h3. Type Conversion
|
191
|
+
|
192
|
+
<pre>
|
193
|
+
Settings.define :dest_time, :type => DateTime
|
194
|
+
Settings.define :fugeddaboudit, :type => Array
|
195
|
+
Settings :fugeddaboudit => 'badabing,badaboom,hey', :dest_time => '1955-11-05'
|
196
|
+
Settings.resolve!
|
197
|
+
Settings[:fugeddaboudit] #=> ['badabing', 'badaboom', 'hey']
|
198
|
+
Settings[:dest_time] #=> #<DateTime: 4870833/2,0,2299161>
|
199
|
+
</pre>
|
200
|
+
|
201
|
+
Configliere can coerce parameter values to Integer, Float, :boolean, Symbol, Array, Date and DateTime. (Make sure to call Settings.resolve! in your script.)
|
202
|
+
|
203
|
+
* :boolean converts nil to nil ; false, 'false', 0, '0' and '' to false; and everything else to true.
|
204
|
+
* Array just does a simple split on ",". It doesn't do any escaping or quoting.
|
205
|
+
* Date and DateTime convert unparseable inputs to nil.
|
206
|
+
|
207
|
+
h3. Description
|
208
|
+
|
209
|
+
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.
|
137
210
|
|
138
211
|
h3. Required Parameters
|
139
212
|
|
@@ -141,31 +214,40 @@ Any required parameter found to be nil raises an error (listing all missing para
|
|
141
214
|
|
142
215
|
h3. Encrypted Parameters
|
143
216
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
217
|
+
Define a param to be encrypted and invoke Settings.save!
|
218
|
+
|
219
|
+
<pre>
|
220
|
+
define 'amazon.api.key', :encrypted => true
|
221
|
+
Settings 'amazon.api.key' => 'fnord'
|
222
|
+
</pre>
|
223
|
+
|
224
|
+
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.
|
225
|
+
|
226
|
+
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
|
148
227
|
|
149
|
-
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 having to find a paperclip and jimmy open your annoying brother's stupid journal
|
228
|
+
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.
|
150
229
|
|
151
230
|
h2. Ruby Block
|
152
231
|
|
232
|
+
<pre>
|
153
233
|
Settings.finally do |c|
|
154
234
|
c.dest_time = (Time.now + 60) if c.username == 'einstein'
|
155
235
|
# you can use hash syntax too
|
156
236
|
c[:dest_time] = (Time.now + 60) if c[:username] == 'einstein'
|
157
237
|
end
|
158
238
|
#
|
159
|
-
# ... rest of setup
|
239
|
+
# ... rest of setup ...
|
160
240
|
#
|
161
241
|
Settings.resolve! # the finally blocks will be called in order
|
242
|
+
</pre>
|
162
243
|
|
163
|
-
Configliere 'finally' blocks are called
|
244
|
+
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.
|
164
245
|
|
165
246
|
h2. Independent Settings
|
166
247
|
|
167
|
-
All of the above
|
248
|
+
All of the above examples use the global variable @Settings@, defined in configliere.rb. You're free to define your own settings universe though:
|
168
249
|
|
250
|
+
<pre>
|
169
251
|
module MyProject
|
170
252
|
cattr_accessor :config
|
171
253
|
self.config = Configliere.new({
|
@@ -175,6 +257,7 @@ All of the above uses the Settings global variable defined in configliere.rb. H
|
|
175
257
|
end
|
176
258
|
pr = proj.new
|
177
259
|
pr.config #=> {:helicity => 'homotopic', :froebenius_matrix => 'unitary' }
|
260
|
+
</pre>
|
178
261
|
|
179
262
|
Values in here don't overlap with the Settings object or any other settings universe. However, every one that pulls in commandline params gets a full copy of the commandline params.
|
180
263
|
|
data/Rakefile
CHANGED
@@ -10,29 +10,14 @@ begin
|
|
10
10
|
|
11
11
|
"" So, Consigliere of mine, I think you should tell your Don what everyone knows. "" -- Don Corleone
|
12
12
|
|
13
|
-
Configliere'
|
14
|
-
|
15
|
-
* *Don't go outside the family*. Requires almost no external resources and almost no code in your script.
|
16
|
-
* *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.
|
17
|
-
* *Be willing to sit down with the Five Families*. Takes settings from (at your option):
|
18
|
-
** Pre-defined defaults from constants
|
19
|
-
** Simple config files
|
20
|
-
** Environment variables
|
21
|
-
** Commandline options
|
22
|
-
** Ruby block called when all other options are in place
|
23
|
-
* *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.
|
24
|
-
* *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.
|
25
|
-
|
26
|
-
fuhgeddaboudit.
|
13
|
+
Configliere manage 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.
|
27
14
|
} #'
|
28
15
|
gem.email = "flip@infochimps.org"
|
29
16
|
gem.homepage = "http://github.com/mrflip/configliere"
|
30
17
|
gem.authors = ["mrflip"]
|
31
18
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
32
19
|
gem.add_development_dependency "yard", ">= 0"
|
33
|
-
gem.add_dependency "highline", ">= 0"
|
34
|
-
gem.add_dependency "yaml", ">= 0"
|
35
|
-
gem.add_dependency "openssl", ">= 0"
|
20
|
+
# gem.add_dependency "highline", ">= 0"
|
36
21
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
37
22
|
end
|
38
23
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/configliere.gemspec
CHANGED
@@ -5,30 +5,17 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{configliere}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["mrflip"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-08}
|
13
13
|
s.default_executable = %q{configliere}
|
14
14
|
s.description = %q{ 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.
|
15
15
|
|
16
16
|
"" So, Consigliere of mine, I think you should tell your Don what everyone knows. "" -- Don Corleone
|
17
17
|
|
18
|
-
Configliere'
|
19
|
-
|
20
|
-
* *Don't go outside the family*. Requires almost no external resources and almost no code in your script.
|
21
|
-
* *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.
|
22
|
-
* *Be willing to sit down with the Five Families*. Takes settings from (at your option):
|
23
|
-
** Pre-defined defaults from constants
|
24
|
-
** Simple config files
|
25
|
-
** Environment variables
|
26
|
-
** Commandline options
|
27
|
-
** Ruby block called when all other options are in place
|
28
|
-
* *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.
|
29
|
-
* *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.
|
30
|
-
|
31
|
-
fuhgeddaboudit.
|
18
|
+
Configliere manage 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.
|
32
19
|
}
|
33
20
|
s.email = %q{flip@infochimps.org}
|
34
21
|
s.executables = ["configliere"]
|
@@ -54,23 +41,24 @@ fuhgeddaboudit.
|
|
54
41
|
"lib/configliere/commandline.rb",
|
55
42
|
"lib/configliere/commandline/commands.rb",
|
56
43
|
"lib/configliere/commandline/options.rb",
|
57
|
-
"lib/configliere/
|
44
|
+
"lib/configliere/config_block.rb",
|
45
|
+
"lib/configliere/config_file.rb",
|
58
46
|
"lib/configliere/core_ext.rb",
|
47
|
+
"lib/configliere/core_ext/blank.rb",
|
59
48
|
"lib/configliere/core_ext/hash.rb",
|
60
49
|
"lib/configliere/crypter.rb",
|
61
50
|
"lib/configliere/define.rb",
|
62
51
|
"lib/configliere/encrypted.rb",
|
63
52
|
"lib/configliere/environment.rb",
|
64
53
|
"lib/configliere/param.rb",
|
65
|
-
"lib/configliere/param_store.rb",
|
66
54
|
"spec/configliere/commandline_spec.rb",
|
67
|
-
"spec/configliere/
|
55
|
+
"spec/configliere/config_block_spec.rb",
|
56
|
+
"spec/configliere/config_file_spec.rb",
|
68
57
|
"spec/configliere/crypter_spec.rb",
|
69
58
|
"spec/configliere/define_spec.rb",
|
70
59
|
"spec/configliere/encrypted_spec.rb",
|
71
60
|
"spec/configliere/environment_spec.rb",
|
72
61
|
"spec/configliere/param_spec.rb",
|
73
|
-
"spec/configliere/param_store_spec.rb",
|
74
62
|
"spec/configliere_spec.rb",
|
75
63
|
"spec/spec.opts",
|
76
64
|
"spec/spec_helper.rb"
|
@@ -82,13 +70,13 @@ fuhgeddaboudit.
|
|
82
70
|
s.summary = %q{Wise, discreet configuration management}
|
83
71
|
s.test_files = [
|
84
72
|
"spec/configliere/commandline_spec.rb",
|
85
|
-
"spec/configliere/
|
73
|
+
"spec/configliere/config_block_spec.rb",
|
74
|
+
"spec/configliere/config_file_spec.rb",
|
86
75
|
"spec/configliere/crypter_spec.rb",
|
87
76
|
"spec/configliere/define_spec.rb",
|
88
77
|
"spec/configliere/encrypted_spec.rb",
|
89
78
|
"spec/configliere/environment_spec.rb",
|
90
79
|
"spec/configliere/param_spec.rb",
|
91
|
-
"spec/configliere/param_store_spec.rb",
|
92
80
|
"spec/configliere_spec.rb",
|
93
81
|
"spec/spec_helper.rb",
|
94
82
|
"examples/commandline_script.rb",
|
@@ -102,22 +90,13 @@ fuhgeddaboudit.
|
|
102
90
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
103
91
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
104
92
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
105
|
-
s.add_runtime_dependency(%q<highline>, [">= 0"])
|
106
|
-
s.add_runtime_dependency(%q<yaml>, [">= 0"])
|
107
|
-
s.add_runtime_dependency(%q<openssl>, [">= 0"])
|
108
93
|
else
|
109
94
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
110
95
|
s.add_dependency(%q<yard>, [">= 0"])
|
111
|
-
s.add_dependency(%q<highline>, [">= 0"])
|
112
|
-
s.add_dependency(%q<yaml>, [">= 0"])
|
113
|
-
s.add_dependency(%q<openssl>, [">= 0"])
|
114
96
|
end
|
115
97
|
else
|
116
98
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
117
99
|
s.add_dependency(%q<yard>, [">= 0"])
|
118
|
-
s.add_dependency(%q<highline>, [">= 0"])
|
119
|
-
s.add_dependency(%q<yaml>, [">= 0"])
|
120
|
-
s.add_dependency(%q<openssl>, [">= 0"])
|
121
100
|
end
|
122
101
|
end
|
123
102
|
|
data/examples/simple_script.rb
CHANGED
@@ -1,21 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
$: << File.dirname(__FILE__)+'/../lib'
|
3
3
|
require 'configliere'
|
4
|
-
SCRIPT_DIR = File.dirname(__FILE__)
|
5
4
|
|
6
5
|
# Intro text
|
7
6
|
puts %Q{
|
8
7
|
This is a demo of the Configliere interface. It takse settings
|
9
8
|
Try running it as
|
10
|
-
|
9
|
+
./examples/simple_script.rb --sprats.wife=fat --spider=drainspout
|
11
10
|
with those args, we
|
12
|
-
expect: {:
|
11
|
+
expect: {:spider=>"drainspout", :cat=>"hat", :sprats=>{:wife=>"fat", :jack=>"lean"}, :cow=>"moon"}
|
13
12
|
}
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
Settings.read
|
18
|
-
|
14
|
+
Settings.use(:commandline, :config_file,
|
15
|
+
:cat => 'bag', :cow => 'moon')
|
16
|
+
Settings.read File.dirname(__FILE__)+'/simple_script.yaml'
|
19
17
|
Settings.resolve!
|
20
18
|
|
21
19
|
# Print results
|
data/examples/simple_script.yaml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
---
|
2
|
-
:
|
3
|
-
|
4
|
-
|
5
|
-
:
|
2
|
+
:cat: hat
|
3
|
+
:spider: tuffet
|
4
|
+
:sprats:
|
5
|
+
:jack: lean
|
data/lib/configliere.rb
CHANGED
@@ -14,7 +14,7 @@ module Configliere
|
|
14
14
|
Configliere::Param.new *args, &block
|
15
15
|
end
|
16
16
|
|
17
|
-
ALL_MIXINS = [:define, :encrypted, :environment, :
|
17
|
+
ALL_MIXINS = [:define, :encrypted, :environment, :config_file, :commandline, :config_block]
|
18
18
|
def self.use *mixins
|
19
19
|
mixins = ALL_MIXINS if mixins.include?(:all)
|
20
20
|
mixins.each do |mixin|
|
@@ -74,9 +74,9 @@ module Configliere
|
|
74
74
|
|
75
75
|
def help
|
76
76
|
help_str = [ usage ]
|
77
|
-
help_str += [ "\nParams:", descriptions.map{|param, desc| "
|
77
|
+
help_str += [ "\nParams:", descriptions.sort_by{|p,d| p.to_s }.map{|param, desc| " --%-25s %s"%[param.to_s+':', desc]}.join("\n"), ] if respond_to?(:descriptions)
|
78
78
|
# help_str += ["\nCommands", commands.map{|cmd, desc| " %-20s %s"%[cmd.to_s+':', desc]}.join("\n")] if respond_to?(:commands)
|
79
|
-
help_str += [ "\nEnvironment Variables:", params_from_environment.map{|param, env| " %-
|
79
|
+
help_str += [ "\nEnvironment Variables can be used to set:", params_from_environment.map{|param, env| " %-27s %s"%[env.to_s+':', param]}.join("\n"), ] if respond_to?(:params_from_environment)
|
80
80
|
help_str.join("\n")
|
81
81
|
end
|
82
82
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Configliere.use :define
|
2
2
|
module Configliere
|
3
|
-
module
|
3
|
+
module ConfigBlock
|
4
4
|
# Config blocks to be executed at end of resolution (just before validation)
|
5
5
|
attr_accessor :final_blocks
|
6
6
|
def final_blocks
|
@@ -36,6 +36,6 @@ module Configliere
|
|
36
36
|
end
|
37
37
|
|
38
38
|
Param.class_eval do
|
39
|
-
include Configliere::
|
39
|
+
include Configliere::ConfigBlock
|
40
40
|
end
|
41
41
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
module Configliere
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# ConfigFile -- load configuration from a simple YAML file
|
5
5
|
#
|
6
|
-
module
|
6
|
+
module ConfigFile
|
7
7
|
# Load params from disk.
|
8
8
|
# * file is in YAML format, as a hash of handle => param_hash pairs
|
9
|
-
# * filename defaults to
|
9
|
+
# * filename defaults to Configliere::DEFAULT_CONFIG_FILE (~/.configliere, probably)
|
10
10
|
def read handle
|
11
11
|
filename = filename_for_handle(handle)
|
12
12
|
begin
|
@@ -21,13 +21,13 @@ module Configliere
|
|
21
21
|
|
22
22
|
# save to disk.
|
23
23
|
# * file is in YAML format, as a hash of handle => param_hash pairs
|
24
|
-
# * filename defaults to
|
24
|
+
# * filename defaults to Configliere::DEFAULT_CONFIG_FILE (~/.configliere, probably)
|
25
25
|
def save! handle
|
26
26
|
filename = filename_for_handle(handle)
|
27
27
|
if handle.is_a?(Symbol)
|
28
|
-
|
28
|
+
ConfigFile.merge_into_yaml_file filename, handle, self.export
|
29
29
|
else
|
30
|
-
|
30
|
+
ConfigFile.write_yaml_file filename, self.export
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -65,6 +65,6 @@ module Configliere
|
|
65
65
|
|
66
66
|
Param.class_eval do
|
67
67
|
# include read / save operations
|
68
|
-
include
|
68
|
+
include ConfigFile
|
69
69
|
end
|
70
70
|
end
|
data/lib/configliere/core_ext.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
class Object
|
2
|
+
##
|
3
|
+
# Returns true if the object is nil or empty (if applicable)
|
4
|
+
#
|
5
|
+
# [].blank? #=> true
|
6
|
+
# [1].blank? #=> false
|
7
|
+
# [nil].blank? #=> false
|
8
|
+
#
|
9
|
+
# @return [TrueClass, FalseClass]
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
def blank?
|
13
|
+
nil? || (respond_to?(:empty?) && empty?)
|
14
|
+
end
|
15
|
+
end # class Object
|
16
|
+
|
17
|
+
class Numeric
|
18
|
+
##
|
19
|
+
# Numerics are never blank
|
20
|
+
#
|
21
|
+
# 0.blank? #=> false
|
22
|
+
# 1.blank? #=> false
|
23
|
+
# 6.54321.blank? #=> false
|
24
|
+
#
|
25
|
+
# @return [FalseClass]
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def blank?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end # class Numeric
|
32
|
+
|
33
|
+
class NilClass
|
34
|
+
##
|
35
|
+
# Nil is always blank
|
36
|
+
#
|
37
|
+
# nil.blank? #=> true
|
38
|
+
#
|
39
|
+
# @return [TrueClass]
|
40
|
+
#
|
41
|
+
# @api public
|
42
|
+
def blank?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end # class NilClass
|
46
|
+
|
47
|
+
class TrueClass
|
48
|
+
##
|
49
|
+
# True is never blank.
|
50
|
+
#
|
51
|
+
# true.blank? #=> false
|
52
|
+
#
|
53
|
+
# @return [FalseClass]
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
def blank?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end # class TrueClass
|
60
|
+
|
61
|
+
class FalseClass
|
62
|
+
##
|
63
|
+
# False is always blank.
|
64
|
+
#
|
65
|
+
# false.blank? #=> true
|
66
|
+
#
|
67
|
+
# @return [TrueClass]
|
68
|
+
#
|
69
|
+
# @api public
|
70
|
+
def blank?
|
71
|
+
true
|
72
|
+
end
|
73
|
+
end # class FalseClass
|
74
|
+
|
75
|
+
class String
|
76
|
+
##
|
77
|
+
# Strips out whitespace then tests if the string is empty.
|
78
|
+
#
|
79
|
+
# "".blank? #=> true
|
80
|
+
# " ".blank? #=> true
|
81
|
+
# " hey ho ".blank? #=> false
|
82
|
+
#
|
83
|
+
# @return [TrueClass, FalseClass]
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
def blank?
|
87
|
+
strip.empty?
|
88
|
+
end
|
89
|
+
end # class String
|
@@ -4,9 +4,9 @@
|
|
4
4
|
class Hash
|
5
5
|
|
6
6
|
# lambda for recursive merges
|
7
|
-
Hash::DEEP_MERGER = proc do |key,v1,v2|
|
7
|
+
::Hash::DEEP_MERGER = proc do |key,v1,v2|
|
8
8
|
(v1.respond_to?(:merge) && v2.respond_to?(:merge)) ? v1.merge(v2.compact, &Hash::DEEP_MERGER) : (v2.nil? ? v1 : v2)
|
9
|
-
end
|
9
|
+
end unless defined?(::Hash::DEEP_MERGER)
|
10
10
|
|
11
11
|
#
|
12
12
|
# Merge hashes recursively.
|
@@ -76,6 +76,16 @@ class Hash
|
|
76
76
|
hsh[last_key]
|
77
77
|
end
|
78
78
|
|
79
|
+
|
80
|
+
#
|
81
|
+
# Treat hash as tree of hashes:
|
82
|
+
#
|
83
|
+
# x = { 1 => :val, :subhash => { 1 => :val1, 2 => :val2 } }
|
84
|
+
# x.deep_delete(:subhash, 1)
|
85
|
+
# #=> :val
|
86
|
+
# x
|
87
|
+
# #=> { 1 => :val, :subhash => { 2 => :val2 } }
|
88
|
+
#
|
79
89
|
def deep_delete *args
|
80
90
|
last_key = args.pop
|
81
91
|
last_hsh = args.empty? ? self : (deep_get(*args)||{})
|
data/lib/configliere/crypter.rb
CHANGED
@@ -64,7 +64,7 @@ module Configliere
|
|
64
64
|
|
65
65
|
# Convert the encrypt_pass passphrase into the key used for encryption
|
66
66
|
def self.encrypt_key encrypt_pass, options={}
|
67
|
-
raise 'Blank encryption password!' if encrypt_pass.
|
67
|
+
raise 'Blank encryption password!' if encrypt_pass.blank?
|
68
68
|
# this provides the required 256 bits of key for the aes-256-cbc cipher
|
69
69
|
Digest::SHA256.digest(encrypt_pass)
|
70
70
|
end
|
data/lib/configliere/define.rb
CHANGED
@@ -13,6 +13,8 @@ module Configliere
|
|
13
13
|
#
|
14
14
|
def define param, definitions={}
|
15
15
|
self.param_definitions[param].merge! definitions
|
16
|
+
self[param] = definitions[:default] if definitions.include?(:default)
|
17
|
+
self.environment_variables definitions[:environment], param if definitions.include?(:environment)
|
16
18
|
end
|
17
19
|
|
18
20
|
def param_definitions
|
@@ -20,23 +22,6 @@ module Configliere
|
|
20
22
|
@param_definitions ||= Hash.new{|hsh, key| hsh[key] = {} }
|
21
23
|
end
|
22
24
|
|
23
|
-
protected
|
24
|
-
# all params with a value for the definable aspect
|
25
|
-
#
|
26
|
-
# @param definable the aspect to list (:description, :type, :encrypted, etc.)
|
27
|
-
def params_with defineable
|
28
|
-
param_definitions.keys.find_all{|param| param_definitions[param][defineable] } || []
|
29
|
-
end
|
30
|
-
|
31
|
-
def definitions_for defineable
|
32
|
-
hsh = {}
|
33
|
-
param_definitions.each do |param, defs|
|
34
|
-
hsh[param] = defs[defineable] if defs[defineable]
|
35
|
-
end
|
36
|
-
hsh
|
37
|
-
end
|
38
|
-
public
|
39
|
-
|
40
25
|
# performs type coercion
|
41
26
|
def resolve!
|
42
27
|
resolve_types!
|
@@ -65,7 +50,7 @@ module Configliere
|
|
65
50
|
|
66
51
|
# All described params with their descriptions
|
67
52
|
def descriptions
|
68
|
-
definitions_for(:description)
|
53
|
+
definitions_for(:description).reject{|param, desc| param_definitions[param][:hide_help] }
|
69
54
|
end
|
70
55
|
|
71
56
|
# List of params that have descriptions
|
@@ -86,33 +71,38 @@ module Configliere
|
|
86
71
|
param_definitions[param][:type]
|
87
72
|
end
|
88
73
|
|
89
|
-
# All
|
90
|
-
def
|
74
|
+
# All typed params with their descriptions
|
75
|
+
def typed_params
|
91
76
|
definitions_for(:type)
|
92
77
|
end
|
93
78
|
|
94
79
|
# List of params that have descriptions
|
95
|
-
def
|
80
|
+
def typed_param_names
|
96
81
|
params_with(:type)
|
97
82
|
end
|
98
83
|
|
84
|
+
require 'date'
|
85
|
+
|
99
86
|
# Coerce all params with types defined to their proper form
|
100
87
|
def resolve_types!
|
101
|
-
|
88
|
+
typed_params.each do |param, type|
|
102
89
|
val = self[param]
|
103
90
|
case
|
104
|
-
when val.nil?
|
91
|
+
when val.nil? then val = nil
|
105
92
|
when (type == :boolean) then
|
106
|
-
if ['false', '0', ''].include?(val
|
107
|
-
when (
|
93
|
+
if ['false', false, 0, '0', ''].include?(val) then val = false else val = true end
|
94
|
+
when ((type == Array) && val.is_a?(String))
|
95
|
+
val = val.split(",") rescue nil
|
96
|
+
# following types map blank to nil
|
97
|
+
when (val.blank?) then val = nil
|
108
98
|
when (type == Float) then val = val.to_f
|
109
99
|
when (type == Integer) then val = val.to_i
|
100
|
+
when (type == Symbol) then val = val.to_s.to_sym rescue nil
|
101
|
+
when ((val.to_s == 'now') && (type == Date)) then val = Date.today
|
102
|
+
when ((val.to_s == 'now') && (type == DateTime)) then val = DateTime.now
|
110
103
|
when (type == Date) then val = Date.parse(val) rescue nil
|
111
104
|
when (type == DateTime) then val = DateTime.parse(val) rescue nil
|
112
|
-
|
113
|
-
require 'time'
|
114
|
-
val = Time.parse(val) rescue nil
|
115
|
-
when (type == Symbol) then val = val.to_s.to_sym rescue nil
|
105
|
+
else # nothing
|
116
106
|
end
|
117
107
|
self[param] = val
|
118
108
|
end
|
@@ -142,6 +132,28 @@ module Configliere
|
|
142
132
|
raise "Missing values for #{missing.map{|s| s.to_s }.sort.join(", ")}" if (! missing.empty?)
|
143
133
|
end
|
144
134
|
|
135
|
+
# all params with a value for the definable aspect
|
136
|
+
#
|
137
|
+
# @param definable the aspect to list (:description, :type, :encrypted, etc.)
|
138
|
+
def params_with defineable
|
139
|
+
param_definitions.keys.find_all{|param| param_definitions[param][defineable] } || []
|
140
|
+
end
|
141
|
+
|
142
|
+
# all params without a value for the definable aspect
|
143
|
+
#
|
144
|
+
# @param definable the aspect to reject (:description, :type, :encrypted, etc.)
|
145
|
+
def params_without defineable
|
146
|
+
param_definitions.keys.reject{|param| param_definitions[param].include?(defineable) } || []
|
147
|
+
end
|
148
|
+
|
149
|
+
def definitions_for defineable
|
150
|
+
hsh = {}
|
151
|
+
param_definitions.each do |param, defs|
|
152
|
+
hsh[param] = defs[defineable] if defs[defineable]
|
153
|
+
end
|
154
|
+
hsh
|
155
|
+
end
|
156
|
+
public
|
145
157
|
end
|
146
158
|
|
147
159
|
Param.class_eval do
|
@@ -1,26 +1,10 @@
|
|
1
|
-
Configliere.use :
|
1
|
+
Configliere.use :config_file, :define, :crypter
|
2
2
|
|
3
3
|
module Configliere
|
4
4
|
module EncryptedParam
|
5
5
|
# The password used in encrypting params during serialization
|
6
6
|
attr_accessor :encrypt_pass
|
7
7
|
|
8
|
-
protected
|
9
|
-
|
10
|
-
# @example
|
11
|
-
# Settings.defaults :username=>"mysql_username", :password=>"mysql_password"
|
12
|
-
# Settings.define :password, :encrypted => true
|
13
|
-
# Settings.exportable
|
14
|
-
# #=> {:username => 'mysql_username', :password=>"\345?r`\222\021"\210\312\331\256\356\351\037\367\326" }
|
15
|
-
def export
|
16
|
-
hsh = super()
|
17
|
-
encrypted_params.each do |param|
|
18
|
-
val = hsh.deep_delete(*dotted_to_deep_keys(param)) or next
|
19
|
-
hsh.deep_set( *(dotted_to_encrypted_keys(param) | [encrypted(val)]) )
|
20
|
-
end
|
21
|
-
hsh
|
22
|
-
end
|
23
|
-
|
24
8
|
# decrypts any encrypted params
|
25
9
|
# then calls the next step in the resolve! chain.
|
26
10
|
def resolve!
|
@@ -38,6 +22,22 @@ module Configliere
|
|
38
22
|
end
|
39
23
|
end
|
40
24
|
|
25
|
+
protected
|
26
|
+
|
27
|
+
# @example
|
28
|
+
# Settings.defaults :username=>"mysql_username", :password=>"mysql_password"
|
29
|
+
# Settings.define :password, :encrypted => true
|
30
|
+
# Settings.exportable
|
31
|
+
# #=> {:username => 'mysql_username', :password=>"\345?r`\222\021"\210\312\331\256\356\351\037\367\326" }
|
32
|
+
def export
|
33
|
+
hsh = super()
|
34
|
+
encrypted_params.each do |param|
|
35
|
+
val = hsh.deep_delete(*dotted_to_deep_keys(param)) or next
|
36
|
+
hsh.deep_set( *(dotted_to_encrypted_keys(param) | [encrypted(val)]) )
|
37
|
+
end
|
38
|
+
hsh
|
39
|
+
end
|
40
|
+
|
41
41
|
# if :encrypted_pass was set as a param, remove it from the hash and set it as an attribute
|
42
42
|
def remove_and_adopt_encrypt_pass_param_if_any!
|
43
43
|
@encrypt_pass = self.delete(:encrypt_pass) if self[:encrypt_pass]
|
@@ -61,12 +61,12 @@ module Configliere
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def decrypted val
|
64
|
-
return val if val.
|
64
|
+
return val if val.blank?
|
65
65
|
Configliere::Crypter.decrypt(val, encrypt_pass)
|
66
66
|
end
|
67
67
|
|
68
|
-
def encrypted
|
69
|
-
return
|
68
|
+
def encrypted val
|
69
|
+
return unless val
|
70
70
|
Configliere::Crypter.encrypt(val, encrypt_pass)
|
71
71
|
end
|
72
72
|
end
|
@@ -10,24 +10,25 @@ module Configliere
|
|
10
10
|
case env
|
11
11
|
when Hash
|
12
12
|
env.each do |env, param|
|
13
|
-
adopt_environment_variable! env, param
|
13
|
+
adopt_environment_variable! env.to_s, param
|
14
14
|
end
|
15
15
|
else
|
16
16
|
param = env.to_s.downcase.to_sym
|
17
|
-
adopt_environment_variable! env, param
|
17
|
+
adopt_environment_variable! env.to_s, param
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def params_from_environment
|
23
|
+
definitions_for(:environment)
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
22
27
|
def adopt_environment_variable! env, param
|
23
|
-
|
28
|
+
param_definitions[param][:environment] ||= env
|
24
29
|
val = ENV[env]
|
25
30
|
self[param] = val if val
|
26
31
|
end
|
27
|
-
|
28
|
-
def params_from_environment
|
29
|
-
definitions_for(:environment)
|
30
|
-
end
|
31
32
|
end
|
32
33
|
|
33
34
|
Param.class_eval do
|
data/lib/configliere/param.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
Configliere.use :
|
2
|
+
Configliere.use :config_block
|
3
3
|
|
4
|
-
describe "Configliere::
|
4
|
+
describe "Configliere::ConfigBlock" do
|
5
5
|
before do
|
6
6
|
@config = Configliere::Param.new :normal_param => 'normal'
|
7
7
|
end
|
@@ -14,7 +14,7 @@ describe "Configliere::ConfigBlocks" do
|
|
14
14
|
@config.resolve!
|
15
15
|
end
|
16
16
|
it 'resolves blocks last' do
|
17
|
-
Configliere.use :
|
17
|
+
Configliere.use :config_block, :define, :encrypted
|
18
18
|
@config.should_receive(:resolve_types!).ordered
|
19
19
|
@config.should_receive(:resolve_finally_blocks!).ordered
|
20
20
|
@config.resolve!
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
Configliere.use :
|
2
|
+
Configliere.use :config_file
|
3
3
|
|
4
|
-
describe "Configliere::
|
4
|
+
describe "Configliere::ConfigFile" do
|
5
5
|
before do
|
6
6
|
@config = Configliere.new :my_param => 'val'
|
7
7
|
end
|
@@ -40,7 +40,7 @@ describe "Configliere::ParamStore" do
|
|
40
40
|
describe 'saves to a config file' do
|
41
41
|
describe 'successfully' do
|
42
42
|
it 'saves a symbol name to the default config file' do
|
43
|
-
Configliere::
|
43
|
+
Configliere::ConfigFile.should_receive(:merge_into_yaml_file).
|
44
44
|
with(Configliere::DEFAULT_CONFIG_FILE, :my_settings, { :my_param => 'val'})
|
45
45
|
@config.save! :my_settings
|
46
46
|
end
|
@@ -61,7 +61,7 @@ describe "Configliere::ParamStore" do
|
|
61
61
|
mock_dump = 'mock_dump'
|
62
62
|
YAML.should_receive(:dump).with({ :my_settings => { :my_param => 'new_val'}, :other_settings => { :that_param => 'other_val'}}).and_return(mock_dump)
|
63
63
|
fake_file.should_receive(:<<).with(mock_dump)
|
64
|
-
Configliere::
|
64
|
+
Configliere::ConfigFile.merge_into_yaml_file '/fake/path.yaml', :my_settings, :my_param => 'new_val'
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -46,24 +46,35 @@ describe "Configliere::Define" do
|
|
46
46
|
require 'date'; require 'time'
|
47
47
|
describe 'type coercion' do
|
48
48
|
[
|
49
|
-
[:boolean, '0', false], [:boolean, 0, false], [:boolean, '', false], [:boolean, [],
|
49
|
+
[:boolean, '0', false], [:boolean, 0, false], [:boolean, '', false], [:boolean, [], true], [:boolean, nil, nil],
|
50
50
|
[:boolean, '1', true], [:boolean, 1, true], [:boolean, '5', true], [:boolean, 'true', true],
|
51
51
|
[Integer, '5', 5], [Integer, 5, 5], [Integer, nil, nil], [Integer, '', nil],
|
52
52
|
[Integer, '5', 5], [Integer, 5, 5], [Integer, nil, nil], [Integer, '', nil],
|
53
53
|
[Float, '5.2', 5.2], [Float, 5.2, 5.2], [Float, nil, nil], [Float, '', nil],
|
54
54
|
[Symbol, 'foo', :foo], [Symbol, :foo, :foo], [Symbol, nil, nil], [Symbol, '', nil],
|
55
|
-
[Date,
|
56
|
-
[DateTime, '1985-11-05 11:00:00', DateTime.parse('1985-11-05 11:00:00')], [DateTime, nil, nil], [DateTime, '', nil],
|
57
|
-
[
|
55
|
+
[Date, '1985-11-05', Date.parse('1985-11-05')], [Date, nil, nil], [Date, '', nil], [Date, 'blah', nil],
|
56
|
+
[DateTime, '1985-11-05 11:00:00', DateTime.parse('1985-11-05 11:00:00')], [DateTime, nil, nil], [DateTime, '', nil], [DateTime, 'blah', nil],
|
57
|
+
[Array, ['this', 'that', 'thother'], ['this', 'that', 'thother']],
|
58
|
+
[Array, 'this,that,thother', ['this', 'that', 'thother']],
|
59
|
+
[Array, 'alone', ['alone'] ],
|
60
|
+
[Array, '', [] ],
|
61
|
+
[Array, nil, nil ],
|
58
62
|
].each do |type, orig, desired|
|
59
63
|
it "for #{type} converts #{orig.inspect} to #{desired.inspect}" do
|
60
64
|
@config.define :param, :type => type
|
61
65
|
@config[:param] = orig ; @config.resolve! ; @config[:param].should == desired
|
62
66
|
end
|
63
67
|
end
|
68
|
+
it 'converts :now to the current moment' do
|
69
|
+
@config.define :param, :type => DateTime
|
70
|
+
@config[:param] = 'now' ; @config.resolve! ; @config[:param].should be_close(DateTime.now, 4)
|
71
|
+
@config[:param] = :now ; @config.resolve! ; @config[:param].should be_close(DateTime.now, 4)
|
72
|
+
@config.define :param, :type => Date
|
73
|
+
@config[:param] = :now ; @config.resolve! ; @config[:param].should be_close(Date.today, 4)
|
74
|
+
@config[:param] = 'now' ; @config.resolve! ; @config[:param].should be_close(Date.today, 4)
|
75
|
+
end
|
64
76
|
end
|
65
77
|
|
66
|
-
|
67
78
|
describe 'defining requireds' do
|
68
79
|
before do
|
69
80
|
@config.define :param_1, :required => true
|
@@ -76,20 +87,19 @@ describe "Configliere::Define" do
|
|
76
87
|
@config.required_params.should include(:param_2)
|
77
88
|
end
|
78
89
|
it 'counts false values as required' do
|
79
|
-
p [@config]
|
80
90
|
@config.defaults :param_1 => true, :param_2 => false
|
81
91
|
@config.validate!.should == true
|
82
92
|
end
|
83
93
|
it 'counts nil-but-set values as missing' do
|
84
94
|
@config.defaults :param_1 => true, :param_2 => nil
|
85
|
-
lambda{ @config.validate! }.should raise_error
|
95
|
+
lambda{ @config.validate! }.should raise_error("Missing values for param_2")
|
86
96
|
end
|
87
97
|
it 'counts never-set values as missing' do
|
88
|
-
lambda{ @config.validate! }.should raise_error
|
98
|
+
lambda{ @config.validate! }.should raise_error("Missing values for param_1, param_2")
|
89
99
|
end
|
90
100
|
it 'lists all missing values when it raises' do
|
91
101
|
Configliere.use :define
|
92
|
-
lambda{
|
102
|
+
lambda{ @config.validate! }.should raise_error("Missing values for param_1, param_2")
|
93
103
|
end
|
94
104
|
end
|
95
105
|
end
|
@@ -54,7 +54,7 @@ describe "Configliere::Encrypted" do
|
|
54
54
|
end
|
55
55
|
it 'encrypts' do
|
56
56
|
Configliere::Crypter.should_receive(:encrypt).and_return(@encrypted_str)
|
57
|
-
Configliere::
|
57
|
+
Configliere::ConfigFile.should_receive(:write_yaml_file).with('/fake/file', :normal_param=>"normal", :encrypted_secret => @encrypted_str)
|
58
58
|
@config.save! '/fake/file'
|
59
59
|
end
|
60
60
|
it 'decrypts' do
|
@@ -35,7 +35,8 @@ describe "Configliere::Param" do
|
|
35
35
|
@config['moon.cheese.smell'].should be_nil
|
36
36
|
@config['moon.non.existent.interim.values'].should be_nil
|
37
37
|
@config['moon.non'].should be_nil
|
38
|
-
lambda{ @config['hat.cat'] }.should raise_error(
|
38
|
+
if (RUBY_VERSION >= '1.9') then lambda{ @config['hat.cat'] }.should raise_error(TypeError)
|
39
|
+
else lambda{ @config['hat.cat'] }.should raise_error(NoMethodError, 'undefined method `[]\' for :cat:Symbol') end
|
39
40
|
@config.should == hsh # shouldn't change from reading
|
40
41
|
end
|
41
42
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
2
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
3
|
|
4
|
-
require 'tempfile'
|
5
|
-
# module Configliere ; DEFAULT_FILE = Tempfile.new("configliere_spec-") ;DEFAULT_FILE.close(false) ; DEFAULT_CONFIG_FILE = DEFAULT_FILE.path ; end
|
6
|
-
|
7
4
|
require 'configliere'
|
8
5
|
require 'spec'
|
9
6
|
require 'spec/autorun'
|
@@ -11,6 +8,3 @@ require 'spec/autorun'
|
|
11
8
|
Spec::Runner.configure do |config|
|
12
9
|
|
13
10
|
end
|
14
|
-
|
15
|
-
# Configliere::DEFAULT_FILE.close!
|
16
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configliere
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mrflip
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-08 00:00:00 -06:00
|
13
13
|
default_executable: configliere
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -32,49 +32,8 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: "0"
|
34
34
|
version:
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: highline
|
37
|
-
type: :runtime
|
38
|
-
version_requirement:
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
40
|
-
requirements:
|
41
|
-
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: "0"
|
44
|
-
version:
|
45
|
-
- !ruby/object:Gem::Dependency
|
46
|
-
name: yaml
|
47
|
-
type: :runtime
|
48
|
-
version_requirement:
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: "0"
|
54
|
-
version:
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: openssl
|
57
|
-
type: :runtime
|
58
|
-
version_requirement:
|
59
|
-
version_requirements: !ruby/object:Gem::Requirement
|
60
|
-
requirements:
|
61
|
-
- - ">="
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
version: "0"
|
64
|
-
version:
|
65
35
|
description: " 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.\n\n \"\" So, Consigliere of mine, I think you should tell your Don what everyone knows. \"\" -- Don Corleone\n\n\
|
66
|
-
Configliere'
|
67
|
-
* *Don't go outside the family*. Requires almost no external resources and almost no code in your script.\n\
|
68
|
-
* *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.\n\
|
69
|
-
* *Be willing to sit down with the Five Families*. Takes settings from (at your option):\n\
|
70
|
-
** Pre-defined defaults from constants\n\
|
71
|
-
** Simple config files\n\
|
72
|
-
** Environment variables\n\
|
73
|
-
** Commandline options\n\
|
74
|
-
** Ruby block called when all other options are in place\n\
|
75
|
-
* *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.\n\
|
76
|
-
* *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.\n\n\
|
77
|
-
fuhgeddaboudit.\n"
|
36
|
+
Configliere manage 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.\n"
|
78
37
|
email: flip@infochimps.org
|
79
38
|
executables:
|
80
39
|
- configliere
|
@@ -101,23 +60,24 @@ files:
|
|
101
60
|
- lib/configliere/commandline.rb
|
102
61
|
- lib/configliere/commandline/commands.rb
|
103
62
|
- lib/configliere/commandline/options.rb
|
104
|
-
- lib/configliere/
|
63
|
+
- lib/configliere/config_block.rb
|
64
|
+
- lib/configliere/config_file.rb
|
105
65
|
- lib/configliere/core_ext.rb
|
66
|
+
- lib/configliere/core_ext/blank.rb
|
106
67
|
- lib/configliere/core_ext/hash.rb
|
107
68
|
- lib/configliere/crypter.rb
|
108
69
|
- lib/configliere/define.rb
|
109
70
|
- lib/configliere/encrypted.rb
|
110
71
|
- lib/configliere/environment.rb
|
111
72
|
- lib/configliere/param.rb
|
112
|
-
- lib/configliere/param_store.rb
|
113
73
|
- spec/configliere/commandline_spec.rb
|
114
|
-
- spec/configliere/
|
74
|
+
- spec/configliere/config_block_spec.rb
|
75
|
+
- spec/configliere/config_file_spec.rb
|
115
76
|
- spec/configliere/crypter_spec.rb
|
116
77
|
- spec/configliere/define_spec.rb
|
117
78
|
- spec/configliere/encrypted_spec.rb
|
118
79
|
- spec/configliere/environment_spec.rb
|
119
80
|
- spec/configliere/param_spec.rb
|
120
|
-
- spec/configliere/param_store_spec.rb
|
121
81
|
- spec/configliere_spec.rb
|
122
82
|
- spec/spec.opts
|
123
83
|
- spec/spec_helper.rb
|
@@ -151,13 +111,13 @@ specification_version: 3
|
|
151
111
|
summary: Wise, discreet configuration management
|
152
112
|
test_files:
|
153
113
|
- spec/configliere/commandline_spec.rb
|
154
|
-
- spec/configliere/
|
114
|
+
- spec/configliere/config_block_spec.rb
|
115
|
+
- spec/configliere/config_file_spec.rb
|
155
116
|
- spec/configliere/crypter_spec.rb
|
156
117
|
- spec/configliere/define_spec.rb
|
157
118
|
- spec/configliere/encrypted_spec.rb
|
158
119
|
- spec/configliere/environment_spec.rb
|
159
120
|
- spec/configliere/param_spec.rb
|
160
|
-
- spec/configliere/param_store_spec.rb
|
161
121
|
- spec/configliere_spec.rb
|
162
122
|
- spec/spec_helper.rb
|
163
123
|
- examples/commandline_script.rb
|