cardiac 0.2.0.pre3 → 0.2.0.pre5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cardiac/client.rb +2 -2
- data/lib/cardiac/log_subscriber.rb +22 -9
- data/lib/cardiac/model/base.rb +1 -0
- data/lib/cardiac/model/cache_decoration.rb +73 -0
- data/lib/cardiac/model/operations.rb +3 -13
- data/lib/cardiac/model/querying.rb +3 -1
- data/lib/cardiac/model.rb +1 -0
- data/lib/cardiac/operation_builder.rb +3 -1
- data/lib/cardiac/railtie.rb +7 -3
- data/lib/cardiac/resource/adapter.rb +13 -14
- data/lib/cardiac/version.rb +1 -1
- data/spec/rails-3.2/Gemfile.lock +1 -1
- data/spec/rails-3.2/app_root/log/test.log +5605 -0
- data/spec/rails-4.0/Gemfile.lock +1 -1
- data/spec/rails-4.0/app_root/log/test.log +7195 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 261e36951731f899ea83b30a9f35c0e69d651abe
|
4
|
+
data.tar.gz: 87e4b496c8d9eb31e1f2c9fb5e06df89a52e27db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 832b11c9e2bd6338857f28c5c9bd41d11e58d90aacbfa38b10eb438c165975a35374252c73f3a5038b9c7d2f1f15d44bdf308ef1728c70521606a84ab64be742
|
7
|
+
data.tar.gz: e9b1188718e09854fe9f7448d2c88859b31a5da351b618484acf744413fce97f660ce9464dcf7db3355e535f3fe552e4bdfd8dc6e158e8f501564628069ab0df
|
data/lib/cardiac/client.rb
CHANGED
@@ -16,8 +16,8 @@ module Cardiac
|
|
16
16
|
def call(env)
|
17
17
|
@app.call(env)
|
18
18
|
ensure
|
19
|
-
if message = env['rack.errors'].
|
20
|
-
Cardiac::Model::Base.logger.error message
|
19
|
+
if message = env['rack.errors'].string.presence
|
20
|
+
Cardiac::Model::Base.logger.error "cardiac: #{message}"
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Cardiac
|
2
2
|
|
3
3
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
4
|
+
class_attribute :verbose
|
5
|
+
self.verbose = false
|
4
6
|
|
5
7
|
delegate :logger, to: '::Cardiac::Model::Base'
|
6
8
|
|
@@ -13,17 +15,28 @@ module Cardiac
|
|
13
15
|
return unless logger.debug?
|
14
16
|
|
15
17
|
payload = event.payload
|
16
|
-
name, url = payload
|
18
|
+
name, url, verb, result = *payload.values_at(:name, :url, :verb, :result)
|
19
|
+
|
20
|
+
cache_trace = result.headers['X-Rack-Client-Cache'] if result
|
17
21
|
|
18
22
|
stats = "#{event.duration.round(1)}ms"
|
19
|
-
stats = "CACHED #{stats}" if name!='CACHE' && /fresh/ ===
|
20
|
-
name = "#{name} #{
|
21
|
-
|
22
|
-
if extra = payload.except(:name, :verb, :url, :
|
23
|
-
extra =
|
23
|
+
stats = "CACHED #{stats}" if cache_trace && name!='CACHE' && /fresh/ === cache_trace
|
24
|
+
name = "#{name} #{verb} (#{stats})"
|
25
|
+
|
26
|
+
if extra = payload.except(:name, :verb, :url, :result).presence
|
27
|
+
extra = extra.map{|key,value|
|
24
28
|
key = key.to_s.underscore.upcase
|
25
|
-
"
|
26
|
-
}
|
29
|
+
"\n\t +#{key}: #{key=='PAYLOAD' ? value : value.inspect}"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
if verbose && result
|
34
|
+
verbosity = Hash===verbose ? verbose : {status: true, cache: true, headers: false, body: false}
|
35
|
+
extra ||= []
|
36
|
+
extra.unshift "\n\t +BODY: #{body.inspect}" if verbosity[:body]
|
37
|
+
extra.unshift "\n\t +HEADERS: #{headers.inspect}" if verbosity[:headers]
|
38
|
+
extra.unshift "CACHE: #{cache_trace}" if verbosity[:cache]
|
39
|
+
extra.unshift result.status if verbosity[:status]
|
27
40
|
end
|
28
41
|
|
29
42
|
if odd?
|
@@ -33,7 +46,7 @@ module Cardiac
|
|
33
46
|
name = color(name, MAGENTA, true)
|
34
47
|
end
|
35
48
|
|
36
|
-
debug " #{name} #{url}#{extra}"
|
49
|
+
debug " #{name} #{url}#{' ['+extra.join('; ')+']' if extra}"
|
37
50
|
end
|
38
51
|
|
39
52
|
def identity(event)
|
data/lib/cardiac/model/base.rb
CHANGED
@@ -15,6 +15,7 @@ module Cardiac
|
|
15
15
|
include Cardiac::Model::Callbacks
|
16
16
|
include Cardiac::Model::Declarations
|
17
17
|
include Cardiac::Model::Operations
|
18
|
+
include Cardiac::Model::CacheDecoration
|
18
19
|
include ActiveSupport::Configurable
|
19
20
|
|
20
21
|
# Instances may not explicitly define their own base resource.
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Cardiac
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Cardiac::Model cache decoration methods.
|
5
|
+
module CacheDecoration
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# The callback to be installed on the adapter.
|
11
|
+
MODEL_CACHE_CONTROL_PROC = Proc.new{|adapter| adapter.klass._model_cache_control(adapter.response) }
|
12
|
+
|
13
|
+
# Causes all find(..) methods to go through an object-level cache,
|
14
|
+
# which is populated on demand whenever it is needed.
|
15
|
+
#
|
16
|
+
# Pass +false+ to uninstall the model cache.
|
17
|
+
def cache_all! options={}
|
18
|
+
if options
|
19
|
+
@_model_cache_control = (Hash===options ? options : {}).update(expires_at: Time.now)
|
20
|
+
__operation_proxy__.__adapter__.after_execute MODEL_CACHE_CONTROL_PROC
|
21
|
+
else
|
22
|
+
@model_cache = @_model_cache_control = nil
|
23
|
+
__operation_proxy__.__adapter__.skip_callback :execute, :after, MODEL_CACHE_CONTROL_PROC
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Internal method that controls the model cache, using the given response object.
|
28
|
+
def _model_cache_control(response)
|
29
|
+
response = Rack::Cache::Response.new(*response.to_a)
|
30
|
+
if response.fresh?
|
31
|
+
@_model_cache_control[:expires_at] = response.expires || (response.date + response.ttl)
|
32
|
+
else
|
33
|
+
@_model_cache_control[:expires_at] = Time.now
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
# Override this internal method to use a local model cache for retrieving all instances.
|
40
|
+
def find_all(*args, &evaluator)
|
41
|
+
unless @_model_cache_control
|
42
|
+
super
|
43
|
+
else
|
44
|
+
if @model_cache.nil? || @_model_cache_control[:expires_at].past?
|
45
|
+
result = super(*args)
|
46
|
+
sort_by = @_model_cache_control[:sort_by] and result.sort_by!(&sort_by)
|
47
|
+
@model_cache = Hash[result.map{|record| record.readonly! ; record.freeze ; [record.id.to_s, record] }]
|
48
|
+
end
|
49
|
+
evaluator ? @model_cache.values.each(&evaluator) : @model_cache.values
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# Override this internal method utilize a market cache for retrieving single instances.
|
56
|
+
# TODO: This should not require knowledge of Model::Base internals.
|
57
|
+
#
|
58
|
+
# @see Cardiac::Model::Querying
|
59
|
+
def find_by_identity(id, &evaluator)
|
60
|
+
unless @_model_cache_control
|
61
|
+
super
|
62
|
+
else
|
63
|
+
find_all if @model_cache.nil? || @_model_cache_control[:expires_at].past?
|
64
|
+
record = @model_cache[id.to_s] unless id.nil?
|
65
|
+
evaluator.call(record) if evaluator
|
66
|
+
record
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -4,28 +4,17 @@ module Cardiac
|
|
4
4
|
module Operations
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
# Extensions that are applied to the OperationHandler.
|
8
|
-
module HandlerExtensions
|
9
|
-
def transmit!(*args)
|
10
|
-
super
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
7
|
# Extensions that are applied to the ResourceAdapter.
|
15
8
|
module AdapterExtensions
|
16
9
|
def __codecs__
|
17
10
|
@__codecs__ ||= Module.new{ include ::Cardiac::Representation::Codecs }
|
18
11
|
end
|
19
|
-
|
20
|
-
def __handler__
|
21
|
-
@__handler__ ||= Class.new(::Cardiac::OperationHandler){ include HandlerExtensions; self }
|
22
|
-
end
|
23
12
|
end
|
24
13
|
|
25
14
|
# Extensions that are applied to the OperationProxy.
|
26
15
|
module ProxyExtensions
|
27
16
|
def __adapter__
|
28
|
-
@__adapter__ ||= Class.new(::Cardiac::ResourceAdapter){
|
17
|
+
@__adapter__ ||= Class.new(::Cardiac::ResourceAdapter){ extend AdapterExtensions ; self }
|
29
18
|
end
|
30
19
|
end
|
31
20
|
|
@@ -34,6 +23,7 @@ module Cardiac
|
|
34
23
|
private
|
35
24
|
|
36
25
|
# All remote operations go through this method.
|
26
|
+
# The decoded payload is returned, after storing the maximum age as represented by the request.
|
37
27
|
def perform_operation(name, *args, &block)
|
38
28
|
proxy = __operation_proxy__.new(base_resource)
|
39
29
|
proxy.klass = self
|
@@ -41,7 +31,7 @@ module Cardiac
|
|
41
31
|
end
|
42
32
|
|
43
33
|
def __operation_proxy__
|
44
|
-
@__operation_proxy__ ||= Class.new(OperationProxy){
|
34
|
+
@__operation_proxy__ ||= Class.new(OperationProxy){ extend ProxyExtensions ; self }
|
45
35
|
end
|
46
36
|
end
|
47
37
|
end
|
@@ -95,7 +95,9 @@ module Cardiac
|
|
95
95
|
|
96
96
|
# @see ActiveRecord::Persistence#instantiate
|
97
97
|
def instantiate(record, options = {})
|
98
|
-
allocate.init_with options.merge('attributes'=>record).stringify_keys
|
98
|
+
record = allocate.init_with options.merge('attributes'=>record).stringify_keys
|
99
|
+
yield record if block_given?
|
100
|
+
record
|
99
101
|
end
|
100
102
|
|
101
103
|
# See ActiveRecord::Relation::FinderMethods#raise_record_not_found_exception
|
data/lib/cardiac/model.rb
CHANGED
data/lib/cardiac/railtie.rb
CHANGED
@@ -28,6 +28,12 @@ module Cardiac
|
|
28
28
|
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
|
29
29
|
"Cardiac::ResourceCache::Middleware"
|
30
30
|
|
31
|
+
initializer 'cardiac.log_subscriber' do |app|
|
32
|
+
ActiveSupport.on_load(:cardiac) do
|
33
|
+
Cardiac::LogSubscriber.verbose = app.config.cardiac.verbose
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
31
37
|
initializer 'cardiac.build_client_middleware' do |app|
|
32
38
|
ActiveSupport.on_load(:cardiac) do
|
33
39
|
Cardiac::Client.tap do |client|
|
@@ -45,9 +51,7 @@ module Cardiac
|
|
45
51
|
# NOTE: Certain headers should ALWAYS be ignored by the client.
|
46
52
|
if client_cache = app.config.cardiac.client_cache
|
47
53
|
client_cache = {} unless Hash===client_cache
|
48
|
-
|
49
|
-
client_cache[:verbose] = app.config.cardiac.verbose unless client_cache.key? :verbose
|
50
|
-
|
54
|
+
client_cache[:verbose] = false unless client_cache.key? :verbose
|
51
55
|
client_cache[:ignore_headers] = Array(client_cache[:ignore_headers]) + ['Set-Cookie','X-Content-Digest']
|
52
56
|
|
53
57
|
client.use Rack::Cache, Hash[ client_cache.map{|k,v| ["rack-cache.#{k}", v] } ]
|
@@ -7,11 +7,11 @@ module Cardiac
|
|
7
7
|
|
8
8
|
# An adapter for performing operations on a resource.
|
9
9
|
class ResourceAdapter
|
10
|
-
include ::ActiveSupport::Callbacks
|
11
10
|
include Representation::LookupMethods
|
12
11
|
include ResourceCache::InstanceMethods
|
13
12
|
|
14
|
-
|
13
|
+
extend ActiveModel::Callbacks
|
14
|
+
define_model_callbacks :resolve, :prepare, :encode, :execute, :decode
|
15
15
|
|
16
16
|
attr_accessor :klass, :resource, :payload, :result
|
17
17
|
|
@@ -66,7 +66,7 @@ module Cardiac
|
|
66
66
|
resolved? or raise UnresolvableResourceError
|
67
67
|
prepared? or prepare! or raise InvalidOperationError
|
68
68
|
encode! *arguments
|
69
|
-
execute!
|
69
|
+
execute! &block
|
70
70
|
ensure
|
71
71
|
decode! if completed?
|
72
72
|
end
|
@@ -120,18 +120,18 @@ module Cardiac
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
-
def execute!
|
123
|
+
def execute! &response_handler
|
124
124
|
run_callbacks :execute do
|
125
125
|
clear_resource_cache unless request_is_safe?
|
126
126
|
|
127
127
|
instrumenter.instrument "operation.cardiac", event=event_attributes do
|
128
128
|
if resource_cache_enabled? http_verb
|
129
129
|
url, headers = __client_options__.slice(:url, :headers)
|
130
|
-
self.result = cache_resource(url.to_s, headers, event) { transmit! }
|
130
|
+
self.result = cache_resource(url.to_s, headers, event) { transmit!(&response_handler) }
|
131
131
|
else
|
132
|
-
self.result = transmit!
|
132
|
+
self.result = transmit!(&response_handler)
|
133
133
|
end
|
134
|
-
event[:
|
134
|
+
event[:result] = response if response
|
135
135
|
end
|
136
136
|
|
137
137
|
completed?
|
@@ -160,8 +160,8 @@ module Cardiac
|
|
160
160
|
|
161
161
|
private
|
162
162
|
|
163
|
-
def transmit!
|
164
|
-
__handler__.new(__client_options__, payload, &
|
163
|
+
def transmit!(&response_handler)
|
164
|
+
__handler__.new(__client_options__, payload, &response_handler).transmit!
|
165
165
|
end
|
166
166
|
|
167
167
|
def model_name
|
@@ -176,20 +176,19 @@ module Cardiac
|
|
176
176
|
h.keep_if{|key,value| key==:verb || key==:url || value.present? }
|
177
177
|
end
|
178
178
|
|
179
|
-
def __codecs__
|
179
|
+
def self.__codecs__
|
180
180
|
@__codecs__ ||= ::Cardiac::Representation::Codecs
|
181
181
|
end
|
182
182
|
|
183
|
-
def __handler__
|
183
|
+
def self.__handler__
|
184
184
|
@__handler__ ||= ::Cardiac::OperationHandler
|
185
185
|
end
|
186
186
|
|
187
|
-
def __client_handler__
|
188
|
-
end
|
189
|
-
|
190
187
|
def __klass_get method_name
|
191
188
|
@klass.public_send(method_name) if @klass && @klass.respond_to?(method_name, false)
|
192
189
|
end
|
190
|
+
|
191
|
+
delegate :__codecs__, :__handler__, to: 'self.class'
|
193
192
|
end
|
194
193
|
|
195
194
|
end
|
data/lib/cardiac/version.rb
CHANGED