shaf_client 0.6.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,18 +1,26 @@
1
1
  require 'shaf_client/error'
2
+ require 'shaf_client/content_type_map'
3
+ require 'shaf_client/resource_extension'
2
4
 
3
5
  class ShafClient
4
- class ResourceMapper
6
+ module ResourceMapper
5
7
  class << self
6
- def for(content_type)
7
- mapping[content_type&.to_sym].tap do |clazz|
8
- next if clazz
9
- raise UnSupportedContentType,
10
- "Can't handle Content-Type: #{content_type}"
11
- end
8
+ def for(content_type:, headers: {}, payload: nil, client: nil)
9
+ content_type = content_type&.to_sym
10
+ profile = profile_from(content_type, headers, payload)
11
+ clazz, extensions = result_for(content_type, payload, profile, client)
12
+
13
+ raise_unsupported_error(content_type) unless clazz
14
+
15
+ [clazz, extensions]
16
+ end
17
+
18
+ def register(content_type, profile = nil, clazz)
19
+ mapping[content_type&.to_sym, profile] = clazz
12
20
  end
13
21
 
14
- def register(content_type, clazz)
15
- mapping[content_type&.to_sym] = clazz
22
+ def unregister(content_type, profile = nil)
23
+ mapping.delete(content_type.to_sym, profile)
16
24
  end
17
25
 
18
26
  def default=(clazz)
@@ -22,7 +30,75 @@ class ShafClient
22
30
  private
23
31
 
24
32
  def mapping
