hashr 0.0.6 → 0.0.7
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/Gemfile.lock +1 -1
- data/lib/hashr.rb +19 -19
- data/lib/hashr/core_ext/ruby/hash.rb +28 -0
- data/lib/hashr/version.rb +1 -1
- data/test/hashr_test.rb +26 -0
- metadata +4 -3
data/Gemfile.lock
CHANGED
data/lib/hashr.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'hashr/core_ext/ruby/hash'
|
2
|
+
|
1
3
|
class Hashr < Hash
|
2
4
|
autoload :EnvDefaults, 'hashr/env_defaults'
|
3
5
|
|
@@ -7,7 +9,7 @@ class Hashr < Hash
|
|
7
9
|
attr_accessor :raise_missing_keys
|
8
10
|
|
9
11
|
def define(definition)
|
10
|
-
@definition = definition
|
12
|
+
@definition = definition.deep_symbolize_keys
|
11
13
|
end
|
12
14
|
|
13
15
|
def definition
|
@@ -15,13 +17,12 @@ class Hashr < Hash
|
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
def initialize(data = {})
|
19
|
-
|
20
|
-
replace(deep_hasherize(deep_merge(self.class.definition, data)))
|
20
|
+
def initialize(data = {}, definition = self.class.definition)
|
21
|
+
replace(deep_hashrize(definition.deep_merge(data.deep_symbolize_keys)))
|
21
22
|
end
|
22
23
|
|
23
24
|
def []=(key, value)
|
24
|
-
super(key, value.is_a?(Hash) ? self.class.new(value) : value)
|
25
|
+
super(key, value.is_a?(Hash) ? self.class.new(value, {}) : value)
|
25
26
|
end
|
26
27
|
|
27
28
|
def respond_to?(name)
|
@@ -40,24 +41,23 @@ class Hashr < Hash
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
Array(modules).each { |mod| meta_class.send(:include, mod) } if modules
|
47
|
-
end
|
44
|
+
def include_modules(modules)
|
45
|
+
Array(modules).each { |mod| meta_class.send(:include, mod) } if modules
|
46
|
+
end
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
def meta_class
|
49
|
+
class << self; self end
|
50
|
+
end
|
52
51
|
|
53
|
-
|
54
|
-
merger = proc { |key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? self.class.new(v1.merge(v2, &merger)) : v2 }
|
55
|
-
left.merge(right || {}, &merger)
|
56
|
-
end
|
52
|
+
protected
|
57
53
|
|
58
|
-
def
|
54
|
+
def deep_hashrize(hash)
|
59
55
|
hash.inject(TEMPLATE.dup) do |result, (key, value)|
|
60
|
-
|
56
|
+
if key.to_sym == :_include
|
57
|
+
result.include_modules(value)
|
58
|
+
else
|
59
|
+
result.store(key.to_sym, value.is_a?(Hash) ? deep_hashrize(value) : value)
|
60
|
+
end
|
61
61
|
result
|
62
62
|
end
|
63
63
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Hash
|
2
|
+
def slice(*keep_keys)
|
3
|
+
h = {}
|
4
|
+
keep_keys.each { |key| h[key] = fetch(key) }
|
5
|
+
h
|
6
|
+
end unless Hash.method_defined?(:slice)
|
7
|
+
|
8
|
+
def except(*less_keys)
|
9
|
+
slice(*keys - less_keys)
|
10
|
+
end unless Hash.method_defined?(:except)
|
11
|
+
|
12
|
+
def deep_symbolize_keys
|
13
|
+
inject({}) { |result, (key, value)|
|
14
|
+
value = value.deep_symbolize_keys if value.is_a?(Hash)
|
15
|
+
result[(key.to_sym rescue key) || key] = value
|
16
|
+
result
|
17
|
+
}
|
18
|
+
end unless Hash.method_defined?(:deep_symbolize_keys)
|
19
|
+
|
20
|
+
# deep_merge_hash! by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
|
21
|
+
MERGER = proc do |key, v1, v2|
|
22
|
+
Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2
|
23
|
+
end
|
24
|
+
|
25
|
+
def deep_merge(other)
|
26
|
+
merge(other, &MERGER)
|
27
|
+
end unless Hash.method_defined?(:deep_merge)
|
28
|
+
end
|
data/lib/hashr/version.rb
CHANGED
data/test/hashr_test.rb
CHANGED
@@ -41,6 +41,24 @@ class HashrTest < Test::Unit::TestCase
|
|
41
41
|
assert_equal false, Hashr.new({ :foo => { :bar => 'bar' } }).foo.baz?
|
42
42
|
end
|
43
43
|
|
44
|
+
test 'mixing symbol and string keys in defaults and data' do
|
45
|
+
Symbolized = Class.new(Hashr) { define :foo => 'foo' }
|
46
|
+
Stringified = Class.new(Hashr) { define 'foo' => 'foo' }
|
47
|
+
NoDefault = Class.new(Hashr)
|
48
|
+
|
49
|
+
assert_equal 'foo', Symbolized.new.foo
|
50
|
+
assert_equal 'foo', Stringified.new.foo
|
51
|
+
assert_nil NoDefault.new.foo
|
52
|
+
|
53
|
+
assert_equal 'foo', Symbolized.new(:foo => 'foo').foo
|
54
|
+
assert_equal 'foo', Stringified.new(:foo => 'foo').foo
|
55
|
+
assert_equal 'foo', NoDefault.new(:foo => 'foo').foo
|
56
|
+
|
57
|
+
assert_equal 'foo', Symbolized.new('foo' => 'foo').foo
|
58
|
+
assert_equal 'foo', Stringified.new('foo' => 'foo').foo
|
59
|
+
assert_equal 'foo', NoDefault.new('foo' => 'foo').foo
|
60
|
+
end
|
61
|
+
|
44
62
|
test 'method assignment works' do
|
45
63
|
hashr = Hashr.new
|
46
64
|
hashr.foo = 'foo'
|
@@ -94,6 +112,14 @@ class HashrTest < Test::Unit::TestCase
|
|
94
112
|
end
|
95
113
|
|
96
114
|
test 'a key :_include includes the given modules' do
|
115
|
+
klass = Class.new(Hashr) do
|
116
|
+
define :foo => { :_include => Module.new { def helper; 'helper'; end } }
|
117
|
+
end
|
118
|
+
hashr = klass.new(:foo => { 'helper' => 'foo' })
|
119
|
+
assert_equal 'helper', klass.new(:foo => { 'helper' => 'foo' }).foo.helper
|
120
|
+
end
|
121
|
+
|
122
|
+
test 'a key :_include includes the given modules (using defaults)' do
|
97
123
|
klass = Class.new(Hashr) do
|
98
124
|
define :foo => { :_include => Module.new { def helper; 'helper'; end } }
|
99
125
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hashr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sven Fuchs
|
@@ -57,6 +57,7 @@ extensions: []
|
|
57
57
|
extra_rdoc_files: []
|
58
58
|
|
59
59
|
files:
|
60
|
+
- lib/hashr/core_ext/ruby/hash.rb
|
60
61
|
- lib/hashr/env_defaults.rb
|
61
62
|
- lib/hashr/version.rb
|
62
63
|
- lib/hashr.rb
|