hashmodel 0.1.1 → 0.2.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.
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