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 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
@@ -0,0 +1,11 @@
1
+ # Change log
2
+
3
+ ## 0.4.0
4
+ ### 2014-11-25
5
+
6
+ - Now at_path and at_path! can look up keys which are symbols, rather than strings.
7
+
8
+ ## 0.3.0
9
+ ### 2012-10-09
10
+
11
+ - Start of the change log. Adds at_path, at_path!, and flatten_key_paths methods to Hash.
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
- unkonwn performance hit.
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 'path_spec'
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 path_spec
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") #=> raises
41
+ my_hash.at_path!("not_a_key") #=> raises
42
42
 
43
43
 
44
44
  ## Contributing
data/hash_path.gemspec CHANGED
@@ -14,4 +14,6 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "hash_path"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = HashPath::VERSION
17
+ gem.add_development_dependency 'rspec', '~> 3.1'
18
+ gem.add_development_dependency 'pry'
17
19
  end
@@ -1,3 +1,3 @@
1
1
  module HashPath
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
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
- path_keys = normalize_path(path)
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
- path_keys = normalize_path(path)
33
- the_keys, current_value = [], self
25
+ the_keys = []
34
26
 
35
- path_keys.each do |key|
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
- current_value = current_value[key]
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
- current_value
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
- if Hash === result
51
- h.merge! result
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 =~ /^\d+$/ ? key.to_i : 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
@@ -0,0 +1,3 @@
1
+ RSpec.configure(&:disable_monkey_patching!)
2
+
3
+ require 'hash_path'
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
- hash: 19
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
- date: 2012-10-10 00:00:00 Z
19
- dependencies: []
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
- files:
31
- - .gitignore
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
- homepage: ""
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
- none: false
49
- requirements:
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
50
68
  - - ">="
51
- - !ruby/object:Gem::Version
52
- hash: 3
53
- segments:
54
- - 0
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
- hash: 3
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: 1.8.24
78
+ rubygems_version: 2.2.2
69
79
  signing_key:
70
- specification_version: 3
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: