ur 0.2.1 → 0.2.3

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: 834735162f5c696d940e546b1908bca87a2b0c8e93d3f20247b1468404071b56
4
+ data.tar.gz: 6083f1cfaf96c4857c43e580398c512e00589f8e0ef9b799f365d2719d8c1848
5
5
  SHA512:
6
- metadata.gz: 17187f65ff16035e72fc7d7e0b9468bd970d337b1f8173fbc2dde15f420ad406aa33ecb440b4b65e0dffb921279660fdedb48b4bb320ce3e4e9a411eec3a21da
7
- data.tar.gz: 8c8d0f0c86af8a97c18dc794e69b84634421607a7e6715120b90fd3d9f74bdd1848a5c422598dbc06fdb0ea7ce4ac474e76b761ec7e2243fdb87b2aa812af292
6
+ metadata.gz: 39f8e38f80a35a4d019bed707745d7835fcdc92e8e162dd90a492ce46c711016cb73789ff57d384ac763f8514a5f5749ccc4f1db75a9d4cad4e96a7512ce8be4
7
+ data.tar.gz: 4c92cbd6cf2dcb597bd6a265cd7c5a892af3ea504a220e82a7cbcc5e06ef421703ead862e0ba5b6ab88b7633050fe93966befc78c50a76c4f5e23155d65c8a7c
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --main README.md --markup=markdown {lib}/**/*.rb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # v0.2.3
2
+
3
+ - JSI v0.7.0
4
+
5
+ # v0.2.2
6
+
7
+ - Ur::Weblink
8
+ - Ruby 3
9
+
1
10
  # v0.2.1
2
11
 
3
12
  - 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).
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'ur' unless Object.const_defined?(:Ur)
4
+ require 'strscan'
4
5
 
5
6
  module Ur
6
7
  # Ur::ContentType represents a Content-Type header field.
@@ -154,21 +155,21 @@ module Ur
154
155
  # @param other_type
155
156
  # @return [Boolean]
156
157
  def type?(other_type)
157
- type && type.casecmp?(other_type)
158
+ type ? type.casecmp?(other_type) : false
158
159
  end
159
160
 
160
161
  # is the 'subtype' portion of our media type equal (case-insensitive) to the given other_subtype
161
162
  # @param other_subtype
162
163
  # @return [Boolean]
163
164
  def subtype?(other_subtype)
164
- subtype && subtype.casecmp?(other_subtype)
165
+ subtype ? subtype.casecmp?(other_subtype) : false
165
166
  end
166
167
 
167
168
  # is the 'suffix' portion of our media type equal (case-insensitive) to the given other_suffix
168
169
  # @param other_suffix
169
170
  # @return [Boolean]
170
171
  def suffix?(other_suffix)
171
- suffix && suffix.casecmp?(other_suffix)
172
+ suffix ? suffix.casecmp?(other_suffix) : false
172
173
  end
173
174
 
