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 ADDED
@@ -0,0 +1,11 @@
1
+ coverage
2
+ rdoc
3
+ doc
4
+ .yardoc
5
+ .bundle
6
+ pkg
7
+ .DS_Store
8
+ *.tmproj
9
+ tmtags
10
+ vendor
11
+ vendor/**/*
data/Gemfile CHANGED
@@ -1,9 +1,2 @@
1
1
  source "http://rubygems.org"
2
-
3
- group :development do
4
- gem "rspec"
5
- gem "cucumber"
6
- gem "bundler"
7
- gem "jeweler"
8
- gem "rcov"
9
- end
2
+ gemspec
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
- jeweler
39
- rcov
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, and array, or even an Object class like String or Array, not
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 also search using boolean like logic e.g.
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
- @hm = HashModel.new(:raw\_data=>@records)
20
- found = @hm.where {@switch == "-x" && @parameter\_type == String}
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.2.0
29
- * Fixed bug if first field name is shorter version of another field name, e.g. :short then :shorter would cause an error.
30
- * Added unflattening records and adding unflattened records.
31
- * Changed field separator to double underscores (to allow unflattening)
32
- * Removed namespace module, it was annoying. Now just instantiate it with HashModel.new instead of MikBe::HashModel.new
33
- * Now allows a single hash, instead of an array of hashes, when creating with HashModel.new(:raw_data => hash)
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
- 0.1.1 Moved to new RubyGems account
235
+ * Initial publish
236
+ * Released on wrong RubyGems account (yanked)
36
237
 
37
- 0.1.0 Initial publish
38
238
 
39
- == Contributing to hash\_model
239
+ ##Contributing to HashModel
40
240
 
41
- * Please feel free to correct any mistakes I make by correcting the code and sending me a pull request. Pull requests are handled ASAP.
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 tests for it. This is important so I don't break it in a future version unintentionally.
48
- * Please try not to mess with the Rakefile, version, or history. 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.
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
- == Copyright
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
- begin
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,19 @@
1
+ x = ["x", "y", "z"]
2
+
3
+ class Foo
4
+
5
+ attr_accessor :array
6
+
7
+ def initialize(input)
8
+ @array = input
9
+ end
10
+
11
+ end
12
+
13
+
14
+
15
+ f = Foo.new(x)
16
+
17
+ x[0] = "change"
18
+
19
+ puts f.array
@@ -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
@@ -1,3 +1 @@
1
1
  Autotest.add_discovery {"rspec2"}
2
- #Autotest.add_discovery {"cucumber"}
3
- #AUTOFEATURE=true
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 they suck... I'm still learning.
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,4 +1,5 @@
1
1
  $: << '.'
2
+ require 'sourcify'
2
3
  require 'hash_model/hash_model'
3
4
  require 'hash_model/exceptions'
4
5
  require 'hash_model/version'
@@ -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
- if !value.nil?
187
+ unless value.nil?
175
188
  # Make sure the field name is available to the proc
176
- flatten_index = @flatten_index
177
- search = proc do
178
- instance_variable_get("@#{flatten_index}") == value
179
- end # search
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 = search
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
- if !value.nil? || !search.nil?
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
- # Group the records in place based on the existing filter
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
- # Find any records with matching group ids
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
- @modified_data << new_record if @filter.nil? ? true : (create_object_from_flat_hash(new_record).instance_eval &@filter)
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
@@ -1,9 +1,9 @@
1
1
  class HashModel
2
2
  module VERSION # :nodoc:
3
3
  MAJOR = 0
4
- MINOR = 2
4
+ MINOR = 3
5
5
  TINY = 0
6
- PRE = nil
6
+ PRE = "beta1"
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
9
 
@@ -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{@switch == "-y"}.should == [@flat_records[2], @flat_records[3]]
749
+ @hm.group{:switch == "-y"}.should == [@flat_records[2], @flat_records[3]]
695
750
  end
696
751
 
697
- it "should work across group_id's if searching for something that returns records from multiple groups" do
698
- @hm.group{@parameter__type == String}.should == [
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
@@ -21,3 +21,15 @@ def create_proc_tester(property_value_hash)
21
21
 
22
22
  proc_test
23
23
  end
24
+
25
+
26
+ # Debug print
27
+ module Kernel
28
+ def dp(value)
29
+ puts ""
30
+ puts "*" * 40
31
+ puts "value: #{value}"
32
+ puts "&" * 40
33
+ puts ""
34
+ end
35
+ end
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: false
4
+ prerelease: true
5
5
  segments:
6
6
  - 0
7
- - 2
7
+ - 3
8
8
  - 0
9
- version: 0.2.0
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-08 00:00:00 -05:00
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: rspec
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: :development
31
- prerelease: false
32
+ type: :runtime
32
33
  version_requirements: *id001
33
34
  - !ruby/object:Gem::Dependency
34
- name: cucumber
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: :development
44
- prerelease: false
45
+ type: :runtime
45
46
  version_requirements: *id002
46
47
  - !ruby/object:Gem::Dependency
47
- name: bundler
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: jeweler
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: mikbe.tk@gmail.com
74
+ email:
75
+ - mikbe.tk@gmail.com
87
76
  executables: []
88
77
 
89
78
  extensions: []
90
79
 
91
- extra_rdoc_files:
92
- - LICENSE.txt
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
- - 0
146
- version: "0"
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