shaf_client 0.5.3 → 0.6.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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/shaf_client.rb +3 -2
- data/lib/shaf_client/curie.rb +5 -0
- data/lib/shaf_client/empty_resource.rb +1 -1
- data/lib/shaf_client/field.rb +75 -0
- data/lib/shaf_client/form.rb +45 -30
- data/lib/shaf_client/hal_form.rb +39 -0
- data/lib/shaf_client/link.rb +30 -7
- data/lib/shaf_client/resource.rb +15 -0
- data/lib/shaf_client/resource_mapper.rb +9 -7
- data/lib/shaf_client/shaf_form.rb +34 -0
- metadata +5 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19b9d623cc520b186b862d8604530daabf1723bc5a3b5d159dac3ecca706f1fb
|
4
|
+
data.tar.gz: 5ee331304969c4c873429914c521be63aaa849f94e5a09c94f6ba4fec06f9049
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85305d86a68ad781d0608aca92c595dca9403a7a420900560fc50828af4b6a663a3731fe7de10b73efaab75e2f0430a5f52ffce1003dcb32b511380e85577358
|
7
|
+
data.tar.gz: f9fc05a4f34e6dad3f83ee583fa8329ae665bf537522a7a1e950a818e97cc869a4109a73f909000cf4ef49a90e4571f595b54b679ce74cedd15826e775dc6a29
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/shaf_client.rb
CHANGED
@@ -6,7 +6,8 @@ require 'json'
|
|
6
6
|
require 'shaf_client/error'
|
7
7
|
require 'shaf_client/middleware/redirect'
|
8
8
|
require 'shaf_client/resource'
|
9
|
-
require 'shaf_client/
|
9
|
+
require 'shaf_client/shaf_form'
|
10
|
+
require 'shaf_client/hal_form'
|
10
11
|
require 'shaf_client/api_error'
|
11
12
|
require 'shaf_client/empty_resource'
|
12
13
|
require 'shaf_client/unknown_resource'
|
@@ -44,7 +45,7 @@ class ShafClient
|
|
44
45
|
)
|
45
46
|
|
46
47
|
body = String(response.body)
|
47
|
-
response.headers['content-type'] =
|
48
|
+
response.headers['content-type'] = nil if body.empty?
|
48
49
|
|
49
50
|
Resource.build(self, body, response.status, response.headers)
|
50
51
|
end
|
data/lib/shaf_client/curie.rb
CHANGED
@@ -4,7 +4,7 @@ class ShafClient
|
|
4
4
|
class EmptyResource < Resource
|
5
5
|
attr_reader :http_status, :headers
|
6
6
|
|
7
|
-
ResourceMapper.register(
|
7
|
+
ResourceMapper.register(nil, self)
|
8
8
|
|
9
9
|
def initialize(_client, _payload, status = nil, headers = {})
|
10
10
|
@http_status = status
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class ShafClient
|
4
|
+
class Field
|
5
|
+
attr_reader :name, :prompt, :required, :read_only,
|
6
|
+
:hidden, :templated, :type, :value, :regex
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
name:,
|
10
|
+
prompt: nil,
|
11
|
+
title: nil,
|
12
|
+
required: false,
|
13
|
+
read_only: false,
|
14
|
+
hidden: false,
|
15
|
+
templated: false,
|
16
|
+
type: nil,
|
17
|
+
value: nil,
|
18
|
+
regex: nil
|
19
|
+
)
|
20
|
+
@name = name.to_sym
|
21
|
+
@prompt = prompt || title || name
|
22
|
+
@required = required
|
23
|
+
@read_only = read_only
|
24
|
+
@hidden = hidden
|
25
|
+
@templated = templated
|
26
|
+
@type = type&.downcase
|
27
|
+
@value = value
|
28
|
+
@regex = parse_regexp(regex)
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid?(value)
|
32
|
+
return false unless validate_required(value)
|
33
|
+
return false unless validate_number(value)
|
34
|
+
return false unless validate_string(value)
|
35
|
+
return false unless validate_regexp(value)
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def validate_required(value)
|
42
|
+
return true unless required
|
43
|
+
return false if String(value).empty?
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_number(value)
|
48
|
+
return true if value.nil?
|
49
|
+
return true unless type
|
50
|
+
return true unless %w[int integer number].include? type
|
51
|
+
value.is_a? Numeric
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate_string(value)
|
55
|
+
return true if value.nil?
|
56
|
+
return true unless type
|
57
|
+
return true unless %w[string text].include? type
|
58
|
+
value.is_a? String
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_regexp(value)
|
62
|
+
str = String(value)
|
63
|
+
return true if str.empty?
|
64
|
+
return true unless regex
|
65
|
+
str.match? regex
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse_regexp(str)
|
69
|
+
return if String(str).empty?
|
70
|
+
Regexp.new(str)
|
71
|
+
rescue RegexpError
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/shaf_client/form.rb
CHANGED
@@ -1,42 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
4
|
+
require 'uri'
|
2
5
|
require 'shaf_client/link'
|
6
|
+
require 'shaf_client/field'
|
3
7
|
|
4
8
|
class ShafClient
|
5
9
|
class Form < Resource
|
6
10
|
|
7
|
-
profile 'shaf-form'
|
8
|
-
|
9
11
|
def values
|
10
12
|
return @values if defined? @values
|
11
13
|
|
12
|
-
@values =
|
13
|
-
|
14
|
+
@values = fields.each_with_object({}) do |field, values|
|
15
|
+
values[field.name] = field.value
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
17
19
|
def [](key)
|
18
|
-
values
|
20
|
+
values.fetch(key.to_sym)
|
19
21
|
end
|
20
22
|
|
21
23
|
def []=(key, value)
|
24
|
+
values.fetch(key.to_sym) # Raise KeyError unless key exist!
|
22
25
|
values[key.to_sym] = value
|
23
26
|
end
|
24
27
|
|
28
|
+
def title
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
25
32
|
def target
|
26
|
-
|
33
|
+
raise NotImplementedError
|
27
34
|
end
|
28
35
|
|
29
36
|
def http_method
|
30
|
-
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
def content_type
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
def fields
|
45
|
+
raise NotImplementedError
|
31
46
|
end
|
32
47
|
|
33
48
|
def submit
|
34
|
-
client.send(
|
49
|
+
client.send(
|
50
|
+
http_method,
|
51
|
+
target,
|
52
|
+
payload: encoded_payload,
|
53
|
+
headers: {'Content-Type' => content_type}
|
54
|
+
)
|
35
55
|
end
|
36
56
|
|
37
57
|
def valid?
|
38
|
-
|
39
|
-
|
58
|
+
field_value_mapping
|
59
|
+
|
60
|
+
fields.all? do |field|
|
61
|
+
value = values[field.name.to_sym]
|
62
|
+
field.valid? value
|
40
63
|
end
|
41
64
|
end
|
42
65
|
|
@@ -50,32 +73,24 @@ class ShafClient
|
|
50
73
|
super
|
51
74
|
end
|
52
75
|
|
53
|
-
def valid_field?(field)
|
54
|
-
key = field['name'].to_sym
|
55
|
-
return false unless validate_required(field, key)
|
56
|
-
return true if values[key].nil?
|
57
|
-
return false unless validate_number(field, key)
|
58
|
-
return false unless validate_string(field, key)
|
59
|
-
true
|
60
|
-
end
|
61
|
-
|
62
76
|
private
|
63
77
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
78
|
+
def encoded_payload
|
79
|
+
if content_type&.downcase == 'application/x-www-form-urlencoded'
|
80
|
+
URI.encode_www_form(values)
|
81
|
+
else
|
82
|
+
JSON.generate(values)
|
83
|
+
end
|
69
84
|
end
|
70
85
|
|
71
|
-
def
|
72
|
-
|
73
|
-
values[key].is_a? String
|
86
|
+
def field_names
|
87
|
+
fields.map { |f| f.name.to_sym }
|
74
88
|
end
|
75
89
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
90
|
+
def field_value_mapping
|
91
|
+
field_names.each_with_object({}) do |name, mapping|
|
92
|
+
mapping[name.to_sym] = values[name.to_sym]
|
93
|
+
end
|
79
94
|
end
|
80
95
|
end
|
81
96
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'shaf_client/form'
|
2
|
+
|
3
|
+
class ShafClient
|
4
|
+
class HalForm < Form
|
5
|
+
attr_accessor :target
|
6
|
+
|
7
|
+
content_type 'application/prs.hal-forms+json'
|
8
|
+
|
9
|
+
def title
|
10
|
+
template[:title]
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
attribute(:name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def http_method
|
18
|
+
template[:method].downcase.to_sym
|
19
|
+
end
|
20
|
+
|
21
|
+
def content_type
|
22
|
+
template[:contentType]
|
23
|
+
end
|
24
|
+
|
25
|
+
def fields
|
26
|
+
template[:properties].map do |values|
|
27
|
+
Field.new(values.transform_keys(&:to_sym))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def template
|
34
|
+
@template ||= attributes
|
35
|
+
.dig(:_templates, 'default')
|
36
|
+
.transform_keys(&:to_sym)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/shaf_client/link.rb
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
class ShafClient
|
4
4
|
class Link
|
5
|
-
attr_reader :templated
|
6
|
-
|
7
5
|
def self.from(data)
|
8
6
|
if data.is_a? Array
|
9
7
|
data.map { |d| new(href: d['href'], templated: d['templated']) }
|
@@ -17,7 +15,9 @@ class ShafClient
|
|
17
15
|
@templated = !!templated
|
18
16
|
end
|
19
17
|
|
20
|
-
|
18
|
+
def templated?
|
19
|
+
@templated
|
20
|
+
end
|
21
21
|
|
22
22
|
def href
|
23
23
|
@href.dup
|
@@ -26,10 +26,9 @@ class ShafClient
|
|
26
26
|
def resolve_templated(**args)
|
27
27
|
return href unless templated?
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
29
|
+
href
|
30
|
+
.then { |href| resolve_required(href, **args) }
|
31
|
+
.then { |href| resolve_optional(href, **args) }
|
33
32
|
end
|
34
33
|
|
35
34
|
def to_h
|
@@ -38,5 +37,29 @@ class ShafClient
|
|
38
37
|
templated: templated?
|
39
38
|
}
|
40
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def resolve_required(href, **args)
|
44
|
+
String(href).gsub(/{(?!\?)([^}]*)}/) do
|
45
|
+
key = $1.to_sym
|
46
|
+
args.fetch key do
|
47
|
+
raise ArgumentError, "missing keyword: :#{key}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def resolve_optional(href, **args)
|
53
|
+
String(href).gsub(/{\?([^}]*)}/) do
|
54
|
+
values = []
|
55
|
+
$1.split(',').each do |key|
|
56
|
+
next unless args.key? key.to_sym
|
57
|
+
values << "#{key}=#{args[key.to_sym]}"
|
58
|
+
end
|
59
|
+
|
60
|
+
next '' if values.empty?
|
61
|
+
"?#{values.join('&')}"
|
62
|
+
end
|
63
|
+
end
|
41
64
|
end
|
42
65
|
end
|
data/lib/shaf_client/resource.rb
CHANGED
@@ -49,6 +49,21 @@ class ShafClient
|
|
49
49
|
client.get_doc(uri)
|
50
50
|
end
|
51
51
|
|
52
|
+
def get_hal_form(rel)
|
53
|
+
href = link(rel).href
|
54
|
+
uri = rel.to_s
|
55
|
+
if uri.match? %r{:[^/]}
|
56
|
+
curie_name, rel = rel.split(':')
|
57
|
+
curie = curie(curie_name)
|
58
|
+
uri = curie.resolve_templated(rel: rel)
|
59
|
+
end
|
60
|
+
|
61
|
+
headers = {'Accept': 'application/prs.hal-forms+json'}
|
62
|
+
client.get(uri, headers: headers).tap do |form|
|
63
|
+
form.target = href if form.respond_to? :target=
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
52
67
|
def reload!
|
53
68
|
self << get(:self, headers: {'Cache-Control': 'no-cache'})
|
54
69
|
end
|
@@ -3,12 +3,8 @@ require 'shaf_client/error'
|
|
3
3
|
class ShafClient
|
4
4
|
class ResourceMapper
|
5
5
|
class << self
|
6
|
-
def all
|
7
|
-
@all ||= {}
|
8
|
-
end
|
9
|
-
|
10
6
|
def for(content_type)
|
11
|
-
|
7
|
+
mapping[content_type&.to_sym].tap do |clazz|
|
12
8
|
next if clazz
|
13
9
|
raise UnSupportedContentType,
|
14
10
|
"Can't handle Content-Type: #{content_type}"
|
@@ -16,11 +12,17 @@ class ShafClient
|
|
16
12
|
end
|
17
13
|
|
18
14
|
def register(content_type, clazz)
|
19
|
-
|
15
|
+
mapping[content_type&.to_sym] = clazz
|
20
16
|
end
|
21
17
|
|
22
18
|
def default=(clazz)
|
23
|
-
|
19
|
+
mapping.default = clazz
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def mapping
|
25
|
+
@mapping ||= {}
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'shaf_client/form'
|
2
|
+
|
3
|
+
class ShafClient
|
4
|
+
class ShafForm < Form
|
5
|
+
|
6
|
+
profile 'shaf-form'
|
7
|
+
|
8
|
+
def title
|
9
|
+
attribute(:title)
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
attribute(:name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def target
|
17
|
+
attribute(:href)
|
18
|
+
end
|
19
|
+
|
20
|
+
def http_method
|
21
|
+
attribute(:method).downcase.to_sym
|
22
|
+
end
|
23
|
+
|
24
|
+
def content_type
|
25
|
+
attribute(:type)
|
26
|
+
end
|
27
|
+
|
28
|
+
def fields
|
29
|
+
attribute(:fields).map do |values|
|
30
|
+
Field.new(values.transform_keys(&:to_sym))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
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.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sammy Henningsson
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
ZMhjYR7sRczGJx+GxGU2EaR0bjRsPVlC4ywtFxoOfRG3WaJcpWGEoAoMJX6Z0bRv
|
31
31
|
M40=
|
32
32
|
-----END CERTIFICATE-----
|
33
|
-
date: 2019-09-
|
33
|
+
date: 2019-09-20 00:00:00.000000000 Z
|
34
34
|
dependencies:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: faraday
|
@@ -106,11 +106,14 @@ files:
|
|
106
106
|
- lib/shaf_client/curie.rb
|
107
107
|
- lib/shaf_client/empty_resource.rb
|
108
108
|
- lib/shaf_client/error.rb
|
109
|
+
- lib/shaf_client/field.rb
|
109
110
|
- lib/shaf_client/form.rb
|
111
|
+
- lib/shaf_client/hal_form.rb
|
110
112
|
- lib/shaf_client/link.rb
|
111
113
|
- lib/shaf_client/middleware/redirect.rb
|
112
114
|
- lib/shaf_client/resource.rb
|
113
115
|
- lib/shaf_client/resource_mapper.rb
|
116
|
+
- lib/shaf_client/shaf_form.rb
|
114
117
|
- lib/shaf_client/unknown_resource.rb
|
115
118
|
homepage: https://github.com/sammyhenningsson/shaf_client
|
116
119
|
licenses:
|
metadata.gz.sig
CHANGED
Binary file
|