rucursive 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format Fuubar
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rucursive.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2012 Wes Morgan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rspec/core/rake_task"
4
+
5
+ task :default => :spec
6
+
7
+ desc "Run specs"
8
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,8 @@
1
+ require "rucursive/version"
2
+ require "rucursive/core_ext"
3
+
4
+ module Rucursive
5
+ def self.included(base)
6
+ Object.send :include, Rucursive::CoreExt::Object
7
+ end
8
+ end
@@ -0,0 +1,132 @@
1
+ module Rucursive
2
+ module CoreExt
3
+ module Object
4
+ def compound?
5
+ is_a?(Array) || is_a?(Hash)
6
+ end
7
+
8
+ ##
9
+ # Recursively traverse a compound data structure and call a supplied
10
+ # block on each value or key/value pair, allowing it to modify the
11
+ # returned data structure as it goes. It does NOT modify the existing
12
+ # data structure.
13
+ #
14
+ # Required arguments: A block that is called on each element of the data
15
+ # structure
16
+ #
17
+ # Return value: A new data structure including any modifications made by
18
+ # the supplied block.
19
+ def recurse(&block)
20
+ if is_a?(Array)
21
+ map do |o|
22
+ if o.compound?
23
+ o.recurse(&block)
24
+ else
25
+ block.call(o.dup) if block.arity == 1
26
+ block.call(nil, o.dup) if block.arity == 2
27
+ block.call(nil, o.dup, :array) if block.arity == 3
28
+ end
29
+ end
30
+ elsif is_a?(Hash)
31
+ new_hash = {}
32
+ each_pair do |k,v|
33
+ if v.compound?
34
+ result = block.call(k, v.dup.freeze) if block.arity == 2
35
+ result = block.call(k, v.dup.freeze, :hash) if block.arity == 3
36
+ if result.is_a?(Hash)
37
+ new_key = result.keys.first
38
+ elsif result.is_a?(Array)
39
+ new_key = result.first
40
+ else
41
+ new_key = result
42
+ end
43
+ new_hash[new_key] = v.recurse(&block)
44
+ else
45
+ begin
46
+ v_param = v.dup
47
+ rescue
48
+ v_param = v
49
+ end
50
+ result = block.call(k, v_param) if block.arity == 2
51
+ result = block.call(k, v_param, :hash) if block.arity == 3
52
+ if result.is_a?(Hash)
53
+ new_hash.merge! result
54
+ elsif result.is_a?(Array)
55
+ new_hash[result.first] = result.second
56
+ else
57
+ new_hash[result] = v
58
+ end
59
+ end
60
+ end
61
+ new_hash
62
+ else
63
+ self
64
+ end
65
+ end
66
+
67
+ ##
68
+ # Just like Object#recurse when called on a Hash, but only passes the
69
+ # values to the supplied block, rather than the keys and values.
70
+ # Behaves the same as Object#recurse on Arrays.
71
+ def recurse_values(&block)
72
+ if is_a?(Array)
73
+ map do |o|
74
+ if o.compound?
75
+ o.recurse_values(&block)
76
+ else
77
+ block.call o
78
+ end
79
+ end
80
+ elsif is_a?(Hash)
81
+ new_hash = {}
82
+ each_pair do |k,v|
83
+ if v.compound?
84
+ new_hash[k] = v.recurse_values(&block)
85
+ else
86
+ new_hash[k] = block.call v
87
+ end
88
+ end
89
+ new_hash
90
+ else
91
+ self
92
+ end
93
+ end
94
+
95
+ ##
96
+ # Just like Object#recurse when called on a Hash, but only passes the
97
+ # keys to the supplied block, rather than the keys and values.
98
+ # Recurses through Arrays looking for Hashes, since Arrays don't really
99
+ # have keys.
100
+ def recurse_keys(&block)
101
+ if is_a?(Array)
102
+ map do |o|
103
+ if o.compound?
104
+ o.recurse_keys(&block)
105
+ else
106
+ o
107
+ end
108
+ end
109
+ elsif is_a?(Hash)
110
+ new_hash = {}
111
+ keys.each do |k|
112
+ new_key = block.call k
113
+ new_hash[new_key] = self[k]
114
+ end
115
+ new_hash.each_pair do |k,v|
116
+ if v.is_a?(Hash)
117
+ new_hash[k] = v.recurse_keys(&block)
118
+ elsif v.is_a?(Array)
119
+ new_ary = v.map do |o|
120
+ o.is_a?(Hash) ? o.recurse_keys(&block) : o
121
+ end
122
+ new_hash[k] = new_ary
123
+ end
124
+ end
125
+ new_hash
126
+ else
127
+ self
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,3 @@
1
+ module Rucursive
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rucursive/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rucursive"
7
+ s.version = Rucursive::VERSION
8
+ s.authors = ["Wes Morgan"]
9
+ s.email = ["cap10morgan@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Recursively traverses data structures}
12
+ s.description = %q{Recursively traverses data structures (Hash & Array currently)}
13
+
14
+ s.rubyforge_project = "rucursive"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rake"
22
+ s.add_development_dependency "rspec"
23
+ s.add_development_dependency "mocha"
24
+ s.add_development_dependency "fuubar"
25
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rucursive::CoreExt do
4
+ describe Rucursive::CoreExt::Object do
5
+ context "top-level Object class" do
6
+ it "should respond to #compound?" do
7
+ Object.new.should respond_to(:compound?)
8
+ end
9
+
10
+ it "should respond to #recurse" do
11
+ Object.new.should respond_to(:recurse)
12
+ end
13
+ end
14
+
15
+ describe "#compound?" do
16
+ it "should return true for a Hash" do
17
+ Hash.new.should be_compound
18
+ end
19
+
20
+ it "should return true for an Array" do
21
+ Array.new.should be_compound
22
+ end
23
+
24
+ it "should return false for a String" do
25
+ String.new.should_not be_compound
26
+ end
27
+
28
+ it "should return false for a Fixnum" do
29
+ 1.should_not be_compound
30
+ end
31
+ end
32
+
33
+ describe "#recurse" do
34
+ it "should call the block on every key,value pair in a Hash" do
35
+ hash = { foo: 'bar', baz: 'qux', gabba: { key1: 'val1', key2: 'val2' } }
36
+ expectation = hash.expects(:recurse)
37
+ hash.each_pair do |k,v|
38
+ expectation.yields(k).yields(v)
39
+ end
40
+ hash[:gabba].each_pair do |k,v|
41
+ expectation.yields(k).yields(v)
42
+ end
43
+ hash.recurse { |k,v| }
44
+ end
45
+
46
+ it "should call the block on every item in an array" do
47
+ ary = [ :foo, 42, 'bar', [ :baz, 0, 'qux' ] ]
48
+ expectation = ary.expects(:recurse)
49
+ ary.each do |o|
50
+ expectation.yields(o)
51
+ end
52
+ ary[3].each do |o|
53
+ expectation.yields(o)
54
+ end
55
+ ary.recurse { |o| }
56
+ end
57
+
58
+ it "should call the block on everything in a complex data structure" do
59
+ data = {
60
+ foo: [ 1, 2, 3, { 4 => 5, 6 => 7 } ],
61
+ bar: {
62
+ colors: [
63
+ {'red' => 'green'},{'yellow' => 'violet'},{'blue' => 'orange'}
64
+ ],
65
+ cars: {
66
+ good: ['Altima', 'Prius', 'Volt'],
67
+ bad: ['Suburban', 'Excursion', 'Grand Cherokee']
68
+ }
69
+ }
70
+ }
71
+ expectation = data.expects(:recurse)
72
+ data.each_pair do |k,v|
73
+ expectation.yields(k).yields(v)
74
+ end
75
+ data[:foo].each do |o|
76
+ expectation.yields(o)
77
+ end
78
+ data[:foo][3].each do |k,v|
79
+ expectation.yields(k).yields(v)
80
+ end
81
+ data[:bar].each_pair do |k,v|
82
+ expectation.yields(k).yields(v)
83
+ end
84
+ data[:bar][:colors].each do |c|
85
+ expectation.yields(c)
86
+ c.each_pair do |k,v|
87
+ expectation.yields(k).yields(v)
88
+ end
89
+ end
90
+ data[:bar][:cars].each do |k,v|
91
+ expectation.yields(k).yields(v)
92
+ v.each do |c|
93
+ expectation.yields(c)
94
+ end
95
+ end
96
+ data.recurse { |k,v| }
97
+ end
98
+ end
99
+
100
+ # TODO: Add tests for recurse_values & recurse_keys
101
+
102
+ end
103
+ end
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift(File.join(File.basename(__FILE__), '..', 'lib'))
2
+ require 'rucursive'
3
+
4
+ RSpec.configure do |c|
5
+ c.mock_with :mocha
6
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rucursive
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Wes Morgan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70296505944240 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70296505944240
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70296505943820 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70296505943820
36
+ - !ruby/object:Gem::Dependency
37
+ name: mocha
38
+ requirement: &70296505943400 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70296505943400
47
+ - !ruby/object:Gem::Dependency
48
+ name: fuubar
49
+ requirement: &70296505942960 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70296505942960
58
+ description: Recursively traverses data structures (Hash & Array currently)
59
+ email:
60
+ - cap10morgan@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - .rspec
67
+ - Gemfile
68
+ - LICENSE
69
+ - Rakefile
70
+ - lib/rucursive.rb
71
+ - lib/rucursive/core_ext.rb
72
+ - lib/rucursive/version.rb
73
+ - rucursive.gemspec
74
+ - spec/core_ext_spec.rb
75
+ - spec/spec_helper.rb
76
+ homepage: ''
77
+ licenses: []
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ segments:
89
+ - 0
90
+ hash: -2942571688483705688
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ segments:
98
+ - 0
99
+ hash: -2942571688483705688
100
+ requirements: []
101
+ rubyforge_project: rucursive
102
+ rubygems_version: 1.8.10
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Recursively traverses data structures
106
+ test_files:
107
+ - spec/core_ext_spec.rb
108
+ - spec/spec_helper.rb