hashmodel 0.4.0.beta1 → 0.4.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/Gemfile.lock +1 -1
  2. data/LICENSE.txt +1 -1
  3. data/README.markdown +65 -27
  4. data/hashmodel.gemspec +1 -1
  5. data/lib/hash_model/hash_model.rb +13 -105
  6. data/lib/hash_model/hash_model_create_object.rb +62 -0
  7. data/lib/hash_model/hash_model_delete.rb +13 -0
  8. data/lib/hash_model/hash_model_filter.rb +37 -0
  9. data/lib/hash_model/hash_model_flatten.rb +47 -0
  10. data/lib/hash_model/hash_model_group.rb +18 -0
  11. data/lib/hash_model/hash_model_update.rb +118 -0
  12. data/lib/hash_model/hash_model_where.rb +27 -0
  13. data/lib/hash_model/version.rb +1 -1
  14. data/lib/hashmodel.rb +1 -0
  15. data/lib/monkey_patch/deep_clone.rb +27 -0
  16. data/spec/hash_model/_current_spec.rb +6 -0
  17. data/spec/hash_model/hash_model_adding_records_spec.rb +338 -0
  18. data/spec/hash_model/hash_model_array_methods_spec.rb +132 -0
  19. data/spec/hash_model/hash_model_comparisons_spec.rb +55 -0
  20. data/spec/hash_model/hash_model_delete_spec.rb +51 -0
  21. data/spec/hash_model/hash_model_flattening_spec.rb +92 -0
  22. data/spec/hash_model/hash_model_group_spec.rb +67 -0
  23. data/spec/hash_model/hash_model_searching_spec.rb +245 -0
  24. data/spec/hash_model/hash_model_spec.rb +1 -1
  25. data/spec/hash_model/hash_model_unflattening_spec.rb +34 -0
  26. data/spec/hash_model/hash_model_update_spec.rb +147 -0
  27. data/spec/hash_model/hash_model_where_spec.rb +287 -0
  28. data/spec/support/configuration.rb +50 -0
  29. data/spec/support/debug_print.rb +13 -0
  30. data/spec/support/proc_tester.rb +17 -0
  31. metadata +49 -27
  32. data/_brainstorm/StrangeMarshal.txt +0 -0
  33. data/_brainstorm/_readme +0 -1
  34. data/_brainstorm/block_wheres.rb +0 -80
  35. data/_brainstorm/clone.rb +0 -19
  36. data/_brainstorm/hash_model_examples.rb +0 -57
  37. data/_brainstorm/hash_test.rb +0 -169
  38. data/_brainstorm/inspect.rb +0 -26
  39. data/_brainstorm/instance_vars.rb +0 -24
  40. data/_brainstorm/proc_tests.rb +0 -14
  41. data/_brainstorm/ref_val.rb +0 -16
  42. data/_brainstorm/regex_captures.rb +0 -18
  43. data/_brainstorm/spliting.rb +0 -46
  44. data/_brainstorm/test.rb +0 -27
  45. data/_brainstorm/unflat.rb +0 -16
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hashmodel (0.4.0)
4
+ hashmodel (0.4.0.beta2)
5
5
  file-tail
6
6
  sourcify
7
7
 
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Mike Bethany
1
+ Copyright (c) 2011 Mike Bethany
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -4,9 +4,9 @@ A simple MVC type model class for storing deeply nested hashes as records.
4
4
  It's meant to be used for small, in-memory recordset that you want an easy, flexible way to query.
5
5
  It is not meant as a data storage device for managing huge datasets.
6
6
 
7
- ## Synopsis
7
+ ## Synopsis ##
8
8
 
9
- The major usefulness of this class is it allows you to filter and search flattened records based on any field. You can even updated and delete data now.
9
+ The major usefulness of this class is it allows you to filter and search flattened records based on any field. You can even updated and delete data now! Exclamation!
10
10
 
11
11
  A field can contain anything, including another hash, a string, an array, or even an Object class like String or Array, not just an instance of an Object class.
