hashmodel 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,14 +1,9 @@
1
1
  source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
5
2
 
6
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
8
3
  group :development do
9
- gem "rspec", ">= 2.2.0"
10
- gem "cucumber", ">= 0.10.0"
11
- gem "bundler", ">= 1.0.0"
12
- gem "jeweler", ">= 1.5.0.pre5"
13
- gem "rcov", ">= 0"
4
+ gem "rspec"
5
+ gem "cucumber"
6
+ gem "bundler"
7
+ gem "jeweler"
8
+ gem "rcov"
14
9
  end
@@ -9,33 +9,32 @@ GEM
9
9
  json (~> 1.4.6)
10
10
  term-ansicolor (~> 1.0.5)
11
11
  diff-lcs (1.1.2)
12
- gherkin (2.3.2)
12
+ gherkin (2.3.3)
13
13
  json (~> 1.4.6)
14
- term-ansicolor (~> 1.0.5)
15
14
  git (1.2.5)
16
- jeweler (1.5.1)
15
+ jeweler (1.5.2)
17
16
  bundler (~> 1.0.0)
18
17
  git (>= 1.2.5)
19
18
  rake
20
19
  json (1.4.6)
21
20
  rake (0.8.7)
22
21
  rcov (0.9.9)
23
- rspec (2.2.0)
24
- rspec-core (~> 2.2)
25
- rspec-expectations (~> 2.2)
26
- rspec-mocks (~> 2.2)
27
- rspec-core (2.2.1)
28
- rspec-expectations (2.2.0)
22
+ rspec (2.4.0)
23
+ rspec-core (~> 2.4.0)
24
+ rspec-expectations (~> 2.4.0)
25
+ rspec-mocks (~> 2.4.0)
26
+ rspec-core (2.4.0)
27
+ rspec-expectations (2.4.0)
29
28
  diff-lcs (~> 1.1.2)
30
- rspec-mocks (2.2.0)
29
+ rspec-mocks (2.4.0)
31
30
  term-ansicolor (1.0.5)
32
31
 
33
32
  PLATFORMS
34
33
  ruby
35
34
 
36
35
  DEPENDENCIES
37
- bundler (>= 1.0.0)
38
- cucumber (>= 0.10.0)
39
- jeweler (>= 1.5.0.pre5)
36
+ bundler
37
+ cucumber
38
+ jeweler
40
39
  rcov
41
- rspec (>= 2.2.0)
40
+ rspec
@@ -21,11 +21,20 @@ found = @hm.where {@switch == "-x" && @parameter\_type == String}
21
21
 
22
22
  ## Usage
23
23
 
24
- Coming soon...
25
24
 
26
- For now take a look at the spec files to see simple examples of how to use the HashModel
27
25
 
26
+ ## Version History
28
27
 
28
+ 0.2.0
29
+ * Fixed bug if first field name is shorter version of another field name, e.g. :short then :shorter would cause an error.
30
+ * Added unflattening records and adding unflattened records.
31
+ * Changed field separator to double underscores (to allow unflattening)
32
+ * Removed namespace module, it was annoying. Now just instantiate it with HashModel.new instead of MikBe::HashModel.new
33
+ * Now allows a single hash, instead of an array of hashes, when creating with HashModel.new(:raw_data => hash)
34
+
35
+ 0.1.1 Moved to new RubyGems account
36
+
37
+ 0.1.0 Initial publish
29
38
 
30
39
  == Contributing to hash\_model
31
40
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ rescue Bundler::BundlerError => e
9
9
  end
10
10
  require 'rake'
11
11
  require './lib/hash_model/version'
12
- version = MikBe::HashModel::VERSION::STRING
12
+ version = HashModel::VERSION::STRING
13
13
 
14
14
  require 'jeweler'
15
15
  Jeweler::Tasks.new do |gem|
@@ -25,19 +25,14 @@ Jeweler::RubygemsDotOrgTasks.new
25
25
 
26
26
  require 'rspec/core'
27
27
  require 'rspec/core/rake_task'
28
- RSpec::Core::RakeTask.new(:spec) do |spec|
28
+ RSpec::Core::RakeTask.new(:rspec) do |spec|
29
29
  spec.pattern = FileList['spec/**/*_spec.rb']
30
30
  end
31
31
 
