hash_path 0.3.0 → 0.4.0
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/CHANGELOG.md +11 -0
- data/README.md +5 -5
- data/hash_path.gemspec +2 -0
- data/lib/hash_path/version.rb +1 -1
- data/lib/hash_path.rb +19 -19
- data/spec/hash_path_spec.rb +87 -0
- data/spec/spec_helper.rb +3 -0
- metadata +57 -45
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: efc30720d5e9dc46735cdbcdca64437b58a0e442
|
4
|
+
data.tar.gz: 5de1e070a617786d9717242cb421a993afca0341
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9b99483587f78bf847bd8ac51cbb38951fecfe9ba73679e37d3bc39341657904d63e0432daf3f1d6481695e0eb91f0658768232cb71e45e7f993401506efecde
|
7
|
+
data.tar.gz: 997d8a91955d890b3657c405c404fd3c60781f1fc886ed3c0e3bfcea343a55be0eca19bca7ae5ea9a4e403279867f1216df8c8326bae176a69cac2c93c7dafc4
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
Provides a simple interface to access hash paths.
|
4
4
|
|
5
|
-
The gem was written to help with specs so use in production code will have an
|
6
|
-
|
5
|
+
The gem was written to help with specs, so use in production code will have an
|
6
|
+
unknown performance hit.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
10
10
|
Add this line to your application's Gemfile:
|
11
11
|
|
12
|
-
gem '
|
12
|
+
gem 'hash_path'
|
13
13
|
|
14
14
|
And then execute:
|
15
15
|
|
@@ -17,7 +17,7 @@ And then execute:
|
|
17
17
|
|
18
18
|
Or install it yourself as:
|
19
19
|
|
20
|
-
$ gem install
|
20
|
+
$ gem install hash_path
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
@@ -38,7 +38,7 @@ Given the hash
|
|
38
38
|
# Or the raise version
|
39
39
|
my_hash.at_path!("foo.bar.baz") #=> 'hai'
|
40
40
|
my_hash.at_path!("foo.bar.barry") #=> raises
|
41
|
-
my_hash.at_path("not_a_key")
|
41
|
+
my_hash.at_path!("not_a_key") #=> raises
|
42
42
|
|
43
43
|
|
44
44
|
## Contributing
|
data/hash_path.gemspec
CHANGED
data/lib/hash_path/version.rb
CHANGED
data/lib/hash_path.rb
CHANGED
@@ -9,35 +9,33 @@ module HashPath
|
|
9
9
|
# @example
|
10
10
|
# my_hash.at_path("foo.bar.baz") # looks in my_hash['foo']['bar']['baz']
|
11
11
|
def at_path(path)
|
12
|
-
|
13
|
-
current_value = self
|
14
|
-
|
15
|
-
path_keys.each do |key|
|
16
|
-
return nil unless current_value.respond_to?(:[])
|
17
|
-
current_value = current_value[key]
|
18
|
-
end
|
19
|
-
current_value
|
12
|
+
at_path!(path) rescue nil
|
20
13
|
end
|
21
14
|
|
22
15
|
# Same as at_path but raises when a path is not found
|
23
16
|
# The raise will give a delimited path of where the path went dead
|
24
17
|
# @example
|
25
|
-
# f = { 'foo' => {'bar' => {'baz' => 'hai'}, "baz" => [1,2] }
|
18
|
+
# f = { 'foo' => {'bar' => {'baz' => 'hai'} }, "baz" => [1,2] }
|
26
19
|
# f.at_path!('foo.not.baz') # Raises, message == 'foo.not'
|
27
20
|
# f.at_path!('not.here.yo') # Raises, message == 'not'
|
28
21
|
# f.at_path!('foo.bar.not') # Raises, message == 'foo.bar.not'
|
29
22
|
# f.at_path!("baz.1") # => 2
|
30
23
|
# @see HashPath#at_path
|
31
24
|
def at_path!(path)
|
32
|
-
|
33
|
-
the_keys, current_value = [], self
|
25
|
+
the_keys = []
|
34
26
|
|
35
|
-
|
36
|
-
raise(PathNotFound, the_keys.join(DELIMITER)) unless current_value.respond_to?(:[])
|
27
|
+
normalize_path(path).reduce(self) do |memo, key|
|
37
28
|
the_keys << key
|
38
|
-
|
29
|
+
case key
|
30
|
+
when String
|
31
|
+
memo.key?(key) ? memo.fetch(key) : memo.fetch(key.to_sym)
|
32
|
+
else
|
33
|
+
memo.fetch(key)
|
34
|
+
end
|
39
35
|
end
|
40
|
-
|
36
|
+
|
37
|
+
rescue => e
|
38
|
+
raise(PathNotFound, the_keys.join(DELIMITER))
|
41
39
|
end
|
42
40
|
|
43
41
|
# Provides flattened hash key paths
|
@@ -45,10 +43,11 @@ module HashPath
|
|
45
43
|
case hash_or_obj
|
46
44
|
when Hash
|
47
45
|
hash_or_obj.inject({}) do |h, (k,v)|
|
48
|
-
full_prefix = [prefix, k].compact.join(
|
46
|
+
full_prefix = [prefix, k].compact.join(DELIMITER)
|
49
47
|
result = flatten_key_paths(v, full_prefix)
|
50
|
-
|
51
|
-
|
48
|
+
case result
|
49
|
+
when Hash
|
50
|
+
h.merge!(result)
|
52
51
|
else
|
53
52
|
h[full_prefix] = result
|
54
53
|
end
|
@@ -60,13 +59,14 @@ module HashPath
|
|
60
59
|
end
|
61
60
|
|
62
61
|
private
|
62
|
+
|
63
63
|
def normalize_path(path)
|
64
64
|
case path
|
65
65
|
when Array
|
66
66
|
path
|
67
67
|
when String, Symbol
|
68
68
|
path.to_s.split(DELIMITER)
|
69
|
-
end.map{|key| key =~
|
69
|
+
end.map{|key| key =~ /\A\d+\z/ ? key.to_i : key }
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe HashPath do
|
4
|
+
describe '#at_path' do
|
5
|
+
it 'returns nil if the key is not found' do
|
6
|
+
expect({}.at_path('foo')).to eq(nil)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'returns a value if it is found' do
|
10
|
+
expect({foo: {bar: 5}}.at_path('foo.bar')).to eq(5)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#at_path!' do
|
15
|
+
it 'looks up a key given by a string' do
|
16
|
+
expect({'foo' => 5}.at_path!('foo')).to eq(5)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'finds a symbol when searching by a string' do
|
20
|
+
expect({foo: 5}.at_path!('foo')).to eq(5)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'looks up a key given by a symbol' do
|
24
|
+
expect({foo: 5}.at_path!(:foo)).to eq(5)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'looks up a symbol key given by an array' do
|
28
|
+
expect({foo: 5}.at_path!(['foo'])).to eq(5)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'looks up a string key given by an array' do
|
32
|
+
expect({'foo' => 5}.at_path!(['foo'])).to eq(5)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'looks up an object key' do
|
36
|
+
expect({73 => 5}.at_path!([73])).to eq(5)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'looks up a second level value' do
|
40
|
+
expect({foo: {bar: 5}}.at_path!(['foo', :bar])).to eq(5)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'raises a nice error when top-level key not found' do
|
44
|
+
expect {
|
45
|
+
{}.at_path!(['foo', 'bar'])
|
46
|
+
}.to raise_error(HashPath::PathNotFound, 'foo')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'raises a nice error when second-level key not found' do
|
50
|
+
expect {
|
51
|
+
{foo: {}}.at_path!(['foo', 'bar'])
|
52
|
+
}.to raise_error(HashPath::PathNotFound, 'foo.bar')
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'a few more cases' do
|
56
|
+
let(:hash) { { 'foo' => {'bar' => {'baz' => 'hai'} }, "baz" => [11,22] } }
|
57
|
+
|
58
|
+
it 'throws an exception with middle key missing' do
|
59
|
+
expect { hash.at_path!('foo.not.baz') }.to raise_error(HashPath::PathNotFound, 'foo.not')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'throws an exception with first key missing' do
|
63
|
+
expect { hash.at_path!('not.here.yo') }.to raise_error(HashPath::PathNotFound, 'not')
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'throws an exception with third key missing' do
|
67
|
+
expect { hash.at_path!('foo.bar.not') }.to raise_error(HashPath::PathNotFound, 'foo.bar.not')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'can traverse an array with a zero-based integer' do
|
71
|
+
expect(hash.at_path!('baz.1')).to eq(22)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#flatten_key_paths' do
|
77
|
+
it 'un-nests hashes' do
|
78
|
+
expect({a: 5, b: {c: 7}}.flatten_key_paths).to eq({'a' => 5, 'b.c' => 7})
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'HashPath::VERSION' do
|
83
|
+
it 'is set' do
|
84
|
+
expect(HashPath::VERSION).not_to eq(nil)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,34 +1,52 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: hash_path
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 0
|
10
|
-
version: 0.3.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Daniel Neighman
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
date: 2014-12-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
21
41
|
description: Easy path navigation for hashes
|
22
|
-
email:
|
42
|
+
email:
|
23
43
|
- dneighman@squareup.com
|
24
44
|
executables: []
|
25
|
-
|
26
45
|
extensions: []
|
27
|
-
|
28
46
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
|
31
|
-
- .
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- CHANGELOG.md
|
32
50
|
- Gemfile
|
33
51
|
- LICENSE
|
34
52
|
- README.md
|
@@ -36,38 +54,32 @@ files:
|
|
36
54
|
- hash_path.gemspec
|
37
55
|
- lib/hash_path.rb
|
38
56
|
- lib/hash_path/version.rb
|
39
|
-
|
57
|
+
- spec/hash_path_spec.rb
|
58
|
+
- spec/spec_helper.rb
|
59
|
+
homepage: ''
|
40
60
|
licenses: []
|
41
|
-
|
61
|
+
metadata: {}
|
42
62
|
post_install_message:
|
43
63
|
rdoc_options: []
|
44
|
-
|
45
|
-
require_paths:
|
64
|
+
require_paths:
|
46
65
|
- lib
|
47
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
-
|
49
|
-
requirements:
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
50
68
|
- - ">="
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
version: "0"
|
56
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
59
73
|
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
62
|
-
segments:
|
63
|
-
- 0
|
64
|
-
version: "0"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
65
76
|
requirements: []
|
66
|
-
|
67
77
|
rubyforge_project:
|
68
|
-
rubygems_version:
|
78
|
+
rubygems_version: 2.2.2
|
69
79
|
signing_key:
|
70
|
-
specification_version:
|
80
|
+
specification_version: 4
|
71
81
|
summary: Easy path navigation for hashes. Useful in specs
|
72
|
-
test_files:
|
73
|
-
|
82
|
+
test_files:
|
83
|
+
- spec/hash_path_spec.rb
|
84
|
+
- spec/spec_helper.rb
|
85
|
+
has_rdoc:
|