174
175
  SOME_TEXT_SUBTYPES = %w(
@@ -215,55 +216,55 @@ module Ur
215
216
  # is this an XML content type?
216
217
  # @return [Boolean]
217
218
  def xml?
218
- suffix ? suffix.casecmp?('xml'): subtype ? subtype.casecmp?('xml') : false
219
+ suffix ? suffix.casecmp?('xml') : subtype ? subtype.casecmp?('xml') : false
219
220
  end
220
221
 
221
222
  # is this a `x-www-form-urlencoded` content type?
222
223
  # @return [Boolean]
223
224
  def form_urlencoded?
224
- suffix ? suffix.casecmp?('x-www-form-urlencoded'): subtype ? subtype.casecmp?('x-www-form-urlencoded') : false
225
+ suffix ? suffix.casecmp?('x-www-form-urlencoded') : subtype ? subtype.casecmp?('x-www-form-urlencoded') : false
225
226
  end
226
227
 
227
228
  # is the 'type' portion of our media type 'text'
228
229
  # @return [Boolean]
229
230
  def type_text?
230
- type && type.casecmp?('text')
231
+ type ? type.casecmp?('text') : false
231
232
  end
232
233
 
233
234
  # is the 'type' portion of our media type 'image'
234
235
  # @return [Boolean]
235
236
  def type_image?
236
- type && type.casecmp?('image')
237
+ type ? type.casecmp?('image') : false
237
238
  end
238
239
 
239
240
  # is the 'type' portion of our media type 'audio'
240
241
  # @return [Boolean]
241
242
  def type_audio?
242
- type && type.casecmp?('audio')
243
+ type ? type.casecmp?('audio') : false
243
244
  end
244
245
 
245
246
  # is the 'type' portion of our media type 'video'
246
247
  # @return [Boolean]
247
248
  def type_video?
248
- type && type.casecmp?('video')
249
+ type ? type.casecmp?('video') : false
249
250
  end
250
251
 
251
252
  # is the 'type' portion of our media type 'application'
252
253
  # @return [Boolean]
253
254
  def type_application?
254
- type && type.casecmp?('application')
255
+ type ? type.casecmp?('application') : false
255
256
  end
256
257
 
257
258
  # is the 'type' portion of our media type 'message'
258
259
  # @return [Boolean]
259
260
  def type_message?
260
- type && type.casecmp?('message')
261
+ type ? type.casecmp?('message') : false
261
262
  end
262
263
 
263
264
  # is the 'type' portion of our media type 'multipart'
264
265
  # @return [Boolean]
265
266
  def type_multipart?
266
- type && type.casecmp?('multipart')
267
+ type ? type.casecmp?('multipart') : false
267
268
  end
268
269
  end
269
270
  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.3".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
+ require 'strscan'
5
+
6
+ module Ur
7
+ # a RFC5988 Web Link
8
+ #
9
+ # https://tools.ietf.org/html/rfc5988
10
+ class Weblink
11
+ # Weblink::Error, base class for all errors of the Weblink class
12
+ class Error < StandardError
13
+ end
14
+
15
+ # error parsing a Weblink
16
+ class ParseError < Error
17
+ end
18
+
19
+ # error when attempting an operation that requires a context URI which was not provided
20
+ class NoContextError < Error
21
+ end
22
+
23
+ # parses an array of Web Links from the value an HTTP Link header, as described in
24
+ # https://tools.ietf.org/html/rfc5988#section-5
25
+ #
26
+ # returns an Array of Weblink objects
27
+ def self.parse_link_value(link_value, context_uri=nil)
28
+ links = []
29
+
30
+ return links unless link_value
31
+
32
+ attr_char = /[a-zA-Z0-9!#\$&+\-.^_`|~]/ # defined in https://tools.ietf.org/html/rfc5987#section-3.2.1
33
+ ptoken = %r([a-zA-Z0-9!#\$%&'()*+\-./:<=>?@\[\]^_`{|}~])
34
+ quoted_string = /"([^"]*)"/
35
+
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,28 @@
1
+ require_relative "lib/ur/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "ur"
5
+ spec.version = UR_VERSION
6
+ spec.authors = ["Ethan"]
7
+ spec.email = ["ethan.ur@unth.net"]
8
+
9
+ spec.summary = 'ur: unified request representation'
10
+ 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.'
11
+ spec.homepage = "https://github.com/notEthan/ur"
12
+ spec.license = "LGPL-3.0"
13
+
14
+ spec.files = [
15
+ 'LICENSE.md',
16
+ 'CHANGELOG.md',
17
+ 'README.md',
18
+ '.yardopts',
19
+ 'resources/ur.schema.yml',
20
+ 'ur.gemspec',
21
+ *Dir['lib/**/*'],
22
+ ].reject { |f| File.lstat(f).ftype == 'directory' }
23
+
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "jsi", "~> 0.7"
27
+ spec.add_dependency "addressable", "~> 2.0"
28
+ 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.3
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-07-29 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.7'
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.7'
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.4.10
89
+ signing_key:
87
90
  specification_version: 4
88
91
  summary: 'ur: unified request representation'
89
92
  test_files: []