hash-walker 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e9e3ee3459b9576580bacf2afe1ae761ff8fa5c1
4
+ data.tar.gz: fe55a7f74e7afcc372a55356c098c4909e9604f0
5
+ SHA512:
6
+ metadata.gz: 488f8cab2d0f644d98319895092139ff07fb6bb8dc8fb65b81b17373d794a10a408ebd7e5219edf313355e3016daa495ec18a6414b9c1600360784d83c752460
7
+ data.tar.gz: 456a4df0c4c0a6b1e1e333ef043a8f0e1c9106761caafb54b892ba6e5a50a0ee8bbaf8e83e933505da466e703aaaebc5253c6bb23ffd9bbd4378120fc57c53bf
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1 @@
1
+ hash-walker
@@ -0,0 +1 @@
1
+ ruby-2.1.1
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hash_walker.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Gal Steinitz
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,137 @@
1
+ # HashWalker
2
+
3
+ Walk a hash like a hash walker would.
4
+
5
+ A ruby DSL for walking through hashes. Its the reverse of XmlBuilder or jbuilder. Works with symbol or string keys.
6
+
7
+ [![Build Status](https://secure.travis-ci.org/al-jazeera-america/hash-walker.png?branch=master)](http://travis-ci.org/al-jazeera-america/hash-walker) [![Code Climate](https://codeclimate.com/github/galori/hash-walker.png)](https://codeclimate.com/al-jazeera-america/hash-walker`)
8
+
9
+ ## Usage
10
+
11
+ given this hash:
12
+
13
+ ```ruby
14
+ hash = {
15
+ :host => 'ruby-lang.org',
16
+ :protocol => 'http://',
17
+ :headers => {:user_agent => 'safari'},
18
+ :cache => {'strategy' => {'type' => 'lazy'}}
19
+ }
20
+ ```
21
+
22
+ you would traverse it with the following ruby DSL:
23
+
24
+ ```ruby
25
+ HashWalker.walk(hash) do
26
+ cache do
27
+ strategy do
28
+ puts type
29
+ end
30
+ end
31
+ end
32
+ ```
33
+
34
+ ### Arrays
35
+
36
+ given this hash:
37
+
38
+ ```ruby
39
+ hash = { stories: [
40
+ {:title => 'a', :url => 'http://some-url/a'},
41
+ {:title => 'b', :url => 'http://some-url/b'},
42
+ {:title => 'c', :url => 'http://some-url/c'}
43
+ ]}
44
+ ```
45
+
46
+ you would traverse it with the following ruby DSL:
47
+
48
+ ```ruby
49
+ HashWalker.walk(hash) do
50
+ stories do
51
+ puts title
52
+ puts url
53
+ end
54
+ end
55
+ ```
56
+
57
+ ### Non existant keys
58
+
59
+ Non existant keys are skipped gracefully
60
+
61
+ ```ruby
62
+ hash = { :set1 => { :a => 1, :b => 1 }}
63
+ ```
64
+
65
+ you would traverse it with the following ruby DSL:
66
+
67
+ ```ruby
68
+ HashWalker.walk(hash) do
69
+ set1 do
70
+ puts a
71
+ end
72
+
73
+ set2 do
74
+ puts a
75
+ end
76
+ end
77
+ ```
78
+
79
+ you would get this output:
80
+
81
+ ```ruby
82
+ 1
83
+ ```
84
+
85
+
86
+ ## Contributing
87
+
88
+ Clone and send a pull request, preferably with a test.
89
+ Run the tests using `rake`
90
+
91
+ * TODO: map vs. join? at least test it
92
+ * TODO: ability to reach out to parent (parent. something?)
93
+ * TODO: ability to reach out to siblings?
94
+ * TODO: Top level arrays/ (are they valid JSON and valid HAshes?)
95
+ * TODO: accept JSON or HASH or HTTParty response
96
+ * TODO: HTTParty adapter. httparty_response.walk()
97
+ * TODO: Adapter for other libaries? VCR? Mechanize? REGEXP? Nokogiri?
98
+ * TODO: return a value from the entire outer bloc
99
+ * TODO: test more stuff at the top level / outer block level.
100
+ * TODO: top level array? (then its not a hash)
101
+ * TODO: support for objects and enumerables along with Hash's and Arrays
102
+ * TODO: access to key names
103
+ * TODO: generate the DSL based on an existing hash (like a VCR cassette?)
104
+ * TODO: don't look for Hash's and Array's, look for objects that act like Hash's and act like Arrays. (objects and enumarbles?)
105
+ * TODO: Create an operator? (possibly using superators?) For example, a tilde unary operator is possible:
106
+
107
+ so instead of
108
+
109
+ ```ruby
110
+ HashWalker::Walk(my_hash) do
111
+ stories do
112
+ puts title
113
+ end
114
+ end
115
+ ```
116
+
117
+ we could do
118
+
119
+ ```ruby
120
+ ~my_hash do
121
+ stories do
122
+ puts title
123
+ end
124
+ end
125
+ ```
126
+
127
+ or
128
+
129
+ we could do
130
+
131
+ ```ruby
132
+ my_hash ~~~ do
133
+ stories do
134
+ puts title
135
+ end
136
+ end
137
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hash_walker/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hash-walker"
8
+ spec.version = HashWalker::VERSION
9
+ spec.authors = ["Gal Steinitz"]
10
+ spec.email = ["gal@steinitz.com"]
11
+ spec.summary = %q{Walk a hash like a hash walker would}
12
+ spec.description = %q{a Ruby DSL for walking through a Hash and processing it}
13
+ spec.homepage = "https://github.com/al-jazeera-america/hash-walker"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_runtime_dependency 'activesupport'
25
+ end
@@ -0,0 +1,15 @@
1
+ require "hash_walker/version"
2
+ require "hash_walker/walker"
3
+ require "hash_walker/walk"
4
+ require "hash_walker/stepper"
5
+ require "hash_walker/stepper_base"
6
+ require "hash_walker/stepper/hash"
7
+ require "hash_walker/stepper/array"
8
+
9
+ require "active_support/core_ext/hash/indifferent_access"
10
+ require "active_support/core_ext/string/inflections"
11
+ require "active_support/core_ext/object/try"
12
+
13
+ module HashWalker
14
+
15
+ end
@@ -0,0 +1,3 @@
1
+ class Stepper
2
+
3
+ end
@@ -0,0 +1,10 @@
1
+ class Stepper::Array < Stepper::Base
2
+
3
+ def step!
4
+ @hash_fragment.map do |entry|
5
+ walker = HashWalker::Walker.new(:hash => entry, :block => @block)
6
+ walker.walk!
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,3 @@
1
+ class Stepper::Hash < Stepper::Base
2
+
3
+ end
@@ -0,0 +1,14 @@
1
+ class Stepper::Base
2
+
3
+ attr_accessor :hash_fragment, :block
4
+
5
+ def step!
6
+ if @block
7
+ walker = HashWalker::Walker.new(:hash => @hash_fragment, :block => @block)
8
+ walker.walk!
9
+ else
10
+ @hash_fragment
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,3 @@
1
+ module HashWalker
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,8 @@
1
+ module HashWalker
2
+
3
+ def self.walk(hash,&blocky)
4
+ walker = HashWalker::Walker.new(:hash => hash, :block => blocky)
5
+ walker.walk!
6
+ end
7
+
8
+ end
@@ -0,0 +1,41 @@
1
+ module HashWalker
2
+ class Walker
3
+
4
+ def initialize(options)
5
+ @hash_fragment = options[:hash]
6
+ @hash_fragment = @hash_fragment.with_indifferent_access if @hash_fragment.is_a? Hash
7
+ @block = options[:block]
8
+ end
9
+
10
+ def walk!
11
+ instance_eval(&@block)
12
+ end
13
+
14
+ def value
15
+ @hash_fragment.respond_to?('keys') && @hash_fragment[@attribute_name]
16
+ end
17
+
18
+ def next_step_is_array?
19
+ (@hash_fragment.is_a?(Hash) && value.is_a?(Array))
20
+ end
21
+
22
+ def get_stepper
23
+ next_step_is_array? ? Stepper::Array : Stepper::Hash
24
+ end
25
+
26
+ def take_one_step
27
+ stepper = get_stepper.new
28
+ stepper.hash_fragment = value
29
+ stepper.block = @block
30
+ stepper.step!
31
+ end
32
+
33
+ def method_missing(*args,&block)
34
+ @attribute_name = args[0]
35
+ @block = block
36
+
37
+ take_one_step
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ describe HashWalker do
4
+ it 'should have a version number' do
5
+ HashWalker::VERSION.should_not be_nil
6
+ end
7
+
8
+ describe 'the DSL' do
9
+ let(:hash) {
10
+ hash = {
11
+ :host => 'ruby-lang.org',
12
+ :protocol => 'http://',
13
+ :headers => {:user_agent => 'safari'},
14
+ :cache => {:strategy => {:type => 'lazy'}}
15
+ }
16
+ }
17
+ it 'access to top level attributes of the hash' do
18
+ HashWalker.walk(hash) do
19
+ host.should == 'ruby-lang.org'
20
+ end
21
+ end
22
+
23
+ it 'allow walking into a key' do
24
+ expect {
25
+ HashWalker.walk(hash) do
26
+ headers do
27
+ raise 'this line was executed!'
28
+ end
29
+ end
30
+ }.to raise_error('this line was executed!')
31
+ end
32
+
33
+ it 'should allow walking into a key and then provide access to its attributes' do
34
+ HashWalker.walk(hash) do
35
+ headers do
36
+ user_agent.should == 'safari'
37
+ end
38
+ end
39
+ end
40
+
41
+ it 'should allow walking down two levels of keys' do
42
+ expect {
43
+ HashWalker.walk(hash) do
44
+ cache do
45
+ strategy do
46
+ raise "We're down two levels!"
47
+ end
48
+ end
49
+ end
50
+ }.to raise_error("We're down two levels!")
51
+ end
52
+
53
+ it 'should allow walking down two levels of keys and reading attributes' do
54
+ HashWalker.walk(hash) do
55
+ cache do
56
+ strategy do
57
+ type.should == 'lazy'
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ it 'should work with strings as keys' do
64
+ hash = {'string_key' => 'String Value'}
65
+ HashWalker.walk(hash) do
66
+ string_key.should == 'String Value'
67
+ end
68
+ end
69
+
70
+ it 'should work with strings as symbols' do
71
+ hash = {:string_key => 'String Value'}
72
+ HashWalker.walk(hash) do
73
+ string_key.should == 'String Value'
74
+ end
75
+ end
76
+
77
+ it 'should do something with a block on a value' do
78
+ hash = {:a => 'b'}
79
+ dummy = double('dummy')
80
+ dummy.should_receive(:block_was_run)
81
+ HashWalker.walk(hash) do
82
+ a do
83
+ dummy.block_was_run
84
+ end
85
+ end
86
+ end
87
+
88
+ it 'should iterate through arrays' do
89
+ hash = {:stories => [{:a => 1},{:a => 2},{:a => 3}]}
90
+ dummy = double('dummy')
91
+ dummy.should_receive(:set_a_value).with(1).ordered
92
+ dummy.should_receive(:set_a_value).with(2).ordered
93
+ dummy.should_receive(:set_a_value).with(3).ordered
94
+
95
+ HashWalker.walk(hash) do
96
+ stories do
97
+ dummy.set_a_value(a)
98
+ end
99
+ end
100
+ end
101
+
102
+ it 'should iterate through arrays and return an array of the results like .map' do
103
+ hash = {:stories => [{:a => 1},{:a => 2},{:a => 3}]}
104
+ HashWalker.walk(hash) do
105
+ stories do
106
+ a
107
+ end.should == [1,2,3]
108
+ end
109
+ end
110
+
111
+ it 'should skip missing keys or attributes without raising an error' do
112
+ hash = {:stories => 'something'}
113
+ expect {
114
+ HashWalker.walk(hash) do
115
+ stories do
116
+ some_non_existant_key
117
+ end
118
+ end
119
+ }.not_to raise_error
120
+ end
121
+ end
122
+ end
123
+
124
+
125
+ # TODO: map vs. join? at least test it
126
+ # TODO: ability to reach out to parent (parent. something?)
127
+ # TODO: ability to reach out to siblings?
128
+ # TODO: Top level arrays/ (are they valid JSON and valid HAshes?)
129
+ # TODO: accept JSON or HASH or HTTParty response
130
+ # TODO: HTTParty adapter. httparty_response.walk()
131
+ # TODO: Adapter for other libaries? VCR? Mechanize? REGEXP? Nokogiri?
132
+ # TODO: return a value from the entire outer bloc
133
+ # TODO: test more stuff at the top level / outer block level
134
+ # TODO: access to key names
135
+ # TODO: generate the DSL based on an existing hash (like a VCR cassette?)
136
+ # TODO: option to raise an error or not raise an error if referencing a non-existant key
137
+ # TODO: don't look for Hash's and Array's, look for objects that act like Hash's and act like Arrays. (objects and enumarbles?)
@@ -0,0 +1,7 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'hash_walker'
3
+
4
+ RSpec.configure do |config|
5
+ config.backtrace_exclusion_patterns = []
6
+
7
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hash-walker
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gal Steinitz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
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'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: a Ruby DSL for walking through a Hash and processing it
70
+ email:
71
+ - gal@steinitz.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".ruby-gemset"
79
+ - ".ruby-version"
80
+ - ".travis.yml"
81
+ - Gemfile
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - hash-walker.gemspec
86
+ - lib/hash_walker.rb
87
+ - lib/hash_walker/stepper.rb
88
+ - lib/hash_walker/stepper/array.rb
89
+ - lib/hash_walker/stepper/hash.rb
90
+ - lib/hash_walker/stepper_base.rb
91
+ - lib/hash_walker/version.rb
92
+ - lib/hash_walker/walk.rb
93
+ - lib/hash_walker/walker.rb
94
+ - spec/hash_walker_spec.rb
95
+ - spec/spec_helper.rb
96
+ homepage: https://github.com/al-jazeera-america/hash-walker
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.2.2
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Walk a hash like a hash walker would
120
+ test_files:
121
+ - spec/hash_walker_spec.rb
122
+ - spec/spec_helper.rb