25
- @mapping ||= {}
33
+ @mapping ||= ContentTypeMap.new
34
+ end
35
+
36
+ def result_for(content_type, payload, profile, client)
37
+ clazz = nil
38
+ extensions = []
39
+
40
+ # Note: mapping typically has a default value, so we need to check that the key really exist
41
+ if mapping.key? content_type, profile
42
+ # Registered classes with profile takes precedence over linked profiles
43
+ clazz = mapping[content_type, profile]
44
+ else
45
+ clazz = mapping[content_type]
46
+ extensions = extensions_for(clazz, profile, payload, client) if profile
47
+ end
48
+
49
+ [clazz, extensions]
50
+ end
51
+
52
+ def profile_from(content_type, headers, payload)
53
+ profile_from_content_type(content_type) ||
54
+ profile_from_link_header(headers) ||
55
+ profile_from_payload_link(content_type, payload)
56
+ rescue StandardError => err
57
+ warn "Exception while looking up profile link relation: #{err}"
58
+ end
59
+
60
+ def profile_from_content_type(content_type)
61
+ return unless content_type
62
+
63
+ content_type[/profile="?([^"\s;]*)/, 1]
64
+ end
65
+
66
+ def profile_from_link_header(headers)
67
+ links = String(headers["link"] || headers["Link"]).split(',')
68
+ profile_link = links.find { |link| link.match?(/rel="?profile"?/) }
69
+ profile_link[/<(.*)>/, 1] if profile_link
70
+ end
71
+
72
+ def profile_from_payload_link(content_type, payload)
73
+ clazz = mapping[content_type]
74
+ resource = clazz&.new(nil, payload)
75
+ return unless resource.respond_to? :link
76
+
77
+ link = resource.link(:profile) { nil }
78
+ link&.href
79
+ end
80
+
81
+ def extensions_for(clazz, profile, payload, client)
82
+ return [] unless clazz && profile && client
83
+
84
+ profile_resource = fetch_profile(profile, client)
85
+ link_relations = clazz.new(nil, payload).actions if payload
86
+
87
+ ResourceExtension.for(profile_resource, clazz, link_relations, client)
88
+ rescue StandardError => err
89
+ warn "Exception while resolving extensions for profile " \
90
+ "#{profile_resource&.name || profile}: #{err}"
91
+ []
92
+ end
93
+
94
+ def fetch_profile(profile, client)
95
+ return unless profile&.start_with? %r{https?://}
96
+
97
+ client.get(profile)
98
+ end
99
+
100
+ def raise_unsupported_error(content_type)
101
+ raise UnSupportedContentType, "Can't handle Content-Type: #{content_type}"
26
102
  end
27
103
  end
28
104
  end
@@ -3,7 +3,8 @@ require 'shaf_client/form'
3
3
  class ShafClient
4
4
  class ShafForm < Form
5
5
 
6
- profile 'shaf-form'
6
+ profile 'shaf-form' # Legacy profiles
7
+ profile 'urn:shaf:form' # New style. Shaf version >= 2.1.0
7
8
 
8
9
  def title
9
10
  attribute(:title)
@@ -27,7 +28,7 @@ class ShafClient
27
28
 
28
29
  def fields
29
30
  attribute(:fields).map do |values|
30
- Field.new(values.transform_keys(&:to_sym))
31
+ Field.new(**values.transform_keys(&:to_sym))
31
32
  end
32
33
  end
33
34
  end
@@ -0,0 +1,70 @@
1
+ class ShafClient
2
+ module StatusCodes
3
+ StatusCode = {
4
+ 100 => 'Continue',
5
+ 101 => 'Switching Protocols',
6
+ 102 => 'Processing',
7
+ 103 => 'Early Hints',
8
+ 200 => 'OK',
9
+ 201 => 'Created',
10
+ 202 => 'Accepted',
11
+ 203 => 'Non-Authoritative Information',
12
+ 204 => 'No Content',
13
+ 205 => 'Reset Content',
14
+ 206 => 'Partial Content',
15
+ 207 => 'Multi-Status',
16
+ 208 => 'Already Reported',
17
+ 226 => 'IM Used',
18
+ 300 => 'Multiple Choices',
19
+ 301 => 'Moved Permanently',
20
+ 302 => 'Found',
21
+ 303 => 'See Other',
22
+ 304 => 'Not Modified',
23
+ 305 => 'Use Proxy',
24
+ 306 => '(Unused)',
25
+ 307 => 'Temporary Redirect',
26
+ 308 => 'Permanent Redirect',
27
+ 400 => 'Bad Request',
28
+ 401 => 'Unauthorized',
29
+ 402 => 'Payment Required',
30
+ 403 => 'Forbidden',
31
+ 404 => 'Not Found',
32
+ 405 => 'Method Not Allowed',
33
+ 406 => 'Not Acceptable',
34
+ 407 => 'Proxy Authentication Required',
35
+ 408 => 'Request Timeout',
36
+ 409 => 'Conflict',
37
+ 410 => 'Gone',
38
+ 411 => 'Length Required',
39
+ 412 => 'Precondition Failed',
40
+ 413 => 'Payload Too Large',
41
+ 414 => 'URI Too Long',
42
+ 415 => 'Unsupported Media Type',
43
+ 416 => 'Range Not Satisfiable',
44
+ 417 => 'Expectation Failed',
45
+ 421 => 'Misdirected Request',
46
+ 422 => 'Unprocessable Entity',
47
+ 423 => 'Locked',
48
+ 424 => 'Failed Dependency',
49
+ 425 => 'Too Early',
50
+ 426 => 'Upgrade Required',
51
+ 428 => 'Precondition Required',
52
+ 429 => 'Too Many Requests',
53
+ 431 => 'Request Header Fields Too Large',
54
+ 451 => 'Unavailable For Legal Reasons',
55
+ 500 => 'Internal Server Error',
56
+ 501 => 'Not Implemented',
57
+ 502 => 'Bad Gateway',
58
+ 503 => 'Service Unavailable',
59
+ 504 => 'Gateway Timeout',
60
+ 505 => 'HTTP Version Not Supported',
61
+ 506 => 'Variant Also Negotiates',
62
+ 507 => 'Insufficient Storage',
63
+ 508 => 'Loop Detected',
64
+ 510 => 'Not Extended',
65
+ 511 => 'Network Authentication Required',
66
+ }
67
+ StatusCode.default = 'Unassigned'
68
+ StatusCode.freeze
69
+ end
70
+ end
@@ -0,0 +1,16 @@
1
+ class ShafClient
2
+ module Test
3
+ module Stubbing
4
+ def stubs
5
+ return unless @adapter == :test
6
+ @stubs ||= Faraday::Adapter::Test::Stubs.new
7
+ end
8
+
9
+ def adapter_args
10
+ args = super
11
+ args << stubs if @adapter == :test
12
+ args
13
+ end
14
+ end
15
+ end
16
+ end
@@ -2,9 +2,9 @@ require 'shaf_client/resource'
2
2
 
3
3
  class ShafClient
4
4
  class UnknownResource < Resource
5
- attr_reader :http_status, :headers, :body
5
+ default_resource_class!
6
6
 
7
- ResourceMapper.default = self
7
+ attr_reader :http_status, :headers, :body
8
8
 
9
9
  def initialize(_client, payload, status = nil, headers = {})
10
10
  @body = payload.freeze
@@ -22,7 +22,7 @@ class ShafClient
22
22
 
23
23
  %i[get put post delete patch, get_doc, reload!].each do |method|
24
24
  define_method(method) do |*_args|
25
- raise "UnknownResource: #{method} not available"
25
+ raise Error, "UnknownResource: #{method} not available"
26
26
  end
27
27
  end
28
28
  end
@@ -0,0 +1,3 @@
1
+ class ShafClient
2
+ VERSION = "1.1.0"
3
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shaf_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sammy Henningsson
@@ -10,27 +10,26 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDXjCCAkagAwIBAgIBATANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDDCFzYW1t
14
- eS5oZW5uaW5nc3Nvbi9EQz1nbWFpbC9EQz1jb20wHhcNMTgwNzE2MTYzNTMzWhcN
15
- MjAwNzE2MTYzNTMzWjAsMSowKAYDVQQDDCFzYW1teS5oZW5uaW5nc3Nvbi9EQz1n
16
- bWFpbC9EQz1jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvkgwt
17
- Zn8obnCelWttayB1BrHBLUK3b8gasRRtbNk4DzAL+EW6sHSVT2u5I7Wws7JQA5VB
18
- NaK7tgvq3CbDLVRl9NrpDCDx09To08stPxDKi6kst1nkSPAD8g0sQlW3voeQTH98
19
- 2Z2H3XUegHhu5Z9PU9T/7V/vZUzHPiPg1tX1JUIGOPAjVGsr7SUetbL171zK4S4Y
20
- tvUkIoNaph+maHttvyYB/ptiZLD53WORKd4Knw3OiJsLtrxr5hhKyQ+txQdF0P8G
21
- +FlR+Je7B0Ek3yg6fEiJgrdcajYCMo8Oe/GRtoHhi6J3LsYA620P1BSCddZQ2XeL
22
- y3rzIZyMU0iaT69nAgMBAAGjgYowgYcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
23
- HQYDVR0OBBYEFLpI49QndnmuiDhwy2XtMps7No1pMCYGA1UdEQQfMB2BG3NhbW15
24
- Lmhlbm5pbmdzc29uQGdtYWlsLmNvbTAmBgNVHRIEHzAdgRtzYW1teS5oZW5uaW5n
25
- c3NvbkBnbWFpbC5jb20wDQYJKoZIhvcNAQELBQADggEBAFJZqH6sgeiTLvMLpxaK
26
- K1GaYSCyZbMutf5C3tIAgkmU5UD6B8R0bw6gTM1deM5NJ60LjzqY7rlK3YKDIbTn
27
- iXMCe9vd4yE/jb5Zi8Wk//9n8CMG68dQpBvmcQ58/M4gTtgsx+lIgXuI5dPQMmRi
28
- bhWQqqWqxT9X6njjfXFk4xn3z6mfFQNPAYqRVeTHUpXBQZPt+bYXRwHPFZGWkx4l
29
- BnuuhYKt3CR7YIgvnsQWlTAcU1Ipdayj6UfYqUtlc6cF3CL96NOx7mgZXV8URFiX
30
- ZMhjYR7sRczGJx+GxGU2EaR0bjRsPVlC4ywtFxoOfRG3WaJcpWGEoAoMJX6Z0bRv
31
- M40=
13
+ MIIDVjCCAj6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAqMSgwJgYDVQQDDB9zYW1t
14
+ eS5oZW5uaW5nc3Nvbi9EQz1oZXkvREM9Y29tMB4XDTIxMDIwMjEzNTY1OFoXDTIy
15
+ MDIwMjEzNTY1OFowKjEoMCYGA1UEAwwfc2FtbXkuaGVubmluZ3Nzb24vREM9aGV5
16
+ L0RDPWNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK+SDC1mfyhu
17
+ cJ6Va21rIHUGscEtQrdvyBqxFG1s2TgPMAv4RbqwdJVPa7kjtbCzslADlUE1oru2
18
+ C+rcJsMtVGX02ukMIPHT1OjTyy0/EMqLqSy3WeRI8APyDSxCVbe+h5BMf3zZnYfd
19
+ dR6AeG7ln09T1P/tX+9lTMc+I+DW1fUlQgY48CNUayvtJR61svXvXMrhLhi29SQi
20
+ g1qmH6Zoe22/JgH+m2JksPndY5Ep3gqfDc6Imwu2vGvmGErJD63FB0XQ/wb4WVH4
21
+ l7sHQSTfKDp8SImCt1xqNgIyjw578ZG2geGLoncuxgDrbQ/UFIJ11lDZd4vLevMh
22
+ nIxTSJpPr2cCAwEAAaOBhjCBgzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNV
23
+ HQ4EFgQUukjj1Cd2ea6IOHDLZe0ymzs2jWkwJAYDVR0RBB0wG4EZc2FtbXkuaGVu
24
+ bmluZ3Nzb25AaGV5LmNvbTAkBgNVHRIEHTAbgRlzYW1teS5oZW5uaW5nc3NvbkBo
25
+ ZXkuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBt310FZ56E/fp/y5Wym1xb4C0owfnI
26
+ LzUqOjXWZTO7RezlBJV/qIwqt6bEjYDQR56zULJFSp4YdoDsratmQ+/kwtbHF7xf
27
+ WYkSE36mhLP2ggQFH9fXtX6XdyIlwFqwEfNW73ZrkBXGjMxLVKIS9uHdN7PoNhbS
28
+ 0YjOZZD/rq1Jf+klwl/G7bBDPjn58DWlUmwzoj49goGS/UBG37RssQxRwPelKHZh
29
+ 5ZlcHq9h5CxVt380OKaU6wMg95RJBd/kUJqmPxxlxMH8QDQinTwZmmFA9wW7PJdy
30
+ wAx8px9LkSjTs0GVLH7VtVRWAELllsswCJktz63Adelx9fmIMgrTYgZM
32
31
  -----END CERTIFICATE-----
33
- date: 2019-10-04 00:00:00.000000000 Z
32
+ date: 2021-04-07 00:00:00.000000000 Z
34
33
  dependencies:
35
34
  - !ruby/object:Gem::Dependency
36
35
  name: faraday
@@ -38,14 +37,14 @@ dependencies:
38
37
  requirements:
39
38
  - - "~>"
40
39
  - !ruby/object:Gem::Version
41
- version: '0.15'
40
+ version: '1.0'
42
41
  type: :runtime
43
42
  prerelease: false
44
43
  version_requirements: !ruby/object:Gem::Requirement
45
44
  requirements:
46
45
  - - "~>"
47
46
  - !ruby/object:Gem::Version
48
- version: '0.15'
47
+ version: '1.0'
49
48
  - !ruby/object:Gem::Dependency
50
49
  name: faraday-http-cache
51
50
  requirement: !ruby/object:Gem::Requirement
@@ -66,14 +65,14 @@ dependencies:
66
65
  requirements:
67
66
  - - "~>"
68
67
  - !ruby/object:Gem::Version
69
- version: '12.0'
68
+ version: '13.0'
70
69
  type: :development
71
70
  prerelease: false
72
71
  version_requirements: !ruby/object:Gem::Requirement
73
72
  requirements:
74
73
  - - "~>"
75
74
  - !ruby/object:Gem::Version
76
- version: '12.0'
75
+ version: '13.0'
77
76
  - !ruby/object:Gem::Dependency
78
77
  name: minitest
79
78
  requirement: !ruby/object:Gem::Requirement
@@ -83,7 +82,7 @@ dependencies:
83
82
  version: '5'
84
83
  - - ">="
85
84
  - !ruby/object:Gem::Version
86
- version: '5.10'
85
+ version: 5.14.3
87
86
  type: :development
88
87
  prerelease: false
89
88
  version_requirements: !ruby/object:Gem::Requirement
@@ -93,28 +92,58 @@ dependencies:
93
92
  version: '5'
94
93
  - - ">="
95
94
  - !ruby/object:Gem::Version
96
- version: '5.10'
95
+ version: 5.14.3
96
+ - !ruby/object:Gem::Dependency
97
+ name: minitest-hooks
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1'
97
110
  description: A HAL client customized for Shaf APIs
98
111
  email: sammy.henningsson@gmail.com
99
- executables: []
112
+ executables:
113
+ - shaf_client
100
114
  extensions: []
101
115
  extra_rdoc_files: []
102
116
  files:
117
+ - bin/shaf_client
118
+ - lib/faraday_http_cache_patch.rb
103
119
  - lib/shaf_client.rb
120
+ - lib/shaf_client/alps/descriptor.rb
121
+ - lib/shaf_client/alps/extension.rb
122
+ - lib/shaf_client/alps_json.rb
104
123
  - lib/shaf_client/api_error.rb
105
124
  - lib/shaf_client/base_resource.rb
125
+ - lib/shaf_client/content_type_map.rb
106
126
  - lib/shaf_client/curie.rb
107
127
  - lib/shaf_client/empty_resource.rb
108
128
  - lib/shaf_client/error.rb
109
129
  - lib/shaf_client/field.rb
110
130
  - lib/shaf_client/form.rb
111
131
  - lib/shaf_client/hal_form.rb
132
+ - lib/shaf_client/hypertext_cache_strategy.rb
112
133
  - lib/shaf_client/link.rb
113
134
  - lib/shaf_client/middleware/redirect.rb
135
+ - lib/shaf_client/mime_types.rb
136
+ - lib/shaf_client/problem_json.rb
114
137
  - lib/shaf_client/resource.rb
138
+ - lib/shaf_client/resource_extension.rb
139
+ - lib/shaf_client/resource_extension/alps_http_method.rb
140
+ - lib/shaf_client/resource_extension/base.rb
115
141
  - lib/shaf_client/resource_mapper.rb
116
142
  - lib/shaf_client/shaf_form.rb
143
+ - lib/shaf_client/status_codes.rb
144
+ - lib/shaf_client/test/stubbing.rb
117
145
  - lib/shaf_client/unknown_resource.rb
146
+ - lib/shaf_client/version.rb
118
147
  homepage: https://github.com/sammyhenningsson/shaf_client
119
148
  licenses:
120
149
  - MIT
@@ -134,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
163
  - !ruby/object:Gem::Version
135
164
  version: '0'
136
165
  requirements: []
137
- rubygems_version: 3.0.6
166
+ rubygems_version: 3.0.3
138
167
  signing_key:
139
168
  specification_version: 4
140
169
  summary: HAL client for Shaf
metadata.gz.sig CHANGED
Binary file