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 CHANGED
@@ -1 +1 @@
1
- 0.5.12
1
+ 0.5.13
@@ -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 self.new.from_json(response.body) # this from_json is defined in ActiveModel::Serializers::JSON
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
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "logical_model"
8
- s.version = "0.5.12"
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-04-20"
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.12
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-04-20 00:00:00.000000000 Z
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: 474828961
396
+ hash: -822604947
395
397
  required_rubygems_version: !ruby/object:Gem::Requirement
396
398
  none: false
397
399
  requirements: