webmention 9.1.0 → 10.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84916e475f4ede9be2eb1cd988b5b4b54e0225b13dbfca4cdc6e4ea0c10ae174
4
- data.tar.gz: 2f6bbd1523b427a6a32297a86c52b35ea6c91ccff0569d46c80272c21e373c7b
3
+ metadata.gz: 18cd676b542de4d7d4507fb30a6475cba645feca8dccebb4230d48904165d1dd
4
+ data.tar.gz: 309bb9ad852cc944a747a1b18a25e04009e9c0095f3249212654b4ee920e5132
5
5
  SHA512:
6
- metadata.gz: 75f2535f613d08e21149a6678a5cc22748346048b567caa977261c6ea9cc55ced8c421d08599a5780ed0bfa78b8091d901ed9b6cf9dd4ea96e5ba908dc5fe1bf
7
- data.tar.gz: eef43a1a408dabacabc445ec7c85c6ff19aaeec7f40de8897b94e38c31e20e511f9a5cd3ba3879d5152a3b82f66fd7256334fec213d1cab9697132a888416cb3
6
+ metadata.gz: f73890fc04da3b8ec912f3b469cdb7f29ef2761b56e0ca4854133981c3b18ecb09c7be7d1e24253935dafd0c858be13fd45c60c0365b2e005f7659ec74ee9467
7
+ data.tar.gz: d00e9b5a4b32fefcdc48e59e3a33d73662e79c563f69517be55984c57ba2fc790d544fac3f58c06b91bee6b92258fa2fe6b7f59aac73c92030d2ca14bbcd4d76
data/CONTRIBUTING.md CHANGED
@@ -8,12 +8,12 @@ There are a couple ways you can help improve webmention-client-ruby:
8
8
 
9
9
  ## Getting Started
10
10
 
