repositories 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.
@@ -0,0 +1,238 @@
1
+ require 'active_record'
2
+ require 'repository/base'
3
+
4
+ module Repository
5
+ class ActiveRecord < Base
6
+
7
+ def initialize(model_klass, options={})
8
+ @model_klass = model_klass
9
+ @domain_model_klass = options[:domain_model_klass]
10
+ end
11
+
12
+ def create!(model_or_hash={})
13
+ attrs = model_or_hash_as_attrs(model_or_hash)
14
+ build_domain_model(model_klass.create!(attrs))
15
+ end
16
+
17
+ def update!(model_or_id, attrs={})
18
+ attributes = attrs || {}
19
+ case
20
+ when model_or_id.is_a?(model_klass)
21
+ if model_or_id.persisted?
22
+ model_or_id.update_attributes(attributes)
23
+ build_domain_model(model_or_id)
24
+ else
25
+ raise ArgumentError.new("Could not update record with id: #{model_or_id.send(primary_key)} because it does not exist")
26
+ end
27
+ when model_or_id.is_a?(domain_model_klass)
28
+ id = model_or_id.send(primary_key)
29
+ if model = model_klass.where(primary_key => id).first
30
+ update!(model, model_or_id.attributes.merge(attributes))
31
+ else
32
+ raise ArgumentError.new("Could not update record with id: #{id} because it does not exist")
33
+ end
34
+ else
35
+ if model = model_klass.where(primary_key => model_or_id).first
36
+ update!(model, attributes)
37
+ else
38
+ raise ArgumentError.new("Could not update record with id: #{model_or_id} because it does not exist")
39
+ end
40
+ end
41
+ end
42
+
43
+ def find_by_id(id)
44
+ self.find.eq(model_klass.primary_key, id).first
45
+ end
46
+
47
+ def execute_find(query)
48
+ scope = apply_filters model_klass, query[:filters]
49
+ scope = apply_sorts scope, query[:sorts]
50
+ scope = apply_limit scope, query[:limit]
51
+ scope = apply_offset scope, query[:offset]
52
+ scope.all.map { |m| build_domain_model(m) }
53
+ end
54
+
55
+ def execute_count(query)
56
+ apply_filters(model_klass, query[:filters]).count
57
+ end
58
+
59
+ def execute_remove!(query)
60
+ apply_filters(model_klass, query[:filters]).delete_all
61
+ end
62
+
63
+ private
64
+
65
+ attr_reader :domain_model_klass
66
+
67
+ def update_data(model_or_id)
68
+ case
69
+ when model_or_id.is_a?(model_klass)
70
+ [model_or_id.send(primary_key), model_or_id.attributes.slice(*model_or_id.changed)]
71
+ when model_or_id.is_a?(domain_model_klass)
72
+ [model_or_id.send(primary_key), model_or_id.attributes]
73
+ else
74
+ [model_or_id, {}]
75
+ end
76
+ end
77
+
78
+ def build_domain_model(model)
79
+ if domain_model_klass
80
+ domain_model_klass.new(model.attributes)
81
+ else
82
+ model
83
+ end
84
+ end
85
+
86
+ def apply_filters(scope, filters)
87
+ apply_filter(scope, Filter.new(nil, 'and', filters))
88
+ end
89
+
90
+ class FakeScope
91
+
92
+ attr_reader :wheres, :variables
93
+
94
+ def initialize
95
+ @wheres = []
96
+ @variables = []
97
+ end
98
+
99
+ def where(sql, *varaiables)
100
+ @wheres << sql
101
+ @variables += varaiables
102
+ self
103
+ end
104
+
105
+ end
106
+
107
+ def apply_filter(scope, filter)
108
+ column = quoted_column(filter.field)
109
+ case filter.operator
110
+ when '='
111
+ if filter.value
112
+ scope.where("#{column} = ?", filter.value)
113
+ else
114
+ scope.where("#{column} IS NULL")
115
+ end
116
+ when '!='
117
+ if filter.value
118
+ scope.where("#{column} <> ? OR #{column} IS NULL", filter.value)
119
+ else
120
+ scope.where("#{column} IS NOT NULL")
121
+ end
122
+ when '<'
123
+ scope.where("#{column} < ?", filter.value)
124
+ when '<='
125
+ scope.where("#{column} <= ?", filter.value)
126
+ when '>'
127
+ scope.where("#{column} > ?", filter.value)
128
+ when '>='
129
+ scope.where("#{column} >= ?", filter.value)
130
+ when 'in'
131
+ apply_contains_filter(scope, column, filter.value, '', lambda { |str|
132
+ "(#{str} AND #{column} IS NOT NULL)"
133
+ }, lambda { |str|
134
+ "(#{str} OR #{column} IS NULL)"
135
+ })
136
+ when '!in'
137
+ non_nil_values, nil_values = filter.value.uniq.partition { |val| !val.nil? }
138
+ case
139
+ when non_nil_values.empty? && nil_values.empty?
140
+ scope
141
+ when non_nil_values.empty? && !nil_values.empty?
142
+ scope.where("#{column} IS NOT NULL")
143
+ when !non_nil_values.empty? && nil_values.empty?
144
+ scope.where("(#{column} NOT IN (?) OR #{column} IS NULL)", non_nil_values)
145
+ when !non_nil_values.empty? && !nil_values.empty?
146
+ scope.where("(#{column} NOT IN (?) AND #{column} IS NOT NULL)", non_nil_values)
147
+ end
148
+ when 'like'
149
+ scope.where("#{column} LIKE #{glob(filter.value)}")
150
+ when 'or'
151
+ apply_and_join_filters(scope, filter.value, ' OR ')
152
+ when 'and'
153
+ apply_and_join_filters(scope, filter.value, ' AND ')
154
+ else
155
+ scope
156
+ end
157
+ end
158
+
159
+ def apply_and_join_filters(scope, filters, join)
160
+ fake_scope = FakeScope.new
161
+ filters.each do |filter|
162
+ apply_filter(fake_scope, filter)
163
+ end
164
+ sql = fake_scope.wheres.join(join)
165
+ sql = "(#{sql})" if fake_scope.wheres.size > 1
166
+ scope.where(sql, *fake_scope.variables)
167
+ end
168
+
169
+ def apply_contains_filter(scope, column, values, _not, if_nil, if_not_nil)
170
+ non_nil_values, nil_values = values.uniq.partition { |val| !val.nil? }
171
+ str = "#{column} #{_not} IN (?)"
172
+ if nil_values.empty?
173
+ str = if_nil.call(str)
174
+ else
175
+ str = if_not_nil.call(str)
176
+ end
177
+ scope.where(str, non_nil_values)
178
+ end
179
+
180
+ def apply_sorts(scope, sorts)
181
+ if sorts.empty?
182
+ scope
183
+ else
184
+ ar_sorts = sorts.reduce([]) do |ar_sorts, sort|
185
+ ar_sorts << "#{quoted_column(sort.field)} #{sort.order}"
186
+ ar_sorts
187
+ end.join(', ')
188
+ scope.order ar_sorts
189
+ end
190
+ end
191
+
192
+ def apply_limit(scope, limit)
193
+ if limit
194
+ scope.limit(limit)
195
+ else
196
+ scope
197
+ end
198
+ end
199
+
200
+ def apply_offset(scope, offset)
201
+ if offset
202
+ scope.offset(offset)
203
+ else
204
+ scope
205
+ end
206
+ end
207
+
208
+ def quoted_column(column)
209
+ ::ActiveRecord::Base.connection.quote_column_name(column)
210
+ end
211
+
212
+ def quoted_value(value)
213
+ ::ActiveRecord::Base.connection.quote(value)
214
+ end
215
+
216
+ def glob(k)
217
+ quoted_value("%#{k}%")
218
+ end
219
+
220
+ def store_record!(attrs)
221
+ record = attrs.dup
222
+ if id = record.delete(primary_key)
223
+ model_klass.update_all(record, {primary_key => id}, {limit: 1})
224
+ else
225
+ model_klass.create!(record)
226
+ end
227
+ end
228
+
229
+ def primary_key
230
+ model_klass.primary_key
231
+ end
232
+
233
+ def remove_model!(model)
234
+ model_klass.delete_all(id: model.id)
235
+ end
236
+
237
+ end
238
+ end
@@ -0,0 +1,55 @@
1
+ require 'time'
2
+ require 'repository/cursor'
3
+ require 'repository/filter_factory'
4
+
5
+ module Repository
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 'repository/filter'
2
+ require 'repository/sort'
3
+ require 'repository/filter_factory'
4
+
5
+ module Repository
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
@@ -0,0 +1,13 @@
1
+ module Repository
2
+ class Filter
3
+
4
+ attr_reader :field, :operator, :value
5
+
6
+ def initialize(field, operator, value)
7
+ @field = field
8
+ @operator = operator
9
+ @value = value
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,87 @@
1
+ require 'repository/filter'
2
+
3
+ module Repository
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
@@ -0,0 +1,206 @@
1
+ require 'multi_json'
2
+ require 'repository/base'
3
+ require 'repository/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 Repository
27
+ class Memory < 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,12 @@
1
+ module Repository
2
+ class Sort
3
+
4
+ attr_reader :field, :order
5
+
6
+ def initialize(field, order)
7
+ @field = field
8
+ @order = order
9
+ end
10
+
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: repositories
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-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.11
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.11
30
+ - !ruby/object:Gem::Dependency
31
+ name: bson_ext
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.8.6
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.8.6
46
+ - !ruby/object:Gem::Dependency
47
+ name: database_cleaner
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.1
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: 0.9.1
62
+ - !ruby/object:Gem::Dependency
63
+ name: mongo
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.8.1
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: 1.8.1
78
+ - !ruby/object:Gem::Dependency
79
+ name: multi_json
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 1.5.0
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: 1.5.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: rake
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 10.0.3
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 10.0.3
110
+ - !ruby/object:Gem::Dependency
111
+ name: rspec
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 2.12.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 2.12.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: sqlite3
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: 1.3.6
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ~>
140
+ - !ruby/object:Gem::Version
141
+ version: 1.3.6
142
+ - !ruby/object:Gem::Dependency
143
+ name: virtus
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ~>
148
+ - !ruby/object:Gem::Version
149
+ version: 0.5.3
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ version: 0.5.3
158
+ description: Repository?
159
+ email:
160
+ - myles.megyesi@gmail.com
161
+ executables: []
162
+ extensions: []
163
+ extra_rdoc_files: []
164
+ files:
165
+ - lib/repository/memory.rb
166
+ - lib/repository/base.rb
167
+ - lib/repository/filter_factory.rb
168
+ - lib/repository/sort.rb
169
+ - lib/repository/filter.rb
170
+ - lib/repository/active_record.rb
171
+ - lib/repository/cursor.rb
172
+ homepage:
173
+ licenses: []
174
+ post_install_message:
175
+ rdoc_options: []
176
+ require_paths:
177
+ - lib
178
+ required_ruby_version: !ruby/object:Gem::Requirement
179
+ none: false
180
+ requirements:
181
+ - - ! '>='
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ required_rubygems_version: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ! '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ requirements: []
191
+ rubyforge_project:
192
+ rubygems_version: 1.8.24
193
+ signing_key:
194
+ specification_version: 3
195
+ summary: Store some data?
196
+ test_files: []