acfs 1.3.2 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- metadata +8 -141
- data/CHANGELOG.md +0 -325
- data/LICENSE +0 -22
- data/README.md +0 -334
- data/acfs.gemspec +0 -37
- data/lib/acfs.rb +0 -49
- data/lib/acfs/adapter/base.rb +0 -26
- data/lib/acfs/adapter/typhoeus.rb +0 -60
- data/lib/acfs/collection.rb +0 -27
- data/lib/acfs/collections/paginatable.rb +0 -75
- data/lib/acfs/configuration.rb +0 -113
- data/lib/acfs/errors.rb +0 -106
- data/lib/acfs/global.rb +0 -99
- data/lib/acfs/location.rb +0 -78
- data/lib/acfs/middleware/base.rb +0 -20
- data/lib/acfs/middleware/json.rb +0 -27
- data/lib/acfs/middleware/logger.rb +0 -23
- data/lib/acfs/middleware/msgpack.rb +0 -30
- data/lib/acfs/middleware/print.rb +0 -21
- data/lib/acfs/middleware/serializer.rb +0 -39
- data/lib/acfs/operation.rb +0 -81
- data/lib/acfs/request.rb +0 -36
- data/lib/acfs/request/callbacks.rb +0 -50
- data/lib/acfs/resource.rb +0 -37
- data/lib/acfs/resource/attributes.rb +0 -268
- data/lib/acfs/resource/attributes/base.rb +0 -28
- data/lib/acfs/resource/attributes/boolean.rb +0 -37
- data/lib/acfs/resource/attributes/date_time.rb +0 -31
- data/lib/acfs/resource/attributes/dict.rb +0 -37
- data/lib/acfs/resource/attributes/float.rb +0 -31
- data/lib/acfs/resource/attributes/integer.rb +0 -27
- data/lib/acfs/resource/attributes/list.rb +0 -34
- data/lib/acfs/resource/attributes/string.rb +0 -24
- data/lib/acfs/resource/attributes/uuid.rb +0 -47
- data/lib/acfs/resource/dirty.rb +0 -35
- data/lib/acfs/resource/initialization.rb +0 -29
- data/lib/acfs/resource/loadable.rb +0 -33
- data/lib/acfs/resource/locatable.rb +0 -128
- data/lib/acfs/resource/operational.rb +0 -22
- data/lib/acfs/resource/persistence.rb +0 -257
- data/lib/acfs/resource/query_methods.rb +0 -264
- data/lib/acfs/resource/service.rb +0 -42
- data/lib/acfs/resource/validation.rb +0 -37
- data/lib/acfs/response.rb +0 -28
- data/lib/acfs/response/formats.rb +0 -25
- data/lib/acfs/response/status.rb +0 -31
- data/lib/acfs/rspec.rb +0 -11
- data/lib/acfs/runner.rb +0 -97
- data/lib/acfs/service.rb +0 -91
- data/lib/acfs/service/middleware.rb +0 -56
- data/lib/acfs/service/middleware/stack.rb +0 -63
- data/lib/acfs/singleton_resource.rb +0 -83
- data/lib/acfs/stub.rb +0 -172
- data/lib/acfs/util.rb +0 -20
- data/lib/acfs/version.rb +0 -14
- data/lib/acfs/yard.rb +0 -5
- data/spec/acfs/adapter/typhoeus_spec.rb +0 -28
- data/spec/acfs/collection_spec.rb +0 -155
- data/spec/acfs/configuration_spec.rb +0 -51
- data/spec/acfs/global_spec.rb +0 -137
- data/spec/acfs/location_spec.rb +0 -23
- data/spec/acfs/middleware/json_spec.rb +0 -63
- data/spec/acfs/middleware/msgpack_spec.rb +0 -60
- data/spec/acfs/operation_spec.rb +0 -10
- data/spec/acfs/request/callbacks_spec.rb +0 -46
- data/spec/acfs/request_spec.rb +0 -77
- data/spec/acfs/resource/attributes/boolean_spec.rb +0 -56
- data/spec/acfs/resource/attributes/date_time_spec.rb +0 -49
- data/spec/acfs/resource/attributes/dict_spec.rb +0 -75
- data/spec/acfs/resource/attributes/float_spec.rb +0 -59
- data/spec/acfs/resource/attributes/integer_spec.rb +0 -34
- data/spec/acfs/resource/attributes/list_spec.rb +0 -58
- data/spec/acfs/resource/attributes/uuid_spec.rb +0 -40
- data/spec/acfs/resource/attributes_spec.rb +0 -179
- data/spec/acfs/resource/dirty_spec.rb +0 -47
- data/spec/acfs/resource/initialization_spec.rb +0 -30
- data/spec/acfs/resource/loadable_spec.rb +0 -20
- data/spec/acfs/resource/locatable_spec.rb +0 -116
- data/spec/acfs/resource/persistance_spec.rb +0 -316
- data/spec/acfs/resource/query_methods_spec.rb +0 -541
- data/spec/acfs/resource/validation_spec.rb +0 -127
- data/spec/acfs/response/formats_spec.rb +0 -50
- data/spec/acfs/response/status_spec.rb +0 -69
- data/spec/acfs/runner_spec.rb +0 -97
- data/spec/acfs/service/middleware_spec.rb +0 -33
- data/spec/acfs/service_spec.rb +0 -46
- data/spec/acfs/singleton_resource_spec.rb +0 -15
- data/spec/acfs/stub_spec.rb +0 -343
- data/spec/acfs_spec.rb +0 -203
- data/spec/fixtures/config.yml +0 -14
- data/spec/spec_helper.rb +0 -41
- data/spec/support/hash.rb +0 -9
- data/spec/support/response.rb +0 -10
- data/spec/support/service.rb +0 -91
- data/spec/support/shared/find_callbacks.rb +0 -48
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'typhoeus'
|
2
|
-
|
3
|
-
module Acfs
|
4
|
-
module Adapter
|
5
|
-
# Adapter for Typhoeus.
|
6
|
-
#
|
7
|
-
class Typhoeus < Base
|
8
|
-
def initialize(**kwargs)
|
9
|
-
@options = kwargs
|
10
|
-
end
|
11
|
-
|
12
|
-
def start
|
13
|
-
hydra.run
|
14
|
-
rescue
|
15
|
-
@hydra = nil
|
16
|
-
raise
|
17
|
-
end
|
18
|
-
|
19
|
-
delegate :abort, to: :hydra
|
20
|
-
|
21
|
-
def run(request)
|
22
|
-
convert_request(request).run
|
23
|
-
end
|
24
|
-
|
25
|
-
def queue(request)
|
26
|
-
hydra.queue convert_request request
|
27
|
-
end
|
28
|
-
|
29
|
-
protected
|
30
|
-
|
31
|
-
def hydra
|
32
|
-
@hydra ||= ::Typhoeus::Hydra.new(**@options)
|
33
|
-
end
|
34
|
-
|
35
|
-
def convert_request(req)
|
36
|
-
request = ::Typhoeus::Request.new req.url,
|
37
|
-
method: req.method,
|
38
|
-
params: req.params,
|
39
|
-
headers: req.headers.merge(
|
40
|
-
'Expect' => '',
|
41
|
-
'Transfer-Encoding' => ''
|
42
|
-
),
|
43
|
-
body: req.body
|
44
|
-
|
45
|
-
request.on_complete do |response|
|
46
|
-
req.complete! convert_response(req, response)
|
47
|
-
end
|
48
|
-
|
49
|
-
request
|
50
|
-
end
|
51
|
-
|
52
|
-
def convert_response(request, response)
|
53
|
-
Acfs::Response.new request,
|
54
|
-
status: response.code,
|
55
|
-
headers: response.headers,
|
56
|
-
body: response.body
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
data/lib/acfs/collection.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'delegate'
|
2
|
-
|
3
|
-
require 'acfs/resource/loadable'
|
4
|
-
require 'acfs/collections/paginatable'
|
5
|
-
|
6
|
-
module Acfs
|
7
|
-
#
|
8
|
-
class Collection < ::Delegator
|
9
|
-
include Resource::Loadable
|
10
|
-
include Acfs::Util::Callbacks
|
11
|
-
include Collections::Paginatable
|
12
|
-
|
13
|
-
def initialize(resource_class)
|
14
|
-
super([])
|
15
|
-
|
16
|
-
@resource_class = resource_class
|
17
|
-
end
|
18
|
-
|
19
|
-
def __getobj__
|
20
|
-
@models
|
21
|
-
end
|
22
|
-
|
23
|
-
def __setobj__(obj)
|
24
|
-
@models = obj
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
module Acfs::Collections
|
2
|
-
#
|
3
|
-
module Paginatable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
def self.operation(_action, opts = {}, &_block)
|
8
|
-
opts[:url]
|
9
|
-
end
|
10
|
-
|
11
|
-
attr_reader :total_pages, :current_page, :total_count
|
12
|
-
end
|
13
|
-
|
14
|
-
def process_response(response)
|
15
|
-
setup_params response.request.params if response.request
|
16
|
-
setup_headers response.headers
|
17
|
-
end
|
18
|
-
|
19
|
-
def next_page(&block)
|
20
|
-
page 'next', &block
|
21
|
-
end
|
22
|
-
|
23
|
-
def prev_page(&block)
|
24
|
-
page 'prev', &block
|
25
|
-
end
|
26
|
-
|
27
|
-
def first_page(&block)
|
28
|
-
page 'first', &block
|
29
|
-
end
|
30
|
-
|
31
|
-
def last_page(&block)
|
32
|
-
page 'last', &block
|
33
|
-
end
|
34
|
-
|
35
|
-
def page(rel, &block)
|
36
|
-
return unless relations[rel]
|
37
|
-
|
38
|
-
@resource_class.all nil, url: relations[rel], &block
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def relations
|
44
|
-
@relations ||= {}
|
45
|
-
end
|
46
|
-
|
47
|
-
def setup_headers(headers)
|
48
|
-
if headers['X-Total-Pages']
|
49
|
-
@total_pages = Integer(headers['X-Total-Pages'])
|
50
|
-
end
|
51
|
-
|
52
|
-
if headers['X-Total-Count']
|
53
|
-
@total_count = Integer(headers['X-Total-Count'])
|
54
|
-
end
|
55
|
-
|
56
|
-
setup_links headers['Link'] if headers['Link']
|
57
|
-
end
|
58
|
-
|
59
|
-
def setup_links(links)
|
60
|
-
links.split(/,\s+/).each do |link|
|
61
|
-
if link =~ /^\s*<([^>]+)>.*\s+rel="([\w_-]+)".*$/
|
62
|
-
relations[Regexp.last_match[2]] = Regexp.last_match[1]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def setup_params(params)
|
68
|
-
@current_page = begin
|
69
|
-
Integer params.fetch(:page, 1)
|
70
|
-
rescue ArgumentError
|
71
|
-
params[:page]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
data/lib/acfs/configuration.rb
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'yaml'
|
3
|
-
|
4
|
-
module Acfs
|
5
|
-
# Acfs configuration is used to locate services and get their base URLs.
|
6
|
-
#
|
7
|
-
class Configuration
|
8
|
-
attr_reader :locations
|
9
|
-
attr_accessor :adapter
|
10
|
-
|
11
|
-
# @api private
|
12
|
-
def initialize
|
13
|
-
@locations = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
# @api public
|
17
|
-
#
|
18
|
-
# Configure using given block. If block accepts zero arguments
|
19
|
-
# bock will be evaluated in context of the configuration instance
|
20
|
-
# otherwise the configuration instance will be given as first arguments.
|
21
|
-
#
|
22
|
-
# @yield [configuration] Give configuration as arguments or evaluate block
|
23
|
-
# in context of configuration object.
|
24
|
-
# @yieldparam configuration [Configuration] Configuration object.
|
25
|
-
# @return [undefined]
|
26
|
-
#
|
27
|
-
def configure(&block)
|
28
|
-
if block.arity > 0
|
29
|
-
block.call self
|
30
|
-
else
|
31
|
-
instance_eval(&block)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# @api public
|
36
|
-
#
|
37
|
-
# @overload locate(service, uri)
|
38
|
-
# Configures URL where a service can be reached.
|
39
|
-
#
|
40
|
-
# @param [Symbol] service Service identity key for service that is reachable under given URL.
|
41
|
-
# @param [String] uri URL where service is reachable. Will be passed to {URI.parse}.
|
42
|
-
# @return [undefined]
|
43
|
-
#
|
44
|
-
# @overload locate(service)
|
45
|
-
# Return configured base URL for given service identity key.
|
46
|
-
#
|
47
|
-
# @param [Symbol] service Service identity key to lookup.
|
48
|
-
# @return [URI, NilClass] Configured base URL or nil.
|
49
|
-
#
|
50
|
-
def locate(service, uri = nil)
|
51
|
-
service = service.to_s.underscore.to_sym
|
52
|
-
if uri.nil?
|
53
|
-
locations[service]
|
54
|
-
else
|
55
|
-
locations[service] = URI.parse uri
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# @api public
|
60
|
-
#
|
61
|
-
# Load configuration from given YAML file.
|
62
|
-
#
|
63
|
-
# @param [String] filename Path to YAML configuration file.
|
64
|
-
# @return [undefined]
|
65
|
-
#
|
66
|
-
def load(filename)
|
67
|
-
config = YAML.load File.read filename
|
68
|
-
env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
69
|
-
|
70
|
-
config = config[env] if config.key? env
|
71
|
-
config.each do |key, value|
|
72
|
-
case key
|
73
|
-
when 'services' then load_services value
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# @api private
|
79
|
-
#
|
80
|
-
# Load services from configuration YAML.
|
81
|
-
#
|
82
|
-
def load_services(services)
|
83
|
-
services.each do |service, data|
|
84
|
-
if (val = data).is_a?(String) || (val = data['locate'])
|
85
|
-
locate service.to_sym, val
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
class << self
|
91
|
-
# @api private
|
92
|
-
#
|
93
|
-
# Return current configuration object.
|
94
|
-
#
|
95
|
-
# @return [Configuration]
|
96
|
-
#
|
97
|
-
def current
|
98
|
-
@configuration ||= new
|
99
|
-
end
|
100
|
-
|
101
|
-
# @api private
|
102
|
-
#
|
103
|
-
# Swap configuration object with given new one. Must be a {Configuration} object.
|
104
|
-
#
|
105
|
-
# @param [Configuration] configuration
|
106
|
-
# @return [undefined]
|
107
|
-
#
|
108
|
-
def set(configuration)
|
109
|
-
@configuration = configuration if configuration.is_a? Configuration
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
data/lib/acfs/errors.rb
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
module Acfs
|
2
|
-
# Acfs base error.
|
3
|
-
#
|
4
|
-
class Error < StandardError
|
5
|
-
def initialize(opts = {}, message = nil)
|
6
|
-
opts.merge! message: message if message
|
7
|
-
super opts[:message]
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class UnsupportedOperation < StandardError; end
|
12
|
-
|
13
|
-
# Response error containing the responsible response object.
|
14
|
-
#
|
15
|
-
class ErroneousResponse < Error
|
16
|
-
attr_reader :response
|
17
|
-
|
18
|
-
def initialize(opts = {})
|
19
|
-
@response = opts[:response]
|
20
|
-
message = opts[:message]
|
21
|
-
if response
|
22
|
-
if message
|
23
|
-
message << ':'
|
24
|
-
else
|
25
|
-
message = 'Received'
|
26
|
-
end
|
27
|
-
message << " #{response.code} for #{response.request.method.upcase} #{response.request.url} #{response.request.format}"
|
28
|
-
else
|
29
|
-
message ||= 'Received erroneous response'
|
30
|
-
end
|
31
|
-
super opts, message
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class AmbiguousStubError < Error
|
36
|
-
attr_reader :stubs, :operation
|
37
|
-
|
38
|
-
def initialize(opts = {})
|
39
|
-
require 'pp'
|
40
|
-
|
41
|
-
@stubs = opts.delete :stubs
|
42
|
-
@operation = opts.delete :operation
|
43
|
-
|
44
|
-
super opts, "Ambiguous stubs for #{operation.action} on #{operation.resource}.\n" +
|
45
|
-
stubs.map {|s| " #{s.opts.pretty_inspect}" }.join
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# Resource not found error raised on a 404 response
|
50
|
-
#
|
51
|
-
class ResourceNotFound < ErroneousResponse
|
52
|
-
end
|
53
|
-
|
54
|
-
#
|
55
|
-
class InvalidResource < ErroneousResponse
|
56
|
-
attr_reader :errors, :resource
|
57
|
-
|
58
|
-
def initialize(opts = {})
|
59
|
-
@errors = opts.delete :errors
|
60
|
-
@resource = opts.delete :resource
|
61
|
-
|
62
|
-
if @errors.is_a?(Hash)
|
63
|
-
opts[:message] ||= @errors.each_pair.map do |k, v|
|
64
|
-
@errors.is_a?(Array) ? "#{k}: #{v.join(', ')}" : "#{k}: #{v}"
|
65
|
-
end.join ', '
|
66
|
-
elsif @errors.is_a?(Array)
|
67
|
-
opts[:message] ||= @errors.join ', '
|
68
|
-
end
|
69
|
-
|
70
|
-
super
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
# A ResourceNotLoaded error will be thrown when calling some
|
75
|
-
# modifing methods on not loaded resources as it is usally
|
76
|
-
# unwanted to call e.g. `update_attributes` on a not loaded
|
77
|
-
# resource.
|
78
|
-
# Correct solution is to first run `Acfs.run` to fetch the
|
79
|
-
# resource and then update the resource.
|
80
|
-
#
|
81
|
-
class ResourceNotLoaded < Error
|
82
|
-
attr_reader :resource
|
83
|
-
|
84
|
-
def initialize(opts = {})
|
85
|
-
@resource = opts.delete :resource
|
86
|
-
super
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Gets raised if ressource type is no valid subclass of
|
91
|
-
# parent resource. Check if the type is set to the correct
|
92
|
-
# Acfs::Resource Name
|
93
|
-
class ResourceTypeError < Error
|
94
|
-
attr_reader :base_class
|
95
|
-
attr_reader :type_name
|
96
|
-
|
97
|
-
def initialize(opts = {})
|
98
|
-
@base_class = opts.delete :base_class
|
99
|
-
@type_name = opts.delete :type_name
|
100
|
-
opts[:message] = "Received resource type `#{type_name}` is no subclass of #{base_class}"
|
101
|
-
super
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class RealRequestsNotAllowedError < StandardError; end
|
106
|
-
end
|
data/lib/acfs/global.rb
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
module Acfs
|
2
|
-
#
|
3
|
-
# Global Acfs module methods.
|
4
|
-
#
|
5
|
-
module Global
|
6
|
-
#
|
7
|
-
# @api private
|
8
|
-
# @return [Runner]
|
9
|
-
#
|
10
|
-
def runner
|
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
|
20
|
-
end
|
21
|
-
|
22
|
-
# @api public
|
23
|
-
#
|
24
|
-
# Run all queued operations.
|
25
|
-
#
|
26
|
-
# @return [undefined]
|
27
|
-
#
|
28
|
-
def run
|
29
|
-
::ActiveSupport::Notifications.instrument 'acfs.before_run'
|
30
|
-
::ActiveSupport::Notifications.instrument 'acfs.run' do
|
31
|
-
runner.start
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# @api public
|
36
|
-
#
|
37
|
-
# Configure acfs using given block.
|
38
|
-
#
|
39
|
-
# @return [undefined]
|
40
|
-
# @see Configuration#configure
|
41
|
-
#
|
42
|
-
def configure(&block)
|
43
|
-
Configuration.current.configure(&block)
|
44
|
-
end
|
45
|
-
|
46
|
-
# @api public
|
47
|
-
#
|
48
|
-
# Reset all queues, stubs and internal state.
|
49
|
-
#
|
50
|
-
def reset
|
51
|
-
::ActiveSupport::Notifications.instrument 'acfs.reset' do
|
52
|
-
runner.clear
|
53
|
-
Acfs::Stub.clear
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# @api public
|
58
|
-
#
|
59
|
-
# Add an additional callback hook to not loaded resource.
|
60
|
-
# If given resource already loaded callback will be invoked immediately.
|
61
|
-
#
|
62
|
-
# This method will be replaced by explicit callback
|
63
|
-
# handling when query methods return explicit future objects.
|
64
|
-
#
|
65
|
-
# @example
|
66
|
-
# user = MyUser.find 1, &callback_one
|
67
|
-
# Acfs.add_callback(user, &callback_two)
|
68
|
-
#
|
69
|
-
def add_callback(resource, &block)
|
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
|
74
|
-
return false if block.nil?
|
75
|
-
|
76
|
-
if resource.nil? || resource.loaded?
|
77
|
-
block.call resource
|
78
|
-
else
|
79
|
-
resource.__callbacks__ << block
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def on(*resources)
|
84
|
-
# If all resources have already been loaded, we run the callback immediately.
|
85
|
-
if resources.all? {|res| res.nil? || res.loaded? }
|
86
|
-
yield(*resources)
|
87
|
-
return
|
88
|
-
end
|
89
|
-
|
90
|
-
# Otherwise, we add a callback to *each* resource with a guard that ensures
|
91
|
-
# that only the very last resource being loaded executes the callback.
|
92
|
-
resources.each do |resource|
|
93
|
-
add_callback resource do |_|
|
94
|
-
yield(*resources) if resources.all? {|res| res.nil? || res.loaded? }
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|