acfs 1.3.1 → 1.5.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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -1
  3. data/README.md +10 -25
  4. data/acfs.gemspec +20 -15
  5. data/lib/acfs.rb +2 -0
  6. data/lib/acfs/adapter/base.rb +6 -8
  7. data/lib/acfs/adapter/typhoeus.rb +25 -6
  8. data/lib/acfs/collection.rb +2 -1
  9. data/lib/acfs/collections/paginatable.rb +4 -3
  10. data/lib/acfs/configuration.rb +14 -7
  11. data/lib/acfs/errors.rb +60 -19
  12. data/lib/acfs/global.rb +12 -2
  13. data/lib/acfs/location.rb +9 -5
  14. data/lib/acfs/middleware/base.rb +5 -1
  15. data/lib/acfs/middleware/json.rb +5 -3
  16. data/lib/acfs/middleware/logger.rb +2 -0
  17. data/lib/acfs/middleware/msgpack.rb +2 -0
  18. data/lib/acfs/middleware/print.rb +2 -0
  19. data/lib/acfs/middleware/serializer.rb +2 -0
  20. data/lib/acfs/operation.rb +20 -3
  21. data/lib/acfs/request.rb +5 -1
  22. data/lib/acfs/request/callbacks.rb +5 -1
  23. data/lib/acfs/resource.rb +2 -0
  24. data/lib/acfs/resource/attributes.rb +5 -2
  25. data/lib/acfs/resource/attributes/base.rb +2 -1
  26. data/lib/acfs/resource/attributes/boolean.rb +2 -0
  27. data/lib/acfs/resource/attributes/date_time.rb +2 -1
  28. data/lib/acfs/resource/attributes/dict.rb +2 -0
  29. data/lib/acfs/resource/attributes/float.rb +5 -3
  30. data/lib/acfs/resource/attributes/integer.rb +2 -0
  31. data/lib/acfs/resource/attributes/list.rb +2 -0
  32. data/lib/acfs/resource/attributes/string.rb +2 -0
  33. data/lib/acfs/resource/attributes/uuid.rb +4 -3
  34. data/lib/acfs/resource/dirty.rb +2 -0
  35. data/lib/acfs/resource/initialization.rb +2 -0
  36. data/lib/acfs/resource/loadable.rb +2 -0
  37. data/lib/acfs/resource/locatable.rb +10 -6
  38. data/lib/acfs/resource/operational.rb +2 -1
  39. data/lib/acfs/resource/persistence.rb +7 -6
  40. data/lib/acfs/resource/query_methods.rb +6 -4
  41. data/lib/acfs/resource/service.rb +3 -1
  42. data/lib/acfs/resource/validation.rb +3 -1
  43. data/lib/acfs/response.rb +2 -0
  44. data/lib/acfs/response/formats.rb +2 -0
  45. data/lib/acfs/response/status.rb +3 -1
  46. data/lib/acfs/rspec.rb +2 -0
  47. data/lib/acfs/runner.rb +6 -1
  48. data/lib/acfs/service.rb +24 -13
  49. data/lib/acfs/service/middleware.rb +2 -0
  50. data/lib/acfs/service/middleware/stack.rb +5 -3
  51. data/lib/acfs/singleton_resource.rb +4 -2
  52. data/lib/acfs/stub.rb +32 -11
  53. data/lib/acfs/util.rb +2 -0
  54. data/lib/acfs/version.rb +4 -2
  55. data/lib/acfs/yard.rb +1 -0
  56. data/spec/acfs/adapter/typhoeus_spec.rb +30 -3
  57. data/spec/acfs/collection_spec.rb +7 -5
  58. data/spec/acfs/configuration_spec.rb +2 -0
  59. data/spec/acfs/global_spec.rb +50 -3
  60. data/spec/acfs/location_spec.rb +2 -0
  61. data/spec/acfs/middleware/json_spec.rb +3 -1
  62. data/spec/acfs/middleware/msgpack_spec.rb +2 -0
  63. data/spec/acfs/operation_spec.rb +2 -0
  64. data/spec/acfs/request/callbacks_spec.rb +2 -0
  65. data/spec/acfs/request_spec.rb +3 -1
  66. data/spec/acfs/resource/attributes/boolean_spec.rb +2 -0
  67. data/spec/acfs/resource/attributes/date_time_spec.rb +2 -0
  68. data/spec/acfs/resource/attributes/dict_spec.rb +4 -2
  69. data/spec/acfs/resource/attributes/float_spec.rb +3 -1
  70. data/spec/acfs/resource/attributes/integer_spec.rb +2 -0
  71. data/spec/acfs/resource/attributes/list_spec.rb +5 -3
  72. data/spec/acfs/resource/attributes/uuid_spec.rb +2 -0
  73. data/spec/acfs/resource/attributes_spec.rb +8 -8
  74. data/spec/acfs/resource/dirty_spec.rb +2 -0
  75. data/spec/acfs/resource/initialization_spec.rb +8 -2
  76. data/spec/acfs/resource/loadable_spec.rb +2 -0
  77. data/spec/acfs/resource/locatable_spec.rb +2 -0
  78. data/spec/acfs/resource/persistance_spec.rb +10 -4
  79. data/spec/acfs/resource/query_methods_spec.rb +24 -17
  80. data/spec/acfs/resource/validation_spec.rb +2 -0
  81. data/spec/acfs/response/formats_spec.rb +3 -1
  82. data/spec/acfs/response/status_spec.rb +2 -0
  83. data/spec/acfs/runner_spec.rb +6 -8
  84. data/spec/acfs/service/middleware_spec.rb +2 -0
  85. data/spec/acfs/service_spec.rb +3 -1
  86. data/spec/acfs/singleton_resource_spec.rb +2 -0
  87. data/spec/acfs/stub_spec.rb +2 -0
  88. data/spec/acfs_spec.rb +2 -0
  89. data/spec/spec_helper.rb +3 -1
  90. data/spec/support/hash.rb +2 -0
  91. data/spec/support/response.rb +2 -0
  92. data/spec/support/service.rb +1 -0
  93. data/spec/support/shared/find_callbacks.rb +2 -0
  94. metadata +13 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '099f37ed68e218d04f91c2f9f636e7b177b84feb8b8e0be4c4403da004937760'