11
- webmention-client-ruby is developed using Ruby 3.4 and is tested against additional Ruby versions using [GitHub Actions](https://github.com/indieweb/webmention-client-ruby/actions).
11
+ webmention-client-ruby is developed using Ruby 4.0 and is tested against additional Ruby versions using [GitHub Actions](https://github.com/indieweb/webmention-client-ruby/actions).
12
12
 
13
13
  > [!TIP]
14
14
  > This project is configured with a [Dev Container](https://containers.dev) which includes everything you'd need to contribute to webmention-client-ruby. If you use a supported code editor or IDE, you're encouraged to use the existing Dev Container setup.
15
15
 
16
- Before making changes to webmention-client-ruby, you'll want to install Ruby 3.4. Using a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm) is recommended. Once you've installed Ruby 3.4 using your method of choice, install the project's gems by running:
16
+ Before making changes to webmention-client-ruby, you'll want to install Ruby 4.0. Using a Ruby version managment tool like [rv](https://github.com/spinel-coop/rv) or [rbenv](https://github.com/rbenv/rbenv) is recommended. Once you've installed Ruby 4.0 using your method of choice, install the project's gems by running:
17
17
 
18
18
  ```sh
19
19
  bundle install
data/README.md CHANGED
@@ -16,9 +16,9 @@ A Ruby gem for sending and verifying [Webmention](https://indieweb.org/Webmentio
16
16
 
17
17
  ## Getting Started
18
18
 
19
- Before installing and using webmention-client-ruby, you'll want to have [Ruby](https://www.ruby-lang.org) 2.7 (or newer) installed. Using a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm) is recommended.
19
+ Before installing and using webmention-client-ruby, you'll want to have [Ruby](https://www.ruby-lang.org) 2.7 (or newer) installed. Using a Ruby version managment tool like [rv](https://github.com/spinel-coop/rv) or [rbenv](https://github.com/rbenv/rbenv) is recommended.
20
20
 
21
- webmention-client-ruby is developed using Ruby 3.4 and is tested against additional Ruby versions using [GitHub Actions](https://github.com/indieweb/webmention-client-ruby/actions).
21
+ webmention-client-ruby is developed using Ruby 4.0 and is tested against additional Ruby versions using [GitHub Actions](https://github.com/indieweb/webmention-client-ruby/actions).
22
22
 
23
23
  ## Installation
24
24
 
@@ -36,7 +36,7 @@ See [USAGE.md](USAGE.md) for documentation of webmention-client-ruby's features.
36
36
 
37
37
  ## Contributing
38
38
 
39
- See [CONTRIBUTING.md](https://github.com/indieweb/webmention-client-ruby/blob/main/CONTRIBUTING.md) for more on how to contribute to webmention-client-ruby. Your help is greatly appreciated!
39
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for more on how to contribute to webmention-client-ruby. Your help is greatly appreciated!
40
40
 
41
41
  By contributing to and participating in the development of webmention-client-ruby, you acknowledge that you have read and agree to the [IndieWeb Code of Conduct](https://indieweb.org/code-of-conduct).
42
42
 
data/USAGE.md CHANGED
@@ -29,7 +29,7 @@ response.class
29
29
  #=> Webmention::ErrorResponse
30
30
 
31
31
  response.message
32
- #=> "No webmention endpoint found for target URL https://aaronpk.example/post/100"
32
+ #=> "No Webmention endpoint found for target URL https://aaronpk.example/post/100"
33
33
  ```
34
34
 
35
35
  A `Webmention::Response` will be returned in all other cases.
@@ -147,6 +147,4 @@ verification.vouch_mentions_source?
147
147
 
148
148
  ## Exception Handling
149
149
 
150
- webmention-client-ruby avoids raising exceptions when making HTTP requests. As noted above, a `Webmention::ErrorResponse` should be returned in cases where an HTTP request triggers an exception.
151
-
152
- When crawling the supplied URL, `Webmention.mentioned_urls` _may_ raise a `NoMethodError` if a `Webmention::ErrorResponse` is returned, or the response is of an unsupported MIME type.
150
+ webmention-client-ruby avoids raising exceptions when making HTTP requests. As noted above, a `Webmention::ErrorResponse` should be returned in cases where an HTTP request triggers an exception. `Webmention.mentioned_urls` will raise a `Burly::UnsupportedMimeType` exception when the response is of an unsupported MIME type, though.
@@ -2,24 +2,12 @@
2
2
 
3
3
  module Webmention
4
4
  class Client
5
- @registered_parsers = {}
6
-
7
- class << self
8
- # @api private
9
- attr_reader :registered_parsers
10
- end
11
-
12
5
  # @return [Url]
13
6
  attr_reader :source_url
14
7
 
15
8
  # @return [Url]
16
9
  attr_reader :vouch_url
17
10
 
18
- # @api private
19
- def self.register_parser(klass)
20
- klass.mime_types.each { |mime_type| @registered_parsers[mime_type] = klass }
21
- end
22
-
23
11
  # Create a new {Client}.
24
12
  #
25
13
  # @example
@@ -38,14 +26,15 @@ module Webmention
38
26
  @vouch_url = Url.new(vouch)
39
27
  end
40
28
 
41
- # :nocov:
42
29
  # @return [String]
30
+ #
31
+ # simplecov:disable
43
32
  def inspect
44
33
  "#<#{self.class}:#{format("%#0x", object_id)} " \
45
34
  "source_url: #{source_url} " \
46
35
  "vouch_url: #{vouch_url}>"
47
36
  end
48
- # :nocov:
37
+ # simplecov:enable
49
38
 
50
39
  # Retrieve unique URLs mentioned by this client's source URL.
51
40
  #
@@ -53,24 +42,18 @@ module Webmention
53
42
  # client = Webmention::Client.new("https://jgarber.example/posts/100")
54
43
  # client.mentioned_urls
55
44
  #
56
- # @raise [NoMethodError]
57
- # Raised when response is an {ErrorResponse} or response is of an
58
- # unsupported MIME type.
45
+ # @raise [Burly::UnsupportedMimeType]
46
+ # Raised when response is of an unsupported MIME type.
59
47
  #
60
48
  # @return [Array<String>]
61
49
  def mentioned_urls
62
50
  response = source_url.response
63
51
 
64
- urls = Set.new(
65
- self.class
66
- .registered_parsers[response.mime_type]
67
- .new(response.body, response.uri)
68
- .results
69
- )
70
-
71
- urls.reject! { |url| url.match(/^#{response.uri}(?:#.*)?$/) }
72
-
73
- urls.to_a.sort
52
+ response
53
+ .mentioned_urls
54
+ .lazy
55
+ .reject { |url| url.match(/^#{response.uri}(?:#.*)?$/) }
56
+ .sort
74
57
  end
75
58
 
76
59
  # Send a webmention from this client's source URL to a target URL.
@@ -85,17 +68,17 @@ module Webmention
85
68
  # @return [Response, ErrorResponse]
86
69
  def send_webmention(target)
87
70
  target_url = Url.new(target)
71
+ endpoint = target_url.webmention_endpoint
72
+ response = target_url.response
88
73
 
89
74
  # A Webmention endpoint exists. Send the request and return the response.
90
- if target_url.webmention_endpoint?
91
- return Request.post(target_url.webmention_endpoint, **request_options_for(target))
92
- end
75
+ return Request.new(:post, endpoint, **request_options_for(target)).perform unless endpoint.nil?
93
76
 
94
77
  # An error was encountered fetching the target URL. Return the response.
95
- return target_url.response unless target_url.response.ok?
78
+ return response unless response.ok?
96
79
 
97
80
  # No Webmention endpoint exists. Return a new ErrorResponse.
98
- ErrorResponse.new("No webmention endpoint found for target URL #{target}", target_url.response.request)
81
+ ErrorResponse.new("No Webmention endpoint found for target URL #{target}", response.request)
99
82
  end
100
83
 
101
84
  # Send webmentions from this client's source URL to multiple target URLs.
@@ -140,7 +123,7 @@ module Webmention
140
123
  opts.transform_values! { |value| value.to_s.strip }
141
124
  opts.reject! { |_, value| value.empty? }
142
125
 
143
- opts
126
+ { form: opts }
144
127
  end
145
128
  end
146
129
  end
@@ -15,6 +15,8 @@ module Webmention
15
15
  # endpoint. The nature of the error is captured in the {#message} instance
16
16
  # method.
17
17
  #
18
+ # @api private
19
+ #
18
20
  # @param message [String]
19
21
  # @param request [Request]
20
22
  def initialize(message, request)
@@ -22,13 +24,19 @@ module Webmention
22
24
  @request = request
23
25
  end
24
26
 
25
- # :nocov:
26
27
  # @return [String]
28
+ #
29
+ # simplecov:disable
27
30
  def inspect
28
31
  "#<#{self.class}:#{format("%#0x", object_id)} " \
29
32
  "message: #{message}>"
30
33
  end
31
- # :nocov:
34
+ # simplecov:enable
35
+
36
+ # @return [Set]
37
+ def mentioned_urls
38
+ Set.new
39
+ end
32
40
 
33
41
  # @return [Boolean]
34
42
  def ok?
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Webmention
4
+ # @api private
4
5
  class Request
5
6
  # Set defaults derived from Webmention specification examples.
6
7
  #
@@ -31,28 +32,23 @@ module Webmention
31
32
  # @return [Hash]
32
33
  attr_reader :options
33
34
 
34
- # Send an HTTP GET request to the supplied URL.
35
+ # Create a new {Request}.
35
36
  #
36
37
  # @example
37
- # Webmention::Request.get("https://jgarber.example/posts/100")
38
- #
39
- # @param url [String]
40
- #
41
- # @return [Response, ErrorResponse]
42
- def self.get(url)
43
- new(:get, url).perform
44
- end
45
-
46
- # Send an HTTP POST request with form-encoded data to the supplied URL.
38
+ # Webmention::Request.new(:get, "https://jgarber.example/posts/100")
47
39
  #
48
40
  # @example
49
- # Webmention::Request.post(
41
+ # Webmention::Request.new(
42
+ # :post,
50
43
  # "https://aaronpk.example/webmention",
51
- # source: "https://jgarber.examples/posts/100",
52
- # target: "https://aaronpk.example/notes/1",
53
- # vouch: "https://tantek.example/notes/1"
44
+ # form: {
45
+ # source: "https://jgarber.examples/posts/100",
46
+ # target: "https://aaronpk.example/notes/1",
47
+ # vouch: "https://tantek.example/notes/1",
48
+ # },
54
49
  # )
55
50
  #
51
+ # @param method [Symbol]
56
52
  # @param url [String]
57
53
  # @param options [Hash{Symbol => String}]
58
54
  # @option options [String] :source
@@ -62,31 +58,21 @@ module Webmention
62
58
  # @option options [String] :vouch
63
59
  # An absolute URL representing a document vouching for the source document.
64
60
  # See https://indieweb.org/Vouch for additional details.
65
- #
66
- # @return [Response, ErrorResponse]
67
- def self.post(url, **options)
68
- new(:post, url, form: options.slice(:source, :target, :vouch)).perform
69
- end
70
-
71
- # Create a new {Request}.
72
- #
73
- # @param method [Symbol]
74
- # @param url [String]
75
- # @param options [Hash{Symbol => String}]
76
61
  def initialize(method, url, **options)
77
62
  @method = method.to_sym
78
63
  @uri = HTTP::URI.parse(url.to_s)
79
64
  @options = options
80
65
  end
81
66
 
82
- # :nocov:
83
67
  # @return [String]
68
+ #
69
+ # simplecov:disable
84
70
  def inspect
85
71
  "#<#{self.class}:#{format("%#0x", object_id)} " \
86
72
  "method: #{method.upcase}, " \
87
73
  "url: #{uri}>"
88
74
  end
89
- # :nocov:
75
+ # simplecov:enable
90
76
 
91
77
  # Submit the {Request}.
92
78
  #
@@ -4,6 +4,12 @@ module Webmention
4
4
  class Response
5
5
  extend Forwardable
6
6
 
7
+ PARSE_CONTEXT = [".h-entry .e-content", ".h-entry", "body"].freeze
8
+ URI_REGEXP = URI::RFC2396_Parser.new.make_regexp(["http", "https"]).freeze
9
+
10
+ private_constant :PARSE_CONTEXT
11
+ private_constant :URI_REGEXP
12
+
7
13
  # @return [Request]
8
14
  attr_reader :request
9
15
 
@@ -37,6 +43,8 @@ module Webmention
37
43
  # of which may be accessed using the delegated {#code} and {#reason}
38
44
  # instance methods.
39
45
  #
46
+ # @api private
47
+ #
40
48
  # @param response [HTTP::Response]
41
49
  # @param request [Request]
42
50
  def initialize(response, request)
@@ -44,15 +52,36 @@ module Webmention
44
52
  @request = request
45
53
  end
46
54
 
47
- # :nocov:
48
55
  # @return [String]
56
+ #
57
+ # simplecov:disable
49
58
  def inspect
50
59
  "#<#{self.class}:#{format("%#0x", object_id)} " \
51
60
  "code: #{code.inspect}, " \
52
61
  "reason: #{reason}, " \
53
62
  "url: #{request.uri}>"
54
63
  end
55
- # :nocov:
64
+ # simplecov:enable
65
+
66
+ # Parse the response body for unique host names.
67
+ #
68
+ # @return [Set<String>]
69
+ def mentioned_hosts
70
+ @mentioned_hosts ||= Set.new(mentioned_urls.map { |url| HTTP::URI.parse(url).host })
71
+ end
72
+
73
+ # Parse the response body for mentioned URLs.
74
+ #
75
+ # @return [Set<String>]
76
+ def mentioned_urls
77
+ @mentioned_urls ||=
78
+ Set.new(
79
+ Burly
80
+ .parse(@response.body, context: PARSE_CONTEXT, mime_type: @response.mime_type)
81
+ .map { |url| @response.uri.join(url).to_s }
82
+ .grep(URI_REGEXP)
83
+ )
84
+ end
56
85
 
57
86
  # @return [Boolean]
58
87
  def ok?
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Webmention
4
+ # @api private
4
5
  class Url
5
6
  extend Forwardable
6
7
 
@@ -18,27 +19,23 @@ module Webmention
18
19
  @uri = HTTP::URI.parse(url.to_s)
19
20
  end
20
21
 
21
- # :nocov:
22
22
  # @return [String]
23
+ #
24
+ # simplecov:disable
23
25
  def inspect
24
26
  "#<#{self.class}:#{format("%#0x", object_id)} " \
25
27
  "uri: #{uri}>"
26
28
  end
27
- # :nocov:
29
+ # simplecov:enable
28
30
 
29
31
  # @return [Response, ErrorResponse]
30
32
  def response
31
- @response ||= Request.get(uri)
33
+ @response ||= Request.new(:get, uri).perform
32
34
  end
33
35
 
34
36
  # @return [String, nil]
35
37
  def webmention_endpoint
36
38
  @webmention_endpoint ||= IndieWeb::Endpoints::Parser.new(response).to_h[:webmention] if response.ok?
37
39
  end
38
-
39
- # @return [Boolean]
40
- def webmention_endpoint?
41
- !webmention_endpoint.nil?
42
- end
43
40
  end
44
41
  end
@@ -4,6 +4,8 @@ module Webmention
4
4
  class Verification
5
5
  # Create a new {Verification}.
6
6
  #
7
+ # @api private
8
+ #
7
9
  # @param source_url [Url]
8
10
  # An {URL} representing a source document.
9
11
  # @param target_url [Url]
@@ -17,70 +19,37 @@ module Webmention
17
19
  @vouch_url = vouch_url
18
20
  end
19
21
 
20
- # :nocov:
21
22
  # @return [String]
23
+ #
24
+ # simplecov:disable
22
25
  def inspect
23
26
  "#<#{self.class}:#{format("%#0x", object_id)} " \
24
- "source_url: #{source_url} " \
25
- "target_url: #{target_url} " \
26
- "vouch_url: #{vouch_url}>"
27
+ "source_url: #{@source_url} " \
28
+ "target_url: #{@target_url} " \
29
+ "vouch_url: #{@vouch_url}>"
27
30
  end
28
- # :nocov:
31
+ # simplecov:enable
29
32
 
30
33
  # @return [Boolean]
31
34
  def source_mentions_target?
32
- @source_mentions_target ||= mentioned_urls(source_url.response).any?(target_url.to_s)
35
+ @source_mentions_target ||= @source_url.response.mentioned_urls.any?(@target_url.to_s)
33
36
  end
34
37
 
35
38
  # @return [Boolean]
36
39
  def verified?
37
- return source_mentions_target? unless verify_vouch?
40
+ return source_mentions_target? && vouch_mentions_source? if verify_vouch?
38
41
 
39
- source_mentions_target? && vouch_mentions_source?
42
+ source_mentions_target?
40
43
  end
41
44
 
42
45
  # @return [Boolean]
43
46
  def verify_vouch?
44
- !vouch_url.nil? && !vouch_url.to_s.strip.empty?
47
+ !@vouch_url.to_s.strip.empty?
45
48
  end
46
49
 
47
50
  # @return [Boolean]
48
51
  def vouch_mentions_source?
49
- @vouch_mentions_source ||=
50
- verify_vouch? && mentioned_domains(vouch_url.response).any?(source_url.uri.host)
51
- end
52
-
53
- private
54
-
55
- # @return [Url]
56
- attr_reader :source_url
57
-
58
- # @return [Url]
59
- attr_reader :target_url
60
-
61
- # @return [Url]
62
- attr_reader :vouch_url
63
-
64
- # @param response [Response]
65
- #
66
- # @raise (see Client#mentioned_urls)
67
- #
68
- # @return [Array<String>]
69
- def mentioned_domains(response)
70
- Set.new(mentioned_urls(response).map { |url| HTTP::URI.parse(url).host }).to_a
71
- end
72
-
73
- # @param response [Response]
74
- #
75
- # @raise (see Client#mentioned_urls)
76
- #
77
- # @return [Array<String>]
78
- def mentioned_urls(response)
79
- Set.new(
80
- Client.registered_parsers[response.mime_type]
81
- .new(response.body, response.uri)
82
- .results
83
- ).to_a
52
+ @vouch_mentions_source ||= verify_vouch? && @vouch_url.response.mentioned_hosts.any?(@source_url.uri.host)
84
53
  end
85
54
  end
86
55
  end
data/lib/webmention.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "json"
4
4
 
5
+ require "burly"
5
6
  require "http"
6
7
  require "indieweb/endpoints"
7
8
  require "nokogiri"
@@ -13,11 +14,6 @@ require_relative "webmention/response"
13
14
  require_relative "webmention/error_response"
14
15
  require_relative "webmention/verification"
15
16
 
16
- require_relative "webmention/parser"
17
- require_relative "webmention/parsers/html_parser"
18
- require_relative "webmention/parsers/json_parser"
19
- require_relative "webmention/parsers/plaintext_parser"
20
-
21
17
  module Webmention
22
18
  # Retrieve unique URLs mentioned by the provided URL.
23
19
  #
@@ -26,9 +22,8 @@ module Webmention
26
22
  #
27
23
  # @param url [String, HTTP::URI, #to_s] An absolute URL.
28
24
  #
29
- # @raise [NoMethodError]
30
- # Raised when response is an {ErrorResponse} or response is of an
31
- # unsupported MIME type.
25
+ # @raise [Burly::UnsupportedMimeType]
26
+ # Raised when response is of an unsupported MIME type.
32
27
  #
33
28
  # @return [Array<String>]
34
29
  def self.mentioned_urls(url)
data/webmention.gemspec CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |spec|
4
4
  spec.required_ruby_version = ">= 2.7"
5
5
 
6
6
  spec.name = "webmention"
7
- spec.version = "9.1.0"
7
+ spec.version = "10.0.0"
8
8
  spec.authors = ["Jason Garber"]
9
9
  spec.email = ["jason@sixtwothree.org"]
10
10
 
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
28
28
  "source_code_uri" => "#{spec.homepage}/tree/v#{spec.version}",
29
29
  }
30
30
 
31
+ spec.add_dependency "burly", "~> 0.4"
31
32
  spec.add_dependency "http", ">= 5.3"
32
33
  spec.add_dependency "indieweb-endpoints", "~> 10.1"
33
34
  spec.add_dependency "nokogiri", ">= 1.14"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webmention
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.1.0
4
+ version: 10.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Garber
@@ -9,6 +9,20 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: burly
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.4'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.4'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: http
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -66,10 +80,6 @@ files:
66
80
  - lib/webmention.rb
67
81
  - lib/webmention/client.rb
68
82
  - lib/webmention/error_response.rb
69
- - lib/webmention/parser.rb
70
- - lib/webmention/parsers/html_parser.rb
71
- - lib/webmention/parsers/json_parser.rb
72
- - lib/webmention/parsers/plaintext_parser.rb
73
83
  - lib/webmention/request.rb
74
84
  - lib/webmention/response.rb
75
85
  - lib/webmention/url.rb
@@ -80,11 +90,11 @@ licenses:
80
90
  - Apache-2.0
81
91
  metadata:
82
92
  bug_tracker_uri: https://github.com/indieweb/webmention-client-ruby/issues
83
- changelog_uri: https://github.com/indieweb/webmention-client-ruby/releases/tag/v9.1.0
84
- documentation_uri: https://rubydoc.info/gems/webmention/9.1.0
93
+ changelog_uri: https://github.com/indieweb/webmention-client-ruby/releases/tag/v10.0.0
94
+ documentation_uri: https://rubydoc.info/gems/webmention/10.0.0
85
95
  homepage_uri: https://github.com/indieweb/webmention-client-ruby
86
96
  rubygems_mfa_required: 'true'
87
- source_code_uri: https://github.com/indieweb/webmention-client-ruby/tree/v9.1.0
97
+ source_code_uri: https://github.com/indieweb/webmention-client-ruby/tree/v10.0.0
88
98
  rdoc_options: []
89
99
  require_paths:
90
100
  - lib
@@ -99,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
109
  - !ruby/object:Gem::Version
100
110
  version: '0'
101
111
  requirements: []
102
- rubygems_version: 4.0.10
112
+ rubygems_version: 4.0.20
103
113
  specification_version: 4
104
114
  summary: A Ruby gem for sending and verifying Webmention notifications.
105
115
  test_files: []
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Webmention
4
- # @api private
5
- class Parser
6
- URI_PARSER = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::Generic::DEFAULT_PARSER
7
-
8
- URI_REGEXP = URI_PARSER.make_regexp(["http", "https"]).freeze
9
-
10
- public_constant :URI_REGEXP
11
-
12
- class << self
13
- # @return [Array<String>]
14
- attr_reader :mime_types
15
- end
16
-
17
- # @param response_body [HTTP::Response::Body, String, #to_s]
18
- # @param response_uri [String, HTTP::URI, #to_s]
19
- def initialize(response_body, response_uri)
20
- @response_body = response_body.to_s
21
- @response_uri = HTTP::URI.parse(response_uri.to_s)
22
- end
23
-
24
- private
25
-
26
- # @return [String]
27
- attr_reader :response_body
28
-
29
- # @return [HTTP::URI]
30
- attr_reader :response_uri
31
- end
32
- end
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Webmention
4
- module Parsers
5
- # @api private
6
- class HtmlParser < Parser
7
- @mime_types = ["text/html"]
8
-
9
- Client.register_parser(self)
10
-
11
- HTML_ATTRIBUTES_MAP = {
12
- "cite" => ["blockquote", "del", "ins", "q"],
13
- "data" => ["object"],
14
- "href" => ["a", "area"],
15
- "poster" => ["video"],
16
- "src" => ["audio", "embed", "img", "source", "track", "video"],
17
- "srcset" => ["img", "source"],
18
- }.freeze
19
-
20
- CSS_SELECTORS_ARRAY = HTML_ATTRIBUTES_MAP
21
- .flat_map { |attribute, names| names.map { |name| "#{name}[#{attribute}]" } }.freeze
22
-
23
- ROOT_NODE_SELECTORS_ARRAY = [".h-entry .e-content", ".h-entry", "body"].freeze
24
-
25
- private_constant :HTML_ATTRIBUTES_MAP
26
- private_constant :CSS_SELECTORS_ARRAY
27
- private_constant :ROOT_NODE_SELECTORS_ARRAY
28
-
29
- # @return [Array<String>] An array of absolute URLs.
30
- def results
31
- @results ||=
32
- extract_urls_from(*url_attributes)
33
- .map { |url| response_uri.join(url).to_s }
34
- .grep(Parser::URI_REGEXP)
35
- end
36
-
37
- private
38
-
39
- # @return [Nokogiri::HTML5::Document]
40
- def doc
41
- Nokogiri.HTML5(response_body)
42
- end
43
-
44
- # @param attributes [Array<Nokogiri::XML::Attr>]
45
- #
46
- # @return [Array<String>]
47
- def extract_urls_from(*attributes)
48
- attributes.flat_map do |attribute|
49
- if attribute.name == "srcset"
50
- attribute.value.split(",").map { |value| value.strip.match(/^\S+/).to_s }
51
- else
52
- attribute.value
53
- end
54
- end
55
- end
56
-
57
- # @return [Nokogiri::XML::Element]
58
- def root_node
59
- doc.at_css(*ROOT_NODE_SELECTORS_ARRAY)
60
- end
61
-
62
- # @return [Array<Nokogiri::XML::Attr>]
63
- def url_attributes
64
- url_nodes.flat_map(&:attribute_nodes).select { |attribute| HTML_ATTRIBUTES_MAP.key?(attribute.name) }
65
- end
66
-
67
- # @return [Nokogiri::XML::NodeSet]
68
- def url_nodes
69
- root_node.css(*CSS_SELECTORS_ARRAY)
70
- end
71
- end
72
- end
73
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Webmention
4
- module Parsers
5
- # @api private
6
- class JsonParser < Parser
7
- @mime_types = ["application/json"]
8
-
9
- Client.register_parser(self)
10
-
11
- # @return [Array<String>] An array of absolute URLs.
12
- def results
13
- @results ||= extract_urls_from(JSON.parse(response_body))
14
- end
15
-
16
- private
17
-
18
- # @param objs [Array<Hash, Array, String, Integer, Boolean, nil>]
19
- #
20
- # @return [Array<String>]
21
- def extract_urls_from(*objs)
22
- objs.flat_map do |obj|
23
- return obj.flat_map { |value| extract_urls_from(value) }.compact if obj.is_a?(Array)
24
- return extract_urls_from(obj.values) if obj.is_a?(Hash)
25
-
26
- obj if obj.is_a?(String) && obj.match?(Parser::URI_REGEXP)
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Webmention
4
- module Parsers
5
- # @api private
6
- class PlaintextParser < Parser
7
- @mime_types = ["text/plain"]
8
-
9
- Client.register_parser(self)
10
-
11
- # @return [Array<String>] An array of absolute URLs.
12
- def results
13
- @results ||= URI_PARSER.extract(response_body, ["http", "https"])
14
- end
15
- end
16
- end
17
- end