ur 0.2.1 → 0.2.2

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: 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: []