4
- data.tar.gz: bfbf0d3dc7f77eb38f16043051350a468baab870b3b002c35bc9f96df492eb07
3
+ metadata.gz: 53acc88297d3217a5d01db2ce713f935835b05438471fd2b69918029b5480954
4
+ data.tar.gz: d61a2f4e5014dab37d4e1a857d548df8dfb42afcaba219005556f203ea68da65
5
5
  SHA512:
6
- metadata.gz: 29c45b69c95afd11cb58af0e02a383a2c1adcfeefb2521a917e1b7f6606a694c66fa0e2d56796e59127d453f4a1f95ab36c6a2e9a384657992b6a821c946c357
7
- data.tar.gz: cba2e6df7a7988d2d06fc8ca303aa63875736c6d0fc6c0013ecbb36038b559bcfc085058c086468389905947aba375d6add11f3e8010ab2cff1b70628edd8770
6
+ metadata.gz: 35f66d3569256b183cb7c78fed7c41f0ce916f41ec081e60696693af8b869d47e797a53474942c4847cefb621e58d3d52ddf629168c63b7b2d558d1db23cf74a
7
+ data.tar.gz: 5e03be0b16cb469061b55a3c4467a4fa71496925caa086ed5d024ed79aaefdcc568afd970d526c284b08b8db06593f51886d8642f035f78f2ed7f89bd1b8f311
@@ -14,9 +14,49 @@
14
14
  ### Breaks
15
15
 
16
16
 
17
- ## 1.3.1 - (2019-07-02)
17
+ ## 1.5.0 - (2020-06-19)
18
+ ---
19
+
20
+ ### New
21
+ * Error classes for more HTTP error responses: `400`, `401`, `403`, `500`, `502`, `503`, `504`.
22
+
23
+ ### Changes
24
+ * Replace deprecated MultiJson with core JSON module
25
+
26
+
27
+ ## 1.4.0 - (2020-06-12)
28
+ ---
29
+
30
+ ### New
31
+ * Use strict TCP keepalive probing by default (5s/5s)
32
+ * Adapter accepts curl request opts
33
+
34
+
35
+ ## 1.3.4 - (2020-03-22)
36
+ ---
37
+
38
+ ### Fixes
39
+ * Empty package build for Gem release 1.3.3
40
+
41
+
42
+ ## 1.3.3 - (2020-03-22)
18
43
  ---
19
44
 
