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.
- data/Gemfile.lock +1 -1
- data/LICENSE.txt +1 -1
- data/README.markdown +65 -27
- data/hashmodel.gemspec +1 -1
- data/lib/hash_model/hash_model.rb +13 -105
- data/lib/hash_model/hash_model_create_object.rb +62 -0
- data/lib/hash_model/hash_model_delete.rb +13 -0
- data/lib/hash_model/hash_model_filter.rb +37 -0
- data/lib/hash_model/hash_model_flatten.rb +47 -0
- data/lib/hash_model/hash_model_group.rb +18 -0
- data/lib/hash_model/hash_model_update.rb +118 -0
- data/lib/hash_model/hash_model_where.rb +27 -0
- data/lib/hash_model/version.rb +1 -1
- data/lib/hashmodel.rb +1 -0
- data/lib/monkey_patch/deep_clone.rb +27 -0
- data/spec/hash_model/_current_spec.rb +6 -0
- data/spec/hash_model/hash_model_adding_records_spec.rb +338 -0
- data/spec/hash_model/hash_model_array_methods_spec.rb +132 -0
- data/spec/hash_model/hash_model_comparisons_spec.rb +55 -0
- data/spec/hash_model/hash_model_delete_spec.rb +51 -0
- data/spec/hash_model/hash_model_flattening_spec.rb +92 -0
- data/spec/hash_model/hash_model_group_spec.rb +67 -0
- data/spec/hash_model/hash_model_searching_spec.rb +245 -0
- data/spec/hash_model/hash_model_spec.rb +1 -1
- data/spec/hash_model/hash_model_unflattening_spec.rb +34 -0
- data/spec/hash_model/hash_model_update_spec.rb +147 -0
- data/spec/hash_model/hash_model_where_spec.rb +287 -0
- data/spec/support/configuration.rb +50 -0
- data/spec/support/debug_print.rb +13 -0
- data/spec/support/proc_tester.rb +17 -0
- metadata +49 -27
- data/_brainstorm/StrangeMarshal.txt +0 -0
- data/_brainstorm/_readme +0 -1
- data/_brainstorm/block_wheres.rb +0 -80
- data/_brainstorm/clone.rb +0 -19
- data/_brainstorm/hash_model_examples.rb +0 -57
- data/_brainstorm/hash_test.rb +0 -169
- data/_brainstorm/inspect.rb +0 -26
- data/_brainstorm/instance_vars.rb +0 -24
- data/_brainstorm/proc_tests.rb +0 -14
- data/_brainstorm/ref_val.rb +0 -16
- data/_brainstorm/regex_captures.rb +0 -18
- data/_brainstorm/spliting.rb +0 -46
- data/_brainstorm/test.rb +0 -27
- data/_brainstorm/unflat.rb +0 -16
data/Gemfile.lock
CHANGED
data/LICENSE.txt
CHANGED
data/README.markdown
CHANGED
@@ -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, :
|
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
|
25
|
+
Or more powerfully you can search using boolean like logic with dynamic variables:
|
26
26
|
|
27
|
-
|
28
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
47
|
+
## Demo App ##
|
36
48
|
|
37
|
-
|
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, :
|
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, :
|
52
|
-
>> {:switch=>"--xtended", :parameter=>{:type=>String, :
|
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, :
|
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, :
|
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, :
|
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, :
|
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", {:
|
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.
|
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.
|
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
|
-
|
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
|
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
|
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
|
-
####
|
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
|
|
data/hashmodel.gemspec
CHANGED
@@ -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
|
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}",
|
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 =
|
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.
|
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 =
|
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
|
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
|