hashmodel 0.2.0 → 0.3.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/Gemfile +1 -8
- data/Gemfile.lock +22 -10
- data/README.markdown +219 -19
- data/Rakefile +1 -43
- data/_brainstorm/block_wheres.rb +80 -0
- data/_brainstorm/clone.rb +19 -0
- data/_brainstorm/hash_model_examples.rb +57 -0
- data/_brainstorm/proc_tests.rb +14 -0
- data/_brainstorm/regex_captures.rb +18 -0
- data/_brainstorm/unflat.rb +16 -0
- data/autotest/discover.rb +0 -2
- data/features/README +1 -1
- data/hashmodel.gemspec +25 -0
- data/lib/hash_model.rb +1 -0
- data/lib/hash_model/hash_model.rb +53 -31
- data/lib/hash_model/version.rb +2 -2
- data/spec/hash_model/hash_model_spec.rb +86 -3
- data/spec/spec_helper.rb +12 -0
- metadata +39 -35
data/.gitignore
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
hashmodel (0.3.0.beta1)
|
5
|
+
file-tail
|
6
|
+
sourcify
|
7
|
+
|
1
8
|
GEM
|
2
9
|
remote: http://rubygems.org/
|
3
10
|
specs:
|
@@ -9,16 +16,11 @@ GEM
|
|
9
16
|
json (~> 1.4.6)
|
10
17
|
term-ansicolor (~> 1.0.5)
|
11
18
|
diff-lcs (1.1.2)
|
19
|
+
file-tail (1.0.5)
|
20
|
+
spruz (>= 0.1.0)
|
12
21
|
gherkin (2.3.3)
|
13
22
|
json (~> 1.4.6)
|
14
|
-
git (1.2.5)
|
15
|
-
jeweler (1.5.2)
|
16
|
-
bundler (~> 1.0.0)
|
17
|
-
git (>= 1.2.5)
|
18
|
-
rake
|
19
23
|
json (1.4.6)
|
20
|
-
rake (0.8.7)
|
21
|
-
rcov (0.9.9)
|
22
24
|
rspec (2.4.0)
|
23
25
|
rspec-core (~> 2.4.0)
|
24
26
|
rspec-expectations (~> 2.4.0)
|
@@ -27,14 +29,24 @@ GEM
|
|
27
29
|
rspec-expectations (2.4.0)
|
28
30
|
diff-lcs (~> 1.1.2)
|
29
31
|
rspec-mocks (2.4.0)
|
32
|
+
ruby2ruby (1.2.5)
|
33
|
+
ruby_parser (~> 2.0)
|
34
|
+
sexp_processor (~> 3.0)
|
35
|
+
ruby_parser (2.0.5)
|
36
|
+
sexp_processor (~> 3.0)
|
37
|
+
sexp_processor (3.0.5)
|
38
|
+
sourcify (0.4.0)
|
39
|
+
ruby2ruby (>= 1.2.5)
|
40
|
+
sexp_processor (>= 3.0.5)
|
41
|
+
spruz (0.2.2)
|
30
42
|
term-ansicolor (1.0.5)
|
31
43
|
|
32
44
|
PLATFORMS
|
33
45
|
ruby
|
34
46
|
|
35
47
|
DEPENDENCIES
|
36
|
-
bundler
|
37
48
|
cucumber
|
38
|
-
|
39
|
-
|
49
|
+
file-tail
|
50
|
+
hashmodel!
|
40
51
|
rspec
|
52
|
+
sourcify
|
data/README.markdown
CHANGED
@@ -11,43 +11,243 @@ model class take a look at ActiveModel, it's probably more of what you're lookin
|
|
11
11
|
## Synopsis
|
12
12
|
|
13
13
|
The major usefulness of this class is it allows you to filter and search flattened records based on any field.
|
14
|
-
A field can contain anything, including another hash, a string,
|
15
|
-
just an instance of an Object class.
|
14
|
+
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.
|
16
15
|
|
17
|
-
You can
|
16
|
+
Searches are very simple and logical. You can search using just using the value of the default index
|
17
|
+
|
18
|
+
records = [
|
19
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
|
20
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"},
|
21
|
+
{:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
|
22
|
+
]
|
23
|
+
hm = HashModel.new(:raw_data=>records)
|
24
|
+
found = hm.where("-x") => Returns an array of flattened records
|
25
|
+
|
26
|
+
|
27
|
+
Or more powerfully you can search using boolean like logic e.g.
|
18
28
|
|
19
|
-
|
20
|
-
found =
|
29
|
+
hm = HashModel.new(:raw_data=>records)
|
30
|
+
found = hm.where {:switch == "-x" && :parameter__type == String} => Returns an array of flattened records
|
21
31
|
|
22
|
-
## Usage
|
23
32
|
|
33
|
+
## Status
|
34
|
+
|
35
|
+
###**Beta: Probably good to go but needs some more real-world testing**###
|
36
|
+
The latest version is still beta but mostly because I didn't realize little time it would take to get the changes I wanted done in version 0.3.0 and I didn't want to release 0.2.0 and 0.3.0 within a day of each other.
|
37
|
+
|
38
|
+
## Usage
|
24
39
|
|
40
|
+
These are just a few of the major methods of the class, to see all the functionality take a look at the RSpec files.
|
41
|
+
|
42
|
+
### **Creating with an array of hashes**
|
43
|
+
records = [
|
44
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
|
45
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"},
|
46
|
+
{:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
|
47
|
+
]
|
48
|
+
hash_model = HashModel.new(:raw_data=>records)
|
49
|
+
|
50
|
+
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}
|
53
|
+
>> {:switch=>"-y", :description=>"lucky what?", :_id=>2, :_group_id=>1}
|
54
|
+
>> {:switch=>"--why", :description=>"lucky what?", :_id=>3, :_group_id=>1}
|
55
|
+
>> {:switch=>"-z", :parameter=>{:type=>String}, :description=>"zee svitch zu moost calz", :_id=>4, :_group_id=>2}
|
56
|
+
|
57
|
+
### **Group ID's and Record ID's**
|
58
|
+
# You may have noticed that there are two fields you didn't add in the flattened records. These are the :_id field and the :_group_id fields.
|
59
|
+
# :_id is a unique ID for the flattened record while :_group_id is unique to the raw record you used to create the HashModel record.
|
60
|
+
|
61
|
+
### **Adding hashes after creation : <<, +, add, concat, push**
|
62
|
+
hash_model = HashModel.new
|
63
|
+
hash_model += records[0]
|
64
|
+
hash_model.concat records[1]
|
65
|
+
hash_model.push records[2]
|
66
|
+
|
67
|
+
|
68
|
+
### **Adding another hash model**
|
69
|
+
# You can also add another HashModel object to the existing one
|
70
|
+
# and it will add the raw records and reflatten.
|
71
|
+
records = [
|
72
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
|
73
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"}
|
74
|
+
]
|
75
|
+
|
76
|
+
records2 = {:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"}
|
77
|
+
|
78
|
+
hash_model = HashModel.new(:raw_data => records)
|
79
|
+
hash_model2 = HashModel.new(:raw_data => records2)
|
80
|
+
|
81
|
+
hash_model << hash_model2
|
82
|
+
# or
|
83
|
+
hash_model += hash_model2
|
84
|
+
|
85
|
+
|
86
|
+
### **Accessing the raw data : raw\_data**
|
87
|
+
# You can always edit and access the raw data via the raw_data property accessor
|
88
|
+
# When you make changes to the raw_data the HashModel will automatically be updated.
|
89
|
+
records = [
|
90
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
|
91
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"},
|
92
|
+
{:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
|
93
|
+
]
|
94
|
+
hm = HashModel.new(:raw_data=>records)
|
95
|
+
|
96
|
+
puts hm.raw_data
|
97
|
+
>> {:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"}
|
98
|
+
>> {:switch => ["-y", "--why"], :description => "lucky what?"}
|
99
|
+
>> {:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"}
|
100
|
+
|
101
|
+
|
102
|
+
### **Iterating over the HashModel : each**
|
103
|
+
# the HashModel acts a lot like an array so you can iterate over it
|
104
|
+
hash_model = HashModel.new(:raw_data=>records)
|
105
|
+
hash_model.each do |record|
|
106
|
+
# record is a hash
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
### **Flattening records : flatten_index**
|
111
|
+
# Flatten index is automatically set to the first field ever given
|
112
|
+
# but you can change it
|
113
|
+
hash_model = HashModel.new(:raw_data=>records)
|
114
|
+
|
115
|
+
puts hash_model.flatten_index
|
116
|
+
>> :switch
|
117
|
+
|
118
|
+
# you can use flattened field names
|
119
|
+
hash_model.flatten_index = :parameter__type
|
120
|
+
|
121
|
+
puts hash_model.flatten_index
|
122
|
+
>> :parameter__type
|
123
|
+
|
124
|
+
puts hash_model
|
125
|
+
>> {:parameter__type=>String, :switch=>["-x", "--xtended"], :parameter__require=>true, :description=>"Xish stuff", :_id=>0, :_group_id=>0}
|
126
|
+
>> {:parameter__type=>nil, :switch=>["-y", "--why"], :description=>"lucky what?", :_id=>1, :_group_id=>1}
|
127
|
+
>> {:parameter__type=>String, :switch=>"-z", :description=>"zee svitch zu moost calz", :_id=>2, :_group_id=>2}
|
128
|
+
|
129
|
+
# Notice that records that don't have the flatten index field have that field added and the value is set to nil
|
130
|
+
|
131
|
+
|
132
|
+
### **Searching Records : where**
|
133
|
+
# This is where the real power of the library is. You can do complex boolean searches using flattened field names.
|
134
|
+
|
135
|
+
# You can search using just a value and it will search based on the flatten_index
|
136
|
+
records = [
|
137
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
138
|
+
{:switch => ["-y", "--why"], :description => "lucky what?", :something => 7},
|
139
|
+
{:switch => "-z", :parameter => {:type => String, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
140
|
+
]
|
141
|
+
hm = HashModel.new(:raw_data=>records)
|
142
|
+
where = hm.where("-x")
|
143
|
+
|
144
|
+
puts where
|
145
|
+
>> {:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0}
|
146
|
+
|
147
|
+
# Best of all you can use complex boolean searches using normal and flattend field names.
|
148
|
+
# Note that flattened field names are seperated with double under lines __
|
149
|
+
hm = HashModel.new(:raw_data=>records)
|
150
|
+
where = hm.where {:something == 7 || (:parameter__type == String && :parameter__required == true)}
|
151
|
+
|
152
|
+
puts where
|
153
|
+
>> {:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0}
|
154
|
+
>> {:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0}
|
155
|
+
>> {:switch=>"-z", :parameter=>{:type=>String, :required=>true}, :description=>"zee svitch zu moost calz", :something=>4, :_id=>4, :_group_id=>2}
|
156
|
+
|
157
|
+
# You can even search using hash values
|
158
|
+
hm = HashModel.new(:raw_data=>records)
|
159
|
+
where = hm.where {:parameter == {:type => String, :required => true}}
|
160
|
+
|
161
|
+
puts where
|
162
|
+
|
163
|
+
>> {:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0},
|
164
|
+
>> {:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0}
|
165
|
+
|
166
|
+
|
167
|
+
### **Finding Sibling Records : group**
|
168
|
+
# Since the HashModel class flattens records it is sometimes useful to know what records were created from the same raw data record.
|
169
|
+
# This works exactly like a where search so you can send just a value or send a block and get all of the sibling records for your search criteria.
|
170
|
+
records = [
|
171
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
172
|
+
{:switch => ["-y", "--why"], :description => "lucky what?", :something => 7},
|
173
|
+
{:switch => "-z", :parameter => {:type => Integer, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
174
|
+
]
|
175
|
+
hm = HashModel.new(:raw_data=>records)
|
176
|
+
group = hm.group {(:parameter__type == String && :parameter__required == true && :something == 4) || :something == 7}
|
177
|
+
|
178
|
+
puts group
|
179
|
+
>> {:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0}
|
180
|
+
>> {:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0}
|
181
|
+
>> {:switch=>"-y", :description=>"lucky what?", :something=>7, :_id=>2, :_group_id=>1}
|
182
|
+
>> {:switch=>"--why", :description=>"lucky what?", :something=>7, :_id=>3, :_group_id=>1}
|
183
|
+
|
184
|
+
|
185
|
+
### **Unflattening records : unflatten**
|
186
|
+
# Anywhere you can add a raw record you can add a flat record
|
187
|
+
hm = HashModel.new
|
188
|
+
hm << {:switch=>"-x", :parameter__type=>String, :parameter__require=>true, :description=>"Xish stuff"}
|
189
|
+
|
190
|
+
puts hm.raw_data
|
191
|
+
>> {:switch => "-x", :parameter => {:type => String, :require => true}, :description => "Xish stuff"}
|
192
|
+
|
193
|
+
# You can also call the unflatten method yourself on an instance or the class itself and send it a record. (It won't mess with the existing data.)
|
194
|
+
deep_hash = {
|
195
|
+
:parameter__type=>String,
|
196
|
+
:switch__deep1__deep3 => "deepTwo",
|
197
|
+
:parameter__type__ruby=>true,
|
198
|
+
:parameter => "glorp",
|
199
|
+
:parameter__require=>true,
|
200
|
+
:switch__deep2 => "deepTwo",
|
201
|
+
:description=>"Xish stuff",
|
202
|
+
:switch => "--xtend",
|
203
|
+
}
|
204
|
+
unflat = HashModel.unflatten(deep_hash)
|
205
|
+
|
206
|
+
puts unflat
|
207
|
+
>> {:parameter=>[{:type=>String}, "glorp", {:require=>true}], :switch=>[{:deep1=>{:deep3=>"deepTwo"}}, {:deep2=>"deepTwo"}, "--xtend"], :description=>"Xish stuff"}
|
208
|
+
|
25
209
|
|
26
210
|
## Version History
|
27
211
|
|
28
|
-
0.
|
29
|
-
|
30
|
-
*
|
31
|
-
|
32
|
-
*
|
33
|
-
*
|
212
|
+
0.3.0.beta1 - 2011.01.09
|
213
|
+
|
214
|
+
* Changed HashModel\#where searches to use symbols instead of @variables.
|
215
|
+
e.g. hm.where{:x == "x" && :y == "y"} instead of the less natural hm.where{@x == "x" && @y == "y"}
|
216
|
+
* Converted the HashModel filter from a proc to a string so it can be viewed and allows the above behavior.
|
217
|
+
* Removed Jeweler and converted to Bundler gem building.
|
218
|
+
* Added usage instructions.
|
219
|
+
* To do: Refactor some ugly code, more usage examples?
|
220
|
+
|
221
|
+
0.2.0 - 2011.01.08
|
222
|
+
|
223
|
+
* Fixed bug if first field name is shorter version of another field name, e.g. :short then :shorter would cause an error.
|
224
|
+
* Added unflattening records and adding unflattened records.
|
225
|
+
* Changed field separator to double underscores (to allow unflattening)
|
226
|
+
* Removed namespace module, it was annoying. Now just instantiate it with HashModel.new instead of MikBe::HashModel.new
|
227
|
+
* Now allows a single hash, instead of an array of hashes, when creating with HashModel.new(:raw_data => hash)
|
228
|
+
|
229
|
+
0.1.1 - 2010.12.15
|
230
|
+
|
231
|
+
* Moved to proper RubyGems account
|
232
|
+
|
233
|
+
0.1.0 - 2010.12.15
|
34
234
|
|
35
|
-
|
235
|
+
* Initial publish
|
236
|
+
* Released on wrong RubyGems account (yanked)
|
36
237
|
|
37
|
-
0.1.0 Initial publish
|
38
238
|
|
39
|
-
|
239
|
+
##Contributing to HashModel
|
40
240
|
|
41
|
-
*
|
241
|
+
* Pull requests are handled ASAP.
|
42
242
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
43
243
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
44
244
|
* Fork the project
|
45
245
|
* Start a feature/bugfix branch
|
46
246
|
* Commit and push until you are happy with your contribution
|
47
|
-
* Make sure to add
|
48
|
-
*
|
247
|
+
* Make sure to add RSpecs in a separate file so I can easily tell what changed (changes without specs will not be pulled) for it.
|
248
|
+
* Changes to the configuration files, version numbers, or branches will not be pulled. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
49
249
|
|
50
|
-
|
250
|
+
##Copyright
|
51
251
|
|
52
252
|
Copyright (c) 2010 Mike Bethany. See LICENSE.txt for further details.
|
53
253
|
|
data/Rakefile
CHANGED
@@ -1,44 +1,2 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'bundler'
|
3
|
-
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'rake'
|
11
|
-
require './lib/hash_model/version'
|
12
|
-
version = HashModel::VERSION::STRING
|
13
|
-
|
14
|
-
require 'jeweler'
|
15
|
-
Jeweler::Tasks.new do |gem|
|
16
|
-
gem.name = "hashmodel"
|
17
|
-
gem.version = version
|
18
|
-
gem.summary = %Q{Store small amounts of dynamic data and easily search fields (even nested ones)}
|
19
|
-
gem.description = %Q{A simple MVC type model class for storing records as an array of hashes. You can store deeply nested hashes and still easily flatten and querying the records using flattened field names.}
|
20
|
-
gem.email = "mikbe.tk@gmail.com"
|
21
|
-
gem.homepage = "http://github.com/mikbe/hashmodel"
|
22
|
-
gem.authors = ["Mike Bethany"]
|
23
|
-
end
|
24
|
-
Jeweler::RubygemsDotOrgTasks.new
|
25
|
-
|
26
|
-
require 'rspec/core'
|
27
|
-
require 'rspec/core/rake_task'
|
28
|
-
RSpec::Core::RakeTask.new(:rspec) do |spec|
|
29
|
-
spec.pattern = FileList['spec/**/*_spec.rb']
|
30
|
-
end
|
31
|
-
|
32
|
-
require 'cucumber/rake/task'
|
33
|
-
Cucumber::Rake::Task.new(:features)
|
34
|
-
|
35
|
-
task :default => :rspec
|
36
|
-
|
37
|
-
require 'rake/rdoctask'
|
38
|
-
Rake::RDocTask.new do |rdoc|
|
39
|
-
|
40
|
-
rdoc.rdoc_dir = 'rdoc'
|
41
|
-
rdoc.title = "hash_model #{version}"
|
42
|
-
rdoc.rdoc_files.include('README*')
|
43
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
44
|
-
end
|
2
|
+
Bundler::GemHelper.install_tasks
|
@@ -0,0 +1,80 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "/../lib"))
|
2
|
+
require 'hash_model'
|
3
|
+
=begin
|
4
|
+
|
5
|
+
# Creates an object with instance variables for each field at every level
|
6
|
+
# This allows using a block like {:field1==true && :field2_subfield21="potato"}
|
7
|
+
def create_object_from_flat_hash(record, hash_record=Class.new.new, parent_key=nil)
|
8
|
+
|
9
|
+
# Iterate through the record creating the object recursively
|
10
|
+
case record
|
11
|
+
when Hash
|
12
|
+
record.each do |key, value|
|
13
|
+
flat_key = "#{parent_key}#{"__" if !parent_key.nil?}#{key}"
|
14
|
+
hash_record.instance_variable_set("@#{flat_key}", value)
|
15
|
+
hash_record = create_object_from_flat_hash(value, hash_record, flat_key)
|
16
|
+
end
|
17
|
+
when Array
|
18
|
+
record.each do |value|
|
19
|
+
hash_record = create_object_from_flat_hash(value, hash_record, parent_key)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
hash_record.instance_variable_set("@#{parent_key}", record)
|
23
|
+
end # case
|
24
|
+
|
25
|
+
hash_record
|
26
|
+
end # create_object_from_flat_hash
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
records = [
|
31
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
32
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"},
|
33
|
+
{:switch => "-z", :parameter => {:type => String, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
34
|
+
]
|
35
|
+
hm = HashModel.new(:raw_data=>records)
|
36
|
+
where = hm.where {:something == 4 && :parameter__type == String && :parameter__required == true}
|
37
|
+
puts "\nWhere:"
|
38
|
+
puts where
|
39
|
+
|
40
|
+
|
41
|
+
records = [
|
42
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
43
|
+
{:switch => ["-y", "--why"], :description => "lucky what?", :something => 7},
|
44
|
+
{:switch => "-z", :parameter => {:type => Integer, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
45
|
+
]
|
46
|
+
hm = HashModel.new(:raw_data=>records)
|
47
|
+
where = hm.where {:parameter == {:type => String, :required => true}}
|
48
|
+
puts "\nWhere:"
|
49
|
+
puts where
|
50
|
+
|
51
|
+
|
52
|
+
puts "\nflat object"
|
53
|
+
flat = create_object_from_flat_hash(hm[0])
|
54
|
+
puts flat.inspect
|
55
|
+
=end
|
56
|
+
|
57
|
+
puts "\nproc"
|
58
|
+
xproc = proc {:parameter == {:type => String, :required => true} && :switch == ["-x", "--xtended"]}
|
59
|
+
xproc_source = xproc.to_source
|
60
|
+
puts "xproc: #{xproc_source}"
|
61
|
+
|
62
|
+
matches = xproc_source.scan(/(\:\S+) ==/)
|
63
|
+
|
64
|
+
puts "matches: #{matches}"
|
65
|
+
puts "\nshow items"
|
66
|
+
matches.each do |item|
|
67
|
+
puts "item: #{item}"
|
68
|
+
end
|
69
|
+
puts 'done'
|
70
|
+
#"proc { #{@filter} }.call".gsub(":", "@")
|
71
|
+
|
72
|
+
#x = "{:parameter == {:type => String, :required => true}, "
|
73
|
+
#x.match
|
74
|
+
|
75
|
+
puts "\nMatch test"
|
76
|
+
text = "The future Ruby is Ruby"
|
77
|
+
m1 = text.scan(/(Ruby)/)
|
78
|
+
puts "m1: #{m1}"
|
79
|
+
|
80
|
+
puts "\n\ndone"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "/../lib"))
|
2
|
+
require 'hash_model'
|
3
|
+
require 'sourcify'
|
4
|
+
|
5
|
+
records = [
|
6
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
|
7
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"},
|
8
|
+
{:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
|
9
|
+
]
|
10
|
+
|
11
|
+
=begin
|
12
|
+
hash_model = HashModel.new(:raw_data=>records)
|
13
|
+
|
14
|
+
records = [
|
15
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
|
16
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"}
|
17
|
+
]
|
18
|
+
|
19
|
+
records2 = {:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"}
|
20
|
+
|
21
|
+
hash_model = HashModel.new(:raw_data => records)
|
22
|
+
hash_model2 = HashModel.new(:raw_data => records2)
|
23
|
+
|
24
|
+
hash_model << hash_model2
|
25
|
+
# or
|
26
|
+
hash_model += hash_model2
|
27
|
+
|
28
|
+
|
29
|
+
# Flatten index is automatically set to the first field ever given
|
30
|
+
# but you can change it
|
31
|
+
records = [
|
32
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :require => true}, :description => "Xish stuff"},
|
33
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"},
|
34
|
+
{:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz"},
|
35
|
+
]
|
36
|
+
hash_model = HashModel.new(:raw_data=>records)
|
37
|
+
|
38
|
+
puts hash_model.flatten_index
|
39
|
+
# you can use flattened field names
|
40
|
+
hash_model.flatten_index = :parameter__type
|
41
|
+
puts hash_model
|
42
|
+
|
43
|
+
>> {:parameter__type=>String, :switch=>["-x", "--xtended"], :parameter__require=>true, :description=>"Xish stuff", :_id=>0, :_group_id=>0}
|
44
|
+
>> {:parameter__type=>nil, :switch=>["-y", "--why"], :description=>"lucky what?", :_id=>1, :_group_id=>1}
|
45
|
+
>> {:parameter__type=>String, :switch=>"-z", :description=>"zee svitch zu moost calz", :_id=>2, :_group_id=>2}
|
46
|
+
|
47
|
+
# Notice that records that don't have the flatten index have their value set to nil
|
48
|
+
=end
|
49
|
+
# The real strength of the class is its ability to search flattened fields
|
50
|
+
hash_model = HashModel.new(:raw_data=>records)
|
51
|
+
|
52
|
+
# default is to use the flatten index
|
53
|
+
puts hash_model.where("-z")
|
54
|
+
|
55
|
+
# but you can also use a block with boolean search parameters
|
56
|
+
# You must write the field names as @variables instead of symbols
|
57
|
+
puts hash_model.where {@parameter_type}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'sourcify'
|
2
|
+
@x = "x"
|
3
|
+
@y = "y"
|
4
|
+
|
5
|
+
search = proc{:x == "x" && :y == "y"}
|
6
|
+
|
7
|
+
@filter = search.to_source.match(/^proc { \((.*)\) }$/)[1]
|
8
|
+
puts "new_search: \"#{@filter}\""
|
9
|
+
puts "\nRun Eval"
|
10
|
+
puts instance_eval("proc { (#{@filter}) }.call".gsub(":", "@"))
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
string = "My phone number is (123) 555-1234."
|
2
|
+
phone_re = /\((\d{3})\)\s+(\d{3})-(\d{4})/
|
3
|
+
m = phone_re.match(string)
|
4
|
+
unless m
|
5
|
+
puts "There was no match..."
|
6
|
+
exit
|
7
|
+
end
|
8
|
+
print "The whole string we started with: "
|
9
|
+
puts m.string
|
10
|
+
print "The entire part of the string that matched: "
|
11
|
+
puts m[0]
|
12
|
+
puts "The three captures: "
|
13
|
+
m.captures.each do |cap|
|
14
|
+
puts "Capture ##{cap}"
|
15
|
+
end
|
16
|
+
puts "Here's another way to get at the first capture:"
|
17
|
+
print "Capture #1: "
|
18
|
+
puts m[1]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "/../lib"))
|
2
|
+
require 'hash_model'
|
3
|
+
|
4
|
+
deep_hash = {
|
5
|
+
:parameter__type=>String,
|
6
|
+
:switch__deep1__deep3 => "deepTwo",
|
7
|
+
:parameter__type__ruby=>true,
|
8
|
+
:parameter => "glorp",
|
9
|
+
:parameter__require=>true,
|
10
|
+
:switch__deep2 => "deepTwo",
|
11
|
+
:description=>"Xish stuff",
|
12
|
+
:switch => "--xtend",
|
13
|
+
}
|
14
|
+
unflat = HashModel.unflatten(deep_hash)
|
15
|
+
|
16
|
+
puts unflat
|
data/autotest/discover.rb
CHANGED
data/features/README
CHANGED
@@ -6,4 +6,4 @@ 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
|
|
9
|
-
Oh, plus
|
9
|
+
Oh, plus my feature specs suck... I'm still learning.
|
data/hashmodel.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "hash_model/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "hashmodel"
|
7
|
+
s.version = HashModel::VERSION::STRING
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Mike Bethany"]
|
10
|
+
s.email = ["mikbe.tk@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/mikbe/hashmodel"
|
12
|
+
s.summary = %q{Store small amounts of dynamic data and easily search fields (even nested ones)}
|
13
|
+
s.description = %q{A simple MVC type model class for storing records as an array of hashes. You can store deeply nested hashes and still easily flatten and querying the records using flattened field names.}
|
14
|
+
|
15
|
+
s.add_dependency "sourcify"
|
16
|
+
s.add_dependency "file-tail"
|
17
|
+
|
18
|
+
s.add_development_dependency "rspec"
|
19
|
+
s.add_development_dependency "cucumber"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
data/lib/hash_model.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'sourcify'
|
1
2
|
# A simple MVC type model class for storing hashes as flattenable, searchable records
|
2
3
|
class HashModel
|
3
4
|
include Enumerable
|
@@ -14,7 +15,7 @@ class HashModel
|
|
14
15
|
|
15
16
|
# Allow a single hash to be added with :raw_data
|
16
17
|
@raw_data = [@raw_data] if @raw_data.class == Hash
|
17
|
-
|
18
|
+
|
18
19
|
check_field_names(@raw_data) if !@raw_data.empty?
|
19
20
|
|
20
21
|
# Setup the flat data
|
@@ -24,7 +25,7 @@ class HashModel
|
|
24
25
|
|
25
26
|
## Properties
|
26
27
|
|
27
|
-
attr_accessor :flatten_index, :raw_data
|
28
|
+
attr_accessor :flatten_index, :raw_data, :filter
|
28
29
|
|
29
30
|
# Sets field name used to flatten the recordset
|
30
31
|
def flatten_index=(value)
|
@@ -37,6 +38,11 @@ class HashModel
|
|
37
38
|
!!@filter
|
38
39
|
end
|
39
40
|
|
41
|
+
def filter=(filter)
|
42
|
+
@filter = filter
|
43
|
+
flatten
|
44
|
+
end
|
45
|
+
|
40
46
|
# Trap changes to raw data so we can re-flatten the data
|
41
47
|
def raw_data=(value)
|
42
48
|
value = [] if value.nil?
|
@@ -72,6 +78,13 @@ class HashModel
|
|
72
78
|
@filter = nil
|
73
79
|
end
|
74
80
|
|
81
|
+
# Force arrays to be cloned
|
82
|
+
def clone
|
83
|
+
hm = HashModel.new(:raw_data=>@raw_data.clone)
|
84
|
+
hm.flatten_index = @flatten_index
|
85
|
+
hm.filter = @filter
|
86
|
+
hm
|
87
|
+
end
|
75
88
|
|
76
89
|
## Operators
|
77
90
|
|
@@ -159,7 +172,7 @@ class HashModel
|
|
159
172
|
self.clone.where!(value, &search)
|
160
173
|
end
|
161
174
|
|
162
|
-
# Search the flattened records using a
|
175
|
+
# Search the flattened records using the default flatten index or a boolean block
|
163
176
|
def where!(value=nil, &search)
|
164
177
|
# Parameter checks
|
165
178
|
raise SyntaxError, "You may only provide a parameter or a block but not both" if value && !search.nil?
|
@@ -171,48 +184,45 @@ class HashModel
|
|
171
184
|
end
|
172
185
|
|
173
186
|
# If given a parameter make our own search based on the flatten index
|
174
|
-
|
187
|
+
unless value.nil?
|
175
188
|
# Make sure the field name is available to the proc
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
189
|
+
if value.class == String
|
190
|
+
string_search = ":#{@flatten_index} == \"#{value}\"".to_s
|
191
|
+
else
|
192
|
+
string_search = ":#{@flatten_index} == #{value}".to_s
|
193
|
+
end
|
194
|
+
else
|
195
|
+
# Convert the proc to a string so it can be viewed
|
196
|
+
# and later have :'s turned into @'s
|
197
|
+
|
198
|
+
# Sourcify can create single or multi-line procs
|
199
|
+
source = search.to_source
|
200
|
+
unless (match = source.match(/^proc do\n(.*)\nend$/))
|
201
|
+
match = source.match(/^proc { (.*) }$/)
|
202
|
+
end
|
203
|
+
string_search = match[1]
|
180
204
|
end # !value.nil?
|
181
205
|
|
182
206
|
# Set and process the filter
|
183
|
-
@filter =
|
207
|
+
@filter = string_search
|
184
208
|
flatten
|
185
209
|
end
|
186
210
|
|
187
211
|
# Return the other records created from the same raw data record as the one(s) searched for
|
188
212
|
def group(value=nil, &search)
|
189
|
-
|
190
|
-
sibling = where(value, &search)
|
191
|
-
else
|
192
|
-
sibling = where &@filter
|
193
|
-
end
|
194
|
-
|
195
|
-
# Get all the unique group id's
|
196
|
-
group_ids = sibling.collect {|hash| hash[:_group_id]}.uniq
|
197
|
-
|
198
|
-
# Find any records with matching group ids
|
199
|
-
where {group_ids.include? @_group_id}
|
213
|
+
self.clone.group!(value, &search)
|
200
214
|
end
|
201
215
|
|
202
|
-
#
|
203
|
-
# This is basically a short hand for filtering based on
|
204
|
-
# group ids of filtered records
|
216
|
+
# Filter in place based on the parent record
|
205
217
|
def group!(value=nil, &search)
|
206
|
-
|
218
|
+
# Filter the recordset if applicable
|
207
219
|
if !value.nil? || !search.nil?
|
208
220
|
where!(value, &search)
|
209
221
|
end
|
210
|
-
|
211
222
|
# Get all the unique group id's
|
212
223
|
group_ids = @modified_data.collect {|hash| hash[:_group_id]}.uniq
|
213
|
-
|
214
|
-
|
215
|
-
where! {group_ids.include? @_group_id}
|
224
|
+
self.filter = "#{group_ids.to_s}.include? :_group_id"
|
225
|
+
flatten
|
216
226
|
end
|
217
227
|
|
218
228
|
# Find the raw data record for a given flat record
|
@@ -244,10 +254,23 @@ class HashModel
|
|
244
254
|
new_record.merge!( duplicate_data.merge!( { :_id=>(id+=1), :_group_id=>group_id } ) )
|
245
255
|
end
|
246
256
|
|
257
|
+
# Change the filter so it looks for variables instead of symbols
|
258
|
+
unless @filter.nil?
|
259
|
+
proc_filter = @filter.clone
|
260
|
+
proc_filter.scan(/(:\S+) ==/).each {|match| proc_filter.sub!(match[0], match[0].sub(":","@"))}
|
261
|
+
proc_filter.sub!(":_group_id", "@_group_id")
|
262
|
+
proc_filter = "proc { #{proc_filter} }.call"
|
263
|
+
end
|
264
|
+
|
247
265
|
# Add the records to modified data if they pass the filter
|
248
|
-
new_records.each do |new_record|
|
249
|
-
|
266
|
+
new_records.each do |new_record|
|
267
|
+
unless @filter.nil?
|
268
|
+
@modified_data << new_record if create_object_from_flat_hash(new_record).instance_eval proc_filter
|
269
|
+
else
|
270
|
+
@modified_data << new_record
|
271
|
+
end
|
250
272
|
end
|
273
|
+
|
251
274
|
end # raw_data.each
|
252
275
|
set_dirty_hash
|
253
276
|
self
|
@@ -340,7 +363,6 @@ class HashModel
|
|
340
363
|
|
341
364
|
private
|
342
365
|
|
343
|
-
|
344
366
|
# Convert a hash of multiple key/value pairs to an array of single hashes.
|
345
367
|
# {:field1 => "value1", :field2 => "value2"}
|
346
368
|
# becomes
|
data/lib/hash_model/version.rb
CHANGED
@@ -632,6 +632,61 @@ describe "HashModel" do
|
|
632
632
|
|
633
633
|
end # not in place
|
634
634
|
|
635
|
+
context "using blocks" do
|
636
|
+
|
637
|
+
it "should search using a single value boolean block" do
|
638
|
+
@hm.where {:switch == "-x"}.should == [@flat_records[0]]
|
639
|
+
end
|
640
|
+
|
641
|
+
it "should search using a complex boolean block" do
|
642
|
+
records = [
|
643
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
644
|
+
{:switch => ["-y", "--why"], :description => "lucky what?"},
|
645
|
+
{:switch => "-z", :parameter => {:type => String, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
646
|
+
]
|
647
|
+
@hm = HashModel.new(:raw_data=>records)
|
648
|
+
@hm.where {:something == 4 && :parameter__required == true}.should == [
|
649
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0},
|
650
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0},
|
651
|
+
{:switch=>"-z", :parameter=>{:type=>String, :required=>true}, :description=>"zee svitch zu moost calz", :something=>4, :_id=>4, :_group_id=>2}
|
652
|
+
]
|
653
|
+
@hm.where {:parameter__type == String && :parameter__required == true && :something == 4}.should == [
|
654
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0},
|
655
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0},
|
656
|
+
{:switch=>"-z", :parameter=>{:type=>String, :required=>true}, :description=>"zee svitch zu moost calz", :something=>4, :_id=>4, :_group_id=>2}
|
657
|
+
]
|
658
|
+
end
|
659
|
+
|
660
|
+
it "should search using a complex, multi-line boolean block" do
|
661
|
+
records = [
|
662
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
663
|
+
{:switch => ["-y", "--why"], :description => "lucky what?", :something => 7},
|
664
|
+
{:switch => "-z", :parameter => {:type => Integer, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
665
|
+
]
|
666
|
+
@hm = HashModel.new(:raw_data=>records)
|
667
|
+
@hm.where {(:parameter__type == String && :parameter__required == true && :something == 4) || :something == 7}.should == [
|
668
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0},
|
669
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0},
|
670
|
+
{:switch=>"-y", :description=>"lucky what?", :something=>7, :_id=>2, :_group_id=>1},
|
671
|
+
{:switch=>"--why", :description=>"lucky what?", :something=>7, :_id=>3, :_group_id=>1}
|
672
|
+
]
|
673
|
+
end
|
674
|
+
|
675
|
+
it "should search with nested hashes in a block" do
|
676
|
+
records = [
|
677
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
678
|
+
{:switch => ["-y", "--why"], :description => "lucky what?", :something => 7},
|
679
|
+
{:switch => "-z", :parameter => {:type => Integer, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
680
|
+
]
|
681
|
+
@hm = HashModel.new(:raw_data=>records)
|
682
|
+
@hm.where {:parameter == {:type => String, :required => true}}.should == [
|
683
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0},
|
684
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0}
|
685
|
+
]
|
686
|
+
end
|
687
|
+
|
688
|
+
end
|
689
|
+
|
635
690
|
it "should return false if tested for inclusion of anything other than a hash" do
|
636
691
|
@hm.include?([:switch=>"-x"]).should == false
|
637
692
|
end
|
@@ -691,17 +746,45 @@ describe "HashModel" do
|
|
691
746
|
end
|
692
747
|
|
693
748
|
it "should return the records in the same raw data record when using a block" do
|
694
|
-
@hm.group{
|
749
|
+
@hm.group{:switch == "-y"}.should == [@flat_records[2], @flat_records[3]]
|
695
750
|
end
|
696
751
|
|
697
|
-
it "should
|
698
|
-
@hm.group{
|
752
|
+
it "should group across group_id's if searching for something that returns records from multiple groups" do
|
753
|
+
@hm.group{:parameter__type == String}.should == [
|
699
754
|
{:switch=>"-x", :parameter=>{:type=>String, :require=>true}, :description=>"Xish stuff", :_id=>0, :_group_id=>0},
|
700
755
|
{:switch=>"--xtended", :parameter=>{:type=>String, :require=>true}, :description=>"Xish stuff", :_id=>1, :_group_id=>0},
|
701
756
|
{:switch => "-z", :parameter => {:type => String}, :description => "zee svitch zu moost calz", :_id=>4, :_group_id=>2}
|
702
757
|
]
|
703
758
|
end
|
704
759
|
|
760
|
+
it "should group with a complex block" do
|
761
|
+
records = [
|
762
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
763
|
+
{:switch => ["-y", "--why"], :description => "lucky what?", :something => 7},
|
764
|
+
{:switch => "-z", :parameter => {:type => Integer, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
765
|
+
]
|
766
|
+
@hm = HashModel.new(:raw_data=>records)
|
767
|
+
@hm.group {(:parameter__type == String && :parameter__required == true && :something == 4) || :something == 7}.should == [
|
768
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0},
|
769
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0},
|
770
|
+
{:switch=>"-y", :description=>"lucky what?", :something=>7, :_id=>2, :_group_id=>1},
|
771
|
+
{:switch=>"--why", :description=>"lucky what?", :something=>7, :_id=>3, :_group_id=>1}
|
772
|
+
]
|
773
|
+
end
|
774
|
+
|
775
|
+
it "should group with nested hashes block" do
|
776
|
+
records = [
|
777
|
+
{:switch => ["-x", "--xtended"], :parameter => {:type => String, :required => true}, :description => "Xish stuff", :something => 4},
|
778
|
+
{:switch => ["-y", "--why"], :description => "lucky what?", :something => 7},
|
779
|
+
{:switch => "-z", :parameter => {:type => Integer, :required => true}, :description => "zee svitch zu moost calz", :something => 4},
|
780
|
+
]
|
781
|
+
@hm = HashModel.new(:raw_data=>records)
|
782
|
+
@hm.group {:parameter == {:type => String, :required => true}}.should == [
|
783
|
+
{:switch=>"-x", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>0, :_group_id=>0},
|
784
|
+
{:switch=>"--xtended", :parameter=>{:type=>String, :required=>true}, :description=>"Xish stuff", :something=>4, :_id=>1, :_group_id=>0}
|
785
|
+
]
|
786
|
+
end
|
787
|
+
|
705
788
|
end # not in place
|
706
789
|
|
707
790
|
context "in place" do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hashmodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: true
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 3
|
8
8
|
- 0
|
9
|
-
|
9
|
+
- beta1
|
10
|
+
version: 0.3.0.beta1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Mike Bethany
|
@@ -14,11 +15,12 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2011-01-
|
18
|
+
date: 2011-01-09 00:00:00 -05:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
22
|
+
name: sourcify
|
23
|
+
prerelease: false
|
22
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
23
25
|
none: false
|
24
26
|
requirements:
|
@@ -27,11 +29,11 @@ dependencies:
|
|
27
29
|
segments:
|
28
30
|
- 0
|
29
31
|
version: "0"
|
30
|
-
type: :
|
31
|
-
prerelease: false
|
32
|
+
type: :runtime
|
32
33
|
version_requirements: *id001
|
33
34
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
35
|
+
name: file-tail
|
36
|
+
prerelease: false
|
35
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
36
38
|
none: false
|
37
39
|
requirements:
|
@@ -40,11 +42,11 @@ dependencies:
|
|
40
42
|
segments:
|
41
43
|
- 0
|
42
44
|
version: "0"
|
43
|
-
type: :
|
44
|
-
prerelease: false
|
45
|
+
type: :runtime
|
45
46
|
version_requirements: *id002
|
46
47
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
48
|
+
name: rspec
|
49
|
+
prerelease: false
|
48
50
|
requirement: &id003 !ruby/object:Gem::Requirement
|
49
51
|
none: false
|
50
52
|
requirements:
|
@@ -54,10 +56,10 @@ dependencies:
|
|
54
56
|
- 0
|
55
57
|
version: "0"
|
56
58
|
type: :development
|
57
|
-
prerelease: false
|
58
59
|
version_requirements: *id003
|
59
60
|
- !ruby/object:Gem::Dependency
|
60
|
-
name:
|
61
|
+
name: cucumber
|
62
|
+
prerelease: false
|
61
63
|
requirement: &id004 !ruby/object:Gem::Requirement
|
62
64
|
none: false
|
63
65
|
requirements:
|
@@ -67,43 +69,36 @@ dependencies:
|
|
67
69
|
- 0
|
68
70
|
version: "0"
|
69
71
|
type: :development
|
70
|
-
prerelease: false
|
71
72
|
version_requirements: *id004
|
72
|
-
- !ruby/object:Gem::Dependency
|
73
|
-
name: rcov
|
74
|
-
requirement: &id005 !ruby/object:Gem::Requirement
|
75
|
-
none: false
|
76
|
-
requirements:
|
77
|
-
- - ">="
|
78
|
-
- !ruby/object:Gem::Version
|
79
|
-
segments:
|
80
|
-
- 0
|
81
|
-
version: "0"
|
82
|
-
type: :development
|
83
|
-
prerelease: false
|
84
|
-
version_requirements: *id005
|
85
73
|
description: A simple MVC type model class for storing records as an array of hashes. You can store deeply nested hashes and still easily flatten and querying the records using flattened field names.
|
86
|
-
email:
|
74
|
+
email:
|
75
|
+
- mikbe.tk@gmail.com
|
87
76
|
executables: []
|
88
77
|
|
89
78
|
extensions: []
|
90
79
|
|
91
|
-
extra_rdoc_files:
|
92
|
-
|
93
|
-
- README.markdown
|
80
|
+
extra_rdoc_files: []
|
81
|
+
|
94
82
|
files:
|
95
83
|
- .document
|
84
|
+
- .gitignore
|
96
85
|
- .rspec
|
97
86
|
- Gemfile
|
98
87
|
- Gemfile.lock
|
99
88
|
- LICENSE.txt
|
100
89
|
- README.markdown
|
101
90
|
- Rakefile
|
91
|
+
- _brainstorm/block_wheres.rb
|
92
|
+
- _brainstorm/clone.rb
|
93
|
+
- _brainstorm/hash_model_examples.rb
|
102
94
|
- _brainstorm/hash_test.rb
|
103
95
|
- _brainstorm/instance_vars.rb
|
96
|
+
- _brainstorm/proc_tests.rb
|
104
97
|
- _brainstorm/ref_val.rb
|
98
|
+
- _brainstorm/regex_captures.rb
|
105
99
|
- _brainstorm/spliting.rb
|
106
100
|
- _brainstorm/test.rb
|
101
|
+
- _brainstorm/unflat.rb
|
107
102
|
- autotest/discover.rb
|
108
103
|
- features/README
|
109
104
|
- features/hash_model_flatten.feature
|
@@ -112,6 +107,7 @@ files:
|
|
112
107
|
- features/step_definitions/hash_model_steps.rb
|
113
108
|
- features/support/env.rb
|
114
109
|
- features/support/helper.rb
|
110
|
+
- hashmodel.gemspec
|
115
111
|
- lib/hash_model.rb
|
116
112
|
- lib/hash_model/exceptions.rb
|
117
113
|
- lib/hash_model/hash_model.rb
|
@@ -132,18 +128,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
128
|
requirements:
|
133
129
|
- - ">="
|
134
130
|
- !ruby/object:Gem::Version
|
135
|
-
hash: -189604924885672181
|
136
131
|
segments:
|
137
132
|
- 0
|
138
133
|
version: "0"
|
139
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
135
|
none: false
|
141
136
|
requirements:
|
142
|
-
- - "
|
137
|
+
- - ">"
|
143
138
|
- !ruby/object:Gem::Version
|
144
139
|
segments:
|
145
|
-
-
|
146
|
-
|
140
|
+
- 1
|
141
|
+
- 3
|
142
|
+
- 1
|
143
|
+
version: 1.3.1
|
147
144
|
requirements: []
|
148
145
|
|
149
146
|
rubyforge_project:
|
@@ -152,5 +149,12 @@ signing_key:
|
|
152
149
|
specification_version: 3
|
153
150
|
summary: Store small amounts of dynamic data and easily search fields (even nested ones)
|
154
151
|
test_files:
|
152
|
+
- features/README
|
153
|
+
- features/hash_model_flatten.feature
|
154
|
+
- features/hash_model_grouping.feature
|
155
|
+
- features/hash_model_search.feature
|
156
|
+
- features/step_definitions/hash_model_steps.rb
|
157
|
+
- features/support/env.rb
|
158
|
+
- features/support/helper.rb
|
155
159
|
- spec/hash_model/hash_model_spec.rb
|
156
160
|
- spec/spec_helper.rb
|