shaf_client 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92a7f2a17ed01c0b131194c0ca4516280d219d5a36a2f3afc38f4ccc314a5f0a
4
- data.tar.gz: f2c91a861378440ded31fa39bd364ad80d4ecf57408f1b51219c746883f254d8
3
+ metadata.gz: 19b9d623cc520b186b862d8604530daabf1723bc5a3b5d159dac3ecca706f1fb
4
+ data.tar.gz: 5ee331304969c4c873429914c521be63aaa849f94e5a09c94f6ba4fec06f9049
5
5
  SHA512:
6
- metadata.gz: 4595ff9d2c6bf0665a0f541f428de36b8f420543a0ad0d6c208dbdc70b7b1d5aa0369dd16e8a5f2cfa254b995aabc7f2151047ab539d24ce32a0002a319d7e21
7
- data.tar.gz: 1933d7180df83cba97c2be59b6bff59c86545151cf9caffab0a7b1e0e036cc152bcd1567c31a1a4f8f3ad0a5719139ff6c01bc09a4e47940a8c3a66925e33432
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/form'
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'] = '__shaf_client_emtpy__' if body.empty?
48
+ response.headers['content-type'] = nil if body.empty?
48
49
 
49
50
  Resource.build(self, body, response.status, response.headers)
50
51
  end
@@ -21,5 +21,10 @@ class ShafClient
21
21
  @href = href
22
22
  @templated = !!templated
23
23
  end
24
+
25
+ def resolve_templated(**args)
26
+ args[:rel] &&= args[:rel].to_s.sub(/#{name}:/, '')
27
+ super(**args)
28
+ end
24
29
  end
25
30
  end
@@ -4,7 +4,7 @@ class ShafClient
4
4
  class EmptyResource < Resource
5
5
  attr_reader :http_status, :headers
6
6
 
7
- ResourceMapper.register('__shaf_client_emtpy__', self)
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
@@ -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 = attribute(:fields).each_with_object({}) do |d, v|
13
- v[d['name'].to_sym] = d['value']
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[key.to_sym]
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
- attribute(:href)
33
+ raise NotImplementedError
27
34
  end
28
35
 
29
36
  def http_method
30
- attribute(:method).downcase.to_sym
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(http_method, target, payload: @values)
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
- attribute(:fields).all? do |field|
39
- valid_field? field
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 validate_required(field, key)
65
- return true unless field['required']
66
- return false if values[key].nil?
67
- return false if values[key].respond_to?(:empty) && values[key].empty?
68
- true
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 validate_string(field, key)
72
- return true unless %w[string text].include? field.fetch('type', '').downcase
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 validate_number(field, key)
77
- return true unless %w[int integer number].include? field.fetch('type', '').downcase
78
- values.fetch(key, 0).is_a? Numeric
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
@@ -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
- alias templated? templated
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
- args.inject(href) do |uri, (key, value)|
30
- value = value.to_s.sub(/.+:/, '')
31
- uri.sub(/{#{key}}/, value)
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
@@ -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
- all[content_type&.to_sym].tap do |clazz|
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
- all[content_type&.to_sym] = clazz
15
+ mapping[content_type&.to_sym] = clazz
20
16
  end
21
17
 
22
18
  def default=(clazz)
23
- all.default = clazz
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.5.3
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-17 00:00:00.000000000 Z
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