45
+ ### Changes
46
+ * Improved handling of low-level connection errors and timeouts
47
+
48
+
49
+ ## 1.3.2 - (2019-09-24)
50
+
51
+
52
+ ### Fixes
53
+ * Fix Acfs.on callbacks for empty find_by results (#42)
54
+
55
+
56
+ ---
57
+
58
+ ## 1.3.1 - (2019-07-02)
59
+
20
60
  ### Fixes
21
61
  * Improve URL argument encoding when building resource requests
22
62
 
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # Acfs - *API client for services*
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/acfs.svg)](http://badge.fury.io/rb/acfs)
4
- [![Build Status](http://img.shields.io/travis/jgraichen/acfs/master.svg)](https://travis-ci.org/jgraichen/acfs)
3
+ [![Gem Version](https://img.shields.io/gem/v/acfs?logo=ruby)](https://rubygems.org/gems/acfs)
4
+ [![Build Status](https://img.shields.io/travis/jgraichen/acfs/master?logo=travis)](https://travis-ci.org/jgraichen/acfs)
5
+ [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/jgraichen/acfs/Test/master?logo=github)](https://github.com/jgraichen/acfs/actions?query=branch%3Amaster)
5
6
  [![Coverage Status](http://img.shields.io/coveralls/jgraichen/acfs/master.svg)](https://coveralls.io/r/jgraichen/acfs)
6
- [![Code Climate](http://img.shields.io/codeclimate/github/jgraichen/acfs.svg)](https://codeclimate.com/github/jgraichen/acfs)
7
- [![Dependency Status](http://img.shields.io/gemnasium/jgraichen/acfs.svg)](https://gemnasium.com/jgraichen/acfs)
8
7
  [![RubyDoc Documentation](http://img.shields.io/badge/rubydoc-here-blue.svg)](http://rubydoc.info/github/jgraichen/acfs/master/frames)
9
8
 
10
9
  Acfs is a library to develop API client libraries for single services within a larger service oriented application.
11
10
 
12
11
  Acfs covers model and service abstraction, convenient query and filter methods, full middleware stack for pre-processing requests and responses on a per service level and automatic request queuing and parallel processing. See Usage for more.
13
12
 
13
+
14
14
  ## Installation
15
15
 
16
16
  Add this line to your application's Gemfile:
@@ -25,6 +25,7 @@ Or install it yourself as:
25
25
 
26
26
  > gem install acfs
27
27
 
28
+
28
29
  ## Usage
29
30
 
30
31
  First you need to define your service(s):
@@ -146,6 +147,7 @@ Acfs has basic update support using `PUT` requests:
146
147
  @user.persisted? # => true
147
148
  ```
148
149
 
150
+
149
151
  ## Singleton resources
150
152
 
151
153
  Singletons can be used in Acfs by creating a new resource which inherits from `SingletonResource`:
@@ -184,6 +186,7 @@ my_single = Single.find name: 'Max'
184
186
  Acfs.run # sends GET request with param to /single?name=Max
185
187
  ```
186
188
 
189
+
187
190
  ## Resource Inheritance
188
191
 
189
192
  Acfs provides a resource inheritance similar to ActiveRecord Single Table Inheritance. If a
@@ -220,6 +223,7 @@ Acfs.run
220
223
  @computer[2].class # => Pc
221
224
  ```
222
225
 
226
+
223
227
  ## Stubbing
224
228
 
225
229
  You can stub resources in applications using an Acfs service client:
@@ -280,6 +284,7 @@ it 'should find user number one' do
280
284
  end
281
285
  ```
282
286
 
287
+
283
288
  ## Instrumentation
284
289
 
285
290
  Acfs supports [instrumentation via active support][1].
@@ -297,21 +302,6 @@ Read [official guide][2] to see to to subscribe.
297
302
  [1]: http://guides.rubyonrails.org/active_support_instrumentation.html
298
303
  [2]: http://guides.rubyonrails.org/active_support_instrumentation.html#subscribing-to-an-event
299
304
 
300
- ## Roadmap
301
-
302
- * Update
303
- * Better new? detection eg. storing ETag from request resources.
304
- * Use PATCH for with only changed attributes and `If-Unmodifed-Since`
305
- and `If-Match` header fields if resource was surly loaded from service
306
- and not created with an id (e.g `User.new id: 5, name: "john"`).
307
- * Conflict detection (ETag / If-Unmodified-Since)
308
- * High level features
309
- * Support for custom mime types on client and server side. (`application/vnd.myservice.user.v2+msgpack`)
310
- * Server side components
311
- * Reusing model definitions for generating responses?
312
- * Rails responders providing REST operations with integrated ETag,
313
- Modified Headers, conflict detection, ...
314
- * Documentation
315
305
 
316
306
  ## Contributing
317
307
 
@@ -323,14 +313,9 @@ Read [official guide][2] to see to to subscribe.
323
313
  7. Push to the branch (`git push origin my-new-feature`)
324
314
  8. Create new Pull Request
325
315
 
326
- ## Contributors
327
-
328
- * [Nicolas Fricke](https://github.com/nicolas-fricke)
329
- * [Tino Junge](https://github.com/tino-junge)
330
- * [Malte Swart](https://github.com/mswart)
331
316
 
332
317
  ## License
333
318
 
334
319
  MIT License
335
320
 
336
- Copyright (c) 2013 Jan Graichen. MIT license, see LICENSE for more details.
321
+ Copyright (c) 2013-2020 Jan Graichen. MIT license, see LICENSE for more details.
@@ -1,5 +1,6 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'acfs/version'
5
6
 
@@ -7,31 +8,35 @@ Gem::Specification.new do |spec|
7
8
  spec.name = 'acfs'
8
9
  spec.version = Acfs::VERSION
9
10
  spec.authors = ['Jan Graichen']
10
- spec.email = %w(jg@altimos.de)
11
- spec.description = 'API Client For Services'
12
- spec.summary = 'An abstract API base client for service oriented application.'
11
+ spec.email = %w[jgraichen@altimos.de]
13
12
  spec.homepage = 'https://github.com/jgraichen/acfs'
14
13
  spec.license = 'MIT'
14
+ spec.description = 'API Client For Services'
15
+ spec.summary = <<~SUMMARY.strip
16
+ An abstract API base client for service oriented application.
17
+ SUMMARY
18
+
19
+ spec.files = Dir['**/*'].grep(%r{
20
+ ^((bin|lib|test|spec|features)/|
21
+ .*\.gemspec|.*LICENSE.*|.*README.*|.*CHANGELOG.*)
22
+ }xi)
15
23
 
16
- spec.files = Dir['**/*'].grep(%r{^((bin|lib|test|spec|features)/|.*\.gemspec|.*LICENSE.*|.*README.*|.*CHANGELOG.*)})
17
24
  spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f) }
18
25
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = %w(lib)
20
-
21
- spec.add_runtime_dependency 'activesupport', '>= 4.2'
22
- spec.add_runtime_dependency 'activemodel', '>= 4.2'
23
- spec.add_runtime_dependency 'actionpack', '>= 4.2'
24
- spec.add_runtime_dependency 'multi_json'
25
-
26
- # Bundle update w/o version resolves to 0.3.3 ...
27
- spec.add_runtime_dependency 'typhoeus', '~> 1.0'
26
+ spec.require_paths = %w[lib]
28
27
 
28
+ spec.add_runtime_dependency 'actionpack', '>= 5.2'
29
+ spec.add_runtime_dependency 'activemodel', '>= 5.2'
30
+ spec.add_runtime_dependency 'activesupport', '>= 5.2'
29
31
  spec.add_runtime_dependency 'rack'
32
+ spec.add_runtime_dependency 'typhoeus', '~> 1.0'
30
33
 
31
34
  spec.add_development_dependency 'bundler'
32
35
 
33
36
  if ENV['TRAVIS_BUILD_NUMBER'] && !ENV['TRAVIS_TAG']
34
37
  # Append travis build number for auto-releases
38
+ # rubocop:disable Gemspec/DuplicatedAssignment
35
39
  spec.version = "#{spec.version}.1.b#{ENV['TRAVIS_BUILD_NUMBER']}"
40
+ # rubocop:enable Gemspec/DuplicatedAssignment
36
41
  end
37
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support'
2
4
  require 'active_support/core_ext/hash'
3
5
  require 'active_support/core_ext/class'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Acfs::Adapter
2
4
  # Base adapter handling operation queuing
3
5
  # and processing.
@@ -5,22 +7,18 @@ module Acfs::Adapter
5
7
  class Base
6
8
  # Start processing queued requests.
7
9
  #
8
- def start
9
- end
10
+ def start; end
10
11
 
11
12
  # Abort running and queued requests.
12
13
  #
13
- def abort
14
- end
14
+ def abort; end
15
15
 
16
16
  # Run request right now skipping queue.
17
17
  #
18
- def run(_)
19
- end
18
+ def run(_); end
20
19
 
21
20
  # Enqueue request to be run later.
22
21
  #
23
- def queue(_)
24
- end
22
+ def queue(_); end
25
23
  end
26
24
  end
@@ -1,17 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'typhoeus'
2
4
 
3
5
  module Acfs
4
6
  module Adapter
7
+ DEFAULT_OPTIONS = {
8
+ tcp_keepalive: true,
9
+ tcp_keepidle: 5,
10
+ tcp_keepintvl: 5
11
+ }.freeze
12
+
5
13
  # Adapter for Typhoeus.
6
14
  #
7
15
  class Typhoeus < Base
8
- def initialize(**kwargs)
9
- @options = kwargs
16
+ def initialize(opts: {}, **kwargs)
17
+ @opts = DEFAULT_OPTIONS.merge(opts)
18
+ @kwargs = kwargs
10
19
  end
11
20
 
12
21
  def start
13
22
  hydra.run
14
- rescue
23
+ rescue StandardError
15
24
  @hydra = nil
16
25
  raise
17
26
  end
@@ -29,20 +38,30 @@ module Acfs
29
38
  protected
30
39
 
31
40
  def hydra
32
- @hydra ||= ::Typhoeus::Hydra.new(**@options)
41
+ @hydra ||= ::Typhoeus::Hydra.new(**@kwargs)
33
42
  end
34
43
 
35
44
  def convert_request(req)
36
- request = ::Typhoeus::Request.new req.url,
45
+ opts = {
37
46
  method: req.method,
38
47
  params: req.params,
39
48
  headers: req.headers.merge(
40
- 'Expect' => '',
49
+ 'Expect' => '',
41
50
  'Transfer-Encoding' => ''
42
51
  ),
43
52
  body: req.body
53
+ }
54
+
55
+ request = ::Typhoeus::Request.new(req.url, **@opts.merge(opts))
44
56
 
45
57
  request.on_complete do |response|
58
+ raise ::Acfs::TimeoutError.new(req) if response.timed_out?
59
+
60
+ if response.code.zero?
61
+ # Failed to get HTTP response
62
+ raise ::Acfs::RequestError.new(req, response.return_message)
63
+ end
64
+
46
65
  req.complete! convert_response(req, response)
47
66
  end
48
67
 
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delegate'
2
4
 
3
5
  require 'acfs/resource/loadable'
4
6
  require 'acfs/collections/paginatable'
5
7
 
6
8
  module Acfs
7
- #
8
9
  class Collection < ::Delegator
9
10
  include Resource::Loadable
10
11
  include Acfs::Util::Callbacks
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Acfs::Collections
2
- #
3
4
  module Paginatable
4
5
  extend ActiveSupport::Concern
5
6
 
@@ -67,8 +68,8 @@ module Acfs::Collections
67
68
  def setup_params(params)
68
69
  @current_page = begin
69
70
  Integer params.fetch(:page, 1)
70
- rescue ArgumentError
71
- params[:page]
71
+ rescue ArgumentError
72
+ params[:page]
72
73
  end
73
74
  end
74
75
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
  require 'yaml'
3
5
 
@@ -25,7 +27,7 @@ module Acfs
25
27
  # @return [undefined]
26
28
  #
27
29
  def configure(&block)
28
- if block.arity > 0
30
+ if block.arity.positive?
29
31
  block.call self
30
32
  else
31
33
  instance_eval(&block)
@@ -37,8 +39,12 @@ module Acfs
37
39
  # @overload locate(service, uri)
38
40
  # Configures URL where a service can be reached.
39
41
  #
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
+ # @param [Symbol] service
43
+ # Service identity key for service that is reachable under given URL.
44
+ #
45
+ # @param [String] uri
46
+ # URL where service is reachable. Will be passed to {URI.parse}.
47
+ #
42
48
  # @return [undefined]
43
49
  #
44
50
  # @overload locate(service)
@@ -64,7 +70,7 @@ module Acfs
64
70
  # @return [undefined]
65
71
  #
66
72
  def load(filename)
67
- config = YAML.load File.read filename
73
+ config = YAML.safe_load(File.read(filename), [], [], true)
68
74
  env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
69
75
 
70
76
  config = config[env] if config.key? env
@@ -95,18 +101,19 @@ module Acfs
95
101
  # @return [Configuration]
96
102
  #
97
103
  def current
98
- @configuration ||= new
104
+ @current ||= new
99
105
  end
100
106
 
101
107
  # @api private
102
108
  #
103
- # Swap configuration object with given new one. Must be a {Configuration} object.
109
+ # Swap configuration object with given new one. Must be
110
+ # a {Configuration} object.
104
111
  #
105
112
  # @param [Configuration] configuration
106
113
  # @return [undefined]
107
114
  #
108
115
  def set(configuration)
109
- @configuration = configuration if configuration.is_a? Configuration
116
+ @current = configuration if configuration.is_a? Configuration
110
117
  end
111
118
  end
112
119
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Acfs
2
4
  # Acfs base error.
3
5
  #
@@ -10,6 +12,24 @@ module Acfs
10
12
 
11
13
  class UnsupportedOperation < StandardError; end
12
14
 
15
+ class RequestError < Error
16
+ attr_reader :request
17
+
18
+ def initialize(request, message)
19
+ @request = request
20
+
21
+ message = "#{message}: #{request.method.upcase} #{request.url}"
22
+
23
+ super message: message
24
+ end
25
+ end
26
+
27
+ class TimeoutError < RequestError
28
+ def initialize(request)
29
+ super(request, 'Timeout reached')
30
+ end
31
+ end
32
+
13
33
  # Response error containing the responsible response object.
14
34
  #
15
35
  class ErroneousResponse < Error
@@ -17,17 +37,15 @@ module Acfs
17
37
 
18
38
  def initialize(opts = {})
19
39
  @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
40
+
41
+ message = if response
42
+ (opts[:message] ? opts[:message] + ':' : 'Received') +
43
+ " #{response.code} for #{response.request.method.upcase}" \
44
+ " #{response.request.url} #{response.request.format}"
45
+ else
46
+ opts[:message] || 'Received erroneous response'
47
+ end
48
+
31
49
  super opts, message
32
50
  end
33
51
  end
@@ -41,17 +59,27 @@ module Acfs
41
59
  @stubs = opts.delete :stubs
42
60
  @operation = opts.delete :operation
43
61
 
44
- super opts, "Ambiguous stubs for #{operation.action} on #{operation.resource}.\n" +
45
- stubs.map {|s| " #{s.opts.pretty_inspect}" }.join
62
+ message = "Ambiguous stubs for #{operation.action} " \
63
+ "on #{operation.resource}.\n" +
64
+ stubs.map {|s| " #{s.opts.pretty_inspect}" }.join
65
+
66
+ super opts, message
46
67
  end
47
68
  end
48
69
 
49
- # Resource not found error raised on a 404 response
50
- #
51
- class ResourceNotFound < ErroneousResponse
52
- end
70
+ # 400
71
+ class BadRequest < ErroneousResponse; end
53
72
 
54
- #
73
+ # 401
74
+ class Unauthorized < ErroneousResponse; end
75
+
76
+ # 403
77
+ class Forbidden < ErroneousResponse; end
78
+
79
+ # 404
80
+ class ResourceNotFound < ErroneousResponse; end
81
+
82
+ # 422
55
83
  class InvalidResource < ErroneousResponse
56
84
  attr_reader :errors, :resource
57
85
 
@@ -71,6 +99,18 @@ module Acfs
71
99
  end
72
100
  end
73
101
 
102
+ # 500
103
+ class ServerError < ErroneousResponse; end
104
+
105
+ # 502
106
+ class BadGateway < ErroneousResponse; end
107
+
108
+ # 503
109
+ class ServiceUnavailable < ErroneousResponse; end
110
+
111
+ # 504
112
+ class GatewayTimeout < ErroneousResponse; end
113
+
74
114
  # A ResourceNotLoaded error will be thrown when calling some
75
115
  # modifing methods on not loaded resources as it is usally
76
116
  # unwanted to call e.g. `update_attributes` on a not loaded
@@ -97,7 +137,8 @@ module Acfs
97
137
  def initialize(opts = {})
98
138
  @base_class = opts.delete :base_class
99
139
  @type_name = opts.delete :type_name
100
- opts[:message] = "Received resource type `#{type_name}` is no subclass of #{base_class}"
140
+ opts[:message] = "Received resource type `#{type_name}` " \
141
+ "is no subclass of #{base_class}"
101
142
  super
102
143
  end
103
144
  end