ur 0.2.1 → 0.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1161e5f2e2219053fc4c54e541feb0d4c6efa1c1af930365e526a88bc0973e1b
4
- data.tar.gz: b42e166ae62f0a651d5425147e64b1d200c09862869188b8f95e52454f7b8e97
3
+ metadata.gz: a39ab1a17905dc8a0fb40eb22896580951abec8cfe78a11c4a1fd558ca6c6917
4
+ data.tar.gz: 5915b4da516b30c6ee291eb7f5a5bb5a8f974d30da327d5660a9b1a0549068a8
5
5
  SHA512:
6
- metadata.gz: 17187f65ff16035e72fc7d7e0b9468bd970d337b1f8173fbc2dde15f420ad406aa33ecb440b4b65e0dffb921279660fdedb48b4bb320ce3e4e9a411eec3a21da
7
- data.tar.gz: 8c8d0f0c86af8a97c18dc794e69b84634421607a7e6715120b90fd3d9f74bdd1848a5c422598dbc06fdb0ea7ce4ac474e76b761ec7e2243fdb87b2aa812af292
6
+ metadata.gz: e59ca34e85e21e8c659a10e57cffad39d3fa718389bed6ccb6e4327cb33b237569517bb8d5c2eb93272a0c20634966697823a7142f1d861ba58c933dad5342c6
7
+ data.tar.gz: 3ab8ad92c6e70fc3dd87928a200a500e8bd5d27440fd9c2b3e35d46d3778aed80122cefda50875cb0bb6f84dcba75fbc24bdc194d88d4f345439b97f98f7b9b6
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --main README.md --markup=markdown {lib}/**/*.rb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # v0.2.2
2
+
3
+ - Ur::Weblink
4
+ - JSI v0.7.0
5
+ - Ruby 3
6
+
1
7
  # v0.2.1
2
8
 
3
9
  - JSI v0.6.0
data/README.md CHANGED
@@ -61,6 +61,6 @@ end
61
61
 
62
62
  ## License
63
63
 
