logical_model 0.5.12 → 0.5.13
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/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:
|