hashy_db 1.1.0 → 2.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/hashy_db/config.rb +18 -0
- data/lib/hashy_db/data_store.rb +44 -112
- data/lib/hashy_db/interface.rb +237 -0
- data/lib/hashy_db/version.rb +34 -2
- data/lib/hashy_db.rb +4 -1
- data/spec/integration/mince_interface_spec.rb +14 -0
- data/spec/units/hashy_db/config_spec.rb +7 -0
- data/spec/units/hashy_db/data_store_spec.rb +21 -0
- data/spec/units/hashy_db/interface_spec.rb +8 -0
- metadata +99 -32
- data/.gitignore +0 -8
- data/.rspec +0 -2
- data/.rvmrc +0 -1
- data/Gemfile +0 -3
- data/LICENSE.txt +0 -20
- data/README.md +0 -65
- data/Rakefile +0 -11
- data/hashy_db.gemspec +0 -25
- data/spec/lib/data_store_spec.rb +0 -137
@@ -0,0 +1,18 @@
|
|
1
|
+
module Mince
|
2
|
+
module HashyDb # :nodoc:
|
3
|
+
# = HashyDb Config
|
4
|
+
#
|
5
|
+
# HashyDb Config specifies the configuration settings for HashyDb
|
6
|
+
#
|
7
|
+
# @author Matt Simpson
|
8
|
+
module Config
|
9
|
+
# Returns the primary key identifier for records. This is necessary because not all databases use the same
|
10
|
+
# primary key.
|
11
|
+
#
|
12
|
+
# @return [Symbol] the name of the primary key field.
|
13
|
+
def self.primary_key
|
14
|
+
:id
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/hashy_db/data_store.rb
CHANGED
@@ -1,123 +1,55 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
1
|
+
module Mince
|
2
|
+
module HashyDb # :nodoc:
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
# = HashyDb Data Store
|
6
|
+
#
|
7
|
+
# HashyDb Data Store stores and retrieves data from a ruby in-memory hash.
|
8
|
+
#
|
9
|
+
# Using this library offers more extensibility and growth for your application. If at any point in time
|
10
|
+
# you want to support a different database for all, or even one, of your classes, you only need to implement
|
11
|
+
# the few methods defined in this class.
|
12
|
+
#
|
13
|
+
# HashyDb Data Store is a singleton object that provides class level interface to the singleton instance.
|
14
|
+
#
|
15
|
+
# Mince::HashyDb::DataStore.instance # => Mince::HashyDb::DataStore object
|
16
|
+
# Mince::HashyDb::DataStore.data # => returns all data stored in the HashyDb database
|
17
|
+
# Mince::HashyDb::DataStore.collection(:some_collection) # => returns all data stored in a specific collection in the HashyDb database
|
18
|
+
#
|
19
|
+
# @author Matt Simpson
|
20
|
+
class DataStore
|
21
|
+
include Singleton
|
22
|
+
|
23
|
+
# Sets the entire data store, for all collections
|
24
|
+
#
|
25
|
+
# @param [Hash] hash the hash to replace the entire data store with
|
26
|
+
def self.set_data(hash)
|
27
|
+
instance.data = hash
|
21
28
|
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def add(collection_name, hash)
|
25
|
-
find_all(collection_name) << hash
|
26
|
-
end
|
27
|
-
|
28
|
-
def replace(collection_name, hash)
|
29
|
-
collection = find_all(collection_name)
|
30
|
-
index = collection.index{ |object| object[:id] == hash[:id] }
|
31
|
-
collection[index] = hash
|
32
|
-
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
# Class level access to the in-memory data store
|
31
|
+
#
|
32
|
+
# @return [Hash] all collections along with the contents of each collection
|
33
|
+
def self.data
|
34
|
+
instance.data
|
37
35
|
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def update_field_with_value(collection_name, primary_key_value, field_name, new_value)
|
41
|
-
find(collection_name, :id, primary_key_value)[field_name] = new_value
|
42
|
-
end
|
43
36
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
def get_for_key_with_value(collection_name, key, value)
|
53
|
-
get_all_for_key_with_value(collection_name, key, value)[0]
|
54
|
-
end
|
55
|
-
|
56
|
-
def get_by_params(collection_name, hash)
|
57
|
-
find_all(collection_name).select do |record|
|
58
|
-
hash.all?{|k,v| record[k] == v }
|
37
|
+
# The collection in the data store
|
38
|
+
#
|
39
|
+
# @param [Symbol] collection_name the name of the collection
|
40
|
+
# @return [Array] all records in the collection, defaults to an empty array
|
41
|
+
def self.collection(collection_name)
|
42
|
+
data[collection_name] ||= []
|
59
43
|
end
|
60
|
-
end
|
61
44
|
|
62
|
-
|
63
|
-
|
64
|
-
|
45
|
+
# The attribute containing the data
|
46
|
+
#
|
47
|
+
# @return [Hash] all collections along with the contents of each collection, defaults to an empty hash
|
48
|
+
attr_accessor :data
|
65
49
|
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def push_to_array(collection_name, identifying_key, identifying_value, array_key, value_to_push)
|
71
|
-
record = find(collection_name, identifying_key, identifying_value)
|
72
|
-
if (record[array_key])
|
73
|
-
record[array_key] << value_to_push
|
74
|
-
else
|
75
|
-
record[array_key] = [value_to_push]
|
50
|
+
def initialize
|
51
|
+
@data = {}
|
76
52
|
end
|
77
|
-
record[array_key].uniq!
|
78
|
-
end
|
79
|
-
|
80
|
-
def remove_from_array(collection_name, identifying_key, identifying_value, array_key, value_to_pop)
|
81
|
-
record = find(collection_name, identifying_key, identifying_value)
|
82
|
-
record[array_key].reject! { |x| x == value_to_pop }
|
83
|
-
end
|
84
|
-
|
85
|
-
def containing_any(collection_name, key, values)
|
86
|
-
find_all(collection_name).select do |x|
|
87
|
-
if x[key].is_a?(Array)
|
88
|
-
(x[key] & values).any?
|
89
|
-
else
|
90
|
-
values.include?(x[key])
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def array_contains(collection_name, key, value)
|
96
|
-
find_all(collection_name).select do |x|
|
97
|
-
x[key] && x[key].include?(value)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def delete_collection(collection_name)
|
102
|
-
data_store.delete(collection_name)
|
103
|
-
end
|
104
|
-
|
105
|
-
def clear
|
106
|
-
data_store.clear
|
107
|
-
end
|
108
|
-
|
109
|
-
def insert(collection_name, data)
|
110
|
-
data_store[collection_name] = data
|
111
|
-
end
|
112
|
-
|
113
|
-
def set_data_store(hash)
|
114
|
-
@data_store = hash
|
115
|
-
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def data_store
|
120
|
-
@data_store ||= ::DB_HASH
|
121
53
|
end
|
122
54
|
end
|
123
55
|
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
module Mince
|
2
|
+
module HashyDb # :nodoc:
|
3
|
+
require 'digest'
|
4
|
+
require_relative 'data_store'
|
5
|
+
require_relative 'config'
|
6
|
+
|
7
|
+
# = HashyDb Data Store
|
8
|
+
#
|
9
|
+
# HashyDb Data Store stores and retrieves data from a ruby in-memory hash.
|
10
|
+
#
|
11
|
+
# Using this library offers more extensibility and growth for your application. If at any point in time
|
12
|
+
# you want to support a different database for all, or even one, of your classes, you only need to implement
|
13
|
+
# the few methods defined in this class.
|
14
|
+
#
|
15
|
+
# HashyDb::DataStore.add 'fruits', id: '1', name: 'Shnawzberry', color: 'redish', quantity: '20'
|
16
|
+
# HashyDb::DataStore.get_for_key_with_value 'fruits', :color, 'redish'
|
17
|
+
#
|
18
|
+
# @author Matt Simpson
|
19
|
+
module Interface
|
20
|
+
|
21
|
+
# Generates a unique ID for a database record
|
22
|
+
#
|
23
|
+
# @note This is necessary because different databases use different types of primary key values. Thus, each mince
|
24
|
+
# implementation must define how to generate a unique id.
|
25
|
+
#
|
26
|
+
# @param [#to_s] salt any object that responds to #to_s
|
27
|
+
# @return [String] A unique id based on the salt and the current time
|
28
|
+
def self.generate_unique_id(salt)
|
29
|
+
Digest::SHA256.hexdigest("#{Time.now}#{salt}")[0..6]
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.primary_key
|
33
|
+
Config.primary_key
|
34
|
+
end
|
35
|
+
|
36
|
+
# Deletes a field from all records in the given collection
|
37
|
+
#
|
38
|
+
# @param [Symbol] collection_name the name of the collection
|
39
|
+
# @param [symbol] field the name of the field to delete
|
40
|
+
def self.delete_field(collection_name, field)
|
41
|
+
find_all(collection_name).each do |row|
|
42
|
+
row.delete(field)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Inserts one record into a collection.
|
47
|
+
#
|
48
|
+
# @param [Symbol] collection_name the name of the collection
|
49
|
+
# @param [Hash] hash a hash of data to be added to the collection
|
50
|
+
def self.add(collection_name, hash)
|
51
|
+
find_all(collection_name) << hash
|
52
|
+
end
|
53
|
+
|
54
|
+
# Replaces a record in the collection based on the primary key's value. The hash must contain a key, defined
|
55
|
+
# by the +primary_key_identifier+ method, with a value. If a record in the data store is found with that key and
|
56
|
+
# value, the entire record will be replaced with the given hash.
|
57
|
+
#
|
58
|
+
# @param [Symbol] collection_name the name of the collection
|
59
|
+
# @param [Hash] hash a hash to replace the record in the collection with
|
60
|
+
def self.replace(collection_name, hash)
|
61
|
+
collection = find_all(collection_name)
|
62
|
+
index = collection.index{ |object| object[primary_key] == hash[primary_key] }
|
63
|
+
collection[index] = hash
|
64
|
+
end
|
65
|
+
|
66
|
+
# Deletes a record that matches the given criteria from the data store.
|
67
|
+
def self.delete_by_params(collection_name, params)
|
68
|
+
find_all(collection_name).reject! do |record|
|
69
|
+
params.all?{|k,v| record[k] == v }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Updates the field with a value for the record for the given id.
|
74
|
+
#
|
75
|
+
# @param [Symbol] collection_name the name of the collection
|
76
|
+
# @param [String] primary_key_value the id of the record
|
77
|
+
# @param [Symbol] field_name the name of the field to update
|
78
|
+
# @param [String] field_value the value to update the field to
|
79
|
+
# @return [void] no specific return value
|
80
|
+
def self.update_field_with_value(collection_name, primary_key_value, field_name, new_value)
|
81
|
+
find(collection_name, primary_key, primary_key_value)[field_name] = new_value
|
82
|
+
end
|
83
|
+
|
84
|
+
# Increments or decrements the field by the given amount for the record for the given id.
|
85
|
+
#
|
86
|
+
# @param [Symbol] collection_name the name of the collection
|
87
|
+
# @param [String] primary_key_value the id of the record
|
88
|
+
# @param [Symbol] field_name the name of the field to update
|
89
|
+
# @param [String] amount the amount to increment or decrement the field by
|
90
|
+
# @return [void] no specific return value
|
91
|
+
def self.increment_field_by_amount(collection_name, primary_key_value, field_name, amount)
|
92
|
+
find(collection_name, primary_key, primary_key_value)[field_name] += amount
|
93
|
+
end
|
94
|
+
|
95
|
+
# Gets all records that have the value for a given key.
|
96
|
+
#
|
97
|
+
# @param [Symbol] collection_name the name of the collection
|
98
|
+
# @param [String] key the key, or field, to get a record for
|
99
|
+
# @param [*] value the value to get a record for
|
100
|
+
# @return [Array] an array of records that match the key and value
|
101
|
+
def self.get_all_for_key_with_value(collection_name, key, value)
|
102
|
+
find_all(collection_name).select { |a| a[key] == value }
|
103
|
+
end
|
104
|
+
|
105
|
+
# Gets the first record that has the value for a given key.
|
106
|
+
#
|
107
|
+
# @param [Symbol] collection_name the name of the collection
|
108
|
+
# @param [String] key the key to find a record by
|
109
|
+
# @param [String] value the value to find a record by
|
110
|
+
# @return [Hash] a hash for the record found by the key and value in the collection
|
111
|
+
def self.get_for_key_with_value(collection_name, key, value)
|
112
|
+
self.get_all_for_key_with_value(collection_name, key, value)[0]
|
113
|
+
end
|
114
|
+
|
115
|
+
# Gets all records that have all of the keys and values in the given hash.
|
116
|
+
#
|
117
|
+
# @param [Symbol] collection_name the name of the collection
|
118
|
+
# @param [Hash] hash a hash to get a record for
|
119
|
+
# @return [Array] an array of all records matching the given hash for the collection
|
120
|
+
def self.get_by_params(collection_name, hash)
|
121
|
+
self.find_all(collection_name).select do |record|
|
122
|
+
hash.all?{|k,v| record[k] == v }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Gets all records for a collection
|
127
|
+
#
|
128
|
+
# @param [Symbol] collection_name the name of the collection
|
129
|
+
# @return [Array] all records for the given collection name
|
130
|
+
def self.find_all(collection_name)
|
131
|
+
DataStore.collection(collection_name)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Gets a record matching a key and value
|
135
|
+
#
|
136
|
+
# @param [Symbol] collection_name the name of the collection
|
137
|
+
# @param [String] key the key to find a record by
|
138
|
+
# @param [*] value a value the find a record by
|
139
|
+
# @return [Hash] a record that matches the given key and value
|
140
|
+
def self.find(collection_name, key, value)
|
141
|
+
find_all(collection_name).find { |x| x[key] == value }
|
142
|
+
end
|
143
|
+
|
144
|
+
# Pushes a value to a record's key that is an array
|
145
|
+
#
|
146
|
+
# @param [Symbol] collection_name the name of the collection
|
147
|
+
# @param [String] identifying_key the field used to find the record
|
148
|
+
# @param [*] identifying_value the value used to find the record
|
149
|
+
# @param [String] array_key the field to push an array to
|
150
|
+
# @param [*] value_to_push the value to push to the array
|
151
|
+
def self.push_to_array(collection_name, identifying_key, identifying_value, array_key, value_to_push)
|
152
|
+
record = find(collection_name, identifying_key, identifying_value)
|
153
|
+
if (record[array_key])
|
154
|
+
record[array_key] << value_to_push
|
155
|
+
else
|
156
|
+
record[array_key] = [value_to_push]
|
157
|
+
end
|
158
|
+
record[array_key].uniq!
|
159
|
+
end
|
160
|
+
|
161
|
+
# Removes a value from a record's key that is an array
|
162
|
+
#
|
163
|
+
# @param [Symbol] collection_name the name of the collection
|
164
|
+
# @param [String] identifying_key the field used to find the record
|
165
|
+
# @param [*] identifying_value the value used to find the record
|
166
|
+
# @param [String] array_key the field to push an array from
|
167
|
+
# @param [*] value_to_remove the value to remove from the array
|
168
|
+
def self.remove_from_array(collection_name, identifying_key, identifying_value, array_key, value_to_pop)
|
169
|
+
record = find(collection_name, identifying_key, identifying_value)
|
170
|
+
record[array_key].reject! { |x| x == value_to_pop }
|
171
|
+
end
|
172
|
+
|
173
|
+
# Returns all records where the given key contains any of the values provided
|
174
|
+
#
|
175
|
+
# @param [Symbol] collection_name the name of the collection
|
176
|
+
# @param [String] key the key to find the record by
|
177
|
+
# @param [Array] values an array of values that the record could contain
|
178
|
+
# @return [Array] all records that contain any of the values given
|
179
|
+
def self.containing_any(collection_name, key, values)
|
180
|
+
find_all(collection_name).select do |x|
|
181
|
+
if x[key].is_a?(Array)
|
182
|
+
(x[key] & values).any?
|
183
|
+
else
|
184
|
+
values.include?(x[key])
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns all records where the given key contains the given value
|
190
|
+
#
|
191
|
+
# @param [Symbol] collection_name the name of the collection
|
192
|
+
# @param [String] key the key to find records by
|
193
|
+
# @param [*] value the value to find a record by
|
194
|
+
# @return [Array] all records where the key contains the given value
|
195
|
+
def self.array_contains(collection_name, key, value)
|
196
|
+
find_all(collection_name).select do |x|
|
197
|
+
x[key] && x[key].include?(value)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Replaces the entire collection with the given data
|
202
|
+
#
|
203
|
+
# @param [Symbol] collection_name the name of the collection
|
204
|
+
# @param [Array] data an array of data hashes to replace and insert into the collection
|
205
|
+
def self.insert(collection_name, data_to_insert)
|
206
|
+
data[collection_name] = data_to_insert
|
207
|
+
end
|
208
|
+
|
209
|
+
# Deletes an entire collection
|
210
|
+
#
|
211
|
+
# @param [Symbol] collection_name the collection to delete from the database
|
212
|
+
# @return [Array] the records in the collection being deleted
|
213
|
+
def self.delete_collection(collection_name)
|
214
|
+
data.delete(collection_name)
|
215
|
+
end
|
216
|
+
|
217
|
+
# Clears the data store.
|
218
|
+
#
|
219
|
+
# Mainly used for rolling back the data store for tests.
|
220
|
+
#
|
221
|
+
# @return [Hash] the data store
|
222
|
+
def self.clear
|
223
|
+
data.clear
|
224
|
+
end
|
225
|
+
|
226
|
+
# Alias to Mince::HashyDb::DataStore.data=
|
227
|
+
def self.set_data(hash)
|
228
|
+
DataStore.set_data hash
|
229
|
+
end
|
230
|
+
|
231
|
+
# Alias to Mince::HashyDb::DataStore.data
|
232
|
+
def self.data
|
233
|
+
DataStore.data
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
data/lib/hashy_db/version.rb
CHANGED
@@ -1,3 +1,35 @@
|
|
1
|
-
module HashyDb
|
2
|
-
|
1
|
+
module HashyDb # :nodoc:
|
2
|
+
# = HashyDb Version
|
3
|
+
#
|
4
|
+
# HashyDb Version specifies the version of this library
|
5
|
+
#
|
6
|
+
# Use these versions to negotiate with for compatibility
|
7
|
+
#
|
8
|
+
# Major version releases indicates a major enhancement, breaks backward compatibility
|
9
|
+
# Minor version release indicates an addition, enhancement or bug fix which is not an immediate need, does not break backward compatibility
|
10
|
+
# Patch version release indicates a bug fix or patch that is an emergency, does not break backward compatibility
|
11
|
+
#
|
12
|
+
# @author Matt Simpson
|
13
|
+
module Version
|
14
|
+
|
15
|
+
# Provides the major level version of the library
|
16
|
+
def self.major
|
17
|
+
2
|
18
|
+
end
|
19
|
+
|
20
|
+
# Provides the minor level version of the library
|
21
|
+
def self.minor
|
22
|
+
0
|
23
|
+
end
|
24
|
+
|
25
|
+
# Provides the patch level version of the library
|
26
|
+
def self.patch
|
27
|
+
'0.pre'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Provides the full version of the library
|
32
|
+
def self.version
|
33
|
+
[Version.major, Version.minor, Version.patch].join(".")
|
34
|
+
end
|
3
35
|
end
|
data/lib/hashy_db.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative '../../lib/hashy_db'
|
2
|
+
require 'mince/shared_examples/interface_example'
|
3
|
+
|
4
|
+
describe 'Mince Interface with HashyDb' do
|
5
|
+
before do
|
6
|
+
Mince::Config.interface = Mince::HashyDb::Interface
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
Mince::HashyDb::Interface.clear
|
11
|
+
end
|
12
|
+
|
13
|
+
it_behaves_like 'a mince interface'
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative '../../../lib/hashy_db/data_store'
|
2
|
+
|
3
|
+
describe Mince::HashyDb::DataStore do
|
4
|
+
it 'has no data by default' do
|
5
|
+
described_class.data.should == {}
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'can add data' do
|
9
|
+
data = mock
|
10
|
+
described_class.set_data(data)
|
11
|
+
|
12
|
+
described_class.data.should == data
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can return a collection' do
|
16
|
+
data = mock
|
17
|
+
described_class.set_data({ some_collection: data })
|
18
|
+
|
19
|
+
described_class.collection(:some_collection).should == data
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require_relative '../../../lib/hashy_db/interface'
|
2
|
+
|
3
|
+
describe Mince::HashyDb::Interface do
|
4
|
+
# due to the low level behavior of this class, it is tested at the integration level
|
5
|
+
# at spec/integration/mince_interface_spec.rb
|
6
|
+
#
|
7
|
+
# Feel free to provide a better implementation of this.
|
8
|
+
end
|
metadata
CHANGED
@@ -1,67 +1,134 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hashy_db
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 2.0.0.pre
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Matt Simpson
|
9
9
|
- Jason Mayer
|
10
|
-
- Asynchrony
|
10
|
+
- Asynchrony
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-
|
14
|
+
date: 2012-10-02 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
|
-
name:
|
17
|
+
name: rake
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ~>
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: '
|
24
|
-
type: :
|
23
|
+
version: '0.9'
|
24
|
+
type: :development
|
25
25
|
prerelease: false
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
27
27
|
none: false
|
28
28
|
requirements:
|
29
29
|
- - ~>
|
30
30
|
- !ruby/object:Gem::Version
|
31
|
-
version: '
|
31
|
+
version: '0.9'
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
33
|
+
name: rspec
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
35
35
|
none: false
|
36
36
|
requirements:
|
37
|
-
- -
|
37
|
+
- - ~>
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '0'
|
39
|
+
version: '2.0'
|
40
40
|
type: :development
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
none: false
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '2.0'
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
|
-
name: rspec
|
49
|
+
name: guard-rspec
|
50
50
|
requirement: !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
|
-
- -
|
53
|
+
- - ~>
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '0'
|
55
|
+
version: '0.6'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
58
|
version_requirements: !ruby/object:Gem::Requirement
|
59
59
|
none: false
|
60
60
|
requirements:
|
61
|
-
- -
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.6'
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: yard
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ~>
|
62
70
|
- !ruby/object:Gem::Version
|
63
|
-
version: '0'
|
64
|
-
|
71
|
+
version: '0.7'
|
72
|
+
type: :development
|
73
|
+
prerelease: false
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0.7'
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: redcarpet
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '2.1'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ~>
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '2.1'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: debugger
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.2'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ~>
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '1.2'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: mince
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - '='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: 2.0.0.pre
|
120
|
+
type: :development
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - '='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: 2.0.0.pre
|
128
|
+
description: Library to interact with in-memory hash database collections. Offers
|
129
|
+
very little technical dependencies. In order to develop or run the tests for your
|
130
|
+
application you just need ruby installed, run bundle install and you're good to
|
131
|
+
go. No need to install and start your database, migrate, etc.
|
65
132
|
email:
|
66
133
|
- matt@railsgrammer.com
|
67
134
|
- jason.mayer@gmail.com
|
@@ -69,18 +136,15 @@ executables: []
|
|
69
136
|
extensions: []
|
70
137
|
extra_rdoc_files: []
|
71
138
|
files:
|
72
|
-
- .gitignore
|
73
|
-
- .rspec
|
74
|
-
- .rvmrc
|
75
|
-
- Gemfile
|
76
|
-
- LICENSE.txt
|
77
|
-
- README.md
|
78
|
-
- Rakefile
|
79
|
-
- hashy_db.gemspec
|
80
139
|
- lib/hashy_db.rb
|
81
140
|
- lib/hashy_db/data_store.rb
|
82
141
|
- lib/hashy_db/version.rb
|
83
|
-
-
|
142
|
+
- lib/hashy_db/config.rb
|
143
|
+
- lib/hashy_db/interface.rb
|
144
|
+
- spec/integration/mince_interface_spec.rb
|
145
|
+
- spec/units/hashy_db/config_spec.rb
|
146
|
+
- spec/units/hashy_db/data_store_spec.rb
|
147
|
+
- spec/units/hashy_db/interface_spec.rb
|
84
148
|
homepage: https://github.com/asynchrony/hashy_db
|
85
149
|
licenses: []
|
86
150
|
post_install_message:
|
@@ -96,15 +160,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
161
|
none: false
|
98
162
|
requirements:
|
99
|
-
- - ! '
|
163
|
+
- - ! '>'
|
100
164
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
165
|
+
version: 1.3.1
|
102
166
|
requirements: []
|
103
167
|
rubyforge_project: hashy_db
|
104
168
|
rubygems_version: 1.8.24
|
105
169
|
signing_key:
|
106
170
|
specification_version: 3
|
107
|
-
summary:
|
171
|
+
summary: Library to interact with in-memory hash database collections
|
108
172
|
test_files:
|
109
|
-
- spec/
|
173
|
+
- spec/integration/mince_interface_spec.rb
|
174
|
+
- spec/units/hashy_db/config_spec.rb
|
175
|
+
- spec/units/hashy_db/data_store_spec.rb
|
176
|
+
- spec/units/hashy_db/interface_spec.rb
|
110
177
|
has_rdoc:
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm use 1.9.3
|
data/Gemfile
DELETED
data/LICENSE.txt
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
Copyright (c) 2012 Matt Simpson and Jason Mayer
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
# What is hashy db?
|
2
|
-
|
3
|
-
Light weight ORM to persist data to a hash.
|
4
|
-
|
5
|
-
Provides an interface for storing and retreiving information to a Hash.
|
6
|
-
|
7
|
-
The motivation behind this is so you can clone the repository down, have ruby installed, run bundle install and be able to run your tests and develop without being dependent on any other setup.
|
8
|
-
|
9
|
-
[@github](https://github.com/asynchrony/HashyDB)
|
10
|
-
[@rubygems](https://rubygems.org/gems/hashy_db)
|
11
|
-
|
12
|
-
# How to use
|
13
|
-
|
14
|
-
view the [example mince rails app](https://github.com/coffeencoke/mince_rails_example) to see how to use this.
|
15
|
-
|
16
|
-
Basic usage is to create a constant called DB_HASH and set it to an empty hash in an initializer file, or whenever your application gets loaded (if you're not running rails).
|
17
|
-
|
18
|
-
<pre>
|
19
|
-
# initializers/datastore.rb
|
20
|
-
::DB_HASH = {}
|
21
|
-
</pre>
|
22
|
-
|
23
|
-
From there you can use Hashy Db to add and retrieve data.
|
24
|
-
|
25
|
-
<pre>
|
26
|
-
# Add a book to the books collection
|
27
|
-
HashyDb::DataStore.add 'books', title: 'The World In Photographs', publisher: 'National Geographic'
|
28
|
-
|
29
|
-
# Retrieve all records from the books collection
|
30
|
-
HashyDb::DataStore.find_all 'books'
|
31
|
-
|
32
|
-
# Update a field with a value for a specific record
|
33
|
-
HashyDb::DataStore.update_field_with_value 'books', 'primary_id_123', :field_name, 'value to update with'
|
34
|
-
|
35
|
-
# Replace a specific book
|
36
|
-
HashyDb::DataStore.replace 'books', id: 1, title: 'A World In Photographs', publisher: 'National Geographic'
|
37
|
-
</pre>
|
38
|
-
|
39
|
-
View the [data_store.rb](https://github.com/asynchrony/hashy_db/blob/master/lib/hashy_db/data_store.rb) file for all methods available.
|
40
|
-
|
41
|
-
Use with [mince data model](https://github.com/asynchrony/mince_data_model) to make it easy to change from one data storage to another, like [Mince](https://github.com/asynchrony/mince), a MongoDB implementation.
|
42
|
-
|
43
|
-
|
44
|
-
# Why would you want this?
|
45
|
-
|
46
|
-
- To defer choosing your database until you know most about your application.
|
47
|
-
- Provides assitance in designing a database agnostic architecture.
|
48
|
-
- Offers very little technical dependencies. In order to develop or run the tests for your application you just need ruby installed, run bundle install and you're good to go. No need to install and start your database, migrate, etc.
|
49
|
-
|
50
|
-
The hash can be loaded in memory and be used as your data store.
|
51
|
-
|
52
|
-
# Contribute
|
53
|
-
|
54
|
-
- fork into a topic branch, write specs, make a pull request.
|
55
|
-
|
56
|
-
# Owners
|
57
|
-
|
58
|
-
Matt Simpson - [@railsgrammer](https://twitter.com/railsgrammer)
|
59
|
-
|
60
|
-
Jason Mayer - [@farkerhaiku](https://twitter.com/farkerhaiku)
|
61
|
-
|
62
|
-
# Contributors
|
63
|
-
|
64
|
-
David Czarnecki - [@czarneckid](https://twitter.com/czarneckid)
|
65
|
-
Amos King - [@adkron](https://twitter.com/adkron)
|
data/Rakefile
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'bundler/gem_tasks'
|
2
|
-
require 'rake'
|
3
|
-
require 'rspec/core/rake_task'
|
4
|
-
|
5
|
-
RSpec::Core::RakeTask.new(:spec) do |spec|
|
6
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
7
|
-
spec.rspec_opts = ['--backtrace']
|
8
|
-
# spec.ruby_opts = ['-w']
|
9
|
-
end
|
10
|
-
|
11
|
-
task :default => :spec
|
data/hashy_db.gemspec
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require 'hashy_db/version'
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "hashy_db"
|
7
|
-
s.version = HashyDb::VERSION
|
8
|
-
s.authors = ["Matt Simpson", "Jason Mayer", "Asynchrony Solutions"]
|
9
|
-
s.email = ["matt@railsgrammer.com", "jason.mayer@gmail.com"]
|
10
|
-
s.homepage = "https://github.com/asynchrony/hashy_db"
|
11
|
-
s.summary = %q{Provides an interface to store and retrieve data in a Hash.}
|
12
|
-
s.description = %q{Provides an interface to store and retrieve data in a Hash.}
|
13
|
-
|
14
|
-
s.rubyforge_project = "hashy_db"
|
15
|
-
|
16
|
-
s.files = `git ls-files`.split("\n")
|
17
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
-
s.require_paths = ["lib"]
|
20
|
-
|
21
|
-
s.add_dependency('activesupport', '~> 3.1')
|
22
|
-
|
23
|
-
s.add_development_dependency('rake')
|
24
|
-
s.add_development_dependency('rspec')
|
25
|
-
end
|
data/spec/lib/data_store_spec.rb
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
require_relative '../../lib/hashy_db/data_store'
|
2
|
-
|
3
|
-
describe HashyDb::DataStore do
|
4
|
-
subject { HashyDb::DataStore.instance }
|
5
|
-
|
6
|
-
let(:data1) { {id: 1, field_1: 'value 1', field_2: 3, field_3: [1, 2, 3], shared_between_1_and_2: 'awesome_value', :some_array => [1, 2, 3, 4]} }
|
7
|
-
let(:data2) { {id: 2, field_1: 'value 1.2', field_2: 6, shared_between_1_and_2: 'awesome_value', :some_array => [4, 5, 6]} }
|
8
|
-
let(:data3) { {id: 3, field_1: 'value 3', field_2: 9, shared_between_1_and_2: 'not the same as 1 and 2', :some_array => [1, 7]} }
|
9
|
-
|
10
|
-
before do
|
11
|
-
subject.set_data_store({})
|
12
|
-
|
13
|
-
subject.insert(:some_collection, [data1, data2, data3])
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'has a primary key identifier' do
|
17
|
-
described_class.primary_key_identifier.should == :id
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "Generating a primary key" do
|
21
|
-
let(:data_model_id) { full_data_model_id[0..6] }
|
22
|
-
let(:full_data_model_id) { '1234567891423456789' }
|
23
|
-
let(:utc) { mock 'utc'}
|
24
|
-
let(:time) { mock 'time', :utc => utc}
|
25
|
-
let(:salt) { mock 'salt to ensure uniqeness' }
|
26
|
-
|
27
|
-
before do
|
28
|
-
Digest::SHA256.stub(:hexdigest => full_data_model_id)
|
29
|
-
Time.stub(:current => time)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should create a reasonably unique id' do
|
33
|
-
Digest::SHA256.should_receive(:hexdigest).with("#{utc}#{salt}").and_return(full_data_model_id)
|
34
|
-
|
35
|
-
described_class.generate_unique_id(salt).should == data_model_id
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'can delete a field' do
|
40
|
-
subject.delete_field(:some_collection, :field_1)
|
41
|
-
|
42
|
-
subject.find_all(:some_collection).each do |row|
|
43
|
-
row.has_key?(:field_1).should be_false
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'can delete a collection' do
|
48
|
-
subject.delete_collection(:some_collection)
|
49
|
-
|
50
|
-
subject.find_all(:some_collection).should == []
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'can delete records that match a given set of fields' do
|
54
|
-
params = { id: 1, field_1: 'value 1' }
|
55
|
-
|
56
|
-
subject.delete_by_params(:some_collection, params)
|
57
|
-
|
58
|
-
subject.find_all(:some_collection).should == [data2, data3]
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'can write and read data to and from a collection' do
|
62
|
-
data4 = {id: 3, field_1: 'value 3', field_2: 9, shared_between_1_and_2: 'not the same as 1 and 2', :some_array => [1, 7]}
|
63
|
-
|
64
|
-
subject.add(:some_collection, data4)
|
65
|
-
subject.find_all(:some_collection).should == [data1, data2, data3, data4]
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'can replace a record' do
|
69
|
-
data2[:field_1] = 'value modified'
|
70
|
-
subject.replace(:some_collection, data2)
|
71
|
-
|
72
|
-
subject.find(:some_collection, :id, 2)[:field_1].should == 'value modified'
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'can update a field with a value on a specific record' do
|
76
|
-
subject.update_field_with_value(:some_collection, 3, :field_2, '10')
|
77
|
-
|
78
|
-
subject.find(:some_collection, :id, 3)[:field_2].should == '10'
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'can increment a field with a given amount for a specific field' do
|
82
|
-
subject.increment_field_by_amount(:some_collection, 1, :field_2, 3)
|
83
|
-
|
84
|
-
subject.find(:some_collection, :id, 1)[:field_2].should == 6
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'can get one document' do
|
88
|
-
subject.find(:some_collection, :field_1, 'value 1').should == data1
|
89
|
-
subject.find(:some_collection, :field_2, 6).should == data2
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'can clear the data store' do
|
93
|
-
subject.clear
|
94
|
-
|
95
|
-
subject.find_all(:some_collection).should == []
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'can get all records of a specific key value' do
|
99
|
-
subject.get_all_for_key_with_value(:some_collection, :shared_between_1_and_2, 'awesome_value').should == [data1, data2]
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'can get all records where a value includes any of a set of values' do
|
103
|
-
subject.containing_any(:some_collection, :some_array, []).should == []
|
104
|
-
subject.containing_any(:some_collection, :some_array, [7, 2, 3]).should == [data1, data3]
|
105
|
-
subject.containing_any(:some_collection, :id, [1, 2, 5]).should == [data1, data2]
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'can get all records where the array includes a value' do
|
109
|
-
subject.array_contains(:some_collection, :some_array, 1).should == [data1, data3]
|
110
|
-
subject.array_contains(:some_collection, :some_array_2, 1).should == []
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'can push a value to an array for a specific record' do
|
114
|
-
subject.push_to_array(:some_collection, :id, 1, :field_3, 'add to existing array')
|
115
|
-
subject.push_to_array(:some_collection, :id, 1, :new_field, 'add to new array')
|
116
|
-
|
117
|
-
subject.find(:some_collection, :id, 1)[:field_3].should include('add to existing array')
|
118
|
-
subject.find(:some_collection, :id, 1)[:new_field].should == ['add to new array']
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'can remove a value from an array for a specific record' do
|
122
|
-
subject.remove_from_array(:some_collection, :id, 1, :field_3, 2)
|
123
|
-
|
124
|
-
subject.find(:some_collection, :id, 1)[:field_3].should_not include(2)
|
125
|
-
end
|
126
|
-
|
127
|
-
it 'can get all records that match a given set of keys and values' do
|
128
|
-
records = subject.get_by_params(:some_collection, field_1: 'value 1', shared_between_1_and_2: 'awesome_value')
|
129
|
-
records.size.should be(1)
|
130
|
-
records.first[:id].should == 1
|
131
|
-
subject.find_all(:some_collection).size.should == 3
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'can get a record for a specific key and value' do
|
135
|
-
subject.get_for_key_with_value(:some_collection, :field_1, 'value 1').should == data1
|
136
|
-
end
|
137
|
-
end
|