64
- [<img align="right" src="https://github.com/notEthan/ur/raw/master/resources/icons/LGPL-3.0.png">](https://www.gnu.org/licenses/lgpl-3.0.html)
64
+ [<img align="right" src="https://www.gnu.org/graphics/lgplv3-147x51.png">](https://www.gnu.org/licenses/lgpl-3.0.html)
65
65
 
66
- Ur is Open Source Software licensed under the terms of the [GNU Lesser General Public License version 3](https://www.gnu.org/licenses/lgpl-3.0.html).
66
+ Ur is licensed under the terms of the [GNU Lesser General Public License version 3](https://www.gnu.org/licenses/lgpl-3.0.html).
@@ -154,21 +154,21 @@ module Ur
154
154
  # @param other_type
155
155
  # @return [Boolean]
156
156
  def type?(other_type)
157
- type && type.casecmp?(other_type)
157
+ type ? type.casecmp?(other_type) : false
158
158
  end
159
159
 
160
160
  # is the 'subtype' portion of our media type equal (case-insensitive) to the given other_subtype
161
161
  # @param other_subtype
162
162
  # @return [Boolean]
163
163
  def subtype?(other_subtype)
164
- subtype && subtype.casecmp?(other_subtype)
164
+ subtype ? subtype.casecmp?(other_subtype) : false
165
165
  end
166
166
 
167
167
  # is the 'suffix' portion of our media type equal (case-insensitive) to the given other_suffix
168
168
  # @param other_suffix
169
169
  # @return [Boolean]
170
170
  def suffix?(other_suffix)
171
- suffix && suffix.casecmp?(other_suffix)
171
+ suffix ? suffix.casecmp?(other_suffix) : false
172
172
  end
173
173
 
174
174
  SOME_TEXT_SUBTYPES = %w(
@@ -215,55 +215,55 @@ module Ur
215
215
  # is this an XML content type?
216
216
  # @return [Boolean]
217
217
  def xml?
218
- suffix ? suffix.casecmp?('xml'): subtype ? subtype.casecmp?('xml') : false
218
+ suffix ? suffix.casecmp?('xml') : subtype ? subtype.casecmp?('xml') : false
219
219
  end
220
220
 
221
221
  # is this a `x-www-form-urlencoded` content type?
222
222
  # @return [Boolean]
223
223
  def form_urlencoded?
224
- suffix ? suffix.casecmp?('x-www-form-urlencoded'): subtype ? subtype.casecmp?('x-www-form-urlencoded') : false
224
+ suffix ? suffix.casecmp?('x-www-form-urlencoded') : subtype ? subtype.casecmp?('x-www-form-urlencoded') : false
225
225
  end
226
226
 
227
227
  # is the 'type' portion of our media type 'text'
228
228
  # @return [Boolean]
229
229
  def type_text?
230
- type && type.casecmp?('text')
230
+ type ? type.casecmp?('text') : false
231
231
  end
232
232
 
233
233
  # is the 'type' portion of our media type 'image'
234
234
  # @return [Boolean]
235
235
  def type_image?
236
- type && type.casecmp?('image')
236
+ type ? type.casecmp?('image') : false
237
237
  end
238
238
 
239
239
  # is the 'type' portion of our media type 'audio'
240
240
  # @return [Boolean]
241
241
  def type_audio?
242
- type && type.casecmp?('audio')
242
+ type ? type.casecmp?('audio') : false
243
243
  end
244
244
 
245
245
  # is the 'type' portion of our media type 'video'
246
246
  # @return [Boolean]
247
247
  def type_video?
248
- type && type.casecmp?('video')
248
+ type ? type.casecmp?('video') : false
249
249
  end
250
250
 
251
251
  # is the 'type' portion of our media type 'application'
252
252
  # @return [Boolean]
253
253
  def type_application?
254
- type && type.casecmp?('application')
254
+ type ? type.casecmp?('application') : false
255
255
  end
256
256
 
257
257
  # is the 'type' portion of our media type 'message'
258
258
  # @return [Boolean]
259
259
  def type_message?
260
- type && type.casecmp?('message')
260
+ type ? type.casecmp?('message') : false
261
261
  end
262
262
 
263
263
  # is the 'type' portion of our media type 'multipart'
264
264
  # @return [Boolean]
265
265
  def type_multipart?
266
- type && type.casecmp?('multipart')
266
+ type ? type.casecmp?('multipart') : false
267
267
  end
268
268
  end
269
269
  end
data/lib/ur/middleware.rb CHANGED
@@ -30,7 +30,7 @@ module Ur
30
30
  class FaradayMiddleware < ::Faraday::Middleware
31
31
  include Ur::Middleware
32
32
  def call(request_env)
33
- ur = Ur.from_faraday_request(request_env, @options.select { |k, _| [:schemas].include?(k) })
33
+ ur = Ur.from_faraday_request(request_env, **@options.select { |k, _| [:schemas].include?(k) })
34
34
  invoke_callback(:before_request, ur)
35
35
  begin_request(ur)
36
36
  ur.faraday_on_complete(@app, request_env) do |response_env|
@@ -43,7 +43,7 @@ module Ur
43
43
  class RackMiddleware
44
44
  include Ur::Middleware
45
45
  def call(env)
46
- ur = Ur.from_rack_request(env, @options.select { |k, _| [:schemas].include?(k) })
46
+ ur = Ur.from_rack_request(env, **@options.select { |k, _| [:schemas].include?(k) })
47
47
  invoke_callback(:before_request, ur)
48
48
  begin_request(ur)
49
49
  ur.with_rack_response(@app, env) do
data/lib/ur/version.rb CHANGED
@@ -1 +1 @@
1
- UR_VERSION = "0.2.1".freeze
1
+ UR_VERSION = "0.2.2".freeze
data/lib/ur/weblink.rb ADDED
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ur' unless Object.const_defined?(:Ur)
4
+
5
+ module Ur
6
+ # a RFC5988 Web Link
7
+ #
8
+ # https://tools.ietf.org/html/rfc5988
9
+ class Weblink
10
+ # Weblink::Error, base class for all errors of the Weblink class
11
+ class Error < StandardError
12
+ end
13
+
14
+ # error parsing a Weblink
15
+ class ParseError < Error
16
+ end
17
+
18
+ # error when attempting an operation that requires a context URI which was not provided
19
+ class NoContextError < Error
20
+ end
21
+
22
+ # parses an array of Web Links from the value an HTTP Link header, as described in
23
+ # https://tools.ietf.org/html/rfc5988#section-5
24
+ #
25
+ # returns an Array of Weblink objects
26
+ def self.parse_link_value(link_value, context_uri=nil)
27
+ links = []
28
+
29
+ return links unless link_value
30
+
31
+ attr_char = /[a-zA-Z0-9!#\$&+\-.^_`|~]/ # defined in https://tools.ietf.org/html/rfc5987#section-3.2.1
32
+ ptoken = %r([a-zA-Z0-9!#\$%&'()*+\-./:<=>?@\[\]^_`{|}~])
33
+ quoted_string = /"([^"]*)"/
34
+
35
+ require 'strscan'
36
+ ss = StringScanner.new(link_value)
37
+ parse_fail = proc do
38
+ raise ParseError, "Unable to parse link value: #{link_value} " +
39
+ "around character #{ss.pos}: #{ss.peek(link_value.length - ss.pos)}"
40
+ end
41
+
42
+ while !ss.eos?
43
+ # get the target_uri, within some angle brackets
44
+ ss.scan(/\s*<([^>]+)>/) || parse_fail.call
45
+ target_uri = ss[1]
46
+ attributes = {}
47
+ # get the attributes: semicolon, some attr_chars, an optional asterisk, equals, and a quoted
48
+ # string or series of unquoted ptokens
49
+ while ss.scan(/\s*;\s*(#{attr_char.source}+\*?)\s*=\s*(?:#{quoted_string.source}|(#{ptoken.source}+))\s*/)
50
+ attributes[ss[1]] = ss[2] || ss[3]
51
+ end
52
+ links << new(target_uri, attributes, context_uri)
53
+ unless ss.eos?
54
+ # either the string ends or has a comma followed by another link
55
+ ss.scan(/\s*,\s*/) || parse_fail.call
56
+ end
57
+ end
58
+ links
59
+ end
60
+
61
+ def initialize(target_uri, attributes, context_uri=nil)
62
+ @target_uri = to_addressable_uri(target_uri)
63
+ @attributes = attributes
64
+ @context_uri = to_addressable_uri(context_uri)
65
+ end
66
+
67
+ # the context uri of the link, as an Addressable URI. this URI must be absolute, and the target_uri
68
+ # may be resolved against it. this is most typically the request URI of a request to a service
69
+ attr_reader :context_uri
70
+
71
+ # RFC 5988 calls it IRI, but nobody else does. we'll throw in an alias.
72
+ alias_method :context_iri, :context_uri
73
+
74
+ # returns the target URI as an Addressable::URI
75
+ attr_reader :target_uri
76
+
77
+ # RFC 5988 calls it IRI, but nobody else does. we'll throw in an alias.
78
+ alias_method :target_iri, :target_uri
79
+
80
+ # attempts to make target_uri absolute, using context_uri if available. raises if
81
+ # there is not information available to make an absolute target URI
82
+ def absolute_target_uri
83
+ if target_uri.absolute?
84
+ target_uri
85
+ elsif context_uri
86
+ context_uri + target_uri
87
+ else
88
+ raise NoContextError, "Target URI is relative but no Context URI given - cannot determine absolute target URI"
89
+ end
90
+ end
91
+
92
+ # link attributes
93
+ attr_reader :attributes
94
+
95
+ # subscript returns an attribute of this Link, if defined, otherwise nil
96
+ def [](attribute_key)
97
+ @attributes[attribute_key]
98
+ end
99
+
100
+ # link rel attribute
101
+ def rel
102
+ self['rel']
103
+ end
104
+
105
+ alias_method :relation_type, :rel
106
+
107
+ # compares relation types in a case-insensitive manner as mandated in
108
+ # https://tools.ietf.org/html/rfc5988#section-4.1
109
+ def rel?(other_rel)
110
+ rel && other_rel && rel.downcase == other_rel.downcase
111
+ end
112
+
113
+ # a string of this weblink, appropriate for adding to a Link header
114
+ def to_s
115
+ "<#{target_uri}>" + attributes.map { |k,v| %Q(; #{k}="#{v}") }.join('')
116
+ end
117
+
118
+ private
119
+
120
+ # if uri is nil, returns nil; otherwise, tries to return a Addressable::URI
121
+ def to_addressable_uri(uri)
122
+ uri.nil? || uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri)
123
+ end
124
+ end
125
+ end
data/lib/ur.rb CHANGED
@@ -19,6 +19,7 @@ module Ur
19
19
  autoload :FaradayMiddleware, 'ur/middleware'
20
20
  autoload :RackMiddleware, 'ur/middleware'
21
21
  autoload :Faraday, 'ur/faraday'
22
+ autoload :Weblink, 'ur/weblink'
22
23
 
23
24
  Request = self.properties['request']
24
25
  Response = self.properties['response']
@@ -51,7 +52,7 @@ module Ur
51
52
  env = request_env
52
53
  end
53
54
 
54
- new({'bound' => 'inbound'}, options).tap do |ur|
55
+ new({'bound' => 'inbound'}, **options).tap do |ur|
55
56
  ur.request['method'] = rack_request.request_method
56
57
 
57
58
  ur.request.addressable_uri = Addressable::URI.new(
@@ -82,7 +83,7 @@ module Ur
82
83
  end
83
84
 
84
85
  def from_faraday_request(request_env, **options)
85
- new({'bound' => 'outbound'}, options).tap do |ur|
86
+ new({'bound' => 'outbound'}, **options).tap do |ur|
86
87
  ur.request['method'] = request_env[:method].to_s
87
88
  ur.request.uri = request_env[:url].normalize.to_s
88
89
  ur.request.headers = request_env[:request_headers]
@@ -114,7 +115,7 @@ module Ur
114
115
  [status, response_headers, response_body_proxy]
115
116
  end
116
117
 
117
- def faraday_on_complete(app, request_env, &block)
118
+ def faraday_on_complete(app, request_env)
118
119
  app.call(request_env).on_complete do |response_env|
119
120
  response.status = response_env[:status]
120
121
  response.headers = response_env[:response_headers]
data/ur.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "ur/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "ur"
7
+ spec.version = UR_VERSION
8
+ spec.authors = ["Ethan"]
9
+ spec.email = ["ethan.ur@unth.net"]
10
+
11
+ spec.summary = 'ur: unified request representation'
12
+ spec.description = 'ur provides a unified representation of a request and response. it can be interpreted from rack, faraday, or potentially other sources, and provides a consistent interface to access the attributes inherent to the request and additional useful parsers and computation from the request.'
13
+ spec.homepage = "https://github.com/notEthan/ur"
14
+ spec.license = "LGPL-3.0"
15
+
16
+ spec.files = [
17
+ 'LICENSE.md',
18
+ 'CHANGELOG.md',
19
+ 'README.md',
20
+ '.yardopts',
21
+ 'resources/ur.schema.yml',
22
+ 'ur.gemspec',
23
+ *Dir['lib/**/*'],
24
+ ].reject { |f| File.lstat(f).ftype == 'directory' }
25
+
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_dependency "jsi", "~> 0.6"
29
+ spec.add_dependency "addressable", "~> 2.0"
30
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ur
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-25 00:00:00.000000000 Z
11
+ date: 2023-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsi
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.6.0
19
+ version: '0.6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.6.0
26
+ version: '0.6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: addressable
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -48,6 +48,7 @@ executables: []
48
48
  extensions: []
49
49
  extra_rdoc_files: []
50
50
  files:
51
+ - ".yardopts"
51
52
  - CHANGELOG.md
52
53
  - LICENSE.md
53
54
  - README.md
@@ -62,12 +63,14 @@ files:
62
63
  - lib/ur/response.rb
63
64
  - lib/ur/sub_ur.rb
64
65
  - lib/ur/version.rb
66
+ - lib/ur/weblink.rb
65
67
  - resources/ur.schema.yml
68
+ - ur.gemspec
66
69
  homepage: https://github.com/notEthan/ur
67
70
  licenses:
68
71
  - LGPL-3.0
69
72
  metadata: {}
70
- post_install_message:
73
+ post_install_message:
71
74
  rdoc_options: []
72
75
  require_paths:
73
76
  - lib
@@ -82,8 +85,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
85
  - !ruby/object:Gem::Version
83
86
  version: '0'
84
87
  requirements: []
85
- rubygems_version: 3.1.2
86
- signing_key:
88
+ rubygems_version: 3.1.6
89
+ signing_key:
87
90
  specification_version: 4
88
91
  summary: 'ur: unified request representation'
89
92
  test_files: []