burp 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/README.rdoc +138 -25
  2. data/VERSION +1 -1
  3. data/burp.gemspec +65 -0
  4. data/lib/burp.rb +51 -16
  5. data/spec/burp_spec.rb +112 -11
  6. metadata +5 -4
@@ -1,46 +1,159 @@
1
- = burp
1
+ = Burp
2
+ == Why Burp?
3
+ Did you ever get a list of structured data (for example an array of hash data) and get a bit of indigestion when you realize that the unique attribute(s) of the data is(are) buried underneath the array? Well, if you're like me you're tired of having to do something like
2
4
 
5
+ structured_array = list_of_stuff.map{|struc_data| organize(struc_data)}
6
+ a_nice_hash = Hash.new[structured_array]
7
+
8
+ Burp provides an easier way
9
+
10
+ == Basic Burp
3
11
  Oh yum, look at this collection of hashes I have to manage. Each with a unique id to represent it:
4
12
 
5
- yummy = [
6
- {:id => :a, :data => "A"},
7
- {:id => :b, :data => "B"},
8
- {:id => :c, :data => "C"}
9
- ]
13
+ yummy = [
14
+ {:id => :a, :data => "A", :other_stuff => "aaa"},
15
+ {:id => :b, :data => "B", :other_stuff => "bbb"},
16
+ {:id => :c, :data => "C", :other_stuff => "ccc"}
17
+ ]
10
18
 
11
- I feel like checking out :b today:
19
+ I feel like referencing :b's data today:
12
20
 
13
21
  Yes, you could just select what you need the boring, ugly way
14
- b_data = yummy.select{|node| node[:id] == :b}.first
22
+
23
+ b_data = yummy.select{|node| node[:id] == :b}.first
24
+
15
25
  That's not hard, but rather than manually select it, let's just let out a hearty burp
16
26
 
17
- burped = Burp.new(yummy, :id)
27
+ burped = Burp.new(yummy, :id)
18
28
 
19
29
  and get good old fashioned hash in return
20
30
 
21
- #=> { :a => {:id => :a, :data => "A" },
22
- :b => {:id => :b, :data => "B" },
23
- :c => {:id => :c, :data => "C" }
31
+ #=> { :a => {:id => :a, :data => "A", :other_stuff => "aaa" },
32
+ :b => {:id => :b, :data => "B", :other_stuff => "bbb" },
33
+ :c => {:id => :c, :data => "C", :other_stuff => "ccc" }
24
34
 
25
35
  meaning that
26
- b_data = burped[:b]
36
+
37
+ b_data = burped[:b]
38
+ #=> {:id => :b, :data => "B", :other_stuff => "bbb" }
39
+
40
+
41
+ Burp also allows you to filter the data if desired by providing a list of fields to keep
42
+
43
+ filtered_burp = Burp.new(yummy, :id, [:data])
44
+
45
+ or if there's only one field of interest and you can't be bothered with array brackets, just
46
+
47
+ filtered_burp = Burp.new(yummy, :id, :data)
48
+
49
+ will work fine as well, and will return
50
+
51
+ #=> { :a => {:data => "A"},
52
+ :b => {:data => "B"},
53
+ :c => {:data => "C"}
27
54
 
28
55
  As a special side-dish, Burp can handle things that are a bit messier as well
29
56
 
