montage_rails 0.3.2 → 0.4.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +28 -0
  4. data/lib/montage_rails/base/column.rb +57 -0
  5. data/lib/montage_rails/base.rb +406 -0
  6. data/lib/montage_rails/errors.rb +7 -0
  7. data/lib/montage_rails/log_subscriber.rb +48 -0
  8. data/lib/montage_rails/query_cache.rb +44 -0
  9. data/lib/montage_rails/railtie.rb +0 -0
  10. data/lib/montage_rails/relation.rb +88 -0
  11. data/lib/montage_rails/version.rb +3 -0
  12. data/lib/montage_rails.rb +57 -0
  13. data/lib/tasks/montage_rails_tasks.rake +4 -0
  14. data/test/dummy/README.rdoc +28 -0
  15. data/test/dummy/Rakefile +6 -0
  16. data/test/dummy/app/assets/javascripts/application.js +13 -0
  17. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  18. data/test/dummy/app/controllers/application_controller.rb +5 -0
  19. data/test/dummy/app/helpers/application_helper.rb +2 -0
  20. data/test/dummy/app/models/actor.rb +3 -0
  21. data/test/dummy/app/models/movie.rb +30 -0
  22. data/test/dummy/app/models/studio.rb +3 -0
  23. data/test/dummy/app/models/test.rb +2 -0
  24. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  25. data/test/dummy/bin/bundle +3 -0
  26. data/test/dummy/bin/rails +4 -0
  27. data/test/dummy/bin/rake +4 -0
  28. data/test/dummy/bin/setup +29 -0
  29. data/test/dummy/config/application.rb +25 -0
  30. data/test/dummy/config/boot.rb +5 -0
  31. data/test/dummy/config/database.yml +25 -0
  32. data/test/dummy/config/environment.rb +5 -0
  33. data/test/dummy/config/environments/development.rb +41 -0
  34. data/test/dummy/config/environments/production.rb +79 -0
  35. data/test/dummy/config/environments/test.rb +42 -0
  36. data/test/dummy/config/initializers/assets.rb +11 -0
  37. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  38. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  39. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  40. data/test/dummy/config/initializers/inflections.rb +16 -0
  41. data/test/dummy/config/initializers/mime_types.rb +4 -0
  42. data/test/dummy/config/initializers/montage.rb +4 -0
  43. data/test/dummy/config/initializers/session_store.rb +3 -0
  44. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  45. data/test/dummy/config/locales/en.yml +23 -0
  46. data/test/dummy/config/routes.rb +56 -0
  47. data/test/dummy/config/secrets.yml +22 -0
  48. data/test/dummy/config.ru +4 -0
  49. data/test/dummy/db/development.sqlite3 +0 -0
  50. data/test/dummy/db/schema.rb +16 -0
  51. data/test/dummy/db/test.sqlite3 +0 -0
  52. data/test/dummy/log/RAILS_ENV=development.log +0 -0
  53. data/test/dummy/log/development.log +1038 -0
  54. data/test/dummy/log/test.log +12368 -0
  55. data/test/dummy/public/404.html +67 -0
  56. data/test/dummy/public/422.html +67 -0
  57. data/test/dummy/public/500.html +66 -0
  58. data/test/dummy/public/favicon.ico +0 -0
  59. data/test/montage_rails/base/column_test.rb +59 -0
  60. data/test/montage_rails/base_test.rb +375 -0
  61. data/test/montage_rails/query_cache_test.rb +68 -0
  62. data/test/montage_rails/relation_test.rb +114 -0
  63. data/test/montage_rails_test.rb +97 -0
  64. data/test/resources/actor_resource.rb +141 -0
  65. data/test/resources/movie_resource.rb +160 -0
  66. data/test/resources/studio_resource.rb +56 -0
  67. data/test/test_helper.rb +196 -0
  68. metadata +123 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c5c2bc4fde46dd63c234dc588be50b964f28174
4
- data.tar.gz: 4194ed623e630feddb105b251dbc175627d5eeb4
3
+ metadata.gz: 277cfc7ce7155045e893a43b55fb439cefcc1fb1
4
+ data.tar.gz: 0b8338daff90f24f126bf6d18daac01205b2a8e8
5
5
  SHA512:
