lab42_nhash 0.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +61 -0
- data/LICENSE +21 -0
- data/README.md +36 -0
- data/demo/000-basic-examples.md +45 -0
- data/demo/010-indifferent-access.md +48 -0
- data/demo/020-afixes.md +108 -0
- data/demo/030-lookup-chains.md +137 -0
- data/demo/060-fallback.md +89 -0
- data/demo/080-interpolation.md +37 -0
- data/demo/applique/require_ae.rb +1 -0
- data/demo/applique/require_nhash.rb +3 -0
- data/lab42_nhash.gemspec +38 -0
- data/lib/lab42/nhash/affixes.rb +48 -0
- data/lib/lab42/nhash/auto_import.rb +3 -0
- data/lib/lab42/nhash/exceptions.rb +5 -0
- data/lib/lab42/nhash/fallbacks.rb +70 -0
- data/lib/lab42/nhash/interpolation.rb +21 -0
- data/lib/lab42/nhash/invocation.rb +16 -0
- data/lib/lab42/nhash/lookup_chains.rb +50 -0
- data/lib/lab42/nhash/version.rb +5 -0
- data/lib/lab42/nhash.rb +76 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/unit/afixes/affix_spec.rb +17 -0
- data/spec/unit/afixes/prefix_spec.rb +22 -0
- data/spec/unit/afixes/suffix_spec.rb +23 -0
- data/spec/unit/fallback/fallback_spec.rb +91 -0
- metadata +199 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 02be76a89cdf9ca8717dff56712bff2479224757
|
4
|
+
data.tar.gz: 419240c05de38a8552b5573ac2152b40714fd76c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b1937b9751c90dd02b23bd092c345d0b2f8844876c16476900487512b9603c5e121b7aed6113070487ac3b948e9cb29c7b8e8053f1f04b213689d5447984ea50
|
7
|
+
data.tar.gz: 188a2fba1f7034068c8d73b4e6847942b05c46bc2b1c56658631f149ffdb7ceef3c392f914cde35264ced0d78f1c5777abe87b39881a6f5718e82a44279df047
|
data/.gitignore
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/lib/bundler/man/
|
26
|
+
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
29
|
+
# Gemfile.lock
|
30
|
+
# .ruby-version
|
31
|
+
# .ruby-gemset
|
32
|
+
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
+
.rvmrc
|
35
|
+
.tmux
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
lab42_nhash (0.1.0.pre)
|
5
|
+
forwarder2 (~> 0.2)
|
6
|
+
ruby_parser (~> 3.6)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
ae (1.8.2)
|
12
|
+
ansi
|
13
|
+
ansi (1.4.3)
|
14
|
+
brass (1.2.1)
|
15
|
+
coderay (1.1.0)
|
16
|
+
columnize (0.8.9)
|
17
|
+
debugger (1.6.6)
|
18
|
+
columnize (>= 0.3.1)
|
19
|
+
debugger-linecache (~> 1.2.0)
|
20
|
+
debugger-ruby_core_source (~> 1.3.2)
|
21
|
+
debugger-linecache (1.2.0)
|
22
|
+
debugger-ruby_core_source (1.3.4)
|
23
|
+
diff-lcs (1.2.5)
|
24
|
+
facets (2.9.3)
|
25
|
+
forwarder2 (0.2.0)
|
26
|
+
method_source (0.8.2)
|
27
|
+
pry (0.9.12.6)
|
28
|
+
coderay (~> 1.0)
|
29
|
+
method_source (~> 0.8)
|
30
|
+
slop (~> 3.4)
|
31
|
+
pry-debugger (0.2.2)
|
32
|
+
debugger (~> 1.3)
|
33
|
+
pry (~> 0.9.10)
|
34
|
+
qed (2.9.1)
|
35
|
+
ansi
|
36
|
+
brass
|
37
|
+
facets (>= 2.8)
|
38
|
+
rspec (2.14.1)
|
39
|
+
rspec-core (~> 2.14.0)
|
40
|
+
rspec-expectations (~> 2.14.0)
|
41
|
+
rspec-mocks (~> 2.14.0)
|
42
|
+
rspec-core (2.14.8)
|
43
|
+
rspec-expectations (2.14.5)
|
44
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
45
|
+
rspec-mocks (2.14.6)
|
46
|
+
ruby_parser (3.6.0)
|
47
|
+
sexp_processor (~> 4.1)
|
48
|
+
sexp_processor (4.4.3)
|
49
|
+
slop (3.5.0)
|
50
|
+
|
51
|
+
PLATFORMS
|
52
|
+
ruby
|
53
|
+
|
54
|
+
DEPENDENCIES
|
55
|
+
ae (~> 1.8)
|
56
|
+
bundler (~> 1.6)
|
57
|
+
lab42_nhash!
|
58
|
+
pry (~> 0.9)
|
59
|
+
pry-debugger (~> 0.2)
|
60
|
+
qed (~> 2.9)
|
61
|
+
rspec (~> 2.14)
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Robert Dober
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# lab42_nested_hash
|
2
|
+
|
3
|
+
A nested hash view with dotted deep access à la I18n.t of Rails and with optional string interpolation. Typically YML loaded Hashes are used.
|
4
|
+
|
5
|
+
|
6
|
+
## Get Access (combined keys with dot notation)
|
7
|
+
|
8
|
+
Please see the [QED](http://rubyworks.github.io/qed/) demos [here](https://github.com/RobertDober/lab42_nested_hash/blob/master/demo/000-basic-examples.md) for detailed explainations and specifications:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
h = { "a" => 1,
|
12
|
+
"b" => { "c" => 2, "d" => true } }
|
13
|
+
|
14
|
+
nh = NHash.new h
|
15
|
+
|
16
|
+
```
|
17
|
+
|
18
|
+
Then `get` lets us access elements
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
nh.get('a').assert == 1
|
22
|
+
nh.get('b.c').assert == 2
|
23
|
+
```
|
24
|
+
|
25
|
+
or _subhashes_:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
nh.get('b').assert.kind_of? NHash
|
29
|
+
```
|
30
|
+
|
31
|
+
|
32
|
+
### Indifferent Access
|
33
|
+
|
34
|
+
### Prefix and Suffix Stacks
|
35
|
+
|
36
|
+
## Fallbacks
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
# Lab42::NHash QED
|
3
|
+
|
4
|
+
## Basic Example Dotted Access
|
5
|
+
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
h = { "a" => 1,
|
9
|
+
"b" => { "c" => 2, "d" => true } }
|
10
|
+
|
11
|
+
nh = NHash.new h
|
12
|
+
|
13
|
+
```
|
14
|
+
|
15
|
+
Then `get` lets us access elements
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
nh.get('a').assert == 1
|
19
|
+
nh.get('b.c').assert == 2
|
20
|
+
```
|
21
|
+
|
22
|
+
or _subhashes_:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
nh.get('b').assert.kind_of? NHash
|
26
|
+
```
|
27
|
+
|
28
|
+
## Non existing keys
|
29
|
+
|
30
|
+
`get` raises a KeyError if there is no such key
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
KeyError.assert.raised? do
|
34
|
+
nh.get 'c'
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
but like `Hash#fetch` a default value or block can remedy at that
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
nh.get( 'c', :default ).assert == :default
|
42
|
+
nh.get( 'c' ){ |key| key + key }.assert == 'cc'
|
43
|
+
```
|
44
|
+
|
45
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
# Lab42::NHash QED
|
3
|
+
|
4
|
+
## Indifferent Access
|
5
|
+
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
h = { "a" => 1,
|
9
|
+
b: { "c" => 2, d: true } }
|
10
|
+
|
11
|
+
nh = NHash.new h
|
12
|
+
|
13
|
+
```
|
14
|
+
|
15
|
+
is not available by default
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
KeyError.assert.raised? do
|
19
|
+
nh.get 'b.c'
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
but it can be enabled
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
nia = nh.with_indifferent_access
|
27
|
+
nia.get( 'b.c' ).assert == 2
|
28
|
+
```
|
29
|
+
|
30
|
+
without affecting the original object
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
KeyError.assert.raised? do
|
34
|
+
nh.get 'b.c'
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
and of course KeyErrors are still raised in case
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
KeyError.assert.raised? do
|
42
|
+
nia.get 'a.b'
|
43
|
+
end
|
44
|
+
KeyError.assert.raised? do
|
45
|
+
nh.get 'a.b'
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
data/demo/020-afixes.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
|
2
|
+
# Lab42::NHash QED
|
3
|
+
|
4
|
+
## Afixed Access
|
5
|
+
|
6
|
+
|
7
|
+
### Prefixes
|
8
|
+
|
9
|
+
YAML documents are typically quite nested and often
|
10
|
+
a common prefix (and less often a common suffix) is
|
11
|
+
used in a given context.
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
h = { "a" => {
|
15
|
+
"b" =>
|
16
|
+
{ "c" => 'abc',
|
17
|
+
"d" => 'abd' } },
|
18
|
+
"x" => {
|
19
|
+
"b" =>
|
20
|
+
{ "c" => 'xbc' } } }
|
21
|
+
|
22
|
+
nh = NHash.new h
|
23
|
+
nh.push_prefix 'a'
|
24
|
+
|
25
|
+
```
|
26
|
+
|
27
|
+
Now `get` keys that start with a '.' are prefixed with a, let us demonstrate:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
nh.get( '.b.c' ).assert == 'abc'
|
31
|
+
```
|
32
|
+
|
33
|
+
but not using the '.' as a prefix I can still access with an _absolute_ key path.
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
nh.get( 'a.b.c').assert == 'abc'
|
37
|
+
```
|
38
|
+
|
39
|
+
### Suffixes and Combination of both
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
nh.push_suffix 'c'
|
43
|
+
nh.get( 'a.b.' ).assert == 'abc'
|
44
|
+
nh.get( 'x.b.' ).assert == 'xbc'
|
45
|
+
|
46
|
+
nh.get( '.b.' ).assert == 'abc'
|
47
|
+
nh.get( 'x.b.' ).assert == 'xbc'
|
48
|
+
```
|
49
|
+
|
50
|
+
|
51
|
+
### The Stack
|
52
|
+
|
53
|
+
As the name suggests we can push and pop suffices and prefices
|
54
|
+
This is convenient as often the suffix/Prefix correspond to
|
55
|
+
a given context in the program.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
nh.push_prefix 'a.b'
|
59
|
+
nh.get('.d').assert == 'abd'
|
60
|
+
2.times{ nh.pop_prefix }
|
61
|
+
KeyError.assert.raised? do
|
62
|
+
nh.get('.d').assert == 'abd'
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
### Temporary Stack Modifiaction with the With Pattern
|
67
|
+
|
68
|
+
An often more convenient way to push values to the stacks is the `with` pattern that will
|
69
|
+
ensure that the stack is popped again at the end of the provided block.
|
70
|
+
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
nh.with_prefix 'a' do |x|
|
74
|
+
# self is passed into the block for convenience
|
75
|
+
x.assert == nh
|
76
|
+
|
77
|
+
# fetch is an alias to get
|
78
|
+
x.fetch( '.b.c' ).assert == 'abc'
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Outside the block the stack will have been restored
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
KeyError.assert.raised? do
|
86
|
+
nh.fetch '.b.c'
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
Works with suffix too
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
nh.with_suffix 'd' do
|
94
|
+
nh.get('a.b.').assert == 'abd'
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
And as it would be combersome to nest a `with_prefix` and a `with_suffix` there is a convenience method
|
99
|
+
`with_afixes` at your disposal:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
nh.with_affixes 'a', 'c' do
|
103
|
+
nh.get('.b.').assert == 'abc'
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
|
108
|
+
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# Lab42::NHash QED
|
2
|
+
|
3
|
+
## Lookup Chains
|
4
|
+
|
5
|
+
These are convenience methods using the more general, but also much more comlicated
|
6
|
+
fallback mechanism that is demonstrated [here](https://github.com/RobertDober/lab42_nested_hash/blob/master/demo/060-fallback.md)
|
7
|
+
|
8
|
+
### Prefix Chains
|
9
|
+
|
10
|
+
This defines a mechanism that will use different prefixes until a prefixed key is found.
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
nh = NHash.new(
|
14
|
+
en: { '1' => 'one', '2' => 'two', '3' => 'three' },
|
15
|
+
fr: { '2' => 'deux', '3' => 'trois' },
|
16
|
+
it: { '3' => 'tre' })
|
17
|
+
.with_indifferent_access
|
18
|
+
```
|
19
|
+
|
20
|
+
Now we can simply define a prefix lookup chain as follows:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
nh.push_prefix_lookup :it, :fr, :en
|
24
|
+
nh.with_prefix :de do
|
25
|
+
get( '.1' ).assert == 'one'
|
26
|
+
get( '.2' ).assert == 'deux'
|
27
|
+
get( '.3' ).assert == 'tre'
|
28
|
+
KeyError.assert.raised? do
|
29
|
+
get( '.4' )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
### Suffix Chains
|
35
|
+
|
36
|
+
are not different of course.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
nh = NHash.new(
|
40
|
+
en: {
|
41
|
+
dog: { one: 'dog', many: 'dogs' },
|
42
|
+
cat: { one: 'cat', many: 'cats' },
|
43
|
+
sheep: { one: 'sheep' }
|
44
|
+
},
|
45
|
+
fr: {
|
46
|
+
dog: { one: 'chien', many: 'chiens' },
|
47
|
+
cat: { one: 'chat' }, # for demonstration purpose we ommit "chats"
|
48
|
+
money: { one: 'argent' }
|
49
|
+
} ).with_indifferent_access
|
50
|
+
```
|
51
|
+
|
52
|
+
Now we define the suffix chain
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
nh.push_suffix_lookup :many, :one
|
56
|
+
```
|
57
|
+
|
58
|
+
proof that this works
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
nh.with_prefix :fr do
|
62
|
+
with_suffix :many do
|
63
|
+
get( '.money.').assert == 'argent'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
However the suffix chain masks the prefix chain, thus we will not find any bovines here:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
nh.with_prefix :fr do
|
72
|
+
with_suffix :many do
|
73
|
+
KeyError.assert.raised? do
|
74
|
+
get( '.sheep.' )
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
|
81
|
+
### Combining Chains
|
82
|
+
|
83
|
+
In order to make both work together we need to implement a backtracking mechanism (or a
|
84
|
+
carthesian product fallback definition). This is done via the `push_affix_lookup` method
|
85
|
+
|
86
|
+
First we reset both lookup chains, for the time being there is only one method that accomplishes
|
87
|
+
this:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
nh.clear_fallbacks!
|
91
|
+
nh.push_affix_lookup prefixes: %w{fr en}, suffixes: %w{many one}
|
92
|
+
```
|
93
|
+
|
94
|
+
Now our sleep endorsing animals are found again:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
nh.with_prefix :fr do
|
98
|
+
with_suffix :many do
|
99
|
+
get( '.sheep.' ).assert == 'sheep'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
This searches for an entry by varying the prefixes first, if you want to vary over the suffixes first
|
105
|
+
the named parameter `suffixes_first` can be set to true. Let us prove the difference by giving yet
|
106
|
+
another demo.
|
107
|
+
|
108
|
+
First we do not set `suffixes_first` and
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
nh.with_prefix :fr do
|
112
|
+
with_suffix :many do
|
113
|
+
get( '.cat.' ).assert == 'chat'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
`'chat'` is found (sorry for the grammatical error).
|
119
|
+
|
120
|
+
Now if we inverse the lookup order
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
nh.clear_fallbacks!
|
124
|
+
nh.push_affix_lookup prefixes: %w{fr en}, suffixes: %w{many one}, suffixes_first: true
|
125
|
+
```
|
126
|
+
|
127
|
+
and try again, we will get
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
nh.with_prefix :fr do
|
131
|
+
with_suffix :many do
|
132
|
+
get( '.cat.' ).assert == 'cats'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
|
2
|
+
# Lab42::NHash QED
|
3
|
+
|
4
|
+
## Fallbacks
|
5
|
+
|
6
|
+
Fallbacks are registred procedures, on a stack, that are executed in LIFO order.
|
7
|
+
They are triggered whenever a `get/fetch` invocation would trigger a `KeyError`.
|
8
|
+
|
9
|
+
The special `again` method is available inside the fallback procedure (and inside *only*)
|
10
|
+
to reexecute the `get/fetch` invocation that triggered the callback (it might trigger the next fallback
|
11
|
+
if applicable)
|
12
|
+
|
13
|
+
A simple example would be to define a fallback that searches with a different affix.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
numbers = NHash.new(
|
17
|
+
en: { '1' => 'one', '2' => 'two', '3' => 'three' },
|
18
|
+
fr: { '1' => 'un', '2' => 'deux' },
|
19
|
+
it: { '1' => 'uno' } )
|
20
|
+
.with_indifferent_access
|
21
|
+
```
|
22
|
+
|
23
|
+
It stands to reason that looking for an italian '2' will get us a `KeyError` raised.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
KeyError.assert.raised? do
|
27
|
+
numbers.with_prefix :it do
|
28
|
+
get '.2'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
We will use _fallbacks_ to implement a lookup strategy. By using `push_fallback`
|
34
|
+
we will have to define them in the reverse execution order, we could also use `unshift_fallback`
|
35
|
+
if that suits your style better.
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# use English as last resort...
|
39
|
+
numbers.push_fallback do |n|
|
40
|
+
n.with_prefix :en do
|
41
|
+
again
|
42
|
+
end
|
43
|
+
end
|
44
|
+
# But try French first
|
45
|
+
numbers.push_fallback do
|
46
|
+
with_prefix( :fr ){ again }
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Please note the two possible styles, a block with arity one ( or negative arity ) will be called
|
51
|
+
with the `NHash` instance as a parameter, all other blocks will be instance_execed with the same
|
52
|
+
instance as receiver.
|
53
|
+
|
54
|
+
These fallbacks will cause the following assertions to hold
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
numbers.get( '.1' ).assert == 'un'
|
58
|
+
numbers.with_prefix :it do
|
59
|
+
get( '.1' ).assert == 'uno'
|
60
|
+
get( '.2' ).assert == 'deux'
|
61
|
+
get( '.3' ).assert == 'three'
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
### With Pattern
|
66
|
+
|
67
|
+
Now if we can limit the validity of a defined fallback stack to a certain scope, we can use
|
68
|
+
`with_fallbacks` so that we do not need to call `clear_fallbacks!` explicitely.
|
69
|
+
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
numbers.clear_fallbacks!
|
73
|
+
KeyError.assert.raised? do
|
74
|
+
numbers.get('.1')
|
75
|
+
end
|
76
|
+
|
77
|
+
numbers.with_fallback do
|
78
|
+
push_fallback do
|
79
|
+
with_prefix( :fr ){ again }
|
80
|
+
end
|
81
|
+
with_prefix :it do
|
82
|
+
get( '.2' ).assert == 'deux'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
KeyError.assert.raised? do
|
86
|
+
numbers.get('.1')
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Lab42::NHash QED
|
2
|
+
|
3
|
+
## Interpolation
|
4
|
+
|
5
|
+
In order to be able to use string interpolation we can use the alternative
|
6
|
+
`get!/fetch!` methods which will expand [ERB](http://www.ruby-doc.org/stdlib-2.1.1/libdoc/erb/rdoc/ERB.html) templates inside
|
7
|
+
string values.
|
8
|
+
|
9
|
+
|
10
|
+
Here is a short demonstration of that feature:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
nh = NHash.new(
|
14
|
+
sum: '<%= get("a")+get("b") %>',
|
15
|
+
a: 41,
|
16
|
+
b: 1,
|
17
|
+
result: 'the sum is <%= get! :sum %>'
|
18
|
+
)
|
19
|
+
.with_indifferent_access
|
20
|
+
```
|
21
|
+
|
22
|
+
`get/fetch` do not do anything
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
nh.get(:result).assert == 'the sum is <%= get! :sum %>'
|
26
|
+
```
|
27
|
+
|
28
|
+
However `get!/fetch!` are made from a completely different kind.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
nh.get!(:sum).assert == '42'
|
32
|
+
nh.fetch!(:result).assert == 'the sum is 42'
|
33
|
+
```
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'ae'
|
data/lab42_nhash.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
base = File.dirname __FILE__
|
3
|
+
$:.unshift File.join( base, 'lib' )
|
4
|
+
|
5
|
+
require 'lab42/nhash/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do | spec |
|
8
|
+
spec.name = 'lab42_nhash'
|
9
|
+
spec.version = Lab42::NHash::VERSION
|
10
|
+
spec.authors = ['Robert Dober']
|
11
|
+
spec.email = %w{ robert.dober@gmail.com }
|
12
|
+
spec.description = %{A Nested Hash with dotted access à la I18n in Rails}
|
13
|
+
spec.summary = %{A nested hash view with dotted deep access à la I18n.t of Rails and with optional string interpolation.
|
14
|
+
Typically YML loaded Hashes are used.}
|
15
|
+
spec.homepage = %{https://github.com/RobertDober/lab42_nested_hash}
|
16
|
+
spec.license = 'MIT'
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.test_files = spec.files.grep(%r{\Atest|\Aspec|\Afeatures|\Ademo/})
|
20
|
+
spec.require_paths = %w{lib}
|
21
|
+
|
22
|
+
# spec.post_install_message = %q{ }
|
23
|
+
|
24
|
+
|
25
|
+
spec.required_ruby_version = '>= 2.0.0'
|
26
|
+
spec.required_rubygems_version = '>= 2.2.2'
|
27
|
+
|
28
|
+
spec.add_dependency 'forwarder2', '~> 0.2'
|
29
|
+
spec.add_dependency 'ruby_parser', '~> 3.6'
|
30
|
+
|
31
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
32
|
+
spec.add_development_dependency 'rspec', '~> 2.14'
|
33
|
+
spec.add_development_dependency 'pry', '~> 0.9'
|
34
|
+
spec.add_development_dependency 'pry-debugger', '~> 0.2'
|
35
|
+
spec.add_development_dependency 'ae', '~> 1.8'
|
36
|
+
spec.add_development_dependency 'qed', '~> 2.9'
|
37
|
+
|
38
|
+
end
|