32
- RSpec::Core::RakeTask.new(:rcov) do |spec|
33
- spec.pattern = 'spec/**/*_spec.rb'
34
- spec.rcov = true
35
- end
36
-
37
32
  require 'cucumber/rake/task'
38
33
  Cucumber::Rake::Task.new(:features)
39
34
 
40
- task :default => :spec
35
+ task :default => :rspec
41
36
 
42
37
  require 'rake/rdoctask'
43
38
  Rake::RDocTask.new do |rdoc|
@@ -0,0 +1,169 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "/../lib"))
2
+ require 'hash_model'
3
+
4
+ hash = {
5
+ :field1 => "f",
6
+ :field2 => {
7
+ :field3 => "f3",
8
+ :field4 => {
9
+ :field5 => "f5",
10
+ :field6 => ["f6", "f7"]
11
+ }
12
+ }
13
+ }
14
+ =begin
15
+
16
+ hash2 = {
17
+ :switch => ["-x", "--xtend"],
18
+ :parameter => {:type => String, :require => true},
19
+ :description => "Xish stuff",
20
+ :field => {:field2 => {:field3 => "ff3", :field4 => "ff4"}}
21
+ }
22
+
23
+ hash2 = {
24
+ :switch => ["-x", "--xtend"],
25
+ :parameter => {:type => String, :require => true},
26
+ :description => "Xish stuff",
27
+ :field => {:field2 => [:field3 => "ff3", :field4 => "ff4", "ff5"]}
28
+ }
29
+
30
+
31
+ hm = HashModel.new
32
+ hm << hash2
33
+ hm.flatten_index = :field__field2
34
+
35
+
36
+ flat = {
37
+ :field2__field4__field5=>"f5",
38
+ :field1=>"f",
39
+ :field3=>"f3",
40
+ :field2__field4__field6=>["f6", "f7"]
41
+ }
42
+
43
+ [
44
+ {
45
+ :field__field2__field3=>"ff3",
46
+ :field__field2__field4=>"ff4",
47
+ :switch=>["-x", "--xtend"],
48
+ :parameter__type=>String,
49
+ :parameter__require=>true,
50
+ :description=>"Xish stuff",
51
+ }
52
+ ]
53
+
54
+ puts "\nhm: #{hm}"
55
+ #hash2 = {:field => "field", :field2__field3 => "field3", :field2__field4 => {:field5 => "field5", :field6 => ["field6", "field7"]}}}
56
+ =end
57
+
58
+
59
+
60
+ def unflatten(input)
61
+ # Seriously in need of a refactor, just looking at this hurts my brain
62
+ case input
63
+ when Hash
64
+ new_record = {}
65
+ input.each do |key, value|
66
+ puts "#{key} => #{value}"
67
+ # recursively look for flattened keys
68
+ keys = key.to_s.split("__", 2)
69
+ if keys[1]
70
+ key = keys[0].to_sym
71
+ value = unflatten({keys[1].to_sym => value})
72
+ end
73
+
74
+ # Don't overwrite existing value
75
+ if (existing = new_record[key])
76
+ # convert to array and search for subkeys if appropriate
77
+ if existing.class == Hash
78
+ # Convert to an array if something other than a hash is added
79
+ unless value.class == Hash
80
+ new_record[key] = hash_to_array(existing)
81
+ new_record[key] << value
82
+ else
83
+ # Search subkeys for duplicate values if it's a hash
84
+ unless (found_keys = existing.keys & value.keys).empty?
85
+ found_keys.each do |found_key|
86
+ if new_record[key][found_key].class == Hash
87
+ unless value[found_key].class == Hash
88
+ new_record[key] = hash_to_array(new_record[key][found_key])
89
+ new_record[key] << value[found_key]
90
+ else
91
+ new_record[key][found_key].merge!(value[found_key])
92
+ end
93
+ end
94
+ end
95
+ else
96
+ new_record[key].merge!(value)
97
+ end
98
+ end
99
+ else
100
+ new_record[key] << value
101
+ end
102
+ else
103
+ new_record.merge!(key => value)
104
+ end
105
+ end
106
+ new_record
107
+ when Array
108
+ # recurse into array
109
+ input.collect! {|item| unflatten(item) }
110
+ else
111
+ input
112
+ end
113
+ end
114
+
115
+
116
+ def hash_to_array(hash)
117
+ array = []
118
+ hash.each do |key, value|
119
+ array << {key => value}
120
+ end
121
+ array
122
+ end
123
+
124
+ hash = [
125
+ {
126
+ :field__field2__field3=>"ff3",
127
+ :field__field2__field4=>"ff4"
128
+ }
129
+ ]
130
+
131
+ hash2 = {
132
+ :switch=>["-x", "--xtend"],
133
+ :parameter__type=>String,
134
+ :parameter__require=>true,
135
+ :description=>"Xish stuff",
136
+ }
137
+
138
+
139
+ hash3 = {
140
+ :switch=>[{:deep1 => "deepOne"}, {:deep2 => "deepTwo"}, "--xtend"],
141
+ :parameter__type=>String,
142
+ :parameter__require=>true,
143
+ :description=>"Xish stuff",
144
+ }
145
+
146
+
147
+ hash4 = {
148
+ :parameter__type=>String,
149
+ :switch__deep1__deep3 => "deepTwo",
150
+ :parameter__type__ruby=>true,
151
+ :parameter => "glorp",
152
+ :parameter__require=>true,
153
+ :switch__deep2 => "deepTwo",
154
+ :description=>"Xish stuff",
155
+ :switch => "--xtend",
156
+ }
157
+
158
+
159
+ unflat = unflatten(hash4)
160
+ puts "\nUnflat: #{unflat}"
161
+
162
+ =begin
163
+ puts "to_a: #{hash2.to_a}"
164
+
165
+ x = [1,2,3]
166
+ y = [3,4,5]
167
+
168
+ puts "\nx & y = #{x & y}"
169
+ =end
@@ -0,0 +1,24 @@
1
+ class Foo
2
+
3
+ attr_accessor :bar
4
+
5
+ def initialize
6
+ @bar = 1
7
+ end
8
+
9
+ def show
10
+ vars = instance_variables
11
+ instance_variables.each do |var|
12
+ puts "var: #{var}"
13
+ end
14
+ print "no vars "
15
+ puts instance_variables.class
16
+ end
17
+
18
+ end
19
+
20
+ f = Foo.new
21
+
22
+ f.show
23
+
24
+ puts f.instance_variables
@@ -0,0 +1,16 @@
1
+
2
+ def test_it(y)
3
+ y.concat("_mod")
4
+ end
5
+
6
+ x = "test"
7
+ test_it x
8
+ puts "x id: #{x.object_id}"
9
+ puts "x: #{x}"
10
+
11
+ z = "z"
12
+ puts "z id: #{z.object_id}"
13
+ puts "z: #{z}"
14
+ z += "_mod"
15
+ puts "z id: #{z.object_id}"
16
+ puts "z: #{z}"
@@ -0,0 +1,46 @@
1
+
2
+ def deflatten(input)
3
+ case input
4
+ when Hash
5
+ new_hash = {}
6
+ input.each do |key,value|
7
+ split_key = key.to_s.split("__",2)
8
+ new_hash_key = split_key[0].to_sym
9
+ if split_key.length > 1
10
+ child_hash = {split_key[1].to_sym => value}
11
+ value = deflatten(child_hash)
12
+ end
13
+
14
+ #look for existing keys so we don't overwrite them
15
+ existing_value = new_hash[new_hash_key]
16
+ if !existing_value.nil?
17
+ if existing_value.class == Hash && value.class == Hash
18
+ value = existing_value.merge(value)
19
+ elsif existing_value.class == Array
20
+ value = existing_value << value
21
+ else
22
+ value = [value, existing_value]
23
+ end
24
+ end
25
+ new_hash.merge!(new_hash_key => value)
26
+ end
27
+ new_hash
28
+ when Array
29
+ input.collect { |value| deflatten(value.clone)}
30
+ else
31
+ input
32
+ end # case
33
+ end
34
+
35
+ hash = {:switch=>"-x", :parameter__type=>String, :parameter__required=>true, :some__value__blrop=>[1,2,3], :some__hash=>{:blah=>"bloo", :bleep=>4}, :some__value=>"something", :some__others=>"others", :some__array=> [1,2,3], :description=>"the x paramemter"}
36
+
37
+ puts ""
38
+ puts ""
39
+ puts "build_hash: #{deflatten(hash)}"
40
+
41
+ {
42
+ :switch=>"-x",
43
+ :parameter=>{:required=>true, :type=>String},
44
+ :some=>{:array=>[1, 2, 3], :others=>"others", :value=>[{:blrop=>[1,2,3]}, "something"], :hash=>{:blah=>"bloo", :bleep=>4}},
45
+ :description=>"the x paramemter"
46
+ }
@@ -0,0 +1,27 @@
1
+ class Fruit
2
+
3
+ def set_defaults
4
+ @color ||= 'green'
5
+ @type ||= 'pear'
6
+ end
7
+
8
+ def initialize(params = {})
9
+ params.each { |key,value| instance_variable_set("@#{key}", value) }
10
+ set_defaults
11
+ instance_variables.each {|var| self.class.send(:attr_accessor, var)}
12
+ end
13
+
14
+ def to_s
15
+ instance_variables.inject("") {|vars, var| vars += "#{var}: #{instance_variable_get(var)}; "}
16
+ end
17
+
18
+ end
19
+
20
+ puts Fruit.new
21
+ puts Fruit.new :color => 'red', :type => 'grape'
22
+ puts Fruit.new :type => 'pomegranate'
23
+ puts Fruit.new :cost => 20.21
24
+ puts Fruit.new :foo => "bar"
25
+
26
+ f = Fruit.new :potato => "salad"
27
+ puts "f.cost.nil? #{f.cost.nil?}"
@@ -2,7 +2,7 @@ These features really only make sense to write when I'm trying to figure out wha
2
2
  functionality I want to add. When I already know it just seems redundant to do it
