lab42_nhash 0.1.0.pre
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.
- 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
|