6
- metadata.gz: 6e78ab4b49d5a76751ce218d8639659f1519a853b554330b535ae338c8fb8e56813f1ed09dcae1e0db914af74c4626b0421f5d7faf2110616bc2077946ba275b
7
- data.tar.gz: bfefffaa585a50703b62c89ea77ee293d973ea53d357becc5bb26d24e5e2ebb44bde279272e7c00ce3ffafdd2d840a277b0df1e5f3058cc61a58a00b36b6f431
6
+ metadata.gz: 87b3d4b9ac86ea2310c782091869252e94f23426f2cf226ef23e0fbfc7b27fd8d3f12941731b7226310ba624510a494203ed0d89695b2e4e28e9f7deb9c5166e
7
+ data.tar.gz: a5a907dceb7a233c2ac321c4984c24a193c91292dc5be1263f473278d0aa6e2f905dd3a9df19aca4b8fbcffd97f5394ce52cc745a3c449ae26223e7813d94a44
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 dphaener
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/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'MontageRails'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ Bundler::GemHelper.install_tasks
18
+
19
+ require 'rake/testtask'
20
+
21
+ Rake::TestTask.new(:test) do |t|
22
+ t.libs << 'lib'
23
+ t.libs << 'test'
24
+ t.pattern = 'test/**/*_test.rb'
25
+ t.verbose = false
26
+ end
27
+
28
+ task default: :test
@@ -0,0 +1,57 @@
1
+ module MontageRails
2
+ class Base
3
+ class Column
4
+ TYPE_MAP = {
5
+ "integer" => Integer,
6
+ "float" => Float,
7
+ "text" => String,
8
+ "date" => Date,
9
+ "time" => Time,
10
+ "datetime" => DateTime,
11
+ "numeric" => Numeric
12
+ }
13
+
14
+ attr_accessor :name, :type, :required
15
+
16
+ alias_method :required?, :required
17
+
18
+ def initialize(name, type, required = false)
19
+ @name = name
20
+ @type = type
21
+ @required = required
22
+ end
23
+
24
+ def value_valid?(value)
25
+ !(required? && value.nil?)
26
+ end
27
+
28
+ # Determines if the string value passed in is an integer
29
+ # Returns true or false
30
+ #
31
+ def is_i?(value)
32
+ /\A\d+\z/ =~ value
33
+ end
34
+
35
+ # Determines if the string value passed in is a float
36
+ # Returns true or false
37
+ #
38
+ def is_f?(value)
39
+ /\A\d+\.\d+\z/ =~ value
40
+ end
41
+
42
+ def coerce(value)
43
+ return value if value.is_a?(TYPE_MAP[type])
44
+
45
+ if is_i?(value)
46
+ coerce_to = Integer
47
+ elsif is_f?(value)
48
+ coerce_to = Float
49
+ else
50
+ coerce_to = TYPE_MAP[type]
51
+ end
52
+
53
+ Virtus::Attribute.build(coerce_to).coerce(value)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,406 @@
1
+ require 'montage_rails/log_subscriber'
2
+ require 'montage_rails/relation'
3
+ require 'montage_rails/base/column'
4
+ require 'active_model'
5
+ require 'virtus'
6
+
7
+ module MontageRails
8
+ class Base
9
+ extend ActiveModel::Callbacks
10
+ include ActiveModel::Model
11
+ include Virtus.model
12
+
13
+ define_model_callbacks :save, :create
14
+
15
+ class << self
16
+ # Delegates all of the relation methods to the class level object, so they can be called on the base class
17
+ #
18
+ delegate :limit, :offset, :order, :where, :first, to: :relation
19
+
20
+ # Delegate the connection to the base module for ease of reference
21
+ #
22
+ delegate :connection, :notify, to: MontageRails
23
+
24
+ cattr_accessor :table_name
25
+
26
+ # Define a new instance of the query cache
27
+ #
28
+ def cache
29
+ @cache ||= QueryCache.new
30
+ end
31
+
32
+ # Hook into the Rails logger
33
+ #
34
+ def logger
35
+ @logger ||= Rails.logger
36
+ end
37
+
38
+ # Setup a class level instance of the MontageRails::Relation object
39
+ #
40
+ def relation
41
+ @relation = Relation.new(self)
42
+ end
43
+
44
+ # Define a has_many relationship
45
+ #
46
+ def has_many(table)
47
+ class_eval do
48
+ define_method(table.to_s.tableize.to_sym) do
49
+ table.to_s.classify.constantize.where("#{self.class.table_name.demodulize.underscore.singularize.foreign_key} = #{id}")
50
+ end
51
+ end
52
+ end
53
+
54
+ # Define a belongs_to relationship
55
+ #
56
+ def belongs_to(table)
57
+ class_eval do
58
+ define_method(table.to_s.tableize.singularize.to_sym) do
59
+ table.to_s.classify.constantize.find_by_id(__send__(table.to_s.foreign_key))
60
+ end
61
+
62
+ define_method("#{table.to_s.tableize.singularize}=") do |record|
63
+ self.__send__("#{table.to_s.foreign_key}=", record.id)
64
+ self
65
+ end
66
+ end
67
+ end
68
+
69
+ # The pluralized table name used in API requests
70
+ #
71
+ def table_name
72
+ self.name.demodulize.underscore.pluralize
73
+ end
74
+
75
+ # Redefine the table name
76
+ #
77
+ def set_table_name(value)
78
+ instance_eval do
79
+ define_singleton_method(:table_name) do
80
+ value
81
+ end
82
+ end
83
+ end
84
+
85
+ alias_method :table_name=, :set_table_name
86
+
87
+ # Returns an array of MontageRails::Base::Column's for the schema
88
+ #
89
+ def columns
90
+ @columns ||= [].tap do |ary|
91
+ response = connection.schema(table_name)
92
+
93
+ return [] unless response.schema.respond_to?(:fields)
94
+
95
+ ary << Column.new("id", "text", false)
96
+ ary << Column.new("created_at", "datetime", false)
97
+ ary << Column.new("updated_at", "datetime", false)
98
+
99
+ response.schema.fields.each do |field|
100
+ ary << Column.new(field["name"], field["datatype"], field["required"])
101
+
102
+ instance_eval do
103
+ define_singleton_method("find_by_#{field["name"]}") do |value|
104
+ where("#{field["name"]} = '#{value}'").first
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # Fetch all the documents
112
+ #
113
+ def all
114
+ relation.to_a
115
+ end
116
+
117
+ # Find a record by the id
118
+ #
119
+ def find_by_id(value)
120
+ response = cache.get_or_set_query(self, value) { connection.document(table_name, value) }
121
+
122
+ if response.success?
123
+ new(response.document.items.merge(persisted: true))
124
+ else
125
+ nil
126
+ end
127
+ end
128
+
129
+ alias_method :find, :find_by_id
130
+
131
+ # Find the record using the given params, or initialize a new one with those params
132
+ #
133
+ def find_or_initialize_by(params = {})
134
+ return nil if params.empty?
135
+
136
+ query = relation.where(params)
137
+
138
+ response = cache.get_or_set_query(self, query) { connection.documents(table_name, query) }
139
+
140
+ if response.success? && response.documents.any?
141
+ new(attributes_from_response(response).merge(persisted: true))
142
+ else
143
+ new(params)
144
+ end
145
+ end
146
+
147
+ # Returns an array of the column names for the table
148
+ #
149
+ def column_names
150
+ columns.map { |c| c.name }
151
+ end
152
+
153
+ # Initialize and save a new instance of the object
154
+ #
155
+ def create(params = {})
156
+ new(params).save
157
+ end
158
+
159
+ # Returns a string like 'Post id:integer, title:string, body:text'
160
+ #
161
+ def inspect
162
+ if self == Base
163
+ super
164
+ else
165
+ attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
166
+ "#{super}(#{attr_list})"
167
+ end
168
+ end
169
+
170
+ def method_missing(method_name, *args, &block)
171
+ __send__(:columns)
172
+
173
+ if respond_to?(method_name.to_sym)
174
+ __send__(method_name.to_sym, *args)
175
+ else
176
+ super(method_name, *args, &block)
177
+ end
178
+ end
179
+
180
+ def respond_to_missing?(method_name, include_private = false)
181
+ __send__(:column_names).include?(method_name.to_s.split("_").first) || super(method_name, include_private)
182
+ end
183
+
184
+ def attributes_from_response(response)
185
+ case response.members
186
+ when Montage::Documents then response.documents.first.attributes.merge(persisted: true)
187
+ when Montage::Document then response.document.attributes.merge(persisted: true)
188
+ when Montage::Errors then raise MontageAPIError, "There was an error with the Montage API: #{response.errors.attributes}"
189
+ when Montage::Error then raise MontageAPIError, "There was an error with the Montage API: #{response.error.attributes}"
190
+ else raise MontageAPIError, "There was an error with the Montage API, please try again."
191
+ end
192
+ end
193
+ end
194
+
195
+ attr_accessor :persisted
196
+
197
+ alias_method :persisted?, :persisted
198
+
199
+ delegate :connection, :notify, to: MontageRails
200
+ delegate :attributes_from_response, to: "self.class"
201
+
202
+ def initialize(params = {})
203
+ initialize_columns
204
+ @persisted = params[:persisted] ? params[:persisted] : false
205
+ @current_method = "Load"
206
+ super(params)
207
+ end
208
+
209
+ # Save the record to the database
210
+ #
211
+ # Will return nil if the attributes are not valid
212
+ #
213
+ # Upon successful creation or update, will return an instance of self, otherwise returns nil
214
+ #
215
+ def save
216
+ run_callbacks :save do
217
+ return nil unless attributes_valid?
218
+
219
+ if persisted?
220
+ @current_method = "Update"
221
+
222
+ response = notify(self) do
223
+ connection.create_or_update_documents(self.class.table_name, [updateable_attributes(true)])
224
+ end
225
+ else
226
+ @current_method = "Create"
227
+
228
+ response = notify(self) do
229
+ connection.create_or_update_documents(self.class.table_name, [updateable_attributes(false)])
230
+ end
231
+ end
232
+
233
+ if response.success?
234
+ if persisted?
235
+ initialize(attributes_from_response(response))
236
+ else
237
+ run_callbacks :create do
238
+ initialize(attributes_from_response(response))
239
+ end
240
+ end
241
+
242
+ self
243
+ else
244
+ response
245
+ end
246
+ end
247
+ end
248
+
249
+ # The bang method for save, which will raise an exception if saving is not successful
250
+ #
251
+ def save!
252
+ unless save
253
+ raise MontageAPIError, response.errors.attributes
254
+ end
255
+ end
256
+
257
+ # Update the given attributes for the document
258
+ #
259
+ # Returns false if the given attributes aren't valid
260
+ #
261
+ # Returns a copy of self if updating is successful
262
+ #
263
+ def update_attributes(params)
264
+ old_attributes = attributes.clone
265
+
266
+ params.each do |key, value|
267
+ if respond_to?(key.to_sym)
268
+ coerced_value = column_for(key.to_s).coerce(value)
269
+ send("#{key}=", coerced_value)
270
+ end
271
+ end
272
+
273
+ return self if old_attributes == attributes
274
+
275
+ if attributes_valid?
276
+ @current_method = id.nil? ? "Create" : "Update"
277
+
278
+ response = notify(self) do
279
+ connection.create_or_update_documents(self.class.table_name, [updateable_attributes(!id.nil?)])
280
+ end
281
+
282
+ initialize(attributes_from_response(response))
283
+ @persisted = true
284
+ self
285
+ else
286
+ initialize(old_attributes)
287
+ false
288
+ end
289
+ end
290
+
291
+ # Destroy the copy of this record from the database
292
+ #
293
+ def destroy
294
+ @current_method = "Delete"
295
+ notify(self) { connection.delete_document(self.class.table_name, id) }
296
+
297
+ @persisted = false
298
+ self
299
+ end
300
+
301
+ # Reload the current document
302
+ #
303
+ def reload
304
+ @current_method = "Load"
305
+
306
+ response = notify(self) do
307
+ connection.document(self.class.table_name, id)
308
+ end
309
+
310
+ initialize(attributes_from_response(response))
311
+ @persisted = true
312
+ self
313
+ end
314
+
315
+ def new_record?
316
+ !persisted?
317
+ end
318
+
319
+ # Returns the Column class instance for the attribute passed in
320
+ #
321
+ def column_for(name)
322
+ self.class.columns.select { |column| column.name == name }.first
323
+ end
324
+
325
+ # Performs a check to ensure that required columns have a value
326
+ #
327
+ def attributes_valid?
328
+ attributes.each do |key, value|
329
+ next unless column_class = column_for(key.to_s)
330
+ return false unless column_class.value_valid?(value)
331
+ end
332
+ end
333
+
334
+ # The attributes used to update the document
335
+ #
336
+ def updateable_attributes(include_id = false)
337
+ include_id ? attributes.except(:created_at, :updated_at) : attributes.except(:created_at, :updated_at, :id)
338
+ end
339
+
340
+ # Required for notifications to work, returns a payload suitable
341
+ # for the log subscriber
342
+ #
343
+ def payload
344
+ {
345
+ reql: reql_payload[@current_method],
346
+ name: "#{self.class.name} #{@current_method}"
347
+ }
348
+ end
349
+
350
+ # Returns an <tt>#inspect</tt>-like string for the value of the
351
+ # attribute +attr_name+. String attributes are elided after 50
352
+ # characters, and Date and Time attributes are returned in the
353
+ # <tt>:db</tt> format. Other attributes return the value of
354
+ # <tt>#inspect</tt> without modification.
355
+ #
356
+ # person = Person.create!(:name => "David Heinemeier Hansson " * 3)
357
+ #
358
+ # person.attribute_for_inspect(:name)
359
+ # # => '"David Heinemeier Hansson David Heinemeier Hansson D..."'
360
+ #
361
+ # person.attribute_for_inspect(:created_at)
362
+ # # => '"2009-01-12 04:48:57"'
363
+ #
364
+ def attribute_for_inspect(attr_name)
365
+ value = attributes[attr_name]
366
+
367
+ if value.is_a?(String) && value.length > 50
368
+ "#{value[0..50]}...".inspect
369
+ elsif value.is_a?(Date) || value.is_a?(Time)
370
+ %("#{value.to_s(:db)}")
371
+ else
372
+ value.inspect
373
+ end
374
+ end
375
+
376
+ # Returns the contents of the record as a nicely formatted string.
377
+ #
378
+ def inspect
379
+ attributes_as_nice_string = self.class.column_names.collect { |name|
380
+ if attributes[name.to_sym] || new_record?
381
+ "#{name}: #{attribute_for_inspect(name.to_sym)}"
382
+ end
383
+ }.compact.join(", ")
384
+ "#<#{self.class} #{attributes_as_nice_string}>"
385
+ end
386
+
387
+ private
388
+
389
+
390
+ def initialize_columns
391
+ self.class.columns.each do |column|
392
+ self.class.__send__(:attribute, column.name.to_sym, Column::TYPE_MAP[column.type])
393
+ end
394
+ end
395
+
396
+ def reql_payload
397
+ {
398
+ "Load" => id,
399
+ "Update" => "#{id}: #{updateable_attributes(true)}",
400
+ "Create" => updateable_attributes,
401
+ "Delete" => id,
402
+ "Save" => updateable_attributes
403
+ }
404
+ end
405
+ end
406
+ end
@@ -0,0 +1,7 @@
1
+ module MontageRails
2
+ class AttributeMissingError < StandardError; end
3
+
4
+ class RelationError < StandardError; end
5
+
6
+ class MontageAPIError < StandardError; end
7
+ end
@@ -0,0 +1,48 @@
1
+ module MontageRails
2
+ class LogSubscriber < ActiveSupport::LogSubscriber
3
+ def self.runtime=(value)
4
+ Thread.current["montage_rails_reql_runtime"] = value
5
+ end
6
+
7
+ def self.runtime
8
+ Thread.current["montage_rails_reql_runtime"] ||= 0
9
+ end
10
+
11
+ def self.reset_runtime
12
+ rt, self.runtime = runtime, 0
13
+ rt
14
+ end
15
+
16
+ def initialize
17
+ super
18
+ @odd_or_even = false
19
+ end
20
+
21
+ def reql(event)
22
+ self.class.runtime += event.duration
23
+ return unless logger.debug?
24
+
25
+ name = '%s (%.1fms)' % [event.payload[:name], event.duration]
26
+ reql = event.payload[:reql]
27
+
28
+ if odd?
29
+ name = color(name, CYAN, true)
30
+ reql = color(reql, nil, true)
31
+ else
32
+ name = color(name, MAGENTA, true)
33
+ end
34
+
35
+ debug " #{name} #{reql}"
36
+ end
37
+
38
+ def odd?
39
+ @odd_or_even = !@odd_or_even
40
+ end
41
+
42
+ def logger
43
+ MontageRails::Base.logger
44
+ end
45
+ end
46
+ end
47
+
48
+ MontageRails::LogSubscriber.attach_to :montage_rails
@@ -0,0 +1,44 @@
1
+ module MontageRails
2
+ class QueryCache
3
+ attr_reader :cache
4
+
5
+ def initialize
6
+ @cache = {}
7
+ end
8
+
9
+ def get_or_set_query(klass, query)
10
+ cached = cache.keys.include?("#{klass}/#{query}")
11
+ ActiveSupport::Notifications.instrument("reql.montage_rails", notification_payload(query, klass, cached)) do
12
+ if cached
13
+ cache["#{klass}/#{query}"]
14
+ else
15
+ response = yield
16
+ cache["#{klass}/#{query}"] = response
17
+ response
18
+ end
19
+ end
20
+ end
21
+
22
+ # Clear the entire query cache
23
+ #
24
+ def clear
25
+ @cache = {}
26
+ end
27
+
28
+ # Remove a certain key from the cache
29
+ # Returns the removed value, or nil if nothin was found
30
+ #
31
+ def remove(key)
32
+ cache.delete(key)
33
+ end
34
+
35
+ private
36
+
37
+ def notification_payload(query, klass, cached = false)
38
+ {
39
+ reql: query,
40
+ name: cached ? "#{klass} Load [CACHE]" : "#{klass} Load"
41
+ }
42
+ end
43
+ end
44
+ end
File without changes