perry 0.5.2 → 0.5.3
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/lib/perry/adapters/abstract_adapter.rb +13 -3
- data/lib/perry/adapters/restful_http_adapter.rb +23 -9
- data/lib/perry/base.rb +2 -2
- data/lib/perry/errors.rb +5 -0
- data/lib/perry/middlewares/cache_records.rb +4 -3
- data/lib/perry/middlewares/model_bridge.rb +8 -3
- data/lib/perry/processors/preload_associations.rb +1 -1
- data/lib/perry/relation.rb +1 -1
- data/lib/perry/version.rb +1 -1
- data/lib/perry.rb +3 -0
- metadata +4 -4
@@ -134,11 +134,14 @@ class Perry::Adapters::AbstractAdapter
|
|
134
134
|
|
135
135
|
# runs the adapter in the specified type mode -- designed to work with the middleware stack
|
136
136
|
def call(mode, options)
|
137
|
-
@stack ||= self.stack_items.inject(self.method(
|
137
|
+
@stack ||= self.stack_items.inject(self.method(:execute)) do |below, (above_klass, above_config)|
|
138
138
|
above_klass.new(below, above_config)
|
139
139
|
end
|
140
140
|
|
141
141
|
options[:mode] = mode.to_sym
|
142
|
+
if options[:relation] && options[:relation].modifiers_value[:noop]
|
143
|
+
options[:noop] = options[:relation].modifiers_value[:noop]
|
144
|
+
end
|
142
145
|
@stack.call(options)
|
143
146
|
end
|
144
147
|
|
@@ -152,6 +155,13 @@ class Perry::Adapters::AbstractAdapter
|
|
152
155
|
self.config[:processors] || []
|
153
156
|
end
|
154
157
|
|
158
|
+
# Proxy method for the stack and the actual adapter action. This method passes the call on to the
|
159
|
+
# appropriate method based on options[:mode] unless the query has a :noop modifier in which case
|
160
|
+
# it returns nil.
|
161
|
+
def execute(options)
|
162
|
+
self.send(options[:mode], options) unless options[:noop]
|
163
|
+
end
|
164
|
+
|
155
165
|
# Abstract read method -- overridden by subclasses
|
156
166
|
def read(options)
|
157
167
|
raise(NotImplementedError,
|
@@ -160,14 +170,14 @@ class Perry::Adapters::AbstractAdapter
|
|
160
170
|
end
|
161
171
|
|
162
172
|
# Abstract write method -- overridden by subclasses
|
163
|
-
def write(
|
173
|
+
def write(options)
|
164
174
|
raise(NotImplementedError,
|
165
175
|
"You must not use the abstract adapter. Implement an adapter that extends the " +
|
166
176
|
"Perry::Adapters::AbstractAdapter class and overrides this method.")
|
167
177
|
end
|
168
178
|
|
169
179
|
# Abstract delete method -- overridden by subclasses
|
170
|
-
def delete(
|
180
|
+
def delete(options)
|
171
181
|
raise(NotImplementedError,
|
172
182
|
"You must not use the abstract adapter. Implement an adapter that extends the " +
|
173
183
|
"Perry::Adapters::AbstractAdapter class and overrides this method.")
|
@@ -13,6 +13,14 @@ module Perry::Adapters
|
|
13
13
|
|
14
14
|
attr_reader :last_response
|
15
15
|
|
16
|
+
def read(options)
|
17
|
+
get_http(options[:relation]).parsed.tap do |result|
|
18
|
+
unless result.is_a?(Array)
|
19
|
+
raise Perry::MalformedResponse, "Expected instance of Array got #{result.inspect}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
16
24
|
def write(options)
|
17
25
|
object = options[:object]
|
18
26
|
params = build_params_from_attributes(object)
|
@@ -25,6 +33,10 @@ module Perry::Adapters
|
|
25
33
|
|
26
34
|
protected
|
27
35
|
|
36
|
+
def get_http(relation)
|
37
|
+
http_call(relation, :get, relation.to_hash.merge(relation.modifiers_value[:query] || {}))
|
38
|
+
end
|
39
|
+
|
28
40
|
def post_http(object, params)
|
29
41
|
http_call(object, :post, params)
|
30
42
|
end
|
@@ -39,19 +51,19 @@ module Perry::Adapters
|
|
39
51
|
|
40
52
|
def http_call(object, method, params={})
|
41
53
|
request_klass = case method
|
54
|
+
when :get then Net::HTTP::Get
|
42
55
|
when :post then Net::HTTP::Post
|
43
56
|
when :put then Net::HTTP::Put
|
44
57
|
when :delete then Net::HTTP::Delete
|
45
58
|
end
|
46
59
|
|
47
|
-
req_uri = self.build_uri(object, method)
|
60
|
+
req_uri = self.build_uri(object, method, params || {})
|
48
61
|
|
49
|
-
|
62
|
+
if [:get, :delete].include?(method)
|
50
63
|
request = request_klass.new([req_uri.path, req_uri.query].join('?'))
|
51
64
|
else
|
52
65
|
request = request_klass.new(req_uri.path)
|
53
|
-
request.set_form_data(params)
|
54
|
-
request
|
66
|
+
request.set_form_data(params)
|
55
67
|
end
|
56
68
|
|
57
69
|
self.log(params, "#{method.to_s.upcase} #{req_uri}") do
|
@@ -97,18 +109,20 @@ module Perry::Adapters
|
|
97
109
|
end
|
98
110
|
end
|
99
111
|
|
100
|
-
def build_uri(object, method)
|
112
|
+
def build_uri(object, method, params={})
|
101
113
|
url = [self.config[:host].gsub(%r{/$}, ''), self.config[:service]]
|
102
|
-
|
114
|
+
if object.is_a?(Perry::Base) && !object.new_record?
|
103
115
|
primary_key = self.config[:primary_key] || object.primary_key
|
104
116
|
pk_value = object.send(primary_key) or raise KeyError
|
105
117
|
url << pk_value
|
106
118
|
end
|
119
|
+
|
107
120
|
uri = URI.parse "#{url.join('/')}#{self.config[:format]}"
|
108
121
|
|
109
|
-
# TRP: method DELETE
|
110
|
-
|
111
|
-
|
122
|
+
# TRP: method GET and DELETE have no POST body so we have to append any default options onto
|
123
|
+
# the query string
|
124
|
+
if [:get, :delete].include?(method)
|
125
|
+
uri.query = (self.config[:default_options] || {}).merge(params).to_query
|
112
126
|
end
|
113
127
|
|
114
128
|
uri
|
data/lib/perry/base.rb
CHANGED
@@ -17,7 +17,7 @@ class Perry::Base
|
|
17
17
|
|
18
18
|
DEFAULT_PRIMARY_KEY = :id
|
19
19
|
|
20
|
-
attr_accessor :attributes, :new_record, :saved, :
|
20
|
+
attr_accessor :attributes, :new_record, :saved, :write_options
|
21
21
|
alias :new_record? :new_record
|
22
22
|
alias :saved? :saved
|
23
23
|
alias :persisted? :saved?
|
@@ -120,7 +120,7 @@ class Perry::Base
|
|
120
120
|
protected
|
121
121
|
|
122
122
|
def fetch_records(relation)
|
123
|
-
self.read_adapter.call(:read, :relation => relation)
|
123
|
+
self.read_adapter.call(:read, :relation => relation)
|
124
124
|
end
|
125
125
|
|
126
126
|
def read_with(adapter_type)
|
data/lib/perry/errors.rb
CHANGED
@@ -16,6 +16,11 @@ module Perry
|
|
16
16
|
class RecordNotSaved < PerryError
|
17
17
|
end
|
18
18
|
|
19
|
+
# Raised when the adapter returns or detects a response that Perry does not understand
|
20
|
+
#
|
21
|
+
class MalformedResponse < PerryError
|
22
|
+
end
|
23
|
+
|
19
24
|
# Used for all association related errors
|
20
25
|
#
|
21
26
|
class AssociationError < PerryError
|
@@ -52,7 +52,7 @@ class Perry::Middlewares::CacheRecords
|
|
52
52
|
cached_values
|
53
53
|
else
|
54
54
|
fresh_values = @adapter.call(options)
|
55
|
-
self.cache_store.write(key, fresh_values) if should_store_in_cache?(fresh_values)
|
55
|
+
self.cache_store.write(key, fresh_values) if should_store_in_cache?(fresh_values, options)
|
56
56
|
fresh_values
|
57
57
|
end
|
58
58
|
end
|
@@ -61,7 +61,8 @@ class Perry::Middlewares::CacheRecords
|
|
61
61
|
Digest::MD5.hexdigest(self.class.to_s + query_hash.to_a.sort { |a,b| a.to_s.first <=> b.to_s.first }.inspect)
|
62
62
|
end
|
63
63
|
|
64
|
-
def should_store_in_cache?(fresh_values)
|
65
|
-
!self.record_count_threshold || fresh_values.size <= self.record_count_threshold
|
64
|
+
def should_store_in_cache?(fresh_values, options)
|
65
|
+
(!self.record_count_threshold || fresh_values.size <= self.record_count_threshold) &&
|
66
|
+
!options[:noop]
|
66
67
|
end
|
67
68
|
end
|
@@ -25,7 +25,7 @@ class Perry::Middlewares::ModelBridge
|
|
25
25
|
protected
|
26
26
|
|
27
27
|
def build_models_from_records(records, options)
|
28
|
-
if options[:relation]
|
28
|
+
if options[:relation] && records
|
29
29
|
records.collect do |attributes|
|
30
30
|
options[:relation].klass.new_from_data_store(attributes)
|
31
31
|
end
|
@@ -37,13 +37,17 @@ class Perry::Middlewares::ModelBridge
|
|
37
37
|
def update_model_after_save(response, model)
|
38
38
|
model.saved = response.success
|
39
39
|
if model.saved
|
40
|
-
if model.new_record? &&
|
40
|
+
if model.new_record? && model.read_adapter
|
41
41
|
key = response.model_attributes[model.primary_key]
|
42
42
|
raise Perry::PerryError.new('primary key not included in response') if key.nil?
|
43
43
|
model.send("#{model.primary_key}=", key)
|
44
44
|
end
|
45
45
|
model.new_record = false
|
46
|
-
|
46
|
+
if model.read_adapter
|
47
|
+
# Clear out cache for this model
|
48
|
+
model.class.modifiers(:reset_cache => true, :noop => true).first
|
49
|
+
model.reload
|
50
|
+
end
|
47
51
|
else
|
48
52
|
add_errors_to_model(response, model, 'not saved')
|
49
53
|
end
|
@@ -51,6 +55,7 @@ class Perry::Middlewares::ModelBridge
|
|
51
55
|
|
52
56
|
def update_model_after_delete(response, model)
|
53
57
|
if response.success
|
58
|
+
model.class.scoped.modifiers(:reset_cache => true, :noop => true).first
|
54
59
|
model.freeze!
|
55
60
|
else
|
56
61
|
add_errors_to_model(response, model, 'not deleted')
|
@@ -25,7 +25,7 @@ class Perry::Processors::PreloadAssociations
|
|
25
25
|
def call(options)
|
26
26
|
results = @adapter.call(options)
|
27
27
|
|
28
|
-
|
28
|
+
if results && !results.empty?
|
29
29
|
relation = options[:relation]
|
30
30
|
(includes = relation.to_hash[:includes] || {}).keys.each do |association_id|
|
31
31
|
association = relation.klass.defined_associations[association_id.to_sym]
|
data/lib/perry/relation.rb
CHANGED
data/lib/perry/version.rb
CHANGED
data/lib/perry.rb
CHANGED
@@ -3,14 +3,17 @@ require 'active_support/core_ext/array'
|
|
3
3
|
require 'active_support/core_ext/class/inheritable_attributes'
|
4
4
|
require 'active_support/core_ext/hash/deep_merge'
|
5
5
|
require 'active_support/core_ext/hash/keys'
|
6
|
+
require 'active_support/core_ext/hash/conversions'
|
6
7
|
begin
|
7
8
|
require 'active_support/core_ext/duplicable' #ActiveSupport 2.3.x
|
8
9
|
Hash.send(:include, ActiveSupport::CoreExtensions::Hash::DeepMerge) unless Hash.instance_methods.include?('deep_merge')
|
10
|
+
Hash.send(:include, ActiveSupport::CoreExtensions::Hash::Conversions) unless Hash.instance_methods.include?('to_query')
|
9
11
|
Hash.send(:include, ActiveSupport::CoreExtensions::Hash::Keys) unless Hash.instance_methods.include?('symbolize_keys')
|
10
12
|
rescue LoadError => exception
|
11
13
|
require 'active_support/core_ext/object/duplicable' #ActiveSupport 3.0.x
|
12
14
|
end
|
13
15
|
require 'active_support/core_ext/module/delegation'
|
16
|
+
require 'active_support/core_ext/object/conversions'
|
14
17
|
|
15
18
|
# TRP: Used for pretty logging
|
16
19
|
autoload :Benchmark, 'benchmark'
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
9
|
+
- 3
|
10
|
+
version: 0.5.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Travis Petticrew
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-17 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|