cardiac 0.2.0.pre3 → 0.2.0.pre5
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.
- 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