acfs 1.0.0.dev.1.b305 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/CHANGELOG.md +64 -0
- data/README.md +2 -2
- data/acfs.gemspec +4 -4
- data/lib/acfs.rb +7 -5
- data/lib/acfs/adapter/base.rb +0 -2
- data/lib/acfs/adapter/typhoeus.rb +17 -13
- data/lib/acfs/collections/paginatable.rb +10 -10
- data/lib/acfs/configuration.rb +4 -5
- data/lib/acfs/errors.rb +10 -9
- data/lib/acfs/global.rb +16 -7
- data/lib/acfs/location.rb +11 -11
- data/lib/acfs/middleware/base.rb +1 -2
- data/lib/acfs/middleware/json.rb +27 -0
- data/lib/acfs/middleware/logger.rb +0 -2
- data/lib/acfs/middleware/msgpack.rb +30 -0
- data/lib/acfs/middleware/print.rb +0 -2
- data/lib/acfs/middleware/serializer.rb +39 -0
- data/lib/acfs/operation.rb +5 -5
- data/lib/acfs/request.rb +4 -4
- data/lib/acfs/request/callbacks.rb +2 -3
- data/lib/acfs/resource.rb +2 -2
- data/lib/acfs/resource/attributes.rb +10 -37
- data/lib/acfs/resource/attributes/base.rb +10 -19
- data/lib/acfs/resource/attributes/boolean.rb +10 -8
- data/lib/acfs/resource/attributes/date_time.rb +6 -9
- data/lib/acfs/resource/attributes/dict.rb +37 -0
- data/lib/acfs/resource/attributes/float.rb +11 -5
- data/lib/acfs/resource/attributes/integer.rb +7 -5
- data/lib/acfs/resource/attributes/list.rb +13 -6
- data/lib/acfs/resource/attributes/string.rb +3 -5
- data/lib/acfs/resource/attributes/uuid.rb +8 -17
- data/lib/acfs/resource/loadable.rb +0 -1
- data/lib/acfs/resource/locatable.rb +0 -4
- data/lib/acfs/resource/operational.rb +0 -2
- data/lib/acfs/resource/persistence.rb +17 -17
- data/lib/acfs/resource/query_methods.rb +3 -5
- data/lib/acfs/resource/service.rb +0 -2
- data/lib/acfs/resource/validation.rb +0 -2
- data/lib/acfs/response.rb +1 -2
- data/lib/acfs/response/formats.rb +1 -2
- data/lib/acfs/response/status.rb +3 -5
- data/lib/acfs/runner.rb +21 -11
- data/lib/acfs/service.rb +4 -6
- data/lib/acfs/service/middleware.rb +20 -30
- data/lib/acfs/service/middleware/stack.rb +63 -0
- data/lib/acfs/singleton_resource.rb +0 -2
- data/lib/acfs/stub.rb +30 -21
- data/lib/acfs/util.rb +1 -1
- data/lib/acfs/version.rb +4 -2
- data/spec/acfs/adapter/typhoeus_spec.rb +12 -4
- data/spec/acfs/collection_spec.rb +45 -33
- data/spec/acfs/configuration_spec.rb +9 -1
- data/spec/acfs/global_spec.rb +21 -3
- data/spec/acfs/middleware/json_spec.rb +63 -0
- data/spec/acfs/middleware/msgpack_spec.rb +60 -0
- data/spec/acfs/operation_spec.rb +10 -0
- data/spec/acfs/request/callbacks_spec.rb +8 -8
- data/spec/acfs/request_spec.rb +5 -5
- data/spec/acfs/resource/attributes/boolean_spec.rb +40 -9
- data/spec/acfs/resource/attributes/date_time_spec.rb +29 -35
- data/spec/acfs/resource/attributes/dict_spec.rb +75 -0
- data/spec/acfs/resource/attributes/float_spec.rb +48 -9
- data/spec/acfs/resource/attributes/integer_spec.rb +34 -0
- data/spec/acfs/resource/attributes/list_spec.rb +43 -19
- data/spec/acfs/resource/attributes/uuid_spec.rb +31 -54
- data/spec/acfs/resource/attributes_spec.rb +17 -31
- data/spec/acfs/resource/locatable_spec.rb +2 -2
- data/spec/acfs/resource/persistance_spec.rb +65 -34
- data/spec/acfs/resource/query_methods_spec.rb +87 -87
- data/spec/acfs/resource/validation_spec.rb +4 -5
- data/spec/acfs/response/formats_spec.rb +1 -1
- data/spec/acfs/response/status_spec.rb +1 -1
- data/spec/acfs/runner_spec.rb +28 -3
- data/spec/acfs/service/middleware_spec.rb +4 -20
- data/spec/acfs/service_spec.rb +3 -5
- data/spec/acfs/singleton_resource_spec.rb +1 -2
- data/spec/acfs/stub_spec.rb +137 -22
- data/spec/acfs_spec.rb +22 -19
- data/spec/spec_helper.rb +2 -1
- data/spec/support/service.rb +10 -6
- data/spec/support/shared/find_callbacks.rb +7 -7
- metadata +37 -30
- data/lib/acfs/middleware/json_decoder.rb +0 -16
- data/lib/acfs/middleware/json_encoder.rb +0 -20
- data/lib/acfs/middleware/msgpack_decoder.rb +0 -26
- data/lib/acfs/middleware/msgpack_encoder.rb +0 -19
- data/spec/acfs/middleware/json_decoder_spec.rb +0 -45
- data/spec/acfs/middleware/msgpack_decoder_spec.rb +0 -36
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
N2QwNTZiNDBiZDc4NjJhNjc3NjU3M2YxOTI4MzY2YWM4ZGZjMzE0MA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6d20f4360733b38c6a3fde5716cf43ff586e7579
|
4
|
+
data.tar.gz: b3f8ba827e8813e21182d1b48d3e17ab4b8e1f89
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
OTBiMjY4ZDE4ZTJjNDk4YjEwZjVjYjEzMGJiNzNkZDY3Y2IxMWM3Y2VhN2Q1
|
11
|
-
M2I1OWI0NTVlODIxMjFiYzJhYTYwZTZjMTI3M2ZmMTQxYjBkYzI=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
Zjk4MzhhNGM0YzNjNmY4ZDAzOWFiYTE2MzViYTdhM2QxMTc0ZTI3MzJkMmI3
|
14
|
-
MThkZDNlYWFiM2FjYmE4MWVkY2I5N2RlZTMwYjA4OGE5ZTZmMmUzM2MxZjUz
|
15
|
-
ZTZkZTNhNmUwNmEyYTIzZGJhZDk0ZjgyN2Q2ZjAzMjkzMzdkMzA=
|
6
|
+
metadata.gz: 0841dd869d9e38ae2cc009c80fa7c9a327f970ee35ec3011f535a5f1f0f43bf6fd086efd1d16256793f8c80abeb6db6962ab7459d3c123f405f62b457639effc
|
7
|
+
data.tar.gz: bd81043d09374bbd5984120563c3425441fda4939fcd3154182aed6e28bd78fb0b6118025c17003ff642c274657ab575bf420045d8bbfd468b0eadaaa79a9cab
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,69 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.0.0
|
4
|
+
|
5
|
+
* Switch to first non-development major as it's long time used in production.
|
6
|
+
* Fix NewRelic RPM inference with middleware stack inherited from `ActionDispatch::MiddlewareStack`.
|
7
|
+
|
8
|
+
## 0.48.0
|
9
|
+
|
10
|
+
* Remove #attribute_types broke since f7e4109 (Sep 2013, v0.23)
|
11
|
+
* Fix attribute inheritance on subclassing broken since commit 7cf1d11 (Apr 2014, v0.43)
|
12
|
+
|
13
|
+
## 0.47.0
|
14
|
+
|
15
|
+
* Change blank value handling of dict and list type (0a12ef1)
|
16
|
+
|
17
|
+
## 0.46.0
|
18
|
+
|
19
|
+
* Rework types system (#39)
|
20
|
+
|
21
|
+
## 0.45.0
|
22
|
+
|
23
|
+
* Fetching multiple records (`find(ary)`) is stable now, but untested (#38)
|
24
|
+
* Middleware stack is build on ActionDispatch::MiddlewareStack now
|
25
|
+
* Deprecate legacy middleware names (xyEncoder, xyDecoder)
|
26
|
+
|
27
|
+
## 0.44.0
|
28
|
+
|
29
|
+
* Add option to configure adapter creation and pass option to typhoeus adapter e.g.
|
30
|
+
limiting concurrency.
|
31
|
+
|
32
|
+
## 0.43.2
|
33
|
+
|
34
|
+
* add `total_count` for paginated collections
|
35
|
+
|
36
|
+
## 0.43.1
|
37
|
+
|
38
|
+
* Fix `:with` condition matching on stubs
|
39
|
+
|
40
|
+
## 0.43.0
|
41
|
+
|
42
|
+
* Remove `Acfs::Model` (inherit from `Acfs::Resource`)
|
43
|
+
* Stub does only a partial match of `:with` attributes now
|
44
|
+
* Allow blocks as stub `:return`s
|
45
|
+
|
46
|
+
## 0.42.0
|
47
|
+
|
48
|
+
* Add simple dict attribute type
|
49
|
+
|
50
|
+
## 0.40.0
|
51
|
+
|
52
|
+
* Change `Resource#persisted?` to return true if it is not new
|
53
|
+
|
54
|
+
## 0.39.1
|
55
|
+
|
56
|
+
* Fix automatic path parameter handling for #destroy
|
57
|
+
|
58
|
+
## 0.39.0
|
59
|
+
|
60
|
+
* Add new event acfs.operation.before_process
|
61
|
+
|
62
|
+
## 0.38.0
|
63
|
+
|
64
|
+
* Allow middlewares to abort request processing
|
65
|
+
* Allow middlewares to receive the request operation object (via the request)
|
66
|
+
|
3
67
|
## 0.37.0
|
4
68
|
|
5
69
|
* Add Acfs.on
|
data/README.md
CHANGED
@@ -250,8 +250,8 @@ it 'should find user number one' do
|
|
250
250
|
expect(user.name).to be == 'John Smith'
|
251
251
|
expect(user.age).to be == 32
|
252
252
|
|
253
|
-
expect(@stub).to
|
254
|
-
expect(@stub).to_not
|
253
|
+
expect(@stub).to be_called
|
254
|
+
expect(@stub).to_not be_called 5.times
|
255
255
|
end
|
256
256
|
|
257
257
|
it 'should not find user number two' do
|
data/acfs.gemspec
CHANGED
@@ -8,13 +8,13 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Acfs::VERSION
|
9
9
|
spec.authors = ['Jan Graichen']
|
10
10
|
spec.email = %w(jg@altimos.de)
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
11
|
+
spec.description = 'API Client For Services'
|
12
|
+
spec.summary = 'An abstract API base client for service oriented application.'
|
13
13
|
spec.homepage = 'https://github.com/jgraichen/acfs'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = Dir['**/*'].grep(%r{^((bin|lib|test|spec|features)/|.*\.gemspec|.*LICENSE.*|.*README.*|.*CHANGELOG.*)})
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) {
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = %w(lib)
|
20
20
|
|
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_runtime_dependency 'multi_json'
|
25
25
|
|
26
26
|
# Bundle update w/o version resolves to 0.3.3 ...
|
27
|
-
spec.add_runtime_dependency 'typhoeus', '
|
27
|
+
spec.add_runtime_dependency 'typhoeus', '~> 1.0'
|
28
28
|
|
29
29
|
spec.add_runtime_dependency 'rack'
|
30
30
|
|
data/lib/acfs.rb
CHANGED
@@ -30,13 +30,16 @@ module Acfs
|
|
30
30
|
module Middleware
|
31
31
|
extend ActiveSupport::Autoload
|
32
32
|
require 'acfs/middleware/base'
|
33
|
+
require 'acfs/middleware/serializer'
|
33
34
|
|
34
35
|
autoload :Print
|
35
36
|
autoload :Logger
|
36
|
-
autoload :
|
37
|
-
autoload :
|
38
|
-
autoload :JsonEncoder
|
39
|
-
autoload :
|
37
|
+
autoload :JSON
|
38
|
+
autoload :JsonDecoder, 'acfs/middleware/json'
|
39
|
+
autoload :JsonEncoder, 'acfs/middleware/json'
|
40
|
+
autoload :MessagePack, 'acfs/middleware/msgpack'
|
41
|
+
autoload :MessagePackDecoder, 'acfs/middleware/msgpack'
|
42
|
+
autoload :MessagePackEncoder, 'acfs/middleware/msgpack'
|
40
43
|
end
|
41
44
|
|
42
45
|
module Adapter
|
@@ -44,4 +47,3 @@ module Acfs
|
|
44
47
|
require 'acfs/adapter/typhoeus'
|
45
48
|
end
|
46
49
|
end
|
47
|
-
|
data/lib/acfs/adapter/base.rb
CHANGED
@@ -2,10 +2,12 @@ require 'typhoeus'
|
|
2
2
|
|
3
3
|
module Acfs
|
4
4
|
module Adapter
|
5
|
-
|
6
5
|
# Adapter for Typhoeus.
|
7
6
|
#
|
8
7
|
class Typhoeus < Base
|
8
|
+
def initialize(**kwargs)
|
9
|
+
@options = kwargs
|
10
|
+
end
|
9
11
|
|
10
12
|
def start
|
11
13
|
hydra.run
|
@@ -14,9 +16,7 @@ module Acfs
|
|
14
16
|
raise
|
15
17
|
end
|
16
18
|
|
17
|
-
|
18
|
-
hydra.abort
|
19
|
-
end
|
19
|
+
delegate :abort, to: :hydra
|
20
20
|
|
21
21
|
def run(request)
|
22
22
|
convert_request(request).run
|
@@ -26,17 +26,21 @@ module Acfs
|
|
26
26
|
hydra.queue convert_request request
|
27
27
|
end
|
28
28
|
|
29
|
-
|
29
|
+
protected
|
30
|
+
|
30
31
|
def hydra
|
31
|
-
@hydra ||= ::Typhoeus::Hydra.new
|
32
|
+
@hydra ||= ::Typhoeus::Hydra.new(**@options)
|
32
33
|
end
|
33
34
|
|
34
35
|
def convert_request(req)
|
35
36
|
request = ::Typhoeus::Request.new req.url,
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
method: req.method,
|
38
|
+
params: req.params,
|
39
|
+
headers: req.headers.merge(
|
40
|
+
'Expect' => '',
|
41
|
+
'Transfer-Encoding' => ''
|
42
|
+
),
|
43
|
+
body: req.body
|
40
44
|
|
41
45
|
request.on_complete do |response|
|
42
46
|
req.complete! convert_response(req, response)
|
@@ -47,9 +51,9 @@ module Acfs
|
|
47
51
|
|
48
52
|
def convert_response(request, response)
|
49
53
|
Acfs::Response.new request,
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
status: response.code,
|
55
|
+
headers: response.headers,
|
56
|
+
body: response.body
|
53
57
|
end
|
54
58
|
end
|
55
59
|
end
|
@@ -1,15 +1,14 @@
|
|
1
1
|
module Acfs::Collections
|
2
|
-
|
3
2
|
#
|
4
3
|
module Paginatable
|
5
4
|
extend ActiveSupport::Concern
|
6
5
|
|
7
6
|
included do
|
8
|
-
def self.operation(
|
7
|
+
def self.operation(_action, opts = {}, &_block)
|
9
8
|
opts[:url]
|
10
9
|
end
|
11
10
|
|
12
|
-
attr_reader :total_pages, :current_page
|
11
|
+
attr_reader :total_pages, :current_page, :total_count
|
13
12
|
end
|
14
13
|
|
15
14
|
def process_response(response)
|
@@ -34,12 +33,9 @@ module Acfs::Collections
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def page(rel, &block)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# raise ArgumentError.new "No relative page `#{rel}'."
|
41
|
-
nil
|
42
|
-
end
|
36
|
+
return unless relations[rel]
|
37
|
+
|
38
|
+
@resource_class.all nil, url: relations[rel], &block
|
43
39
|
end
|
44
40
|
|
45
41
|
private
|
@@ -53,13 +49,17 @@ module Acfs::Collections
|
|
53
49
|
@total_pages = Integer(headers['X-Total-Pages'])
|
54
50
|
end
|
55
51
|
|
52
|
+
if headers['X-Total-Count']
|
53
|
+
@total_count = Integer(headers['X-Total-Count'])
|
54
|
+
end
|
55
|
+
|
56
56
|
setup_links headers['Link'] if headers['Link']
|
57
57
|
end
|
58
58
|
|
59
59
|
def setup_links(links)
|
60
60
|
links.split(/,\s+/).each do |link|
|
61
61
|
if link =~ /^\s*<([^>]+)>.*\s+rel="([\w_-]+)".*$/
|
62
|
-
relations[
|
62
|
+
relations[Regexp.last_match[2]] = Regexp.last_match[1]
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
data/lib/acfs/configuration.rb
CHANGED
@@ -2,11 +2,11 @@ require 'uri'
|
|
2
2
|
require 'yaml'
|
3
3
|
|
4
4
|
module Acfs
|
5
|
-
|
6
5
|
# Acfs configuration is used to locate services and get their base URLs.
|
7
6
|
#
|
8
7
|
class Configuration
|
9
8
|
attr_reader :locations
|
9
|
+
attr_accessor :adapter
|
10
10
|
|
11
11
|
# @api private
|
12
12
|
def initialize
|
@@ -28,7 +28,7 @@ module Acfs
|
|
28
28
|
if block.arity > 0
|
29
29
|
block.call self
|
30
30
|
else
|
31
|
-
instance_eval
|
31
|
+
instance_eval(&block)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -64,10 +64,10 @@ module Acfs
|
|
64
64
|
# @return [undefined]
|
65
65
|
#
|
66
66
|
def load(filename)
|
67
|
-
config = YAML
|
67
|
+
config = YAML.load File.read filename
|
68
68
|
env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
69
69
|
|
70
|
-
config = config[env] if config.
|
70
|
+
config = config[env] if config.key? env
|
71
71
|
config.each do |key, value|
|
72
72
|
case key
|
73
73
|
when 'services' then load_services value
|
@@ -88,7 +88,6 @@ module Acfs
|
|
88
88
|
end
|
89
89
|
|
90
90
|
class << self
|
91
|
-
|
92
91
|
# @api private
|
93
92
|
#
|
94
93
|
# Return current configuration object.
|
data/lib/acfs/errors.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Acfs
|
2
|
-
|
3
2
|
# Acfs base error.
|
4
3
|
#
|
5
4
|
class Error < StandardError
|
@@ -23,20 +22,20 @@ module Acfs
|
|
23
22
|
message << ": #{response.code}"
|
24
23
|
if response.data
|
25
24
|
message << "\n with content:\n "
|
26
|
-
message << response.data.map{|k,v| "#{k.inspect}: #{v.inspect}"}.join("\n ")
|
25
|
+
message << response.data.map {|k, v| "#{k.inspect}: #{v.inspect}" }.join("\n ")
|
27
26
|
end
|
28
27
|
if response.headers.any?
|
29
28
|
message << "\n with headers:\n "
|
30
|
-
message << response.headers.map{|k,v| "#{k}: #{v}"}.join("\n ")
|
29
|
+
message << response.headers.map {|k, v| "#{k}: #{v}" }.join("\n ")
|
31
30
|
end
|
32
31
|
message << "\nbased on request: #{response.request.method.upcase} #{response.request.url} #{response.request.format}"
|
33
32
|
if response.request.data
|
34
33
|
message << "\n with content:\n "
|
35
|
-
message << response.request.data.map{|k,v| "#{k.inspect}: #{v.inspect}"}.join("\n ")
|
34
|
+
message << response.request.data.map {|k, v| "#{k.inspect}: #{v.inspect}" }.join("\n ")
|
36
35
|
end
|
37
36
|
if response.request.headers.any?
|
38
37
|
message << "\n with headers:\n "
|
39
|
-
message << response.request.headers.map{|k,v| "#{k}: #{v}"}.join("\n ")
|
38
|
+
message << response.request.headers.map {|k, v| "#{k}: #{v}" }.join("\n ")
|
40
39
|
end
|
41
40
|
end
|
42
41
|
super opts, message
|
@@ -47,12 +46,14 @@ module Acfs
|
|
47
46
|
attr_reader :stubs, :operation
|
48
47
|
|
49
48
|
def initialize(opts = {})
|
49
|
+
require 'pp'
|
50
|
+
|
50
51
|
@stubs = opts.delete :stubs
|
51
52
|
@operation = opts.delete :operation
|
52
53
|
|
53
|
-
super opts,
|
54
|
+
super opts, "Ambiguous stubs for #{operation.action} on #{operation.resource}.\n" +
|
55
|
+
stubs.map {|s| " #{s.opts.pretty_inspect}" }.join
|
54
56
|
end
|
55
|
-
|
56
57
|
end
|
57
58
|
|
58
59
|
# Resource not found error raised on a 404 response
|
@@ -67,7 +68,7 @@ module Acfs
|
|
67
68
|
def initialize(opts = {})
|
68
69
|
@errors = opts.delete :errors
|
69
70
|
@resource = opts.delete :resource
|
70
|
-
opts[:message] ||= @errors.map{
|
71
|
+
opts[:message] ||= @errors.map {|k, v| "#{k}: #{v.join ', '}" }.join ', ' if @errors.is_a? Hash
|
71
72
|
opts[:message] ||= @errors.join ', ' if @errors.is_a? Array
|
72
73
|
super
|
73
74
|
end
|
@@ -99,7 +100,7 @@ module Acfs
|
|
99
100
|
def initialize(opts = {})
|
100
101
|
@base_class = opts.delete :base_class
|
101
102
|
@type_name = opts.delete :type_name
|
102
|
-
opts[:message] = "
|
103
|
+
opts[:message] = "Received resource type `#{type_name}` is no subclass of #{base_class}"
|
103
104
|
super
|
104
105
|
end
|
105
106
|
end
|
data/lib/acfs/global.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
1
1
|
module Acfs
|
2
|
-
|
2
|
+
#
|
3
3
|
# Global Acfs module methods.
|
4
4
|
#
|
5
5
|
module Global
|
6
|
-
|
6
|
+
#
|
7
7
|
# @api private
|
8
8
|
# @return [Runner]
|
9
9
|
#
|
10
10
|
def runner
|
11
|
-
|
11
|
+
Thread.current[:acfs_runner] ||= begin
|
12
|
+
adapter = Configuration.current.adapter
|
13
|
+
|
14
|
+
if adapter
|
15
|
+
Runner.new adapter.call
|
16
|
+
else
|
17
|
+
Runner.new Adapter::Typhoeus.new
|
18
|
+
end
|
19
|
+
end
|
12
20
|
end
|
13
21
|
|
14
22
|
# @api public
|
@@ -59,9 +67,10 @@ module Acfs
|
|
59
67
|
# Acfs.add_callback(user, &callback_two)
|
60
68
|
#
|
61
69
|
def add_callback(resource, &block)
|
62
|
-
|
63
|
-
|
64
|
-
|
70
|
+
unless resource.respond_to?(:__callbacks__)
|
71
|
+
raise ArgumentError.new 'Given resource is not an Acfs resource ' \
|
72
|
+
"delegator but a: #{resource.class.name}"
|
73
|
+
end
|
65
74
|
return false if block.nil?
|
66
75
|
|
67
76
|
if resource.loaded?
|
@@ -73,7 +82,7 @@ module Acfs
|
|
73
82
|
|
74
83
|
def on(*resources)
|
75
84
|
resources.each do |resource|
|
76
|
-
add_callback resource do |
|
85
|
+
add_callback resource do |_|
|
77
86
|
yield(*resources) unless resources.any? {|res| !res.loaded? }
|
78
87
|
end
|
79
88
|
end
|
data/lib/acfs/location.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Acfs
|
2
|
-
|
3
2
|
# @api private
|
4
3
|
#
|
5
4
|
# Describes a URL with placeholders.
|
@@ -7,17 +6,17 @@ module Acfs
|
|
7
6
|
class Location
|
8
7
|
attr_reader :arguments, :raw, :struct, :args
|
9
8
|
|
10
|
-
REGEXP= /^:([A-z][A-z0-9_]*)$/
|
9
|
+
REGEXP = /^:([A-z][A-z0-9_]*)$/
|
11
10
|
|
12
11
|
def initialize(uri, args = {})
|
13
12
|
@raw = URI.parse uri
|
14
13
|
@args = args
|
15
|
-
@struct = raw.path.split('/').reject(&:empty?).map{|s| s =~ REGEXP ?
|
16
|
-
@arguments = struct.select{|s| Symbol
|
14
|
+
@struct = raw.path.split('/').reject(&:empty?).map {|s| s =~ REGEXP ? Regexp.last_match[1].to_sym : s }
|
15
|
+
@arguments = struct.select {|s| s.is_a?(Symbol) }
|
17
16
|
end
|
18
17
|
|
19
18
|
def build(args = {})
|
20
|
-
unless Hash
|
19
|
+
unless args.is_a?(Hash)
|
21
20
|
raise ArgumentError.new "URI path arguments must be a hash, `#{args.inspect}' given."
|
22
21
|
end
|
23
22
|
|
@@ -25,8 +24,8 @@ module Acfs
|
|
25
24
|
end
|
26
25
|
|
27
26
|
def extract_from(*args)
|
28
|
-
args =
|
29
|
-
arguments.each{|key| collect[key] = extract_arg key, args }
|
27
|
+
args = {}.tap do |collect|
|
28
|
+
arguments.each {|key| collect[key] = extract_arg key, args }
|
30
29
|
end
|
31
30
|
|
32
31
|
build args
|
@@ -34,7 +33,7 @@ module Acfs
|
|
34
33
|
|
35
34
|
def str
|
36
35
|
uri = raw.dup
|
37
|
-
uri.path = URI.escape '/' + struct.map{|s| lookup_arg(s, args) }.join('/')
|
36
|
+
uri.path = URI.escape '/' + struct.map {|s| lookup_arg(s, args) }.join('/')
|
38
37
|
uri.to_s
|
39
38
|
end
|
40
39
|
|
@@ -44,16 +43,17 @@ module Acfs
|
|
44
43
|
alias_method :to_s, :raw_uri
|
45
44
|
|
46
45
|
private
|
46
|
+
|
47
47
|
def extract_arg(key, hashes)
|
48
48
|
hashes.each_with_index do |hash, index|
|
49
|
-
return (index == 0 ? hash.delete(key) : hash.fetch(key)) if hash.
|
49
|
+
return (index == 0 ? hash.delete(key) : hash.fetch(key)) if hash.key?(key)
|
50
50
|
end
|
51
51
|
|
52
52
|
nil
|
53
53
|
end
|
54
54
|
|
55
55
|
def lookup_arg(arg, args)
|
56
|
-
Symbol
|
56
|
+
arg.is_a?(Symbol) ? lookup_replacement(arg, args) : arg
|
57
57
|
end
|
58
58
|
|
59
59
|
def lookup_replacement(sym, args)
|
@@ -67,7 +67,7 @@ module Acfs
|
|
67
67
|
args.fetch(sym.to_s) do
|
68
68
|
args.fetch(sym) do
|
69
69
|
if args[:raise].nil? || args[:raise]
|
70
|
-
raise ArgumentError.new "URI path argument `#{sym}' missing on `#{
|
70
|
+
raise ArgumentError.new "URI path argument `#{sym}' missing on `#{self}'. Given: `#{args}.inspect'"
|
71
71
|
else
|
72
72
|
":#{sym}"
|
73
73
|
end
|