30
- fly_in_my_soup = [
31
- {:id => :a, :data => "A"},
32
- {:id => :b, :data => "B"},
33
- {:id => :c, :data => "C"},
34
- {:fly => :d, :data => "D"}
35
- ]
57
+ fly_in_my_soup = [
58
+ {:id => :a, :data => "A"},
59
+ {:id => :b, :data => "B"},
60
+ {:id => :c, :data => "C"},
61
+ {:fly => :d, :data => "D"}
62
+ ]
63
+
64
+ yummy_soup = Burped.new(fly_in_my_soup, :id)
65
+ #=> { :a => {:id => :a, :data => "A" },
66
+ :b => {:id => :b, :data => "B" },
67
+ :c => {:id => :c, :data => "C" }
68
+
69
+ fly = yummy_soup.left_overs
70
+ #=> [{:fly => :d, :data => "D"}]
71
+
72
+ == Advanced Burp
73
+ Burp's not only good for lists of hashes, it can work for a list of any arbitrary data, and you can set any key you'd like to the underlying data.
74
+
75
+ Examples Ahoy!
76
+
77
+ Let's say our IronChef gem (don't go look for it, I just made that up) provides us a list of foods and some information about them, however the food information is encapsulated in its own class, something like:
78
+
79
+ class Food
80
+ attr_accessor :name, :tastiness, :prep_effort
81
+
82
+ def initialize(name, tastiness, prep_effort)
83
+ @name = name
84
+ @tastiness = tastiness
85
+ @prep_effort = prep_effort
86
+ end
87
+ end
88
+
89
+ So when inspecting this array of food objects I see something like:
90
+
91
+ pp food_array
92
+ #=>
93
+ [#<Food:0xb41368
94
+ @name="bacon",
95
+ @prep_effort="nuke it",
96
+ @tastiness="awesome">,
97
+ #<Food:0xb41308
98
+ @name="tofu",
99
+ @prep_effort="mix it in something",
100
+ @tastiness="meh">,
101
+ #<Food:0xb412a8
102
+ @name="beer",
103
+ @prep_effort="mooch from buddy",
104
+ @tastiness="essential to life">]
105
+
106
+ Ok, so maybe I'm just interested in the preparation of said food items, we can use the name attribute for our key, and pull out the prep effort.
107
+
108
+ To do this with Burp, we can create a custom id label with a proc:
109
+
110
+ food_name = lambda{ |item| item.name }
111
+
112
+ just use it like this in Burp
113
+
114
+ food_data = Burp.new(food_array, food_name)
115
+ #=>
116
+ {"bacon"=>
117
+ #<Food:0x8a9c8bc
118
+ @name="bacon",
119
+ @prep_effort="nuke it",
120
+ @tastiness="awesome">,
121
+ "tofu"=>
122
+ #<Food:0x8a9c86c
123
+ @name="tofu",
124
+ @prep_effort="mix it in something",
125
+ @tastiness="meh">,
126
+ "beer"=>
127
+ #<Food:0x8a9c81c
128
+ @name="beer",
129
+ @prep_effort="mooch from buddy",
130
+ @tastiness="essential to life">}
131
+
132
+ Ah, that's a little bit better, now I can get my desired food object (beer of course) just by
133
+
134
+ food_data["beer"]
135
+ #=>
136
+ #<Food:0x8a9c81c
137
+ @name="beer",
138
+ @prep_effort="mooch from buddy",
139
+ @tastiness="essential to life">}
140
+
141
+ and to prepare I can just call prep_effort
142
+
143
+ food_data["beer"].prep_effort
144
+
145
+ But, we can go a step further, and have burp provided us just the information we want
146
+
147
+ filter = lambda{|item| item.prep_effort}
148
+
149
+ food_prep = Burp.new(food_array, food_name, filter)
150
+ #=> {"bacon"=>"nuke it", "tofu"=>"mix it in something", "beer"=>"mooch from buddy"}
151
+
152
+ food_prep["beer"]
153
+ #=> "mooch from buddy"
36
154
 
37
- yummy_soup = Burped.new(fly_in_my_soup)
38
- #=> { :a => {:id => :a, :data => "A" },
39
- :b => {:id => :b, :data => "B" },
40
- :c => {:id => :c, :data => "C" }
41
155
 
42
- fly = yummy_soup.left_overs
43
- #=> [{:fly => :d, :data => "D"}]
156
+ Now if you'll excuse me, I'm hungry and have to grab something to eat.
44
157
 
45
158
  == Contributing to burp