12
12
 
@@ -14,7 +14,7 @@ Searches are very simple and logical. You can search using just using the value
14
14
 
15
15
  require 'hashmodel'
16
16
  records = [
17
- {:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
17
+ {:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff"},
18
18
  {:switch => ["-y", "--why"], :description => "lucky what?"},
19
19
  {:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
20
20
  ]
@@ -22,34 +22,50 @@ Searches are very simple and logical. You can search using just using the value
22
22
  found = hash_model.where("-x") => Returns an array of flattened records
23
23
 
24
24
 
25
- Or more powerfully you can search using boolean like logic e.g.
25
+ Or more powerfully you can search using boolean like logic with dynamic variables:
26
26
 
27
- hash_model = HashModel.new(:raw_data=>records)
28
- found = hash_model.where {:switch == "-x" && :parameter__type == String} => Returns an array of flattened records
27
+ x = "-x"
28
+ param_type = String
29
+ found = hash_model.where {:switch == x && :parameter__type == param_type} => Returns an array of flattened records
30
+
31
+ If you want to update a record in place you can do that as well:
32
+
33
+ x = "-x"
34
+ param_type = String
35
+ updated = hash_model.update!(x, :parameter__type => param_type) => Returns an array of flattened records
36
+
37
+ For more info checkout the rdocs and also checkout the change history below. I go in-depth on the new method calls.
38
+
39
+ ## Status ##
29
40
 
41
+ 2011.03.19 - Beta: 0.4.0.beta2
30
42
 
31
- ## Status
43
+ Lots of changes with this one. The major changes are the ability to write to the HashModel data. See Version History for details.
32
44
 
33
- 2011.03.19 - Beta: 0.4.0.beta01
45
+ I fixed a **huge** bug that caused variables not to be ignored in boolean searches. It's all fixed now and there are specs to prove make sure it doesn't happen again.
34
46
 
35
- Lots of changes with this one. Mostly the ability to write to the HashModel and a few bug fixes. See Version History for details.
47
+ ## Demo App ##
36
48
 
37
- ## Usage
49
+ Check out Widget for a demo of just how easy it is to use HashModel. It now has a lot of complexity but it's a breeze to use:
50
+
51
+ https://github.com/mikbe/widget
52
+
53
+ ## Usage ##
38
54
 
39
55
  I've covered most of the major stuff here but to see all of the functionality take a look at the RSpec files.
40
56
 
41
57
  ### **Creating with an array of hashes**
42
58
  require 'hashmodel'
43
59
  records = [
44
- {:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
60
+ {:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff"},
45
61
  {:switch => ["-y", "--why"], :description => "lucky what?"},
46
62
  {:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
47
63
  ]
48
64
  hash_model = HashModel.new(:raw_data=>records)
49
65
 
50
66
  puts hash_model
51
- >> {:switch=>"-x", :parameter=>{:type=>String, :require=>true}, :description=>"Xish stuff", :_id=>0, :_group_id=>0}
52
- >> {:switch=>"--xtended", :parameter=>{:type=>String, :require=>true}, :description=>"Xish stuff", :_id=>1, :_group_id=>0}
67
+ >> {:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>0, :_group_id=>0}
68
+ >> {:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>1, :_group_id=>0}
53
69
  >> {:switch=>"-y", :description=>"lucky what?", :_id=>2, :_group_id=>1}
54
70
  >> {:switch=>"--why", :description=>"lucky what?", :_id=>3, :_group_id=>1}
55
71
  >> {:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>4, :_group_id=>2}
@@ -73,7 +89,7 @@ I've covered most of the major stuff here but to see all of the functionality ta
73
89
  # You can also add another HashModel object to the existing one
74
90
  # and it will add the raw records and reflatten.
75
91
  records = [
76
- {:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
92
+ {:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff"},
77
93
  {:switch => ["-y", "--why"], :description => "lucky what?"}
78
94
  ]
79
95
 
@@ -91,14 +107,14 @@ I've covered most of the major stuff here but to see all of the functionality ta
91
107
  # You can always edit and access the raw data via the raw_data property accessor
92
108
  # When you make changes to the raw_data the HashModel will automatically be updated.
93
109
  records = [
94
- {:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
110
+ {:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff"},
95
111
  {:switch => ["-y", "--why"], :description => "lucky what?"},
96
112
  {:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
97
113
  ]
98
114
  hash_model = HashModel.new(:raw_data=>records)
99
115
 
100
116
  puts hash_model.raw_data
101
- >> {:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"}
117
+ >> {:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff"}
102
118
  >> {:switch => ["-y", "--why"], :description => "lucky what?"}
103
119
  >> {:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"}
104
120
 
@@ -196,7 +212,7 @@ I've covered most of the major stuff here but to see all of the functionality ta
196
212
  hash_model << {:switch=>"-x", :parameter__type=>String, :parameter__require=>true, :description=>"Xish stuff"}
197
213
 
198
214
  puts hash_model.raw_data
199
- >> {:switch => "-x", :parameter => {:type => String, :require => true}, :description => "Xish stuff"}
215
+ >> {:switch => "-x", :parameter => {:type => String, :required => true}, :description => "Xish stuff"}
200
216
 
201
217
  # You can also call the unflatten method on an instance or the class itself and send it a record. (It won't mess with the existing data.)
202
218
  deep_hash = {
@@ -212,19 +228,28 @@ I've covered most of the major stuff here but to see all of the functionality ta
212
228
  unflat = HashModel.unflatten(deep_hash)
213
229
 
214
230
  puts unflat
215
- >> {:parameter=>[{:type=>String}, "glorp", {:require=>true}], :switch=>[{:deep1=>{:deep3=>"deepTwo"}}, {:deep2=>"deepTwo"}, "--xtend"], :description=>"Xish stuff"}
231
+ >> {:parameter=>[{:type=>String}, "glorp", {:required=>true}], :switch=>[{:deep1=>{:deep3=>"deepTwo"}}, {:deep2=>"deepTwo"}, "--xtend"], :description=>"Xish stuff"}
216
232
 
217
233
 
218
234
  ## Version History ##
219
235
 
220
- 0.4.0.beta01 - 2011.03-19
236
+ 0.4.0.beta2 - 2011.03-21
221
237
 
222
238
  Lots of updates and code fixes for this release. After using it for a little while I've broken down and added the write functionality I was avoiding previously.
223
239
 
240
+ I fixed a **major** bug/design flaw that didn't let you use variables in a boolean block. For instance this was supposed to work but didn't:
241
+
242
+ x = "-x"
243
+ hm.where{:x == x}
244
+
245
+ It works properly now.
246
+
224
247
  **Additions/Changes**
225
248
 
226
249
  #### Methods: `update` and `update!` methods ####
227
- These methods use a `where` like search that is slightly different. The methods look like this `update(default_index_search, field_new_value_hash, boolean_search_block)`. So if you search using a single value, a default index search, then you put the update hashes at the end. If you want to search using a boolean search then you put the update hashes at the beginning.
250
+ These methods use a `where` like search that is slightly different. As you would expect the `update` method returns a changed copy of the HashModel while `update!` changes the data in place.
251
+
252
+ The methods look like this `update(default_index_search, field_new_value_hash, boolean_search_block)`. So if you search using a single value, a default index search, then you put the update hashes at the end. If you want to search using a boolean search then you put the update hashes at the beginning.
228
253
 
229
254
  For instance:
230
255
 
@@ -234,17 +259,29 @@ For instance:
234
259
  # Boolean search
235
260
  my_hash_model.update(:parameter__type=>Fixnum) {:switch == "-x"}
236
261
 
237
- You don't have to put in any search criteria at all though, you can just put in the field you want updated and it will update all records that are in the current filter set.
238
262
 
263
+ You can update more than one field at a time as well. When you do this make sure you wrap them in hash markers {}:
239
264
 
240
- #### Methods: `update` and `update!` methods ####
241
- Just like `update` and `update!` but will also add a hash if it doesn't exist already.
265
+ my_hash_model.update("-x", {:field_1=>"new value", :field_2=>"another new value"})
242
266
 
243
- For instance if your HashModel has a record like `{:a=>"a"}` and you do `my_hash_model.update(:b=>"b")` it won't change that record, but it you do `my_hash_model.update_and_add(:b=>"b")` then your record will be `{:a=>'a', :b=>"b"}`.
244
267
 
268
+ It's important to note that searches in an `update` will search the entire recordset. i.e. they will ignore the current filter. They will reset that filter when they are done so if you change the value of the primary index then you'll have an empty recordset. I realize it would be better to make the filters additive, and I will, but that will have to wait for the next update.
269
+
270
+ You don't have to put in any search criteria at all though, you can just put in the field you want updated and it will update all records that are in the current filter set.
271
+
272
+ my_hash_model.update(:field_1=>"new value")
273
+
274
+ All of the `update` methods will return the records that were updated with the updates in place. If no records were updated then it will return an empty array. It currently returns the raw records that are or would be deleted but I will be changing it to return the flattened records. That will be in the next update.
275
+
276
+ #### Methods: `update_and_add` and `update_and_add!` methods ####
277
+ Just like `update` and `update!` but will also add a hash if it doesn't exist already. Again the ! method changes the records in place.
278
+
279
+ For instance if your HashModel has a record like `{:a=>"a"}` and you do `my_hash_model.update(:b=>"b")` it won't change that record, but it you do `my_hash_model.update_and_add(:b=>"b")` then your record will be `{:a=>'a', :b=>"b"}`.
245
280
 
246
281
  #### Methods: `delete` and `delete!` ####
247
- These use a the standard `where` type search used everywhere else. This function removes data from the raw data so if you have other flattened records that are based on that raw data they will no longer exist since the data that generated them is gone.
282
+ These use the standard `where` type search used everywhere else. You guessed it, the `delete!` method deletes in place while the `delete` method returns the records that would be deleted.
283
+
284
+ This function removes data from the raw data so if you have other flattened records that are based on that raw data they will no longer exist since the data that generated them is gone.
248
285
 
249
286
  Just like an array these methods return the records they deleted.
250
287
 
@@ -258,7 +295,7 @@ Filter has been changed from a property to a method. It is exactly like a `where
258
295
  Changed to be truly destructive. If you run a where! on the class you're losing records that don't match it. The non-destructive version `where` is changed in that it does not contain the raw data of any records that don't match the `where` clause but the original HashModel remains untouched.
259
296
 
260
297
  #### Removed: `group!` ####
261
- Since bangs (!) are all now destructive, to bring the class inline with Ruby standards, it doesn't make logical sense to have a a group method that deletes all data except the search data then tries to find siblings; they were just deleted with the destructive call. Instead just use `group` and it will return the sibling records without touching the data in the HashModel.
298
+ Since bangs (!) are all now destructive, to bring the class inline with Ruby standards, it doesn't make logical sense to have a a group method that deletes all data except the search data then tries to find siblings; they would have been deleted with the destructive call. Instead just use `group` and it will return the sibling records without touching the data in the HashModel.
262
299
 
263
300
  #### Other changes ####
264
301
  Because of the new destructive methods all input values will be cloned. You don't have to worry about cloning input objects yourself. If it's clonable HashModel will clone it.
@@ -267,7 +304,8 @@ I've reorganized the code into multiple files based on functionality to make it
267
304
 
268
305
  Cleaned up RSpecs a little along the lines of reorganization.
269
306
 
270
- #### Bug fixes ####
307
+ #### Bugs fixed ####
308
+ * Didn't use variable in where searches.
271
309
  * Threw error if you searched an empty HashModel (can't build a flatten index on nothing)
272
310
  * Couldn't change the flatten index in some rare cases.
273
311
 
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.email = ["mikbe.tk@gmail.com"]
11
11
  s.homepage = "http://github.com/mikbe/hashmodel"
12
12
  s.summary = %q{Store nested hashes as records and easily search them (even nested ones)}
13
- s.description = %q{A simple MVC type model class for storing records based on nested hashes as an array of hashes. You can store deeply nested hashes and still easily flatten and query the records using flattened field names.}
13
+ s.description = %q{A hash based MVC model class that makes searching and updating deeply nested hashes a breeze. You can store deeply nested hashes and still easily flatten, query, and update the records using flattened field names.}
14
14
 
15
15
  s.add_dependency "sourcify"
16
16
  s.add_dependency "file-tail"
@@ -4,7 +4,8 @@ require 'hash_model/hash_model_group'
4
4
  require 'hash_model/hash_model_filter'
5
5
  require 'hash_model/hash_model_update'
6
6
  require 'hash_model/hash_model_where'
7
-
7
+ require 'hash_model/hash_model_flatten'
8
+ require 'hash_model/hash_model_create_object'
8
9
 
9
10
  # A simple MVC type model class for storing hashes as flattenable, searchable records
10
11
  class HashModel
@@ -19,7 +20,7 @@ class HashModel
19
20
 
20
21
  # Set values given as hashes
21
22
  parameters.each { |key,value|
22
- instance_variable_set("@#{key}", smart_clone(value)) }
23
+ instance_variable_set("@#{key}", value.deep_clone) }
23
24
 
24
25
  # Allow a single hash to be added with :raw_data
25
26
  @raw_data = [@raw_data] if @raw_data.class == Hash
@@ -33,7 +34,7 @@ class HashModel
33
34
 
34
35
  ## Properties
35
36
 
36
- attr_accessor :flatten_index, :raw_data, :filter_proc
37
+ attr_accessor :flatten_index, :raw_data, :filter_proc, :filter_binding
37
38
 
38
39
  # Sets field name used to flatten the recordset
39
40
  def flatten_index=(value)
@@ -68,7 +69,7 @@ class HashModel
68
69
  value = [] if value.nil?
69
70
  raise SyntaxError, "Raw data may only be an array of hashes" if value.class != Array
70
71
  check_field_names(value)
71
- @raw_data = smart_clone(value)
72
+ @raw_data = value.deep_clone
72
73
  flatten
73
74
  end
74
75
 
@@ -96,15 +97,17 @@ class HashModel
96
97
  @unflatten_data = []
97
98
  @flatten_index = nil
98
99
  @filter_proc = nil
100
+ @filter_binding = nil
99
101
  end
100
102
 
101
103
  # Force internal arrays and variables to be cloned
102
104
  def clone
103
105
  return self if @raw_data.empty?
104
106
  flatten
105
- hm = HashModel.new(:raw_data=>@raw_data.clone)
106
- hm.flatten_index = @flatten_index
107
- hm.filter_proc = @filter_proc
107
+ hm = HashModel.new(:raw_data=>@raw_data.deep_clone)
108
+ hm.flatten_index = @flatten_index.clone
109
+ hm.filter_proc = @filter_proc.clone
110
+ hm.filter_binding = @filter_binding
108
111
  hm
109
112
  end
110
113
 
@@ -113,7 +116,7 @@ class HashModel
113
116
  # Overload Array#<< function so we can create the flatten index as the first record is added.
114
117
  # This also allows us to send back this instance of the HashModel instead of an array.
115
118
  def <<(value)
116
- value = smart_clone(value)
119
+ value = value.deep_clone
117
120
  case value
118
121
  when HashModel
119
122
  @raw_data.concat(value.raw_data)
@@ -188,60 +191,12 @@ class HashModel
188
191
  end
189
192
 
190
193
  # Find the raw data record based on the search criteria
191
- def parents(index_search=nil, &block_search)
194
+ def parents(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, &block_search)
192
195
  flat_records = where(index_search, &block_search)
193
196
  flat_records.collect{|flat| @raw_data[flat[:_group_id]]}.uniq
194
197
  end
195
198
 
196
- # Set the array value for self to the flattened hashes based on the flatten_index
197
- def flatten
198
- # Don't flatten the data if we don't need to
199
- return self unless dirty?
200
-
201
- id = -1
202
- group_id = -1
203
- @modified_data.clear
204
- # set the flatten index if this is the first time the function is called
205
- @flatten_index = @raw_data[0].keys[0] if @raw_data != [] && @flatten_index.nil?
206
- flatten_index = @flatten_index.to_s
207
-
208
-
209
- # Change the filter so it looks for variables instead of symbols
210
- unless @filter_proc.nil?
211
- proc_filter = @filter_proc.clone
212
- proc_filter.scan(/(:\S+) ==/).each {|match| proc_filter.sub!(match[0], match[0].sub(":","@"))}
213
- proc_filter.sub!(":_group_id", "@_group_id")
214
- proc_filter = "proc { #{proc_filter} }.call"
215
- end
216
- #dp "newfilter: #{proc_filter}"
217
-
218
-
219
- # Flatten and filter the raw data
220
- @raw_data.each do |record|
221
- new_records, duplicate_data = flatten_hash(record, flatten_index)
222
- # catch raw data records that don't have the flatten index
223
- new_records << {@flatten_index.to_sym=>nil} if new_records.empty?
224
- group_id += 1
225
- new_records.collect! do |new_record|
226
- # Double bangs aren't needed but are they more efficient?
227
- new_record.merge!( duplicate_data.merge!( { :_id=>(id+=1), :_group_id=>group_id } ) )
228
- end
229
-
230
- # Add the records to modified data if they pass the filter
231
- new_records.each do |new_record|
232
- #dp "rec: #{new_record}"
233
- unless @filter_proc.nil?
234
- flat = create_object_from_flat_hash(new_record)
235
- @modified_data << new_record if flat.instance_eval proc_filter
236
- else
237
- @modified_data << new_record
238
- end
239
- end
240
199
 
241
- end # raw_data.each
242
- set_dirty_hash
243
- self
244
- end # flatten
245
200
 
246
201
  # If the hash_model has been changed but not flattened
247
202
  def dirty?
@@ -409,18 +364,10 @@ class HashModel
409
364
 
410
365
  # Add records for matching flatten fields and save duplicate record data for later addition to each record.
411
366
  input.each do |key, value|
412
- #puts "\nkey: #{key}; value: #{value}"
413
367
  flat_key = "#{parent_key}#{"__" if !parent_key.nil?}#{key}"
414
-
415
- #puts "flat_key: #{flat_key}"
416
- #puts "flat_index: #{flatten_index}"
417
-
418
368
  flat_key_starts_with_flatten_index = flat_key.start_with?("#{flatten_index}__")
419
369
  flatten_index_starts_with_flat_key = flatten_index.start_with?(flat_key)
420
-
421
- #puts "flat_key_starts_with_flatten_index: #{flat_key_starts_with_flatten_index}"
422
- #puts "flatten_index_starts_with_flat_key: #{flatten_index_starts_with_flat_key}"
423
-
370
+
424
371
  # figure out what we need to do based on where we're at in the record's value tree and man does it look ugly
425
372
  if flat_key == flatten_index
426
373
  # go deeper
@@ -454,30 +401,6 @@ class HashModel
454
401
  return recordset, duplicate_data
455
402
  end # flatten_hash
456
403
 
457
- # Creates an object with instance variables for each field at every level
458
- # This allows using a block like {:field1==true && :field2_subfield21="potato"}
459
- def create_object_from_flat_hash(record, hash_record=Class.new.new, parent_key=nil)
460
-
461
- # Iterate through the record creating the object recursively
462
- case record
463
- when Hash
464
- record.each do |key, value|
465
- flat_key = "#{parent_key}#{"__" if !parent_key.nil?}#{key}"
466
- hash_record.instance_variable_set("@#{flat_key}", value)
467
- hash_record = create_object_from_flat_hash(value, hash_record, flat_key)
468
- end
469
- when Array
470
- hash_record.instance_variable_set("@#{parent_key}", record)
471
- record.each do |value|
472
- hash_record = create_object_from_flat_hash(value, hash_record, parent_key) if value.class == Hash
473
- end
474
- else
475
- hash_record.instance_variable_set("@#{parent_key}", record)
476
- end # case
477
-
478
- hash_record
479
- end # create_object_from_flat_hash
480
-
481
404
  # Deal with the array methods allowing multiple functions to use the same code
482
405
  # You couldn't do this with alias because you can't tell what alias is used.
483
406
  #
@@ -517,20 +440,5 @@ class HashModel
517
440
  end
518
441
  end
519
442
 
520
- # It's annoying to raise an error if an object can't
521
- # be cloned, like in the case of symbols, It is much
522
- # more friendly, and less surprising too, just to
523
- # return the same object so you can go about your work.
524
- # The only reason I clone is to protect the values, if
525
- # the values don't need to be protected I don't want an
526
- # annoying error message hosing up my whole day. </rant>
527
- def smart_clone(object)
528
- # Stupid error trapping
529
- begin
530
- object.clone
531
- rescue
532
- object
533
- end
534
- end
535
443
 
536
444
  end # HashModel
@@ -0,0 +1,62 @@
1
+ class HashModel
2
+
3
+ # Creates an object with instance variables for each field at every level
4
+ # This allows using a block like {:field1==true && :field2_subfield21="potato"}
5
+ def create_object_from_flat_hash_old(record, hash_record=Class.new.new, parent_key=nil)
6
+
7
+ # Iterate through the record creating the object recursively
8
+ case record
9
+ when Hash
10
+ record.each do |key, value|
11
+ flat_key = "#{parent_key}#{"__" if !parent_key.nil?}#{key}"
12
+ hash_record.instance_variable_set("@#{flat_key}", value)
13
+ hash_record = create_object_from_flat_hash(value, hash_record, flat_key)
14
+ end
15
+ when Array
16
+ hash_record.instance_variable_set("@#{parent_key}", record)
17
+ record.each do |value|
18
+ hash_record = create_object_from_flat_hash(value, hash_record, parent_key) if value.class == Hash
19
+ end
20
+ else
21
+ hash_record.instance_variable_set("@#{parent_key}", record)
22
+ end # case
23
+ hash_record
24
+ end # create_object_from_flat_hash
25
+
26
+ def create_value_string(record)
27
+ variables_string = ""
28
+ remove_string = ""
29
+ variables_array, remove_array = create_wide_values(record)
30
+ variables_array.each{|record|variables_string+="@#{record};"}
31
+ remove_array.each{|record|remove_string+="remove_instance_variable(:@#{record});"}
32
+ [variables_string,remove_string]
33
+ end
34
+
35
+ # Creates an object with instance variables for each field at every level
36
+ # This allows using a block like {:field1==true && :field2_subfield21="potato"}
37
+ def create_wide_values(record, variable_array=[], remove_array=[], parent_key=nil)
38
+ # Iterate through the record creating the object recursively
39
+ case record
40
+ when Hash
41
+ record.each do |key, value|
42
+ flat_key = "#{parent_key}#{"__" if !parent_key.nil?}#{key}"
43
+ if value
44
+ variable_array << "#{flat_key}=#{value.inspect}"
45
+ remove_array << "#{flat_key}"
46
+ end
47
+ variable_array, remove_array = create_wide_values(value, variable_array, remove_array, flat_key)
48
+ end
49
+ when Array
50
+ variable_array << "#{parent_key}=#{record.inspect}"
51
+ remove_array << "#{parent_key}"
52
+ record.each do |value|
53
+ variable_array, remove_array = create_wide_values(value, variable_array, remove_array, parent_key) if value.class == Hash
54
+ end
55
+ else
56
+ variable_array << "#{parent_key}=#{record.inspect}"
57
+ remove_array << "#{parent_key}"
58
+ end # case
59
+ [variable_array.uniq, remove_array.uniq]
60
+ end
61
+
62
+ end