configliere 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +1 -3
- data/CHANGELOG.textile +19 -0
- data/README.textile +49 -15
- data/VERSION +1 -1
- data/configliere.gemspec +12 -4
- data/examples/config_block.rb +11 -0
- data/examples/encrypted_script.rb +17 -0
- data/lib/configliere/commandline.rb +23 -6
- data/lib/configliere/config_block.rb +29 -13
- data/lib/configliere/config_file.rb +3 -1
- data/lib/configliere/core_ext/hash.rb +4 -2
- data/lib/configliere/core_ext/sash.rb +169 -0
- data/lib/configliere/define.rb +20 -2
- data/lib/configliere/encrypted.rb +2 -2
- data/lib/configliere/environment.rb +5 -4
- data/lib/configliere/param.rb +57 -34
- data/spec/configliere/config_file_spec.rb +7 -0
- data/spec/configliere/core_ext/hash_spec.rb +78 -0
- data/spec/configliere/core_ext/sash_spec.rb +313 -0
- data/spec/configliere/environment_spec.rb +2 -1
- data/spec/configliere/param_spec.rb +16 -10
- metadata +12 -4
- data/lib/configliere/commandline/commands.rb +0 -30
- data/lib/configliere/commandline/options.rb +0 -4
data/lib/configliere/define.rb
CHANGED
@@ -13,13 +13,15 @@ module Configliere
|
|
13
13
|
#
|
14
14
|
def define param, definitions={}
|
15
15
|
self.param_definitions[param].merge! definitions
|
16
|
+
self.use(:environment) if definitions.include?(:encrypted)
|
17
|
+
self.use(:encrypted) if definitions.include?(:encrypted)
|
16
18
|
self[param] = definitions[:default] if definitions.include?(:default)
|
17
19
|
self.environment_variables definitions[:environment], param if definitions.include?(:environment)
|
18
20
|
end
|
19
21
|
|
20
22
|
def param_definitions
|
21
23
|
# initialize the param_definitions as an auto-vivifying hash if it's never been set
|
22
|
-
@param_definitions ||=
|
24
|
+
@param_definitions ||= Sash.new{|hsh, key| hsh[key] = Sash.new }
|
23
25
|
end
|
24
26
|
|
25
27
|
# performs type coercion
|
@@ -153,7 +155,23 @@ module Configliere
|
|
153
155
|
end
|
154
156
|
hsh
|
155
157
|
end
|
156
|
-
|
158
|
+
|
159
|
+
# Pretend that any #define'd parameter is a method
|
160
|
+
#
|
161
|
+
# @example
|
162
|
+
# Settings.define :foo
|
163
|
+
# Settings.foo = 4
|
164
|
+
# Settings.foo #=> 4
|
165
|
+
def method_missing meth, *args
|
166
|
+
meth.to_s =~ /^(\w+)(=)?$/
|
167
|
+
name, setter = [$1, $2]
|
168
|
+
super unless name && param_definitions.include?(name)
|
169
|
+
if setter && (args.size == 1)
|
170
|
+
self[$1] = args.first
|
171
|
+
elsif (!setter) && args.empty?
|
172
|
+
self[meth]
|
173
|
+
else super ; end
|
174
|
+
end
|
157
175
|
end
|
158
176
|
|
159
177
|
Param.class_eval do
|
@@ -32,7 +32,7 @@ module Configliere
|
|
32
32
|
def export
|
33
33
|
hsh = super()
|
34
34
|
encrypted_params.each do |param|
|
35
|
-
val = hsh.deep_delete(*
|
35
|
+
val = hsh.deep_delete(*convert_key(param)) or next
|
36
36
|
hsh.deep_set( *(dotted_to_encrypted_keys(param) | [encrypted(val)]) )
|
37
37
|
end
|
38
38
|
hsh
|
@@ -50,7 +50,7 @@ module Configliere
|
|
50
50
|
# dotted_to_encrypted_keys('amazon.api.key')
|
51
51
|
# #=> [:amazon, :api, :encrypted_key]
|
52
52
|
def dotted_to_encrypted_keys param
|
53
|
-
encrypted_path =
|
53
|
+
encrypted_path = convert_key(param).dup
|
54
54
|
encrypted_path[-1] = "encrypted_#{encrypted_path.last}".to_sym
|
55
55
|
encrypted_path
|
56
56
|
end
|
@@ -9,12 +9,12 @@ module Configliere
|
|
9
9
|
envs.each do |env|
|
10
10
|
case env
|
11
11
|
when Hash
|
12
|
-
env.each do |
|
13
|
-
adopt_environment_variable!
|
12
|
+
env.each do |param, env|
|
13
|
+
adopt_environment_variable! param, env
|
14
14
|
end
|
15
15
|
else
|
16
16
|
param = env.to_s.downcase.to_sym
|
17
|
-
adopt_environment_variable!
|
17
|
+
adopt_environment_variable! param, env
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -24,7 +24,8 @@ module Configliere
|
|
24
24
|
end
|
25
25
|
|
26
26
|
protected
|
27
|
-
def adopt_environment_variable!
|
27
|
+
def adopt_environment_variable! param, env
|
28
|
+
env = env.to_s
|
28
29
|
param_definitions[param][:environment] ||= env
|
29
30
|
val = ENV[env]
|
30
31
|
self[param] = val if val
|
data/lib/configliere/param.rb
CHANGED
@@ -1,22 +1,48 @@
|
|
1
|
+
require 'configliere/core_ext/sash.rb'
|
1
2
|
module Configliere
|
3
|
+
class ParamParent < ::Hash
|
4
|
+
def finally *args, &block
|
5
|
+
nil #no-op
|
6
|
+
end
|
7
|
+
# default export method: self
|
8
|
+
def export
|
9
|
+
to_hash
|
10
|
+
end
|
11
|
+
# terminate resolution chain
|
12
|
+
def resolve!
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate!
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
2
20
|
#
|
3
21
|
# Hash of fields to store.
|
4
22
|
#
|
5
23
|
# Any field name beginning with 'decrypted_' automatically creates a
|
6
24
|
# counterpart 'encrypted_' field using the encrypt_pass.
|
7
25
|
#
|
8
|
-
class Param < ::
|
26
|
+
class Param < Configliere::ParamParent
|
9
27
|
|
10
|
-
#
|
28
|
+
# @param constructor<Object>
|
29
|
+
# The default value for the mash. Defaults to an empty hash.
|
11
30
|
#
|
12
|
-
# @
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
31
|
+
# @details [Alternatives]
|
32
|
+
# If constructor is a Hash, a new mash will be created based on the keys of
|
33
|
+
# the hash and no default value will be set.
|
34
|
+
def initialize(constructor = {})
|
35
|
+
if constructor.is_a?(Hash)
|
36
|
+
super()
|
37
|
+
update(constructor) unless constructor.empty?
|
38
|
+
else
|
39
|
+
super(constructor)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Hash] The mash as a Hash with string keys.
|
44
|
+
def to_hash
|
45
|
+
Hash.new(default).merge(self)
|
20
46
|
end
|
21
47
|
|
22
48
|
#
|
@@ -47,53 +73,50 @@ module Configliere
|
|
47
73
|
|
48
74
|
def []= param, val
|
49
75
|
if param =~ /\./
|
50
|
-
return deep_set( *(
|
76
|
+
return deep_set( *(convert_key(param) | [val]) )
|
51
77
|
else
|
52
|
-
super param
|
78
|
+
super param, val
|
53
79
|
end
|
54
80
|
end
|
55
81
|
|
56
82
|
def [] param
|
57
83
|
if param =~ /\./
|
58
|
-
return deep_get( *
|
84
|
+
return deep_get( *convert_key(param) )
|
59
85
|
else
|
60
|
-
super param
|
86
|
+
super param
|
61
87
|
end
|
62
88
|
end
|
63
89
|
|
64
90
|
def delete param
|
65
91
|
if param =~ /\./
|
66
|
-
return deep_delete( *
|
92
|
+
return deep_delete( *convert_key(param) )
|
67
93
|
else
|
68
|
-
super param
|
94
|
+
super param
|
69
95
|
end
|
70
96
|
end
|
71
97
|
|
72
|
-
# returns an actual Hash, not a Param < Hash
|
73
|
-
def to_hash
|
74
|
-
{}.merge! self
|
75
|
-
end
|
76
|
-
|
77
98
|
def use *args
|
78
99
|
hsh = args.pop if args.last.is_a?(Hash)
|
79
100
|
Configliere.use *args
|
80
|
-
|
101
|
+
self.deep_merge!(hsh) unless hsh.nil?
|
81
102
|
end
|
82
103
|
|
104
|
+
# see Configliere::ConfigBlock#finally
|
105
|
+
def finally *args, &block
|
106
|
+
use :config_block
|
107
|
+
super
|
108
|
+
end
|
83
109
|
protected
|
84
|
-
#
|
85
|
-
#
|
86
|
-
|
87
|
-
|
110
|
+
# @param key<Object> The key to convert.
|
111
|
+
#
|
112
|
+
# @param [Object]
|
113
|
+
# The converted key. A dotted param ('moon.cheese.type') becomes
|
114
|
+
# an array of sequential keys for deep_set and deep_get
|
115
|
+
#
|
116
|
+
# @api private
|
117
|
+
def convert_key dotted
|
118
|
+
dotted.to_s.split(".").map{|key| key.to_sym }
|
88
119
|
end
|
89
120
|
|
90
|
-
# simple (no-arg) method_missing callse
|
91
|
-
def method_missing meth, *args
|
92
|
-
if args.empty? && meth.to_s =~ /^\w+$/
|
93
|
-
self[meth]
|
94
|
-
elsif args.size == 1 && meth.to_s =~ /^(\w+)=$/
|
95
|
-
self[$1] = args.first
|
96
|
-
else super(meth, *args) end
|
97
|
-
end
|
98
121
|
end
|
99
122
|
end
|
@@ -4,6 +4,7 @@ Configliere.use :config_file
|
|
4
4
|
describe "Configliere::ConfigFile" do
|
5
5
|
before do
|
6
6
|
@config = Configliere.new :my_param => 'val'
|
7
|
+
FileUtils.stub! :mkdir_p
|
7
8
|
end
|
8
9
|
|
9
10
|
describe 'loads a config file' do
|
@@ -50,6 +51,12 @@ describe "Configliere::ConfigFile" do
|
|
50
51
|
fake_file.should_receive(:<<).with("--- \n:my_param: val\n")
|
51
52
|
@config.save! '/fake/path.yaml'
|
52
53
|
end
|
54
|
+
it 'ensures the directory exists' do
|
55
|
+
fake_file = StringIO.new('', 'w')
|
56
|
+
File.stub!(:open).with('/fake/path.yaml', 'w').and_yield(fake_file)
|
57
|
+
FileUtils.should_receive(:mkdir_p).with('/fake')
|
58
|
+
@config.save! '/fake/path.yaml'
|
59
|
+
end
|
53
60
|
end
|
54
61
|
end
|
55
62
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../spec_helper'))
|
2
|
+
|
3
|
+
describe Hash do
|
4
|
+
before(:each) do
|
5
|
+
@hash = { :hsh1a => { :hsh2 => { :key3 => "val3" }, :key2 => "val2" }, :key1b => 'val1b' }
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#deep_merge!" do
|
9
|
+
it "merges two subhashes when they share a key" do
|
10
|
+
@hash.deep_merge!(:hsh1a => { :hsh2 => { :key3a => "val3a" } })
|
11
|
+
@hash.should == { :hsh1a => { :hsh2 => { :key3a => "val3a", :key3 => "val3" }, :key2 => "val2" }, :key1b => 'val1b' }
|
12
|
+
end
|
13
|
+
it "preserves values in the original" do
|
14
|
+
@hash.deep_merge! :other_key => "other_val"
|
15
|
+
@hash[:hsh1a][:key2].should == "val2"
|
16
|
+
@hash[:other_key].should == "other_val"
|
17
|
+
end
|
18
|
+
it "replaces values from the given Hash" do
|
19
|
+
@hash.deep_merge!(:hsh1a => { :hsh2 => { :key3 => "new_val3" }, :key2 => { "other2" => "other_val2" }})
|
20
|
+
@hash[:hsh1a][:hsh2][:key3].should == 'new_val3'
|
21
|
+
@hash[:hsh1a][:key2].should == { "other2" => "other_val2" }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
describe "#deep_set" do
|
27
|
+
it 'should set a new value (single arg)' do
|
28
|
+
@hash.deep_set :new_key, 'new_val'
|
29
|
+
@hash[:new_key].should == 'new_val'
|
30
|
+
end
|
31
|
+
it 'should set a new value (multiple args)' do
|
32
|
+
@hash.deep_set :hsh1a, :hsh2, :new_key, 'new_val'
|
33
|
+
@hash[:hsh1a][:hsh2][:new_key].should == 'new_val'
|
34
|
+
end
|
35
|
+
it 'should replace an existing value (single arg)' do
|
36
|
+
@hash.deep_set :key1b, 'new_val'
|
37
|
+
@hash[:key1b].should == 'new_val'
|
38
|
+
end
|
39
|
+
it 'should replace an existing value (multiple args)' do
|
40
|
+
@hash.deep_set :hsh1a, :hsh2, 'new_val'
|
41
|
+
@hash[:hsh1a][:hsh2].should == 'new_val'
|
42
|
+
end
|
43
|
+
it 'should auto-vivify intermediate hashes' do
|
44
|
+
@hash.deep_set :one, :two, :three, :four, 'new_val'
|
45
|
+
@hash[:one][:two][:three][:four].should == 'new_val'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#deep_delete" do
|
50
|
+
it 'should remove the key from the array (multiple args)' do
|
51
|
+
@hash.deep_delete(:hsh1a)
|
52
|
+
@hash[:hsh1a].should be_nil
|
53
|
+
@hash.should == { :key1b => 'val1b'}
|
54
|
+
end
|
55
|
+
it 'should remove the key from the array (multiple args)' do
|
56
|
+
@hash.deep_delete(:hsh1a, :hsh2, :key3)
|
57
|
+
@hash[:hsh1a][:hsh2][:key3].should be_nil
|
58
|
+
@hash.should == {:key1b=>"val1b", :hsh1a=>{:key2=>"val2", :hsh2=>{}}}
|
59
|
+
end
|
60
|
+
it 'should return the value if present (single args)' do
|
61
|
+
returned_val = @hash.deep_delete(:key1b)
|
62
|
+
returned_val.should == 'val1b'
|
63
|
+
end
|
64
|
+
it 'should return the value if present (multiple args)' do
|
65
|
+
returned_val = @hash.deep_delete(:hsh1a, :hsh2, :key3)
|
66
|
+
returned_val.should == 'val3'
|
67
|
+
end
|
68
|
+
it 'should return nil if the key is absent (single arg)' do
|
69
|
+
returned_val = @hash.deep_delete(:hsh1a, :hsh2, :missing_key)
|
70
|
+
returned_val.should be_nil
|
71
|
+
end
|
72
|
+
it 'should return nil if the key is absent (multiple args)' do
|
73
|
+
returned_val = @hash.deep_delete(:missing_key)
|
74
|
+
returned_val.should be_nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../spec_helper'))
|
2
|
+
|
3
|
+
class AwesomeHash < Hash
|
4
|
+
end
|
5
|
+
|
6
|
+
describe Sash do
|
7
|
+
before(:each) do
|
8
|
+
@hash = { "str_key" => "strk_val", :sym_key => "symk_val" }
|
9
|
+
@sub = AwesomeHash.new("str_key" => "strk_val", :sym_key => "symk_val")
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
describe "#deep_merge!" do
|
14
|
+
before do
|
15
|
+
@sash = Sash.new :hsh1 => { :hsh2 => { :key3 => "val3" }, :key2 => "val2" }
|
16
|
+
end
|
17
|
+
it "merges two subhashes when they share a key" do
|
18
|
+
@sash.deep_merge!(:hsh1 => { :hsh2 => { :key3a => "val3a" } })
|
19
|
+
@sash.should == { :hsh1 => { :hsh2 => { :key3a => "val3a", :key3 => "val3" }, :key2 => "val2" } }
|
20
|
+
end
|
21
|
+
it "merges two subhashes when they share a symbolized key" do
|
22
|
+
@sash.deep_merge!(:hsh1 => { "hsh2" => { "key3a" => "val3a" } })
|
23
|
+
@sash.should == { :hsh1 => { :hsh2 => { :key3a => "val3a", :key3 => "val3" }, :key2 => "val2" } }
|
24
|
+
end
|
25
|
+
it "preserves values in the original" do
|
26
|
+
@sash.deep_merge! :other_key => "other_val"
|
27
|
+
@sash[:other_key].should == "other_val"
|
28
|
+
@sash[:hsh1][:key2].should == "val2"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "converts all keys into symbols when param is a Hash" do
|
32
|
+
@sash.deep_merge!(:hsh1 => { "hsh2" => { "key3a" => "val3a" } })
|
33
|
+
@sash.should == { :hsh1 => { :hsh2 => { :key3a => "val3a", :key3 => "val3" }, :key2 => "val2" } }
|
34
|
+
end
|
35
|
+
it "converts all Hash values into Sashes if param is a Hash" do
|
36
|
+
@sash.deep_merge!({:hsh1 => { :hsh2 => { :key3a => "val3a" } }, :other1 => { "other2" => "other_val2" }})
|
37
|
+
@sash[:hsh1].should be_an_instance_of(Sash)
|
38
|
+
@sash[:hsh1][:hsh2].should be_an_instance_of(Sash)
|
39
|
+
@sash[:other1].should be_an_instance_of(Sash)
|
40
|
+
end
|
41
|
+
it "replaces values from the given Hash" do
|
42
|
+
@sash.deep_merge!(:hsh1 => { :hsh2 => { :key3 => "new_val3" }, :key2 => { "other2" => "other_val2" }})
|
43
|
+
@sash[:hsh1][:hsh2][:key3].should == 'new_val3'
|
44
|
+
@sash[:hsh1][:key2].should == { :other2 => "other_val2" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#initialize" do
|
49
|
+
it 'converts all keys into symbols when param is a Hash' do
|
50
|
+
sash = Sash.new(@hash)
|
51
|
+
sash.keys.any? { |key| key.is_a?(String) }.should be_false
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'converts all pure Hash values into Sashes if param is a Hash' do
|
55
|
+
sash = Sash.new :sym_key => @hash
|
56
|
+
|
57
|
+
sash[:sym_key].should be_an_instance_of(Sash)
|
58
|
+
# sanity check
|
59
|
+
sash[:sym_key][:sym_key].should == "symk_val"
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'doesn not convert Hash subclass values into Sashes' do
|
63
|
+
sash = Sash.new :sub => @sub
|
64
|
+
sash[:sub].should be_an_instance_of(AwesomeHash)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'converts all value items if value is an Array' do
|
68
|
+
sash = Sash.new :arry => { :sym_key => [@hash] }
|
69
|
+
|
70
|
+
sash[:arry].should be_an_instance_of(Sash)
|
71
|
+
# sanity check
|
72
|
+
sash[:arry][:sym_key].first[:sym_key].should == "symk_val"
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'delegates to superclass constructor if param is not a Hash' do
|
77
|
+
sash = Sash.new("dash berlin")
|
78
|
+
|
79
|
+
sash["unexisting key"].should == "dash berlin"
|
80
|
+
end
|
81
|
+
end # describe "#initialize"
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
describe "#update" do
|
86
|
+
it 'converts all keys into symbols when param is a Hash' do
|
87
|
+
sash = Sash.new(@hash)
|
88
|
+
sash.update("starry" => "night")
|
89
|
+
|
90
|
+
sash.keys.any?{|key| key.is_a?(String) }.should be_false
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'converts all Hash values into Sashes if param is a Hash' do
|
94
|
+
sash = Sash.new :hash => @hash
|
95
|
+
sash.update(:hash => { :sym_key => "is buggy in Ruby 1.8.6" })
|
96
|
+
|
97
|
+
sash[:hash].should be_an_instance_of(Sash)
|
98
|
+
end
|
99
|
+
end # describe "#update"
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
describe "#[]=" do
|
104
|
+
it 'converts key into symbol' do
|
105
|
+
sash = Sash.new(@hash)
|
106
|
+
sash["str_key"] = { "starry" => "night" }
|
107
|
+
|
108
|
+
sash.keys.any?{|key| key.is_a?(String) }.should be_false
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'converts all Hash value into Sash' do
|
112
|
+
sash = Sash.new :hash => @hash
|
113
|
+
sash[:hash] = { :sym_key => "is buggy in Ruby 1.8.6" }
|
114
|
+
|
115
|
+
sash[:hash].should be_an_instance_of(Sash)
|
116
|
+
end
|
117
|
+
end # describe "#[]="
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
describe "#key?" do
|
122
|
+
before(:each) do
|
123
|
+
@sash = Sash.new(@hash)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'converts key before lookup' do
|
127
|
+
@sash.key?("str_key").should be_true
|
128
|
+
@sash.key?(:str_key).should be_true
|
129
|
+
|
130
|
+
@sash.key?("sym_key").should be_true
|
131
|
+
@sash.key?(:sym_key).should be_true
|
132
|
+
|
133
|
+
@sash.key?(:rainclouds).should be_false
|
134
|
+
@sash.key?("rainclouds").should be_false
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'is aliased as include?' do
|
138
|
+
@sash.include?("str_key").should be_true
|
139
|
+
@sash.include?(:str_key).should be_true
|
140
|
+
|
141
|
+
@sash.include?("sym_key").should be_true
|
142
|
+
@sash.include?(:sym_key).should be_true
|
143
|
+
|
144
|
+
@sash.include?(:rainclouds).should be_false
|
145
|
+
@sash.include?("rainclouds").should be_false
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'is aliased as member?' do
|
149
|
+
@sash.member?("str_key").should be_true
|
150
|
+
@sash.member?(:str_key).should be_true
|
151
|
+
|
152
|
+
@sash.member?("sym_key").should be_true
|
153
|
+
@sash.member?(:sym_key).should be_true
|
154
|
+
|
155
|
+
@sash.member?(:rainclouds).should be_false
|
156
|
+
@sash.member?("rainclouds").should be_false
|
157
|
+
end
|
158
|
+
end # describe "#key?"
|
159
|
+
|
160
|
+
def arrays_should_be_equal arr1, arr2
|
161
|
+
arr1.sort_by{|s| s.to_s }.should == arr2.sort_by{|s| s.to_s }
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "#dup" do
|
165
|
+
it 'returns instance of Sash' do
|
166
|
+
Sash.new(@hash).dup.should be_an_instance_of(Sash)
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'preserves keys' do
|
170
|
+
sash = Sash.new(@hash)
|
171
|
+
dup = sash.dup
|
172
|
+
|
173
|
+
arrays_should_be_equal sash.keys, dup.keys
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'preserves value' do
|
177
|
+
sash = Sash.new(@hash)
|
178
|
+
dup = sash.dup
|
179
|
+
|
180
|
+
arrays_should_be_equal sash.values, dup.values
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
describe "#to_hash" do
|
187
|
+
it 'returns instance of Hash' do
|
188
|
+
Sash.new(@hash).to_hash.should be_an_instance_of(Hash)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'preserves keys' do
|
192
|
+
sash = Sash.new(@hash)
|
193
|
+
converted = sash.to_hash
|
194
|
+
arrays_should_be_equal sash.keys, converted.keys
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'preserves value' do
|
198
|
+
sash = Sash.new(@hash)
|
199
|
+
converted = sash.to_hash
|
200
|
+
arrays_should_be_equal sash.values, converted.values
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
describe "#stringify_keys" do
|
207
|
+
it 'returns instance of Sash' do
|
208
|
+
Sash.new(@hash).stringify_keys.should be_an_instance_of(Hash)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'converts keys to symbols' do
|
212
|
+
sash = Sash.new(@hash)
|
213
|
+
converted = sash.stringify_keys
|
214
|
+
|
215
|
+
converted_keys = converted.keys.sort{|k1, k2| k1.to_s <=> k2.to_s}
|
216
|
+
orig_keys = sash.keys.map{|k| k.to_sym}.sort{|i1, i2| i1.to_s <=> i2.to_s}
|
217
|
+
|
218
|
+
converted_keys.should == orig_keys
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'preserves value' do
|
222
|
+
sash = Sash.new(@hash)
|
223
|
+
converted = sash.stringify_keys
|
224
|
+
|
225
|
+
arrays_should_be_equal sash.values, converted.values
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
|
231
|
+
describe "#delete" do
|
232
|
+
it 'converts Symbol key into String before deleting' do
|
233
|
+
sash = Sash.new(@hash)
|
234
|
+
|
235
|
+
sash.delete(:sym_key)
|
236
|
+
sash.key?("hash").should be_false
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'works with String keys as well' do
|
240
|
+
sash = Sash.new(@hash)
|
241
|
+
|
242
|
+
sash.delete("str_key")
|
243
|
+
sash.key?("str_key").should be_false
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
|
249
|
+
describe "#merge" do
|
250
|
+
before(:each) do
|
251
|
+
@sash = Sash.new(@hash).merge(:no => "in between")
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'returns instance of Sash' do
|
255
|
+
@sash.should be_an_instance_of(Sash)
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'merges in give Hash' do
|
259
|
+
@sash["no"].should == "in between"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
|
265
|
+
describe "#fetch" do
|
266
|
+
before(:each) do
|
267
|
+
@sash = Sash.new(@hash).merge(:no => "in between")
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'converts key before fetching' do
|
271
|
+
@sash.fetch("no").should == "in between"
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'returns alternative value if key lookup fails' do
|
275
|
+
@sash.fetch("flying", "screwdriver").should == "screwdriver"
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
describe "#default" do
|
281
|
+
before(:each) do
|
282
|
+
@sash = Sash.new(:yet_another_technical_revolution)
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'returns default value unless key exists in sash' do
|
286
|
+
@sash.default("peak oil is now behind, baby").should == :yet_another_technical_revolution
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'returns existing value if key is String and exists in sash' do
|
290
|
+
@sash.update("no" => "in between")
|
291
|
+
@sash.default("no").should == "in between"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
describe "#values_at" do
|
297
|
+
before(:each) do
|
298
|
+
@sash = Sash.new(@hash).merge(:no => "in between")
|
299
|
+
end
|
300
|
+
|
301
|
+
it 'is indifferent to whether keys are strings or symbols' do
|
302
|
+
@sash.values_at("sym_key", :str_key, :no).should == ["symk_val", "strk_val", "in between"]
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
|
307
|
+
describe "#symbolize_keys!" do
|
308
|
+
it 'returns the sash itself' do
|
309
|
+
sash = Sash.new(@hash)
|
310
|
+
sash.symbolize_keys!.object_id.should == sash.object_id
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|