46
159
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.1
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{burp}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Dave M"]
12
+ s.date = %q{2011-04-13}
13
+ s.description = %q{Tell it which hash key in the array of hashes to use as the hash id, and voila a hash is made from your array}
14
+ s.email = %q{dmarti21@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "burp.gemspec",
29
+ "lib/burp.rb",
30
+ "spec/burp_spec.rb",
31
+ "spec/spec_helper.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/forforf/burp}
34
+ s.licenses = ["MIT"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.3.7}
37
+ s.summary = %q{Turns an array of hashes into a hash of hashes}
38
+ s.test_files = [
39
+ "spec/burp_spec.rb",
40
+ "spec/spec_helper.rb"
41
+ ]
42
+
43
+ if s.respond_to? :specification_version then
44
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
49
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
50
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
51
+ s.add_development_dependency(%q<rcov>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
54
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
55
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
56
+ s.add_dependency(%q<rcov>, [">= 0"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
60
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
62
+ s.add_dependency(%q<rcov>, [">= 0"])
63
+ end
64
+ end
65
+
@@ -1,31 +1,66 @@
1
1
  class Burp < Hash
2
2
  attr_reader :left_overs
3
- #Converts an array of hashes into a hash
3
+ #Converts a list of data (i.e. an array) into a ruby hash structure
4
+ #
4
5
  #It takes as arguments,the array of hashes (each hash representing node data)
5
6
  #and a field in the hash (node data) to use as the key for the returned hash
6
- def initialize(node_list, id)
7
+ def initialize(node_list, id_key, data_filter = nil)
7
8
  @left_overs = []
8
- node_list.map do |node|
9
- #better error information and eliminate nil keys
10
- node = validate(node, id)
11
- #it's left over if the primary hash key doesn't exist in the node
12
- add_leftovers(self, @left_overs, node) unless ( node[id] && node.keys.include?(id) )
9
+ node_list.map do |raw_node|
10
+ node_id = find_id(raw_node, id_key)
11
+ if node_ok?(raw_node, node_id)
12
+ node_burp(raw_node, node_id, data_filter) #adds to self (i.e. this hash)
13
+ else
14
+ @left_overs << raw_node
15
+ end
13
16
  end
14
17
  end
18
+
19
+ def node_ok?(raw_node, node_id)
20
+ resp = true
21
+ resp = false if self.has_key?(node_id)
22
+ resp = false if raw_node && node_id.nil?
23
+ resp
24
+ end
15
25
 
26
+ def node_burp(raw_node, node_id, data_filter)
27
+ node_data = find_data(raw_node, data_filter)
28
+ self[node_id] = node_data
29
+ end
30
+
31
+
32
+ def find_id(node, id_key)
33
+ if id_key.is_a? Proc
34
+ id_key.call(node)
35
+ else
36
+ validate(node, id_key)
37
+ end
38
+ end
39
+
40
+ def find_data(node, data_filter)
41
+ return node unless data_filter
42
+ if data_filter.is_a? Proc
43
+ node_data = data_filter.call(node)
44
+ else
45
+ #Done this way to allow any object that supports [], []= and has_key? methods
46
+ #I'm intentionally avoiding Hash#select/reject for this (selfish) reason
47
+ data_filter = [data_filter].flatten
48
+ new_data = {}
49
+ data_filter.each do |key|
50
+ if node.has_key?(key)
51
+ new_data[key] = validate(node, key)
52
+ end
53
+ end
54
+ new_data
55
+ end
56
+ end
57
+
16
58
  def validate(node, id)
17
59
  begin
18
- self[node[id]] = node
60
+ node[id]
19
61
  rescue TypeError #replacing an unhelpful error with something more helpful
20
62
  raise ArgumentError, "Can't use #{id.inspect} as a valid key in #{node.inspect}. "\
21
- "Maybe array elements are not hashes?"
63
+ "Maybe you're trying a hash method on something other than a hash?"
22
64
  end
23
65
  end
24
-
25
- def add_leftovers(main_hash, left_overs, node)
26
- #remove nil hash from main_hash
27
- main_hash.delete(nil)
28
- #add data to left overs (excluding nil data)
29
- left_overs << node if node
30
- end
31
66
  end
@@ -1,26 +1,64 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
+ module BurpSpecH
3
4
 
4
- describe "Burp" do
5
+ #Food Stuff for Advanced Burp
6
+ class Food
7
+ attr_accessor :name, :tastiness, :prep_effort
8
+ def initialize(name, tastiness, prep_effort)
9
+ @name = name
10
+ @tastiness = tastiness
11
+ @prep_effort = prep_effort
12
+ end
13
+ end
14
+
15
+ Foods = {'bacon' => {:taste => 'awesome', :prep => 'nuke it'},
16
+ 'tofu' => {:taste => 'meh', :prep => 'mix it in something'},
17
+ 'beer' => {:taste => 'essential to life', :prep => 'mooch from buddy'}
18
+ }
19
+ FoodNames = Foods.keys
20
+
21
+ def self.make_food
22
+ #make us an array of Food objects
23
+ FoodNames.map do |food_name| Food.new(food_name,
24
+ Foods[food_name][:taste],
25
+ Foods[food_name][:prep])
26
+ end
27
+ end
28
+
29
+ #Baseic stuff for Basic (and Advanced) Burp
30
+
31
+ NiceArray = [{:id => :a, :data => "A", :other_stuff => "aaa"},
32
+ {:id => :b, :data => "B", :other_stuff => "bbb"},
33
+ {:id => :c, :data => "C", :other_stuff => "ccc"}]
34
+
35
+ #notice the last id typo
36
+ DirtyArray = [{:id => :a, :data => "A", :other_stuff => "aaa"},
37
+ {:id => :b, :data => "B", :other_stuff => "bbb"},
38
+ {:id => :c, :data => "C", :other_stuff => "ccc"},
39
+ {:iidd => :d, :data => "D"}]
40
+ end
41
+
42
+ describe "Basic Burp" do
5
43
  before(:each) do
6
- @nice_array = [{:id => :a, :data => "A"},
7
- {:id => :b, :data => "B"},
8
- {:id => :c, :data => "C"}]
9
- @nice_burped = {:a => {:id => :a, :data => "A"},
10
- :b => {:id => :b, :data => "B"},
11
- :c => {:id => :c, :data => "C"}}
44
+ @nice_array = BurpSpecH::NiceArray
45
+
46
+ @nice_burped = {:a => {:id => :a, :data => "A", :other_stuff => "aaa"},
47
+ :b => {:id => :b, :data => "B", :other_stuff => "bbb"},
48
+ :c => {:id => :c, :data => "C", :other_stuff => "ccc"}}
12
49
 
13
50
  @not_an_array = @nice_burped #its a hash now
14
51
 
15
52
  #notice the last id typo
16
- @dirty_array = [{:id => :a, :data => "A"},
17
- {:id => :b, :data => "B"},
18
- {:id => :c, :data => "C"},
19
- {:iidd => :d, :data => "D"}]
53
+ @dirty_array = BurpSpecH::DirtyArray
20
54
 
21
55
  @dirty_burped = @nice_burped
22
56
 
23
57
  @dirty_left_overs = [{:iidd => :d, :data => "D"}]
58
+
59
+ @filtered_burp = {:a => {:data => "A"},
60
+ :b => {:data => "B"},
61
+ :c => {:data => "C"}}
24
62
  end
25
63
 
26
64
  it "makes a hash out of a nicely formed array" do
@@ -37,4 +75,67 @@ describe "Burp" do
37
75
  my_dirty_burp.should == @dirty_burped
38
76
  my_dirty_burp.left_overs.should == @dirty_left_overs
39
77
  end
78
+
79
+ it "filters data" do
80
+ filtered_burp = Burp.new(@dirty_array, :id, :data)
81
+ filtered_burp.should == @filtered_burp
82
+ end
83
+
84
+
85
+ end
86
+
87
+ describe "Advanced Burp" do
88
+ include BurpSpecH
89
+
90
+ before(:each) do
91
+ @food_list = BurpSpecH.make_food
92
+ @id_block = lambda{|item| item.name}
93
+ @filtered_food_block = lambda{|item| item.prep_effort}
94
+ @filtered_simple_block = lambda{|item| item[:data].downcase}
95
+ @nice_array = NiceArray
96
+ @nice_burped_proc = {:a => "a",
97
+ :b => "b",
98
+ :c => "c"}
99
+ @dirty_array = DirtyArray
100
+ @dirty_bupred_proc = @nice_burped_proc
101
+ @dirty_left_overs = [{:iidd => :d, :data => "D"}]
102
+ @filtered_burp = {'bacon' => 'nuke it',
103
+ 'tofu' => 'mix it in something',
104
+ 'beer' => 'mooch from buddy'}
105
+ end
106
+
107
+ it "is passed a food list" do
108
+ @food_list.should be_an Array
109
+ end
110
+
111
+ it "uses blocks for ids without vomiting" do
112
+ my_burp = Burp.new(@food_list, @id_block)
113
+ my_burp['bacon'].should be_a Food
114
+ my_burp['bacon'].tastiness.should == "awesome"
115
+ my_burp['bacon'].prep_effort.should == "nuke it"
116
+
117
+ #comprehensive test
118
+ FoodNames.each do |food_name|
119
+ my_burp[food_name].should be_a Food
120
+ my_burp[food_name].tastiness.should == Foods[food_name][:taste]
121
+ my_burp[food_name].prep_effort.should == Foods[food_name][:prep]
122
+ end
123
+ end
124
+
125
+ it "uses blocks for nice data without vomiting" do
126
+ my_burp = Burp.new(@nice_array, :id, @filtered_simple_block)
127
+ my_burp.should == @nice_burped_proc
128
+ end
129
+
130
+ it "uses blocks for dirty data without vomiting" do
131
+ my_dirty_burp = Burp.new(@dirty_array, :id, @filtered_simple_block)
132
+ my_dirty_burp.should == @nice_burped_proc
133
+ my_dirty_burp.left_overs.should == @dirty_left_overs
134
+ end
135
+
136
+ it "uses blocks for both ids and data without vomiting" do
137
+ my_burp = Burp.new(@food_list, @id_block, @filtered_food_block)
138
+ my_burp.should == @filtered_burp
139
+ end
140
+
40
141
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 0
8
7
  - 1
9
- version: 0.0.1
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Dave M
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-04-12 00:00:00 +00:00
17
+ date: 2011-04-13 00:00:00 +00:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -93,6 +93,7 @@ files:
93
93
  - README.rdoc
94
94
  - Rakefile
95
95
  - VERSION
96
+ - burp.gemspec
96
97
  - lib/burp.rb
97
98
  - spec/burp_spec.rb
98
99
  - spec/spec_helper.rb
@@ -110,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
111
  requirements:
111
112
  - - ">="
112
113
  - !ruby/object:Gem::Version
113
- hash: 771572209
114
+ hash: 997682877
114
115
  segments:
115
116
  - 0
116
117
  version: "0"