memorydb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/memorydb.rb +9 -0
- data/lib/memorydb/base.rb +55 -0
- data/lib/memorydb/cursor.rb +168 -0
- data/lib/memorydb/db.rb +206 -0
- data/lib/memorydb/filter.rb +13 -0
- data/lib/memorydb/filter_factory.rb +87 -0
- data/lib/memorydb/sort.rb +12 -0
- metadata +132 -0
data/lib/memorydb.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'memorydb/cursor'
|
3
|
+
require 'memorydb/filter_factory'
|
4
|
+
|
5
|
+
module MemoryDb
|
6
|
+
class Base
|
7
|
+
|
8
|
+
def find
|
9
|
+
cursor
|
10
|
+
end
|
11
|
+
|
12
|
+
def filter
|
13
|
+
@filter_factory ||= FilterFactory.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove_by_id!(id)
|
17
|
+
if model = find_by_id(id)
|
18
|
+
remove_model!(model)
|
19
|
+
else
|
20
|
+
raise ArgumentError.new("Could not remove record with id: #{id} because it does not exist")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove!(model=nil)
|
25
|
+
if model
|
26
|
+
remove_by_id!(model.send(primary_key))
|
27
|
+
else
|
28
|
+
cursor.remove!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :model_klass
|
35
|
+
|
36
|
+
def cursor
|
37
|
+
Cursor.new(self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def model_or_hash_as_attrs(model_or_hash)
|
41
|
+
if model_or_hash
|
42
|
+
if model_or_hash.is_a?(Hash)
|
43
|
+
model_or_hash
|
44
|
+
elsif model_or_hash.is_a?(model_klass)
|
45
|
+
model_or_hash.attributes
|
46
|
+
else
|
47
|
+
raise ArgumentError.new("A hash or a #{model_klass} must be given to create a record")
|
48
|
+
end
|
49
|
+
else
|
50
|
+
{}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'memorydb/filter'
|
2
|
+
require 'memorydb/sort'
|
3
|
+
require 'memorydb/filter_factory'
|
4
|
+
|
5
|
+
module MemoryDb
|
6
|
+
class Cursor
|
7
|
+
|
8
|
+
def initialize(query_executor)
|
9
|
+
@query_executor = query_executor
|
10
|
+
@filters = []
|
11
|
+
@sorts = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def eq(field, value)
|
15
|
+
@filters << filter_factory.eq(field, value)
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def not_eq(field, value)
|
20
|
+
@filters << filter_factory.not_eq(field, value)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def lt(field, value)
|
25
|
+
@filters << filter_factory.lt(field, value)
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def lte(field, value)
|
30
|
+
@filters << filter_factory.lte(field, value)
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def gt(field, value)
|
35
|
+
@filters << filter_factory.gt(field, value)
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def gte(field, value)
|
40
|
+
@filters << filter_factory.gte(field, value)
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def in(field, value)
|
45
|
+
@filters << filter_factory.in(field, value)
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def not_in(field, value)
|
50
|
+
@filters << filter_factory.not_in(field, value)
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def like(field, value)
|
55
|
+
@filters << filter_factory.like(field, value)
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def or(*filters)
|
60
|
+
@filters << filter_factory.or(*filters)
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def sort(field, order)
|
65
|
+
assert_field!(field)
|
66
|
+
assert_order!(order)
|
67
|
+
@sorts << Sort.new(field, order.to_sym)
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def limit(limit)
|
72
|
+
if limit
|
73
|
+
assert_int!('Limit', limit)
|
74
|
+
@limit = limit.to_i
|
75
|
+
end
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def offset(offset)
|
80
|
+
if offset
|
81
|
+
assert_int!('Offset', offset)
|
82
|
+
@offset = offset.to_i
|
83
|
+
end
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
def count
|
88
|
+
query_executor.execute_count(query)
|
89
|
+
end
|
90
|
+
|
91
|
+
def all
|
92
|
+
query_executor.execute_find(query)
|
93
|
+
end
|
94
|
+
|
95
|
+
def first
|
96
|
+
query_executor.execute_find(
|
97
|
+
query.merge(
|
98
|
+
sorts: sorts_for_first,
|
99
|
+
limit: 1
|
100
|
+
)).first
|
101
|
+
end
|
102
|
+
|
103
|
+
def last
|
104
|
+
query_executor.execute_find(
|
105
|
+
query.merge(
|
106
|
+
sorts: sorts_for_last,
|
107
|
+
limit: 1
|
108
|
+
)).first
|
109
|
+
end
|
110
|
+
|
111
|
+
def remove!
|
112
|
+
query_executor.execute_remove!(query)
|
113
|
+
end
|
114
|
+
|
115
|
+
def first
|
116
|
+
query_executor.execute_find(
|
117
|
+
query.merge(
|
118
|
+
limit: 1
|
119
|
+
)).first
|
120
|
+
end
|
121
|
+
|
122
|
+
def query
|
123
|
+
{
|
124
|
+
:type => @type,
|
125
|
+
:filters => @filters,
|
126
|
+
:sorts => @sorts,
|
127
|
+
:offset => @offset,
|
128
|
+
:limit => @limit
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
attr_reader :query_executor
|
135
|
+
|
136
|
+
def filter_factory
|
137
|
+
@filter_factory ||= FilterFactory.new
|
138
|
+
end
|
139
|
+
|
140
|
+
def sorts_for_first
|
141
|
+
@sorts
|
142
|
+
end
|
143
|
+
|
144
|
+
def sorts_for_last
|
145
|
+
sorts_for_first.map do |sort|
|
146
|
+
Sort.new(sort.field, sort.order == :asc ? :desc : :asc)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def assert_field!(field)
|
151
|
+
unless field.is_a?(String) || field.is_a?(Symbol)
|
152
|
+
raise ArgumentError.new "Field name must be a String or Symbol but you gave #{PP.pp(field, '')}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def assert_order!(order)
|
157
|
+
unless [:asc, :desc, 'asc', 'desc'].include?(order)
|
158
|
+
raise ArgumentError.new "Sort order must be 'asc' or 'desc' but you gave #{PP.pp(order, '')}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def assert_int!(name, num)
|
163
|
+
unless num.is_a?(Integer) || (num.is_a?(String) && num =~ /\d+/)
|
164
|
+
raise ArgumentError.new "#{name} must be an integer but you gave #{PP.pp(num, '')}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/lib/memorydb/db.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require 'memorydb/base'
|
3
|
+
require 'memorydb/cursor'
|
4
|
+
|
5
|
+
# for sorting on booleans
|
6
|
+
class FalseClass
|
7
|
+
def <(other)
|
8
|
+
other
|
9
|
+
end
|
10
|
+
|
11
|
+
def >(other)
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TrueClass
|
17
|
+
def <(other)
|
18
|
+
other
|
19
|
+
end
|
20
|
+
|
21
|
+
def >(other)
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module MemoryDb
|
27
|
+
class Db < Base
|
28
|
+
|
29
|
+
def initialize(model_klass, options={})
|
30
|
+
@model_klass = model_klass
|
31
|
+
@id = 0
|
32
|
+
@store = {}
|
33
|
+
@primary_key = options[:primary_key]
|
34
|
+
end
|
35
|
+
|
36
|
+
def create!(attrs={})
|
37
|
+
_id = id
|
38
|
+
attrs = model_or_hash_as_attrs(attrs)
|
39
|
+
verify_attributes!(attrs)
|
40
|
+
attributes = attrs.merge(primary_key => _id)
|
41
|
+
store!(_id, attributes)
|
42
|
+
model_klass.new(attributes)
|
43
|
+
end
|
44
|
+
|
45
|
+
def update!(model_or_id, attributes={})
|
46
|
+
attributes ||= {}
|
47
|
+
model = case
|
48
|
+
when model_or_id.is_a?(model_klass)
|
49
|
+
if model = find_by_id(model_or_id.send(primary_key))
|
50
|
+
model_or_id
|
51
|
+
else
|
52
|
+
raise ArgumentError.new("Could not update record with id: #{model_or_id.send(primary_key)} because it does not exist") unless model
|
53
|
+
end
|
54
|
+
|
55
|
+
else
|
56
|
+
if model = find_by_id(model_or_id)
|
57
|
+
model
|
58
|
+
else
|
59
|
+
raise ArgumentError.new("Could not update record with id: #{model_or_id} because it does not exist") unless model
|
60
|
+
end
|
61
|
+
end
|
62
|
+
updated_attrs = model.attributes.merge(attributes_without_pkey(attributes))
|
63
|
+
store!(model.send(primary_key), updated_attrs)
|
64
|
+
model_klass.new(updated_attrs)
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_by_id(id)
|
68
|
+
find.eq(primary_key, id).first
|
69
|
+
end
|
70
|
+
|
71
|
+
###########################
|
72
|
+
# These methods are called by the cursor. Do not call them directly. Or call them. Whatever. Either one.
|
73
|
+
|
74
|
+
def raw_find(query)
|
75
|
+
models = all_models
|
76
|
+
models = apply_transforms models, query[:transforms]
|
77
|
+
models = filter_models models, query[:filters]
|
78
|
+
models = sort_models models, query[:sorts]
|
79
|
+
models = offset_models models, query[:offset]
|
80
|
+
models = limit_models models, query[:limit]
|
81
|
+
end
|
82
|
+
|
83
|
+
def execute_find(query)
|
84
|
+
models = raw_find(query)
|
85
|
+
models.map { |h| model_klass.new(h) }
|
86
|
+
end
|
87
|
+
|
88
|
+
def execute_count(query)
|
89
|
+
execute_find(query).size
|
90
|
+
end
|
91
|
+
|
92
|
+
def execute_remove!(query)
|
93
|
+
execute_find(query).each do |model|
|
94
|
+
remove_model!(model)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
###########################
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
attr_reader :primary_key
|
103
|
+
|
104
|
+
def verify_attributes!(attrs)
|
105
|
+
null_model = model_klass.new
|
106
|
+
allowed_attributes = null_model.attributes.keys.map(&:to_sym)
|
107
|
+
attrs.each do |key, value|
|
108
|
+
unless allowed_attributes.include?(key.to_sym)
|
109
|
+
raise ArgumentError.new("Unknown attribute: #{key}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def attributes_without_pkey(attributes)
|
115
|
+
attributes.reject { |k, v| k == primary_key }
|
116
|
+
end
|
117
|
+
|
118
|
+
def apply_transforms(models, transforms)
|
119
|
+
models.map do |model|
|
120
|
+
(transforms || []).reduce(model) do |model, transform|
|
121
|
+
transform.call(model)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def filter_models(models, filters)
|
127
|
+
models.select do |model|
|
128
|
+
(filters || []).all? do |filter|
|
129
|
+
filter_matches?(filter, model)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def filter_matches?(filter, model)
|
135
|
+
value = model[filter.field]
|
136
|
+
case filter.operator
|
137
|
+
when '='; value == filter.value
|
138
|
+
when '!='; value != filter.value
|
139
|
+
when '<'; value && value < filter.value
|
140
|
+
when '<='; value && value <= filter.value
|
141
|
+
when '>'; value && value > filter.value
|
142
|
+
when '>='; value && value >= filter.value
|
143
|
+
when 'in'; filter.value.include?(value)
|
144
|
+
when '!in'; !filter.value.include?(value)
|
145
|
+
when 'or'; filter.value.any? do |sub_filter|
|
146
|
+
filter_matches?(sub_filter, model)
|
147
|
+
end
|
148
|
+
when 'like'; value =~ /#{filter.value}/i
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def sort_models(models, sorts)
|
153
|
+
models.sort { |model1, model2| compare_models(model1, model2, sorts) }
|
154
|
+
end
|
155
|
+
|
156
|
+
def compare_models(model1, model2, sorts)
|
157
|
+
sorts.each do |sort|
|
158
|
+
result = compare_model(model1, model2, sort)
|
159
|
+
return result if result
|
160
|
+
end
|
161
|
+
0
|
162
|
+
end
|
163
|
+
|
164
|
+
def compare_model(model1, model2, sort)
|
165
|
+
field1, field2 = model1[sort.field], model2[sort.field]
|
166
|
+
field1 == field2 ? nil :
|
167
|
+
field1 < field2 && sort.order == :asc ? -1 :
|
168
|
+
field1 > field2 && sort.order == :desc ? -1 : 1
|
169
|
+
end
|
170
|
+
|
171
|
+
def limit_models(models, limit)
|
172
|
+
if limit
|
173
|
+
models.take(limit)
|
174
|
+
else
|
175
|
+
models
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def offset_models(models, offset)
|
180
|
+
if offset
|
181
|
+
models.drop(offset)
|
182
|
+
else
|
183
|
+
models
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def all_models
|
188
|
+
@store.values.map do |raw_record|
|
189
|
+
model_klass.new(MultiJson.load(raw_record)).attributes
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def store!(id, attributes)
|
194
|
+
@store[id] = MultiJson.dump(attributes)
|
195
|
+
end
|
196
|
+
|
197
|
+
def remove_model!(model)
|
198
|
+
@store.delete(model.send(primary_key))
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
|
202
|
+
def id
|
203
|
+
@id += 1
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'memorydb/filter'
|
2
|
+
|
3
|
+
module MemoryDb
|
4
|
+
class FilterFactory
|
5
|
+
|
6
|
+
def eq(field, value)
|
7
|
+
assert_field!(field)
|
8
|
+
Filter.new(field, '=', value)
|
9
|
+
end
|
10
|
+
|
11
|
+
def not_eq(field, value)
|
12
|
+
assert_field!(field)
|
13
|
+
Filter.new(field, '!=', value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def lt(field, value)
|
17
|
+
assert_field!(field)
|
18
|
+
assert_not_nil!('Less than', value)
|
19
|
+
Filter.new(field, '<', value)
|
20
|
+
end
|
21
|
+
|
22
|
+
def lte(field, value)
|
23
|
+
assert_field!(field)
|
24
|
+
assert_not_nil!('Less than or equal to', value)
|
25
|
+
Filter.new(field, '<=', value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def gt(field, value)
|
29
|
+
assert_field!(field)
|
30
|
+
assert_not_nil!('Greater than', value)
|
31
|
+
Filter.new(field, '>', value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def gte(field, value)
|
35
|
+
assert_field!(field)
|
36
|
+
assert_not_nil!('Greater than or equal to', value)
|
37
|
+
Filter.new(field, '>=', value)
|
38
|
+
end
|
39
|
+
|
40
|
+
def in(field, value)
|
41
|
+
assert_field!(field)
|
42
|
+
assert_to_a!('Inclusion', value)
|
43
|
+
Filter.new(field, 'in', value.to_a)
|
44
|
+
end
|
45
|
+
|
46
|
+
def not_in(field, value)
|
47
|
+
assert_field!(field)
|
48
|
+
assert_to_a!('Exclusion', value)
|
49
|
+
Filter.new(field, '!in', value.to_a)
|
50
|
+
end
|
51
|
+
|
52
|
+
def like(field, value)
|
53
|
+
assert_field!(field)
|
54
|
+
assert_str_or_sym!(value, 'Value')
|
55
|
+
Filter.new(field, 'like', value)
|
56
|
+
end
|
57
|
+
|
58
|
+
def or(*filters)
|
59
|
+
Filter.new(nil, 'or', filters)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def assert_to_a!(name, value)
|
65
|
+
unless value.respond_to?(:to_a)
|
66
|
+
raise ArgumentError.new "#{name} filter value must respond to to_a but #{PP.pp(value, '')} does not"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def assert_not_nil!(name, value)
|
71
|
+
if value.nil?
|
72
|
+
raise ArgumentError.new "#{name} filter value cannot be nil"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def assert_field!(field)
|
77
|
+
assert_str_or_sym!(field, 'Field name')
|
78
|
+
end
|
79
|
+
|
80
|
+
def assert_str_or_sym!(value, name)
|
81
|
+
unless value.is_a?(String) || value.is_a?(Symbol)
|
82
|
+
raise ArgumentError.new "#{name} must be a String or Symbol but you gave #{PP.pp(value, '')}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: memorydb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Myles Megyesi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: multi_json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.7.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.7.6
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: multi_json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.5.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 10.0.3
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 10.0.3
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.12.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.12.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: virtus
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.5.3
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.5.3
|
94
|
+
description: An in memory database
|
95
|
+
email:
|
96
|
+
- myles.megyesi@gmail.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- lib/memorydb/db.rb
|
102
|
+
- lib/memorydb/base.rb
|
103
|
+
- lib/memorydb/filter_factory.rb
|
104
|
+
- lib/memorydb/sort.rb
|
105
|
+
- lib/memorydb/filter.rb
|
106
|
+
- lib/memorydb/cursor.rb
|
107
|
+
- lib/memorydb.rb
|
108
|
+
homepage:
|
109
|
+
licenses: []
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 1.8.24
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: An in memory database
|
132
|
+
test_files: []
|