logical_model 0.5.12 → 0.5.13
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/logical_model.rb +11 -2
- data/lib/logical_model/cache.rb +132 -0
- data/lib/logical_model/rest_actions.rb +5 -1
- data/logical_model.gemspec +4 -2
- data/spec/lib/logical_model/cache_spec.rb +136 -0
- metadata +5 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.13
|
data/lib/logical_model.rb
CHANGED
@@ -12,6 +12,7 @@ require 'logical_model/safe_log'
|
|
12
12
|
require 'logical_model/associations'
|
13
13
|
require 'logical_model/api_key'
|
14
14
|
require 'logical_model/attributes'
|
15
|
+
require 'logical_model/cache'
|
15
16
|
|
16
17
|
# Logical Model, not persistant on DB, works through API. (replaces ActiveResource)
|
17
18
|
#
|
@@ -50,6 +51,8 @@ require 'logical_model/attributes'
|
|
50
51
|
# RemoteResource.delete(params[:id])
|
51
52
|
# RemoteResource#destroy
|
52
53
|
class LogicalModel
|
54
|
+
extend ActiveModel::Callbacks
|
55
|
+
define_model_callbacks :create, :save, :update, :destroy, :initialize
|
53
56
|
|
54
57
|
include LogicalModel::Hydra
|
55
58
|
include LogicalModel::ResponsesConfiguration
|
@@ -59,6 +62,7 @@ class LogicalModel
|
|
59
62
|
include LogicalModel::ApiKey
|
60
63
|
include LogicalModel::SafeLog
|
61
64
|
include LogicalModel::Associations
|
65
|
+
include LogicalModel::Cache
|
62
66
|
|
63
67
|
# include ActiveModel Modules that are usefull
|
64
68
|
extend ActiveModel::Naming
|
@@ -67,8 +71,6 @@ class LogicalModel
|
|
67
71
|
include ActiveModel::Validations
|
68
72
|
include ActiveModel::MassAssignmentSecurity
|
69
73
|
|
70
|
-
extend ActiveModel::Callbacks
|
71
|
-
define_model_callbacks :create, :save, :update, :destroy
|
72
74
|
|
73
75
|
self.include_root_in_json = false
|
74
76
|
|
@@ -81,6 +83,13 @@ class LogicalModel
|
|
81
83
|
self.attributes = attributes
|
82
84
|
end
|
83
85
|
|
86
|
+
def initialize_with_callback(attributes = {})
|
87
|
+
run_callbacks :initialize do
|
88
|
+
initialize_without_callback(attributes)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
alias_method_chain :initialize, :callback
|
92
|
+
|
84
93
|
class << self
|
85
94
|
attr_accessor :timeout, :retries,
|
86
95
|
:json_root
|
@@ -0,0 +1,132 @@
|
|
1
|
+
class LogicalModel
|
2
|
+
module Cache
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:extend, ClassMethods)
|
6
|
+
base.send(:include, InstanceMethods)
|
7
|
+
base.send(:after_initialize, :initialize_loaded_at)
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
attr_accessor :loaded_at
|
12
|
+
|
13
|
+
def initialize_loaded_at
|
14
|
+
self.loaded_at = Time.now
|
15
|
+
end
|
16
|
+
|
17
|
+
def _save
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def _save_with_cache
|
22
|
+
model_name = self.class.to_s.pluralize.underscore
|
23
|
+
self.class.logger.debug "LogicalModel Log CACHE: Delete cache for #{model_name}\/#{self.id}-.*"
|
24
|
+
self.class.cache_store.delete_matched(/#{model_name}\/#{self.id}-.*/)
|
25
|
+
_save_without_cache
|
26
|
+
end
|
27
|
+
alias_method_chain :_save, :cache
|
28
|
+
|
29
|
+
def _update(params={})
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def _update_with_cache(params={})
|
34
|
+
model_name = self.class.to_s.pluralize.underscore
|
35
|
+
self.class.logger.debug "LogicalModel Log CACHE: Delete cache for #{model_name}\/#{self.id}-.*"
|
36
|
+
self.class.cache_store.delete_matched(/#{model_name}\/#{self.id}-.*/)
|
37
|
+
_update_without_cache params
|
38
|
+
end
|
39
|
+
alias_method_chain :_update, :cache
|
40
|
+
|
41
|
+
def _destroy(params={})
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def _destroy_with_cache(params={})
|
46
|
+
model_name = self.class.to_s.pluralize.underscore
|
47
|
+
self.class.logger.debug "LogicalModel Log CACHE: Delete cache for #{model_name}\/#{self.id}-.*"
|
48
|
+
self.class.cache_store.delete_matched(/#{model_name}\/#{self.id}-.*/)
|
49
|
+
_destroy_without_cache
|
50
|
+
end
|
51
|
+
alias_method_chain :_destroy, :cache
|
52
|
+
end
|
53
|
+
|
54
|
+
module ClassMethods
|
55
|
+
attr_accessor :expires_in
|
56
|
+
|
57
|
+
def cache_store
|
58
|
+
@cache_store ||= Rails.cache
|
59
|
+
end
|
60
|
+
|
61
|
+
# Will return key for cache
|
62
|
+
# @param id [String] (nil)
|
63
|
+
# @param params [Hash]
|
64
|
+
def cache_key(id, params = {})
|
65
|
+
model_name = self.to_s.pluralize.underscore
|
66
|
+
params_hash = Digest::MD5.hexdigest(params.to_s)
|
67
|
+
|
68
|
+
cache_key = "#{model_name}/#{id}-#{params_hash}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def async_find(id, params={})
|
72
|
+
super(id, params)
|
73
|
+
end
|
74
|
+
|
75
|
+
def async_find_with_cache(id, params = {}, &block)
|
76
|
+
# Generate key based on params
|
77
|
+
cache_key = self.cache_key(id, params)
|
78
|
+
# If there is a cached value return it
|
79
|
+
self.logger.debug "LogicalModel Log CACHE: Reading cache key=#{cache_key}"
|
80
|
+
cached_result = self.cache_store.read(cache_key)
|
81
|
+
if cached_result
|
82
|
+
yield cached_result
|
83
|
+
else
|
84
|
+
self.logger.debug 'LogicalModel Log CACHE: Cache not present. Calling find_async without cache'
|
85
|
+
async_find_without_cache(id, params, &block)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
alias_method_chain :async_find, :cache
|
89
|
+
|
90
|
+
def async_find_response(id, params={}, body)
|
91
|
+
super(id, params, body)
|
92
|
+
end
|
93
|
+
|
94
|
+
def async_find_response_with_cache(id, params={}, body)
|
95
|
+
# remove params not used in cache_key
|
96
|
+
%w(app_key token).each {|k| params.delete(k) }
|
97
|
+
cache_value = async_find_response_without_cache(id, params, body)
|
98
|
+
# Generate key based on params
|
99
|
+
cache_key = self.cache_key(id, params)
|
100
|
+
self.logger.debug "LogicalModel Log CACHE: Writing cache key=#{cache_key}"
|
101
|
+
self.cache_store.write(cache_key, cache_value, :expires_in => self.expires_in || 10.minutes)
|
102
|
+
cache_value
|
103
|
+
end
|
104
|
+
alias_method_chain :async_find_response, :cache
|
105
|
+
|
106
|
+
def delete(id, params={})
|
107
|
+
super(id, params)
|
108
|
+
end
|
109
|
+
|
110
|
+
def delete_with_cache(id, params = {})
|
111
|
+
model_name = self.to_s.pluralize.underscore
|
112
|
+
self.logger.debug "LogicalModel Log CACHE: Delete cache for #{model_name}\/#{id}-.*"
|
113
|
+
self.cache_store.delete_matched(/#{model_name}\/#{id}-.*/)
|
114
|
+
delete_without_cache(id, params)
|
115
|
+
end
|
116
|
+
alias_method_chain :delete, :cache
|
117
|
+
|
118
|
+
def delete_multiple(ids, params={})
|
119
|
+
super(ids, params)
|
120
|
+
end
|
121
|
+
|
122
|
+
def delete_multiple_with_cache(ids, params = {})
|
123
|
+
model_name = self.to_s.pluralize.underscore
|
124
|
+
self.logger.debug "LogicalModel Log CACHE: Delete cache for #{model_name}\/(#{ids.join('|')})-.*"
|
125
|
+
self.cache_store.delete_matched(/#{model_name}\/(#{ids.join('|')})-.*/)
|
126
|
+
delete_multiple_without_cache(ids, params)
|
127
|
+
end
|
128
|
+
alias_method_chain :delete_multiple, :cache
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -352,7 +352,7 @@ class LogicalModel
|
|
352
352
|
request.on_complete do |response|
|
353
353
|
if response.code >= 200 && response.code < 400
|
354
354
|
log_ok(response)
|
355
|
-
yield
|
355
|
+
yield async_find_response(id, params, response.body)
|
356
356
|
else
|
357
357
|
log_failed(response)
|
358
358
|
end
|
@@ -361,6 +361,10 @@ class LogicalModel
|
|
361
361
|
self.hydra.queue(request)
|
362
362
|
end
|
363
363
|
|
364
|
+
def async_find_response(id, params, body)
|
365
|
+
self.new.from_json(body) # this from_json is defined in ActiveModel::Serializers::JSON
|
366
|
+
end
|
367
|
+
|
364
368
|
# synchronic find
|
365
369
|
def find(id, params = {})
|
366
370
|
result = nil
|
data/logical_model.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "logical_model"
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.13"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Dwayne Macgowan"]
|
12
|
-
s.date = "2014-
|
12
|
+
s.date = "2014-06-13"
|
13
13
|
s.description = "LogicalModel allows to use a resource as a model. It is based on web presentation http://www.slideshare.net/ihower/serviceoriented-design-and-implement-with-rails3"
|
14
14
|
s.email = "dwaynemac@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
"lib/logical_model/associations/belongs_to.rb",
|
39
39
|
"lib/logical_model/associations/has_many_keys.rb",
|
40
40
|
"lib/logical_model/attributes.rb",
|
41
|
+
"lib/logical_model/cache.rb",
|
41
42
|
"lib/logical_model/hydra.rb",
|
42
43
|
"lib/logical_model/responses_configuration.rb",
|
43
44
|
"lib/logical_model/rest_actions.rb",
|
@@ -50,6 +51,7 @@ Gem::Specification.new do |s|
|
|
50
51
|
"models/user.rb",
|
51
52
|
"spec/client_spec.rb",
|
52
53
|
"spec/lib/logical_model/associations/has_many_keys_spec.rb",
|
54
|
+
"spec/lib/logical_model/cache_spec.rb",
|
53
55
|
"test/helper.rb",
|
54
56
|
"test/test_logical_model.rb",
|
55
57
|
"test/typhoeus_mocks.rb"
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require './lib/logical_model'
|
2
|
+
|
3
|
+
describe LogicalModel::Cache do
|
4
|
+
describe "when included" do
|
5
|
+
before do
|
6
|
+
class Example < LogicalModel
|
7
|
+
|
8
|
+
attribute :id
|
9
|
+
attribute :name
|
10
|
+
|
11
|
+
self.hydra = Typhoeus::Hydra.new
|
12
|
+
|
13
|
+
self.enable_delete_multiple = true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "adds expires_in class method" do
|
18
|
+
Example.should respond_to :expires_in
|
19
|
+
end
|
20
|
+
|
21
|
+
it "adds loaded_at as instance method" do
|
22
|
+
Example.new.should respond_to :loaded_at
|
23
|
+
end
|
24
|
+
|
25
|
+
it "initializes loaded_at" do
|
26
|
+
model = Example.new
|
27
|
+
model.run_callbacks :initialize
|
28
|
+
model.loaded_at.should_not be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should use params to build cache_key" do
|
32
|
+
cache_key = Example.cache_key('id', {})
|
33
|
+
cache_key2 = Example.cache_key('id', {:param => true})
|
34
|
+
cache_key.should_not == cache_key2
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should chain find_async" do
|
38
|
+
Example.should respond_to :async_find_with_cache
|
39
|
+
Example.should respond_to :async_find_without_cache
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "cached value present" do
|
43
|
+
before do
|
44
|
+
Example.stub_chain(:cache_store, :read).and_return("test")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "#async_find should return the cached value" do
|
48
|
+
Example.async_find("id") { |r| @result = r}
|
49
|
+
@result.should == "test"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "cached value not present" do
|
54
|
+
before do
|
55
|
+
Example.stub_chain(:cache_store, :read).and_return(nil)
|
56
|
+
Example.stub_chain(:cache_store, :write).and_return(nil)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "#async_find should look for the value" do
|
60
|
+
Example.should_receive(:async_find_without_cache)
|
61
|
+
Example.async_find("id") {|r| @result = r}
|
62
|
+
end
|
63
|
+
|
64
|
+
it "#async_find_response should store the value in the cache" do
|
65
|
+
Example.should_receive(:async_find_response_without_cache)
|
66
|
+
Example.async_find_response("id", {}, "test")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "save" do
|
71
|
+
before do
|
72
|
+
Example.stub_chain(:cache_store, :read).and_return(Example.new)
|
73
|
+
Example.stub_chain(:cache_store, :delete_matched).and_return(nil)
|
74
|
+
Example.async_find("id") {|r| @result = r}
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should clear cache" do
|
78
|
+
Example.cache_store.should_receive(:delete_matched)
|
79
|
+
@result.save
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "update" do
|
84
|
+
before do
|
85
|
+
Example.stub_chain(:cache_store, :read).and_return(Example.new)
|
86
|
+
Example.stub_chain(:cache_store, :delete_matched).and_return(nil)
|
87
|
+
Example.any_instance.stub(:_update_without_cache).and_return(true)
|
88
|
+
Example.async_find("id") {|r| @result = r}
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should clear cache" do
|
92
|
+
@result.should_receive(:_update_without_cache)
|
93
|
+
@result.update({:name => "test"})
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "destroy" do
|
98
|
+
before do
|
99
|
+
Example.stub_chain(:cache_store, :read).and_return(Example.new)
|
100
|
+
Example.stub_chain(:cache_store, :delete_matched).and_return(nil)
|
101
|
+
Example.async_find("id") {|r| @result = r}
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should clear cache" do
|
105
|
+
Example.cache_store.should_receive(:delete_matched)
|
106
|
+
@result.destroy
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "delete" do
|
111
|
+
before do
|
112
|
+
Example.stub_chain(:cache_store, :read).and_return(Example.new)
|
113
|
+
Example.stub_chain(:cache_store, :delete_matched).and_return(nil)
|
114
|
+
Example.async_find("id") {|r| @result = r}
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should clear cache" do
|
118
|
+
Example.cache_store.should_receive(:delete_matched)
|
119
|
+
Example.delete("id")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "delete_multiple" do
|
124
|
+
before do
|
125
|
+
Example.stub_chain(:cache_store, :read).and_return(Example.new)
|
126
|
+
Example.stub_chain(:cache_store, :delete_matched).and_return(nil)
|
127
|
+
Example.async_find("id") {|r| @result = r}
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should clear cache" do
|
131
|
+
Example.cache_store.should_receive(:delete_matched)
|
132
|
+
Example.delete_multiple(["id1","id2"])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logical_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.13
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-06-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -361,6 +361,7 @@ files:
|
|
361
361
|
- lib/logical_model/associations/belongs_to.rb
|
362
362
|
- lib/logical_model/associations/has_many_keys.rb
|
363
363
|
- lib/logical_model/attributes.rb
|
364
|
+
- lib/logical_model/cache.rb
|
364
365
|
- lib/logical_model/hydra.rb
|
365
366
|
- lib/logical_model/responses_configuration.rb
|
366
367
|
- lib/logical_model/rest_actions.rb
|
@@ -373,6 +374,7 @@ files:
|
|
373
374
|
- models/user.rb
|
374
375
|
- spec/client_spec.rb
|
375
376
|
- spec/lib/logical_model/associations/has_many_keys_spec.rb
|
377
|
+
- spec/lib/logical_model/cache_spec.rb
|
376
378
|
- test/helper.rb
|
377
379
|
- test/test_logical_model.rb
|
378
380
|
- test/typhoeus_mocks.rb
|
@@ -391,7 +393,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
391
393
|
version: '0'
|
392
394
|
segments:
|
393
395
|
- 0
|
394
|
-
hash:
|
396
|
+
hash: -822604947
|
395
397
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
396
398
|
none: false
|
397
399
|
requirements:
|