acfs 0.10.0 → 0.11.0
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/README.md +1 -1
- data/lib/acfs.rb +1 -0
- data/lib/acfs/adapter/typhoeus.rb +10 -1
- data/lib/acfs/errors.rb +17 -1
- data/lib/acfs/middleware/logger.rb +25 -0
- data/lib/acfs/model/attributes.rb +1 -1
- data/lib/acfs/model/query_methods.rb +16 -3
- data/lib/acfs/response.rb +13 -6
- data/lib/acfs/response/status.rb +33 -0
- data/lib/acfs/version.rb +1 -1
- data/spec/acfs/middleware/json_decoder_spec.rb +1 -1
- data/spec/acfs/middleware/msgpack_decoder_spec.rb +1 -1
- data/spec/acfs/model/query_methods_spec.rb +81 -29
- data/spec/acfs/response/formats_spec.rb +1 -1
- data/spec/acfs/response/status_spec.rb +69 -0
- data/spec/spec_helper.rb +4 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69903ec6f49f6fb0d192c60aa302ddc9ba16f940
|
4
|
+
data.tar.gz: bb15a106632b4d5f3681d829bee1b4e547d61039
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4acac2d53426422d60c59502fde95f17893fabced18c70d9236c3473c1250be5ac492f8ff6271db2073340af96725dee05748a6a5de43d9f92fa330fb3ef060d
|
7
|
+
data.tar.gz: d4aefee793caaad3a20afcc1c703b07882492805ad80ce70efb9fafda71700f425ed2246e8964e03c839cfd1f9ebe6da255872316afceabe15bea413161ad518
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ level and automatic request queuing and parallel processing. See Usage for more.
|
|
13
13
|
|
14
14
|
Add this line to your application's Gemfile:
|
15
15
|
|
16
|
-
gem 'acfs', '~> 0.
|
16
|
+
gem 'acfs', '~> 0.11.0'
|
17
17
|
|
18
18
|
**Note:** Acfs is under development. I'll try to avoid changes to the public
|
19
19
|
API but internal APIs may change quite often.
|
data/lib/acfs.rb
CHANGED
@@ -21,6 +21,12 @@ module Acfs
|
|
21
21
|
hydra.queue convert_request(req)
|
22
22
|
end
|
23
23
|
|
24
|
+
# Remove all requests from queue.
|
25
|
+
#
|
26
|
+
def clear
|
27
|
+
hydra.abort
|
28
|
+
end
|
29
|
+
|
24
30
|
protected
|
25
31
|
def hydra
|
26
32
|
@hydra ||= ::Typhoeus::Hydra.new
|
@@ -41,7 +47,10 @@ module Acfs
|
|
41
47
|
end
|
42
48
|
|
43
49
|
def convert_response(request, response)
|
44
|
-
Acfs::Response.new
|
50
|
+
Acfs::Response.new request,
|
51
|
+
status: response.code,
|
52
|
+
headers: response.headers,
|
53
|
+
body: response.body
|
45
54
|
end
|
46
55
|
end
|
47
56
|
end
|
data/lib/acfs/errors.rb
CHANGED
@@ -2,6 +2,22 @@ module Acfs
|
|
2
2
|
|
3
3
|
# Acfs base error.
|
4
4
|
#
|
5
|
-
class Error < StandardError
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Response error containing the responsible response object.
|
9
|
+
#
|
10
|
+
class ErroneousResponse < Error
|
11
|
+
attr_accessor :response
|
12
|
+
|
13
|
+
def initialize(response)
|
14
|
+
self.response = response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Resource not found error raised on a 404 response
|
19
|
+
#
|
20
|
+
class ResourceNotFound < ErroneousResponse
|
21
|
+
end
|
6
22
|
|
7
23
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Acfs
|
4
|
+
module Middleware
|
5
|
+
|
6
|
+
# Log requests and responses.
|
7
|
+
#
|
8
|
+
class Logger < Base
|
9
|
+
|
10
|
+
def initialize(app, options = {})
|
11
|
+
super
|
12
|
+
@logger = options[:logger] if options[:logger]
|
13
|
+
end
|
14
|
+
|
15
|
+
def response(res, nxt)
|
16
|
+
logger.info "[ACFS] #{res.request.method.to_s.upcase} #{res.request.url} -> #{res.status}"
|
17
|
+
nxt.call res
|
18
|
+
end
|
19
|
+
|
20
|
+
def logger
|
21
|
+
@logger ||= ::Logger.new STDOUT
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -73,7 +73,7 @@ module Acfs::Model
|
|
73
73
|
#
|
74
74
|
def write_attribute(name, value, opts = {})
|
75
75
|
if (type = self.class.attribute_types[name.to_sym]).nil?
|
76
|
-
raise "Unknown attribute
|
76
|
+
raise "Unknown attribute `#{name}`."
|
77
77
|
end
|
78
78
|
|
79
79
|
write_raw_attribute name, value.nil? ? nil : type.cast(value), opts
|
@@ -58,9 +58,13 @@ module Acfs::Model
|
|
58
58
|
model = self.new
|
59
59
|
|
60
60
|
request = Acfs::Request.new url(id.to_s) do |response|
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
if response.success?
|
62
|
+
model.attributes = response.data
|
63
|
+
model.loaded!
|
64
|
+
block.call model unless block.nil?
|
65
|
+
else
|
66
|
+
raise_error_for response
|
67
|
+
end
|
64
68
|
end
|
65
69
|
service.queue request
|
66
70
|
|
@@ -81,6 +85,15 @@ module Acfs::Model
|
|
81
85
|
end
|
82
86
|
end
|
83
87
|
end
|
88
|
+
|
89
|
+
def raise_error_for(response)
|
90
|
+
case response.code
|
91
|
+
when 404
|
92
|
+
raise ::Acfs::ResourceNotFound.new response
|
93
|
+
else
|
94
|
+
raise ::Acfs::ErroneousResponse.new response
|
95
|
+
end
|
96
|
+
end
|
84
97
|
end
|
85
98
|
end
|
86
99
|
end
|
data/lib/acfs/response.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'acfs/response/formats'
|
2
|
+
require 'acfs/response/status'
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
2
4
|
|
3
5
|
module Acfs
|
4
6
|
|
@@ -7,15 +9,20 @@ module Acfs
|
|
7
9
|
#
|
8
10
|
class Response
|
9
11
|
attr_accessor :data
|
10
|
-
attr_reader :
|
12
|
+
attr_reader :headers, :body
|
11
13
|
|
12
14
|
include Response::Formats
|
15
|
+
include Response::Status
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
#delegate :status, :status_message, :success?, :modified?, :timed_out?,
|
18
|
+
# :response_body, :response_headers, :response_code, :headers,
|
19
|
+
# to: :response
|
20
|
+
|
21
|
+
def initialize(request, data = {})
|
22
|
+
@request = request
|
23
|
+
@status = data[:status]
|
24
|
+
@headers = data[:headers]
|
25
|
+
@body = data[:body]
|
19
26
|
end
|
20
27
|
end
|
21
28
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Acfs
|
2
|
+
class Response
|
3
|
+
|
4
|
+
# Method to fetch information about response status.
|
5
|
+
#
|
6
|
+
module Status
|
7
|
+
|
8
|
+
# Return response status code. Will return zero if
|
9
|
+
# request was not executed or failed on client side.
|
10
|
+
#
|
11
|
+
def status_code
|
12
|
+
return @status.to_i if defined? :@status
|
13
|
+
#return response.response_code unless response.nil?
|
14
|
+
#0
|
15
|
+
end
|
16
|
+
alias :code :status_code
|
17
|
+
|
18
|
+
# Return true if response was successful indicated by
|
19
|
+
# response status code.
|
20
|
+
#
|
21
|
+
def success?
|
22
|
+
code >= 200 && code < 300
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return true unless response status code indicates that
|
26
|
+
# resource was not modified according to send precondition headers.
|
27
|
+
#
|
28
|
+
def modified?
|
29
|
+
code != 304
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/acfs/version.rb
CHANGED
@@ -5,7 +5,7 @@ describe Acfs::Middleware::JsonDecoder do
|
|
5
5
|
let(:body) { data.to_param }
|
6
6
|
let(:headers) { {} }
|
7
7
|
let(:request) { Acfs::Request.new "fubar" }
|
8
|
-
let(:response) { Acfs::Response.new request, 200, headers, body }
|
8
|
+
let(:response) { Acfs::Response.new request, status: 200, headers: headers, body: body }
|
9
9
|
let(:decoder) { Acfs::Middleware::JsonDecoder.new lambda { |req| req } }
|
10
10
|
|
11
11
|
before do
|
@@ -5,7 +5,7 @@ describe Acfs::Middleware::MessagePackDecoder do
|
|
5
5
|
let(:body) { data.to_param }
|
6
6
|
let(:headers) { {} }
|
7
7
|
let(:request) { Acfs::Request.new "fubar" }
|
8
|
-
let(:response) { Acfs::Response.new request, 200, headers, body }
|
8
|
+
let(:response) { Acfs::Response.new request, status: 200, headers: headers, body: body }
|
9
9
|
let(:decoder) { Acfs::Middleware::MessagePackDecoder.new lambda { |req| req } }
|
10
10
|
|
11
11
|
before do
|
@@ -5,28 +5,63 @@ describe Acfs::Model::QueryMethods do
|
|
5
5
|
|
6
6
|
describe '.find' do
|
7
7
|
context 'with single id' do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
context 'with successful response' do
|
9
|
+
before do
|
10
|
+
stub_request(:get, 'http://users.example.org/users/1').to_return(
|
11
|
+
body: MessagePack.dump({ id: 1, name: 'Anon', age: 12 }),
|
12
|
+
headers: {'Content-Type' => 'application/x-msgpack'})
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should load a single remote resource' do
|
16
|
+
user = model.find 1
|
17
|
+
Acfs.run
|
18
|
+
|
19
|
+
expect(user.attributes).to be == { id: 1, name: 'Anon', age: 12 }.stringify_keys
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should invoke callback after model is loaded' do
|
23
|
+
proc = Proc.new { }
|
24
|
+
proc.should_receive(:call) do |user|
|
25
|
+
expect(user).to be === @user
|
26
|
+
expect(user).to be_loaded
|
27
|
+
end
|
28
|
+
|
29
|
+
@user = model.find 1, &proc
|
30
|
+
Acfs.run
|
31
|
+
end
|
12
32
|
end
|
13
33
|
|
14
|
-
|
15
|
-
|
16
|
-
|
34
|
+
context 'with 404 response' do
|
35
|
+
before do
|
36
|
+
stub_request(:get, 'http://users.example.org/users/1').to_return(
|
37
|
+
status: 404,
|
38
|
+
body: MessagePack.dump({ error: 'not found' }),
|
39
|
+
headers: {'Content-Type' => 'application/x-msgpack'})
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should raise a NotFound error' do
|
43
|
+
@user = model.find 1
|
17
44
|
|
18
|
-
|
45
|
+
expect { Acfs.run }.to raise_error(Acfs::ResourceNotFound)
|
46
|
+
|
47
|
+
expect(@user).to_not be_loaded
|
48
|
+
end
|
19
49
|
end
|
20
50
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
51
|
+
context 'with 500 response' do
|
52
|
+
before do
|
53
|
+
stub_request(:get, 'http://users.example.org/users/1').to_return(
|
54
|
+
status: 500,
|
55
|
+
headers: {'Content-Type' => 'text/plain'})
|
26
56
|
end
|
27
57
|
|
28
|
-
|
29
|
-
|
58
|
+
it 'should raise a response error' do
|
59
|
+
@user = model.find 1
|
60
|
+
|
61
|
+
expect { Acfs.run }.to raise_error(Acfs::ErroneousResponse)
|
62
|
+
|
63
|
+
expect(@user).to_not be_loaded
|
64
|
+
end
|
30
65
|
end
|
31
66
|
end
|
32
67
|
|
@@ -40,25 +75,42 @@ describe Acfs::Model::QueryMethods do
|
|
40
75
|
headers: {'Content-Type' => 'application/x-msgpack'})
|
41
76
|
end
|
42
77
|
|
43
|
-
|
44
|
-
|
45
|
-
|
78
|
+
context 'with successful response' do
|
79
|
+
it 'should load a multiple remote resources' do
|
80
|
+
users = model.find 1, 2
|
81
|
+
Acfs.run
|
46
82
|
|
47
|
-
|
48
|
-
|
49
|
-
|
83
|
+
expect(users.size).to be == 2
|
84
|
+
expect(users[0].attributes).to be == { id: 1, name: 'Anon', age: 12 }.stringify_keys
|
85
|
+
expect(users[1].attributes).to be == { id: 2, name: 'Johnny', age: 42 }.stringify_keys
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should invoke callback after all models are loaded' do
|
89
|
+
proc = Proc.new { }
|
90
|
+
proc.should_receive(:call) do |users|
|
91
|
+
expect(users).to be === @users
|
92
|
+
expect(users.size).to be == 2
|
93
|
+
expect(users).to be_loaded
|
94
|
+
end
|
95
|
+
|
96
|
+
@users = model.find 1, 2, &proc
|
97
|
+
Acfs.run
|
98
|
+
end
|
50
99
|
end
|
51
100
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
101
|
+
context 'with one 404 response' do
|
102
|
+
before do
|
103
|
+
stub_request(:get, 'http://users.example.org/users/1').to_return(
|
104
|
+
status: 404,
|
105
|
+
body: MessagePack.dump({ error: 'not found' }),
|
106
|
+
headers: {'Content-Type' => 'application/x-msgpack'})
|
58
107
|
end
|
59
108
|
|
60
|
-
|
61
|
-
|
109
|
+
it 'should raise resource not found error' do
|
110
|
+
model.find 1, 2
|
111
|
+
|
112
|
+
expect { Acfs.run }.to raise_error(Acfs::ResourceNotFound)
|
113
|
+
end
|
62
114
|
end
|
63
115
|
end
|
64
116
|
end
|
@@ -6,7 +6,7 @@ describe Acfs::Response::Formats do
|
|
6
6
|
let(:headers) { { 'Content-Type' => mime_type } }
|
7
7
|
let(:request) { Acfs::Request.new 'fubar' }
|
8
8
|
let(:body) { nil }
|
9
|
-
let(:response) { Acfs::Response.new request, status, headers, body }
|
9
|
+
let(:response) { Acfs::Response.new request, status: status, headers: headers, body: body }
|
10
10
|
|
11
11
|
context 'without Content-Type header' do
|
12
12
|
let(:headers) { {} }
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Acfs::Response::Status do
|
4
|
+
let(:status) { 200 }
|
5
|
+
let(:mime_type) { 'application/unknown' }
|
6
|
+
let(:headers) { { 'Content-Type' => mime_type } }
|
7
|
+
let(:request) { Acfs::Request.new 'fubar' }
|
8
|
+
let(:body) { nil }
|
9
|
+
let(:response) { Acfs::Response.new request, status: status, headers: headers, body: body }
|
10
|
+
|
11
|
+
describe '#status_code alias #code' do
|
12
|
+
context 'when given' do
|
13
|
+
let(:status) { 200 }
|
14
|
+
|
15
|
+
it 'should return status code' do
|
16
|
+
expect(response.code).to be == 200
|
17
|
+
expect(response.status_code).to be == 200
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when nil' do
|
22
|
+
let(:status) { nil }
|
23
|
+
|
24
|
+
it 'should return zero' do
|
25
|
+
expect(response.code).to be == 0
|
26
|
+
expect(response.status_code).to be == 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#success?' do
|
32
|
+
context 'with success status code' do
|
33
|
+
let(:status) { 200 }
|
34
|
+
it { expect(response).to be_success }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with error status code' do
|
38
|
+
let(:status) { 500 }
|
39
|
+
it { expect(response).to_not be_success }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with zero status code' do
|
43
|
+
let(:status) { nil }
|
44
|
+
it { expect(response).to_not be_success }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#modified?' do
|
49
|
+
context 'with success status code' do
|
50
|
+
let(:status) { 200 }
|
51
|
+
it { expect(response).to be_modified }
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with not modified status code' do
|
55
|
+
let(:status) { 304 }
|
56
|
+
it { expect(response).to_not be_modified }
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with error status code' do
|
60
|
+
let(:status) { 500 }
|
61
|
+
it { expect(response).to be_modified }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with zero status code' do
|
65
|
+
let(:status) { nil }
|
66
|
+
it { expect(response).to be_modified }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acfs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Graichen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -204,6 +204,7 @@ files:
|
|
204
204
|
- lib/acfs/middleware/base.rb
|
205
205
|
- lib/acfs/middleware/json_decoder.rb
|
206
206
|
- lib/acfs/middleware/json_encoder.rb
|
207
|
+
- lib/acfs/middleware/logger.rb
|
207
208
|
- lib/acfs/middleware/msgpack_decoder.rb
|
208
209
|
- lib/acfs/middleware/msgpack_encoder.rb
|
209
210
|
- lib/acfs/middleware/print.rb
|
@@ -224,6 +225,7 @@ files:
|
|
224
225
|
- lib/acfs/request/callbacks.rb
|
225
226
|
- lib/acfs/response.rb
|
226
227
|
- lib/acfs/response/formats.rb
|
228
|
+
- lib/acfs/response/status.rb
|
227
229
|
- lib/acfs/service.rb
|
228
230
|
- lib/acfs/service/middleware.rb
|
229
231
|
- lib/acfs/service/request_handler.rb
|
@@ -240,6 +242,7 @@ files:
|
|
240
242
|
- spec/acfs/request/callbacks_spec.rb
|
241
243
|
- spec/acfs/request_spec.rb
|
242
244
|
- spec/acfs/response/formats_spec.rb
|
245
|
+
- spec/acfs/response/status_spec.rb
|
243
246
|
- spec/acfs/service_spec.rb
|
244
247
|
- spec/acfs_spec.rb
|
245
248
|
- spec/spec_helper.rb
|
@@ -281,6 +284,7 @@ test_files:
|
|
281
284
|
- spec/acfs/request/callbacks_spec.rb
|
282
285
|
- spec/acfs/request_spec.rb
|
283
286
|
- spec/acfs/response/formats_spec.rb
|
287
|
+
- spec/acfs/response/status_spec.rb
|
284
288
|
- spec/acfs/service_spec.rb
|
285
289
|
- spec/acfs_spec.rb
|
286
290
|
- spec/spec_helper.rb
|