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
@@ -0,0 +1,13 @@
|
|
1
|
+
class HashModel
|
2
|
+
|
3
|
+
# Returns a copy of the HashModel with raw data deleted based on the search criteria
|
4
|
+
def delete(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, &block_search)
|
5
|
+
self.clone.delete!(index_search, &block_search)
|
6
|
+
end
|
7
|
+
|
8
|
+
# Deletes the raw data records based on the search criteria
|
9
|
+
def delete!(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, &block_search)
|
10
|
+
parents(index_search, &block_search).each{|parent| @raw_data.delete(parent)}
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class HashModel
|
2
|
+
|
3
|
+
|
4
|
+
# Filter the flattened records based on the value of the
|
5
|
+
# default index or by using a boolean logic block:
|
6
|
+
# filter("x")
|
7
|
+
# filter{:x==4 and :y!="potato"}
|
8
|
+
def filter(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, &block_search)
|
9
|
+
# Parameter checks
|
10
|
+
raise SyntaxError, "You may only provide a parameter or a block but not both" unless index_search==:DontSearchForThis_195151c48a254db2949ed102c81ec579 or block_search.nil?
|
11
|
+
return self if @raw_data.empty?
|
12
|
+
|
13
|
+
# Allow clearing the filter and returning the entire recordset if nothing is given
|
14
|
+
if index_search == :DontSearchForThis_195151c48a254db2949ed102c81ec579 && block_search.nil?
|
15
|
+
@filter_proc = nil
|
16
|
+
@filter_binding = nil
|
17
|
+
return flatten
|
18
|
+
end
|
19
|
+
|
20
|
+
# If given a parameter make our own search based on the flatten index
|
21
|
+
unless index_search == :DontSearchForThis_195151c48a254db2949ed102c81ec579
|
22
|
+
string_search = "(:#{@flatten_index} == #{index_search.inspect})".to_s # << the to_s makes sure it's evaluated now
|
23
|
+
@filter_binding = nil
|
24
|
+
else
|
25
|
+
# Convert the proc to a string so it can have :'s turned into @'s
|
26
|
+
# We only want the internals so we can write the proc the way we want
|
27
|
+
string_search = block_search.to_source(:strip_enclosure => true)
|
28
|
+
@filter_binding = block_search.binding
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set and process the filter
|
32
|
+
@filter_proc = string_search
|
33
|
+
flatten
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class HashModel
|
2
|
+
|
3
|
+
# Processes the raw_data and flattens the records based on the filter (set by filter or a where search)
|
4
|
+
def flatten
|
5
|
+
# Don't flatten the data if we don't need to
|
6
|
+
return self unless dirty?
|
7
|
+
|
8
|
+
id = -1
|
9
|
+
group_id = -1
|
10
|
+
@modified_data.clear
|
11
|
+
# set the flatten index if this is the first time the function is called
|
12
|
+
@flatten_index = @raw_data[0].keys[0] if @raw_data != [] && @flatten_index.nil?
|
13
|
+
flatten_index = @flatten_index.to_s
|
14
|
+
# Change the filter so it looks for variables instead of symbols
|
15
|
+
unless @filter_proc.nil?
|
16
|
+
proc_filter = @filter_proc.clone
|
17
|
+
proc_filter.scan(/(:\S+) ==/).each {|match| proc_filter.sub!(match[0], match[0].sub(":","@"))}
|
18
|
+
proc_filter.sub!(":_group_id", "@_group_id")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Flatten and filter the raw data
|
22
|
+
@raw_data.each do |record|
|
23
|
+
new_records, duplicate_data = flatten_hash(record, flatten_index)
|
24
|
+
# catch raw data records that don't have the flatten index
|
25
|
+
new_records << {@flatten_index.to_sym=>nil} if new_records.empty?
|
26
|
+
group_id += 1
|
27
|
+
new_records.collect! do |new_record|
|
28
|
+
# Double bangs aren't needed but are they more efficient?
|
29
|
+
new_record.merge!( duplicate_data.merge!( { :_id=>(id+=1), :_group_id=>group_id } ) )
|
30
|
+
end
|
31
|
+
|
32
|
+
# Add the records to modified data if they pass the filter
|
33
|
+
new_records.each do |new_record|
|
34
|
+
unless @filter_proc.nil?
|
35
|
+
variables_string, remove_string = create_value_string(new_record)
|
36
|
+
@modified_data << new_record if eval("#{variables_string}return_value=#{proc_filter};#{remove_string}return_value", @filter_binding)
|
37
|
+
else
|
38
|
+
@modified_data << new_record
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end # raw_data.each
|
43
|
+
set_dirty_hash
|
44
|
+
self
|
45
|
+
end # flatten
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class HashModel
|
2
|
+
|
3
|
+
# Return the other records created from the same raw data record as the one(s) searched for
|
4
|
+
def group(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, &block_search)
|
5
|
+
group_hm = self.clone
|
6
|
+
# Filter the recordset if applicable
|
7
|
+
if !index_search.nil? || !block_search.nil?
|
8
|
+
group_hm.filter(index_search, &block_search)
|
9
|
+
end
|
10
|
+
# Get all the unique group id's
|
11
|
+
group_ids = group_hm.collect {|hash| hash[:_group_id]}.uniq
|
12
|
+
# reset the filter
|
13
|
+
group_hm.filter
|
14
|
+
group_hm.filter_proc = "#{group_ids.to_s}.include? :_group_id"
|
15
|
+
group_hm.flatten
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
class HashModel
|
2
|
+
|
3
|
+
# Returns a copy of the HashModel that matches the search criteria
|
4
|
+
# updated using the update_hash. This affects the raw_data.
|
5
|
+
def update(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, update_hash, &block_search)
|
6
|
+
self.clone.update!(index_search, update_hash, &block_search)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Destructively updates the raw data for the records that match the
|
10
|
+
# search criteria. Since this affects the raw_data so if more than one record
|
11
|
+
# is based on the raw_data that's changed that record will be changed too.
|
12
|
+
# Returns the records that were updated.
|
13
|
+
def update!(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, update_hash, &block_search)
|
14
|
+
|
15
|
+
# only filter if they sent something to be filter otherwise leave the filter alone
|
16
|
+
unless index_search == :DontSearchForThis_195151c48a254db2949ed102c81ec579 && block_search.nil?
|
17
|
+
old_filter = @filter_proc
|
18
|
+
old_binding = @filter_binding
|
19
|
+
filter(index_search, &block_search)
|
20
|
+
end
|
21
|
+
|
22
|
+
changed = recursive_update_root(update_hash)
|
23
|
+
|
24
|
+
if old_filter
|
25
|
+
@filter_proc = old_filter
|
26
|
+
@filter_binding = old_binding
|
27
|
+
flatten
|
28
|
+
end
|
29
|
+
|
30
|
+
changed
|
31
|
+
end
|
32
|
+
|
33
|
+
# Updates existing hashes with a given value and also
|
34
|
+
# adds the full root to the key if it doesn't already exist.
|
35
|
+
# Returns a new instance of the original HashModel
|
36
|
+
def update_and_add(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, update_hash, &block_search)
|
37
|
+
self.clone.update_and_add!(index_search, update_hash, &block_search)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Updates existing hashes with a given value and also
|
41
|
+
# adds the full root to the key if it doesn't already exist.
|
42
|
+
# Destructively updated the existing HashModel
|
43
|
+
def update_and_add!(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, update_hash, &block_search)
|
44
|
+
|
45
|
+
# only filter if they sent something to be filter otherwise leave the filter alone
|
46
|
+
unless index_search == :DontSearchForThis_195151c48a254db2949ed102c81ec579 && block_search.nil?
|
47
|
+
old_filter = @filter_proc
|
48
|
+
old_binding = @filter_binding
|
49
|
+
filter(index_search, &block_search)
|
50
|
+
end
|
51
|
+
|
52
|
+
changed = recursive_update_root(update_hash, true)
|
53
|
+
|
54
|
+
if old_filter
|
55
|
+
@filter_proc = old_filter
|
56
|
+
@filter_binding = old_binding
|
57
|
+
flatten
|
58
|
+
end
|
59
|
+
|
60
|
+
changed
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
# Loops through the filtered recordset and sends each record off to be recursivly changed
|
66
|
+
def recursive_update_root(update_hash, add=false)
|
67
|
+
changed_record_ids = []
|
68
|
+
each do |record|
|
69
|
+
save_change = []
|
70
|
+
update_hash.each do |key,value|
|
71
|
+
unflat = unflatten(key=>value)
|
72
|
+
recursive_update_worker(@raw_data[record[:_group_id]], unflat, key, nil, add, record[:_id], save_change)
|
73
|
+
end
|
74
|
+
changed_record_ids << save_change.uniq[0] unless save_change.empty?
|
75
|
+
end
|
76
|
+
# clear the filter so we can get changed records if the filter is
|
77
|
+
# the field that changed (also causes records to update)
|
78
|
+
# This looks ripe for a refactor
|
79
|
+
if @filter_proc
|
80
|
+
old_filter = @filter_proc
|
81
|
+
old_binding = @filter_binding
|
82
|
+
@filter_proc = nil
|
83
|
+
@filter_binding = nil
|
84
|
+
end
|
85
|
+
# now that we've changed the raw data update the values in the flattened records
|
86
|
+
filter
|
87
|
+
# Grab the changed records
|
88
|
+
changed = @modified_data.select{|record| changed_record_ids.include?(record[:_id])}
|
89
|
+
if old_filter
|
90
|
+
@filter_proc = old_filter
|
91
|
+
@filter_binding = old_binding
|
92
|
+
flatten
|
93
|
+
end
|
94
|
+
changed
|
95
|
+
end
|
96
|
+
|
97
|
+
# Loops through the hash that represents the changes to make and recurses into as needed
|
98
|
+
def recursive_update_worker(target_hash, source_hash, terminal_key, parent_key, add, record_id, save_change)
|
99
|
+
source_hash.each do |source_hash_key, source_hash_value|
|
100
|
+
current_key = "#{parent_key}#{"__" if parent_key}#{source_hash_key}".to_sym
|
101
|
+
if current_key == terminal_key
|
102
|
+
return unless target_hash[source_hash_key] or add
|
103
|
+
target_hash[source_hash_key] = source_hash_value
|
104
|
+
save_change << record_id
|
105
|
+
else
|
106
|
+
if target_hash.is_a? Hash
|
107
|
+
recursive_update_worker(target_hash[source_hash_key], source_hash[source_hash_key], terminal_key, current_key, add, record_id, save_change)
|
108
|
+
else
|
109
|
+
if add
|
110
|
+
target_hash = source_hash
|
111
|
+
save_change << record_id
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class HashModel
|
2
|
+
|
3
|
+
# Search creating a new instance of HashModel based on this one
|
4
|
+
def where(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, &block_search)
|
5
|
+
self.clone.where!(index_search, &block_search)
|
6
|
+
end
|
7
|
+
|
8
|
+
# Search the flattened records using the default flatten index or a boolean block
|
9
|
+
def where!(index_search=:DontSearchForThis_195151c48a254db2949ed102c81ec579, &block_search)
|
10
|
+
filter(index_search, &block_search)
|
11
|
+
|
12
|
+
# Delete the raw records that don't have matches
|
13
|
+
good_group_ids = unflatten(@modified_data).collect{|record| record[:_group_id]}.uniq
|
14
|
+
index = -1;
|
15
|
+
@raw_data.delete_if {|record| !good_group_ids.include?(index+=1)}
|
16
|
+
|
17
|
+
# Remove the non-matching values from raw data for the filter_index
|
18
|
+
good_values = self.collect{|record| record[@flatten_index]}
|
19
|
+
@raw_data.each do |record|
|
20
|
+
if record[@flatten_index].is_a? Array
|
21
|
+
record[@flatten_index].delete_if{|value| !good_values.include?(value) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/hash_model/version.rb
CHANGED
data/lib/hashmodel.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
# Make sure there are no references left over
|
4
|
+
def deep_clone
|
5
|
+
Marshal.load(Marshal.dump(self))
|
6
|
+
end
|
7
|
+
|
8
|
+
# It's annoying to raise an error if an object can't
|
9
|
+
# be cloned, like in the case of symbols, It is much
|
10
|
+
# more friendly, and less surprising too, just to
|
11
|
+
# return the same object so you can go about your work.
|
12
|
+
# The only reason I clone is to protect the values, if
|
13
|
+
# the values don't need to be protected I don't want an
|
14
|
+
# annoying error message hosing up my whole day. </rant>
|
15
|
+
#
|
16
|
+
# Note: this is needed so deep_clone can work properly... don't get me started.
|
17
|
+
alias :__stupid_clone__ :clone
|
18
|
+
def clone
|
19
|
+
# I wonder what this will break...
|
20
|
+
begin
|
21
|
+
self.__stupid_clone__
|
22
|
+
rescue
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,338 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HashModel do
|
4
|
+
|
5
|
+
context "when adding records" do
|
6
|
+
|
7
|
+
it "should allow a hash of values to be added" do
|
8
|
+
proc { @hm << {:switch => ["-x", "--xtended"], :description => "Xish stuff"} }.should_not raise_error
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should allow a single hash to be added with :raw_data" do
|
12
|
+
hash = {:switch => ["-x", "--xtended"], :description => "Xish stuff"}
|
13
|
+
@hm = HashModel.new(:raw_data => hash)
|
14
|
+
@hm.raw_data.should == [{:switch=>["-x", "--xtended"], :description=>"Xish stuff"}]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should allow a hash of values to be added using the keyword 'add'" do
|
18
|
+
proc { @hm.add(:switch => ["-x", "--xtended"], :description => "Xish stuff") }.should_not raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should allow an array of hashes to be added as if they were multiple records" do
|
22
|
+
proc { @hm << @records }.should_not raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow another HashModel to be added" do
|
26
|
+
@hm.add(@hm2).should == @flat_records_all
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should add a hash with a symbol as a value" do
|
30
|
+
@hm = HashModel.new
|
31
|
+
@hm << {:switch => :default}
|
32
|
+
@hm.should == [{:switch=>:default, :_id=>0, :_group_id=>0}]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should add an array with mixed value types" do
|
36
|
+
@records = [
|
37
|
+
{:switch => ["-x", "--xtended", :default], :parameter => {:type => String, :required => true}, :description => "Xish stuff"},
|
38
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"},
|
39
|
+
{:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
|
40
|
+
]
|
41
|
+
@hm = HashModel.new(:raw_data=>@records)
|
42
|
+
@hm.should == [
|
43
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>0, :_group_id=>0},
|
44
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>1, :_group_id=>0},
|
45
|
+
{:switch=>:default, :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>2, :_group_id=>0},
|
46
|
+
{:switch=>"-y", :description=>"lucky what?", :_id=>3, :_group_id=>1},
|
47
|
+
{:switch=>"--why", :description=>"lucky what?", :_id=>4, :_group_id=>1},
|
48
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>5, :_group_id=>2}
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should add an array of arrays as values and not recurse into them" do
|
53
|
+
@records = [
|
54
|
+
{ :switch => [ [5, 6], [1, 2] ] }
|
55
|
+
]
|
56
|
+
@hm = HashModel.new(:raw_data=>@records)
|
57
|
+
@hm.should == [{:switch=>[5, 6], :_id=>0, :_group_id=>0}, {:switch=>[1, 2], :_id=>1, :_group_id=>0}]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "shouldn't recurse into arrays with hash values" do
|
61
|
+
@records = [
|
62
|
+
{ :switch => [ [5, 6], [1, :blah=>2] ] }
|
63
|
+
]
|
64
|
+
@hm = HashModel.new(:raw_data=>@records)
|
65
|
+
@hm.should == [{:switch=>[5, 6], :_id=>0, :_group_id=>0}, {:switch=>[1, :blah=>2], :_id=>1, :_group_id=>0}]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should allow an array of HashModels to be added" do
|
69
|
+
@hm.add([@hm, @hm2])
|
70
|
+
@hm.should == [
|
71
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>0, :_group_id=>0},
|
72
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>1, :_group_id=>0},
|
73
|
+
{:switch=>"-y", :description=>"lucky what?", :_id=>2, :_group_id=>1},
|
74
|
+
{:switch=>"--why", :description=>"lucky what?", :_id=>3, :_group_id=>1},
|
75
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>4, :_group_id=>2},
|
76
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>5, :_group_id=>3},
|
77
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>6, :_group_id=>3},
|
78
|
+
{:switch=>"-y", :description=>"lucky what?", :_id=>7, :_group_id=>4},
|
79
|
+
{:switch=>"--why", :description=>"lucky what?", :_id=>8, :_group_id=>4},
|
80
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>9, :_group_id=>5},
|
81
|
+
{:switch=>"-p", :parameter=>{:type=>Hash, :required=>false}, :description=>"Pea soup", :_id=>10, :_group_id=>6},
|
82
|
+
{:switch=>"--pea", :parameter=>{:type=>Hash, :required=>false}, :description=>"Pea soup", :_id=>11, :_group_id=>6},
|
83
|
+
{:switch=>"-q", :description=>"exit the game", :_id=>12, :_group_id=>7},
|
84
|
+
{:switch=>"--quit", :description=>"exit the game", :_id=>13, :_group_id=>7},
|
85
|
+
{:switch=>"-r", :parameter=>{:type=>Fixnum}, :description=>"Arrrrrrrrrrgh!", :_id=>14, :_group_id=>8}
|
86
|
+
]
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should allow field names that are longer versions of other names" do
|
90
|
+
@hm = HashModel.new
|
91
|
+
@hm << {:long => "short", :longer => "long"}
|
92
|
+
@hm.should == [{:long => "short", :longer => "long"}]
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should raise an error if something other than a hash, an array of hashes, or another HashModel (or an array of them) is added" do
|
96
|
+
proc { @hm << ["-x", "--xtended", "Xish stuff"] }.should raise_error
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should allow an array of hashes to be specified when creating the HashModel" do
|
100
|
+
proc { HashModel.new(:raw_data=>@records) }.should_not raise_error
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should retain the raw data used when creating the HashModel" do
|
104
|
+
@hm.raw_data.should == @records
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should return a HashModel object when adding records using <<" do
|
108
|
+
(@hm << @records[0]).class.should == HashModel
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return the same HashModel instance when adding records using <<" do
|
112
|
+
(@hm << @records[0]).object_id.should == @hm.object_id
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should allow chaining of record adds using <<" do
|
116
|
+
proc {@hm << @records[0] << @records[1] << @records[2]}.should_not raise_error
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should contain all of the records when chaining record adds" do
|
120
|
+
@hm = HashModel.new
|
121
|
+
@hm << @records[0] << @records[1] <<@records[2]
|
122
|
+
@hm.raw_data.should == @records
|
123
|
+
end
|
124
|
+
|
125
|
+
context "flattened records" do
|
126
|
+
|
127
|
+
it "should allow a flattened record to be added" do
|
128
|
+
@hm = HashModel.new
|
129
|
+
@hm << {:switch=>"-x", :parameter__type=>String, :parameter__required=>true, :description=>"Xish stuff"}
|
130
|
+
@hm.raw_data.should == [{:switch => "-x", :parameter => {:type => String, :required => true}, :description => "Xish stuff"}]
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should allow a flattened record to be added even with arrays in it" do
|
134
|
+
@hm = HashModel.new
|
135
|
+
@hm << {:switch=>["-x", "--xtend"],
|
136
|
+
:parameter__type=>String,
|
137
|
+
:parameter__required=>true,
|
138
|
+
:description=>"Xish stuff",
|
139
|
+
:field__field2 => {:field3 => "ff3", :field4 => "ff4"}
|
140
|
+
}
|
141
|
+
@hm.raw_data.should == [
|
142
|
+
{
|
143
|
+
:switch => ["-x", "--xtend"],
|
144
|
+
:parameter => {:type => String, :required => true},
|
145
|
+
:description => "Xish stuff",
|
146
|
+
:field => {:field2 => {:field3 => "ff3", :field4 => "ff4"}}
|
147
|
+
}
|
148
|
+
]
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should allow deeply flattened record to be added" do
|
152
|
+
deep_hash = {
|
153
|
+
:parameter__type=>String,
|
154
|
+
:switch__deep1__deep3 => "deepTwo",
|
155
|
+
:parameter__type__ruby=>true,
|
156
|
+
:parameter => "glorp",
|
157
|
+
:parameter__required=>true,
|
158
|
+
:switch__deep2 => "deepTwo",
|
159
|
+
:description=>"Xish stuff",
|
160
|
+
:switch => "--xtend",
|
161
|
+
}
|
162
|
+
@hm = HashModel.new
|
163
|
+
@hm << deep_hash
|
164
|
+
@hm.raw_data.should == [
|
165
|
+
{
|
166
|
+
:parameter => [
|
167
|
+
{:type=>String},
|
168
|
+
"glorp",
|
169
|
+
{:required=>true}
|
170
|
+
],
|
171
|
+
:switch => [
|
172
|
+
{:deep1 => {:deep3=>"deepTwo"}},
|
173
|
+
{:deep2=>"deepTwo"},
|
174
|
+
"--xtend"
|
175
|
+
],
|
176
|
+
:description=>"Xish stuff"
|
177
|
+
}
|
178
|
+
]
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
context "using the + sign" do
|
185
|
+
|
186
|
+
it "should return a HashModel class when adding an Array" do
|
187
|
+
(@hm + @records2).class.should == HashModel
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should return a HashModel class when adding a HashModel" do
|
191
|
+
(@hm + @hm2).class.should == HashModel
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should return a different HashModel instance" do
|
195
|
+
(@hm + @records2).object_id.should_not == @hm.object_id
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should contain the records of both recordsets when adding an Array" do
|
199
|
+
(@hm + @records2).raw_data.should == (@records + @records2)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should contain the records of both recordsets when adding a HashModel" do
|
203
|
+
(@hm + @hm2).raw_data.should == (@records + @records2)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should use the flatten index of the receiver HashModel" do
|
207
|
+
hm2 = HashModel.new
|
208
|
+
hm2 << {:potato=>7}
|
209
|
+
(@hm + hm2).flatten_index.should == :switch
|
210
|
+
(hm2 + @hm).flatten_index.should == :potato
|
211
|
+
end
|
212
|
+
|
213
|
+
end # "when using the plus sign"
|
214
|
+
|
215
|
+
context "using the += sign" do
|
216
|
+
|
217
|
+
it "should return a HashModel class" do
|
218
|
+
(@hm += @records2).class.should == HashModel
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should return the same HashModel instance when using += to add an array" do
|
222
|
+
(@hm += @records2).object_id.should == @hm.object_id
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should contain the records of both recordsets when adding an Array" do
|
226
|
+
@hm += @records2
|
227
|
+
@hm.raw_data.should == (@records + @records2)
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should contain the records of both recordsets when adding a HashModel" do
|
231
|
+
@hm += @hm2
|
232
|
+
@hm.raw_data.should == (@records + @records2)
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should not alter the added HashModel" do
|
236
|
+
proc{@hm += @hm2}.should_not change(@hm2, :raw_data)
|
237
|
+
end
|
238
|
+
|
239
|
+
end # "when using the += sign"
|
240
|
+
|
241
|
+
context "using the * sign" do
|
242
|
+
|
243
|
+
it "should return a HashRecord" do
|
244
|
+
(@hm * 2).class.should == HashModel
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should return a different HashRecord" do
|
248
|
+
(@hm * 2).object_id.should_not == @hm.object_id
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should return a HashModel with twice the amount of raw data if * 2'd" do
|
252
|
+
(@hm * 2).raw_data.should == [
|
253
|
+
{:switch=>["-x", "--xtended"], :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff"},
|
254
|
+
{:switch=>["-y", "--why"], :description=>"lucky what?"},
|
255
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz"},
|
256
|
+
{:switch=>["-x", "--xtended"], :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff"},
|
257
|
+
{:switch=>["-y", "--why"], :description=>"lucky what?"},
|
258
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz"}
|
259
|
+
]
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
context "using the *= sign" do
|
265
|
+
|
266
|
+
it "should return the same HashModel" do
|
267
|
+
(@hm *= 2).object_id.should == @hm.object_id
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should change current raw to twice its old raw data if *= 2'd" do
|
271
|
+
@hm *= 2
|
272
|
+
@hm.should == [
|
273
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>0, :_group_id=>0},
|
274
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>1, :_group_id=>0},
|
275
|
+
{:switch=>"-y", :description=>"lucky what?", :_id=>2, :_group_id=>1},
|
276
|
+
{:switch=>"--why", :description=>"lucky what?", :_id=>3, :_group_id=>1},
|
277
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>4, :_group_id=>2},
|
278
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>5, :_group_id=>3},
|
279
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>6, :_group_id=>3},
|
280
|
+
{:switch=>"-y", :description=>"lucky what?", :_id=>7, :_group_id=>4},
|
281
|
+
{:switch=>"--why", :description=>"lucky what?", :_id=>8, :_group_id=>4},
|
282
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>9, :_group_id=>5}
|
283
|
+
]
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
context "using concat" do
|
289
|
+
|
290
|
+
it "should concatinate using a single Hash" do
|
291
|
+
@hm.concat(@records2[0]).should == [
|
292
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>0, :_group_id=>0},
|
293
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>1, :_group_id=>0},
|
294
|
+
{:switch=>"-y", :description=>"lucky what?", :_id=>2, :_group_id=>1},
|
295
|
+
{:switch=>"--why", :description=>"lucky what?", :_id=>3, :_group_id=>1},
|
296
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>4, :_group_id=>2},
|
297
|
+
{:switch=>"-p", :parameter=>{:type=>Hash, :required=>false}, :description=>"Pea soup", :_id=>5, :_group_id=>3},
|
298
|
+
{:switch=>"--pea", :parameter=>{:type=>Hash, :required=>false}, :description=>"Pea soup", :_id=>6, :_group_id=>3}
|
299
|
+
]
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should concatinate using an array" do
|
303
|
+
@hm.concat(@records2).should == @flat_records_all
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should concatinate using a HashModel" do
|
307
|
+
@hm.concat(@hm2).should == @flat_records_all
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
context "using push" do
|
313
|
+
|
314
|
+
it "should add a single Hash" do
|
315
|
+
@hm.push(@records2[0]).should == [
|
316
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>0, :_group_id=>0},
|
317
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :_id=>1, :_group_id=>0},
|
318
|
+
{:switch=>"-y", :description=>"lucky what?", :_id=>2, :_group_id=>1},
|
319
|
+
{:switch=>"--why", :description=>"lucky what?", :_id=>3, :_group_id=>1},
|
320
|
+
{:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>4, :_group_id=>2},
|
321
|
+
{:switch=>"-p", :parameter=>{:type=>Hash, :required=>false}, :description=>"Pea soup", :_id=>5, :_group_id=>3},
|
322
|
+
{:switch=>"--pea", :parameter=>{:type=>Hash, :required=>false}, :description=>"Pea soup", :_id=>6, :_group_id=>3}
|
323
|
+
]
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should add an array" do
|
327
|
+
@hm.push(@records2).should == @flat_records_all
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should add a HashModel" do
|
331
|
+
@hm.push(@hm2).should == @flat_records_all
|
332
|
+
end
|
333
|
+
|
334
|
+
end
|
335
|
+
|
336
|
+
end # adding records
|
337
|
+
|
338
|
+
end
|