3
3
  here since this app is such a low level library.
4
4
 
5
- The Cucumber methodologies don't seem to be necessary most of the time since I
5
+ The Cucumber methodologies don't seem to be necessary most of the time since
6
6
  RSpec seems to be a more natural fit for a programming library. I'm probably
7
7
  wrong but it really does seem to be a lot of redundancy for this application.
8
8
 
@@ -27,8 +27,8 @@ Scenario: Flatten input hashes to the default flatten index
27
27
  When the HashModel is populated with the test table
28
28
  Then the HashModel recordset should look like
29
29
  | id | group_id | switch | description |
30
- | :hm_id=>0 | :hm_group_id=> 0 | :switch=>"-x" | :description=>"This is a description" |
31
- | :hm_id=>1 | :hm_group_id=> 0 | :switch=>"--xtended" | :description=>"This is a description" |
32
- | :hm_id=>2 | :hm_group_id=> 1 | :switch=>"-y" | :description=>"Why not?" |
33
- | :hm_id=>3 | :hm_group_id=> 2 | :switch=>"-z" | :description=>"head for zee hills" |
34
- | :hm_id=>4 | :hm_group_id=> 2 | :switch=>"--zee" | :description=>"head for zee hills" |
30
+ | :_id=>0 | :_group_id=> 0 | :switch=>"-x" | :description=>"This is a description" |
31
+ | :_id=>1 | :_group_id=> 0 | :switch=>"--xtended" | :description=>"This is a description" |
32
+ | :_id=>2 | :_group_id=> 1 | :switch=>"-y" | :description=>"Why not?" |
33
+ | :_id=>3 | :_group_id=> 2 | :switch=>"-z" | :description=>"head for zee hills" |
34
+ | :_id=>4 | :_group_id=> 2 | :switch=>"--zee" | :description=>"head for zee hills" |
@@ -17,7 +17,7 @@ Scenario: Search using a parameter
17
17
  When we search with the single parameter "-x"
18
18
  Then the search recordset should look like
19
19
  | id | group_id | switch | description |
20
- | :hm_id=>0 | :hm_group_id=> 0 | :switch=>"-x" | :description=>"This is a description" |
20
+ | :_id=>0 | :_group_id=> 0 | :switch=>"-x" | :description=>"This is a description" |
21
21
 
22
22
  @active
23
23
  Scenario: Search using a block of boolean logic
@@ -26,7 +26,7 @@ Scenario: Search using a block of boolean logic
26
26
  When we search with the block {@switch == "-x"}
27
27
  Then the search recordset should look like
28
28
  | id | group_id | switch | description |
29
- | :hm_id=>0 | :hm_group_id=> 0 | :switch=>"-x" | :description=>"This is a description" |
29
+ | :_id=>0 | :_group_id=> 0 | :switch=>"-x" | :description=>"This is a description" |
30
30
 
31
31
 
32
32