html2rss 0.8.1 → 0.8.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: 134aacbabf1b61aadcdb6d96757d329bde20429027f97c2c3bbd0328bb02cd7b
4
- data.tar.gz: 2e6ef3c8a38df3e54983670b17d574bfe771069f662414e58a5c0572ab922b1f
3
+ metadata.gz: dc1a99cdc487b0367e8af1145d876b84d043cf5abe31fdf8e7662e6ac3ab72c9
4
+ data.tar.gz: 57c41b955c3d35c7681d2213518d7faca1f5fe536f08fb6715547180b31c3312
5
5
  SHA512:
6
- metadata.gz: 4e3b80225d14b44820f742f484a418e2d0b90060f7e329f2c89a2786795a1d87bf372f194e873d4a109d8c3649399e0716a41f65479c1b60ef9b8202154a8e48
7
- data.tar.gz: ed5c095e4457d11208fa67634e526f1345c64f9d48d48df3eb11b8a5ebeb9cb203a62ae329f5388491d57435b1326bf25771349e3a374dc424094d3da60822e0
6
+ metadata.gz: 9d47c5c10bacc651a25fa90b1054d5658c7d4a1fe803a22dbcbeda42e931acc55cbbb39b8d7eafaf948bcc497d7961c4dca7c795cd955a7b6bbfe58c6a3925f2
7
+ data.tar.gz: 8521bcc416c72c86407c99b2e60950c5b3c683ea8aa05012e0ee829e6cfc33e8320564480c99f824d2c2da7f1732d638da26589fc4a4875e0e0a75b3c4e6a1d2
@@ -1,4 +1,13 @@
1
- # [](https://github.com/gildesmarais/html2rss/compare/v0.8.1...v) (2019-11-08)
1
+ # [](https://github.com/gildesmarais/html2rss/compare/v0.8.2...v) (2019-11-09)
2
+
3
+
4
+
5
+ ## [0.8.2](https://github.com/gildesmarais/html2rss/compare/v0.8.1...v0.8.2) (2019-11-09)
6
+
7
+
8
+ ### Features
9
+
10
+ * improve url handling by sanitizing and normalizing urls ([#70](https://github.com/gildesmarais/html2rss/issues/70)) ([02cd551](https://github.com/gildesmarais/html2rss/commit/02cd551))
2
11
 
3
12
 
4
13
 
@@ -1,12 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- html2rss (0.8.1)
4
+ html2rss (0.8.2)
5
5
  activesupport (~> 5.0)
6
+ addressable (~> 2.7)
6
7
  builder
7
8
  faraday (~> 0.15)
8
9
  faraday_middleware (~> 0.13)
9
- hashie (~> 3.6)
10
10
  kramdown
11
11
  mime-types (> 3.0)
12
12
  nokogiri (>= 1.10, < 2.0)
@@ -23,6 +23,8 @@ GEM
23
23
  i18n (>= 0.7, < 2)
24
24
  minitest (~> 5.1)
25
25
  tzinfo (~> 1.1)
26
+ addressable (2.7.0)
27
+ public_suffix (>= 2.0.2, < 5.0)
26
28
  ast (2.4.0)
27
29
  builder (3.2.3)
28
30
  byebug (11.0.1)
@@ -40,7 +42,6 @@ GEM
40
42
  multipart-post (>= 1.2, < 3)
41
43
  faraday_middleware (0.13.1)
42
44
  faraday (>= 0.7.4, < 1.0)
43
- hashie (3.6.0)
44
45
  i18n (1.7.0)
45
46
  concurrent-ruby (~> 1.0)
46
47
  jaro_winkler (1.5.4)
@@ -59,6 +60,7 @@ GEM
59
60
  parallel (1.18.0)
60
61
  parser (2.6.5.0)
61
62
  ast (~> 2.4.0)
63
+ public_suffix (4.0.1)
62
64
  rainbow (3.0.0)
63
65
  reverse_markdown (1.3.0)
64
66
  nokogiri
data/README.md CHANGED
@@ -61,6 +61,8 @@ The contents of both hashes are explained below.
61
61
  | `description` | optional | String | auto-generated | |
62
62
  | `ttl` | optional | Integer | `360` | TTL in _minutes_ |
63
63
  | `time_zone` | optional | String | `'UTC'` | TimeZone name |
64
+ | `language` | optional | String | `'en'` | Language code |
65
+ | `author` | optional | String | | Format: `email (Name)'` |
64
66
  | `headers` | optional | Hash | `{}` | Set HTTP request headers. See notes below. |
65
67
  | `json` | optional | Boolean | `false` | Handle JSON response. See notes below. |
66
68
 
@@ -413,10 +415,10 @@ Use this to e.g. have Cookie or Authorization information sent or to spoof the U
413
415
  url: 'https://example.com',
414
416
  title: "Example with http headers",
415
417
  headers: {
416
- "User-Agent" => "html2rss-request",
417
- "X-Something" => "Foobar",
418
- "Authorization" => "Token deadbea7",
419
- "Cookie" => "monster=MeWantCookie"
418
+ "User-Agent": "html2rss-request",
419
+ "X-Something": "Foobar",
420
+ "Authorization": "Token deadbea7",
421
+ "Cookie": "monster=MeWantCookie"
420
422
  }
421
423
  },
422
424
  selectors: {}
@@ -30,10 +30,10 @@ Gem::Specification.new do |spec|
30
30
  spec.require_paths = ['lib']
31
31
 
32
32
  spec.add_dependency 'activesupport', '~> 5.0'
33
+ spec.add_dependency 'addressable', '~> 2.7'
33
34
  spec.add_dependency 'builder'
34
35
  spec.add_dependency 'faraday', '~> 0.15'
35
36
  spec.add_dependency 'faraday_middleware', '~> 0.13'
36
- spec.add_dependency 'hashie', '~> 3.6'
37
37
  spec.add_dependency 'kramdown'
38
38
  spec.add_dependency 'mime-types', '> 3.0'
39
39
  spec.add_dependency 'nokogiri', '>= 1.10', '< 2.0'
@@ -27,8 +27,9 @@ module Html2rss
27
27
  class Gsub
28
28
  def initialize(value, env)
29
29
  @value = value
30
- @pattern = env[:options]['pattern'].to_regexp || env[:options]['pattern']
31
- @replacement = env[:options]['replacement']
30
+ options = env[:options]
31
+ @pattern = options[:pattern].to_regexp || options[:pattern]
32
+ @replacement = options[:replacement]
32
33
  end
33
34
 
34
35
  ##
@@ -26,7 +26,7 @@ module Html2rss
26
26
  ##
27
27
  # @return [String]
28
28
  def get
29
- URI(@value.to_s.split(' ').join).to_s
29
+ URI(Html2rss::Utils.sanitize_url(@value)).to_s
30
30
  end
31
31
  end
32
32
  end
@@ -34,8 +34,8 @@ module Html2rss
34
34
  ##
35
35
  # @return [String]
36
36
  def get
37
- ending = @options.fetch('end', @value.length).to_i
38
- @value[@options['start'].to_i..ending]
37
+ ending = @options.fetch(:end, @value.length).to_i
38
+ @value[@options[:start].to_i..ending]
39
39
  end
40
40
  end
41
41
  end
@@ -33,33 +33,36 @@ module Html2rss
33
33
  @value = value
34
34
  @options = env[:options]
35
35
  @item = env[:item]
36
+ @string = @options[:string]
36
37
  end
37
38
 
38
39
  ##
39
40
  # @return [String]
40
41
  def get
41
- if @options['methods']
42
- string % methods
43
- else
44
- names = string.scan(/%[<|{](\w*)[>|}]/).flatten
45
- names.uniq!
42
+ return format_string_with_methods if @options[:methods]
46
43
 
47
- format(string, names.map { |name| [name.to_sym, item_value(name)] }.to_h)
48
- end
44
+ names = string.scan(/%[<|{](\w*)[>|}]/)
45
+ names.flatten!
46
+ names.compact!
47
+ names.map!(&:to_sym)
48
+
49
+ format(string, names.map { |name| [name, item_value(name)] }.to_h)
49
50
  end
50
51
 
51
52
  private
52
53
 
53
- def string
54
- @options['string']
55
- end
54
+ attr_reader :string
56
55
 
57
56
  def methods
58
- @methods ||= @options['methods'].map(&method(:item_value))
57
+ @methods ||= @options[:methods].map(&method(:item_value))
58
+ end
59
+
60
+ def format_string_with_methods
61
+ string % methods
59
62
  end
60
63
 
61
64
  def item_value(method_name)
62
- method_name.to_s == 'self' ? @value.to_s : @item.public_send(method_name.to_sym).to_s
65
+ method_name.to_sym == :self ? @value.to_s : @item.public_send(method_name).to_s
63
66
  end
64
67
  end
65
68
  end
@@ -1,79 +1,87 @@
1
+ require 'active_support/core_ext/hash'
2
+
1
3
  module Html2rss
2
4
  ##
3
5
  # The Config class abstracts from the config data structure and
4
6
  # provides default values.
5
7
  class Config
6
8
  def initialize(feed_config, global_config = {})
7
- @global_config = Utils::IndifferentAccessHash.new global_config
8
- @feed_config = Utils::IndifferentAccessHash.new feed_config
9
- @channel_config = Utils::IndifferentAccessHash.new @feed_config.fetch('channel', {})
9
+ @global_config = global_config.deep_symbolize_keys
10
+ @feed_config = feed_config.deep_symbolize_keys
11
+ @channel_config = @feed_config.fetch(:channel, {})
10
12
  end
11
13
 
12
14
  def author
13
- channel_config.fetch 'author', 'html2rss'
15
+ channel_config.fetch :author, 'html2rss'
14
16
  end
15
17
 
16
18
  def ttl
17
- channel_config.fetch 'ttl', 360
19
+ channel_config.fetch :ttl, 360
18
20
  end
19
21
 
20
22
  def title
21
- channel_config.fetch 'title' do
22
- uri = URI(url)
23
+ channel_config.fetch(:title) { generated_title }
24
+ end
25
+
26
+ def generated_title
27
+ uri = URI(url)
23
28
 
24
- nicer_path = uri.path.split('/')
25
- nicer_path.reject! { |p| p == '' }
26
- nicer_path.map!(&:titleize)
29
+ nicer_path = uri.path.split('/')
30
+ nicer_path.reject! { |part| part == '' }
27
31
 
28
- nicer_path.any? ? "#{uri.host}: #{nicer_path.join(' ')}" : uri.host
29
- end
32
+ nicer_path.any? ? "#{uri.host}: #{nicer_path.join(' ').titleize}" : uri.host
30
33
  end
31
34
 
32
35
  def language
33
- channel_config.fetch 'language', 'en'
36
+ channel_config.fetch :language, 'en'
34
37
  end
35
38
 
36
39
  def description
37
- channel_config.fetch 'description', "Latest items from #{url}."
40
+ channel_config.fetch :description, "Latest items from #{url}."
38
41
  end
39
42
 
40
43
  def url
41
- channel_config.dig 'url'
44
+ channel_config.dig :url
42
45
  end
43
46
  alias link url
44
47
 
45
48
  def time_zone
46
- channel_config.fetch 'time_zone', 'UTC'
49
+ channel_config.fetch :time_zone, 'UTC'
47
50
  end
48
51
 
49
52
  def json?
50
- channel_config.fetch 'json', false
53
+ channel_config.fetch :json, false
51
54
  end
52
55
 
53
56
  def headers
54
- global_config.fetch('headers', {}).merge(channel_config.fetch('headers', {}))
57
+ global_config.fetch(:headers, {}).merge(channel_config.fetch(:headers, {}))
55
58
  end
56
59
 
57
60
  def attribute_options(name)
58
- feed_config.dig('selectors').fetch(name, {}).merge('channel' => channel_config)
61
+ feed_config.dig(:selectors).fetch(name, {}).merge(channel: channel_config)
59
62
  end
60
63
 
61
64
  def attribute?(name)
62
- attribute_names.include?(name.to_s)
65
+ attribute_names.include?(name)
63
66
  end
64
67
 
65
- def categories
66
- feed_config.dig('selectors').fetch('categories', []).map(&:to_sym)
68
+ def category_selectors
69
+ categories = feed_config.dig(:selectors, :categories)
70
+ return [] unless categories
71
+
72
+ categories = categories.keep_if { |category| category.to_s != '' }
73
+ categories.map!(&:to_sym)
74
+ categories.uniq!
75
+
76
+ categories
67
77
  end
68
78
 
69
79
  def selector(name)
70
- feed_config.dig('selectors', name, 'selector')
80
+ feed_config.dig(:selectors, name, :selector)
71
81
  end
72
82
 
73
83
  def attribute_names
74
- @attribute_names ||= feed_config.fetch('selectors', {}).keys.map(&:to_s).tap do |attrs|
75
- attrs.delete('items')
76
- end
84
+ @attribute_names ||= feed_config.fetch(:selectors, {}).keys.tap { |attrs| attrs.delete(:items) }
77
85
  end
78
86
 
79
87
  private
@@ -18,55 +18,58 @@ module Html2rss
18
18
  # @return [RSS:Rss]
19
19
  def rss
20
20
  RSS::Maker.make('2.0') do |maker|
21
- add_channel(maker)
21
+ add_channel(maker.channel)
22
22
 
23
- feed_items.map { |feed_item| add_item(feed_item, maker.items.new_item) }
23
+ items.each { |item| add_item(item, maker.items.new_item) }
24
24
  end
25
25
  end
26
26
 
27
- private
27
+ def self.add_categories(categories, item_maker)
28
+ categories.each { |category| item_maker.categories.new_category.content = category }
29
+ end
28
30
 
29
- attr_reader :config
31
+ def self.add_enclosure_from_url(url, item_maker)
32
+ return unless url
30
33
 
31
- def add_channel(maker)
32
- %i[language author title description link ttl].each do |attribute_name|
33
- maker.channel.public_send("#{attribute_name}=".to_sym, config.public_send(attribute_name))
34
- end
34
+ enclosure = item_maker.enclosure
35
+ content_type = MIME::Types.type_for(File.extname(url).delete('.'))
35
36
 
36
- maker.channel.generator = "html2rss V. #{::Html2rss::VERSION}"
37
- maker.channel.lastBuildDate = Time.now.to_s
37
+ enclosure.type = content_type.any? ? content_type.first.to_s : 'application/octet-stream'
38
+ enclosure.length = 0
39
+ enclosure.url = url
38
40
  end
39
41
 
40
- def feed_items
41
- @feed_items ||= Item.from_url(config.url, config).keep_if(&:valid?)
42
+ def self.add_guid(item, item_maker)
43
+ guid = item_maker.guid
44
+ guid.content = Digest::SHA1.hexdigest(item.title)
45
+ guid.isPermaLink = false
42
46
  end
43
47
 
44
- def add_item(feed_item, rss_item)
45
- feed_item.available_attributes.each do |attribute_name|
46
- rss_item.public_send("#{attribute_name}=".to_sym, feed_item.public_send(attribute_name))
47
- end
48
+ private
48
49
 
49
- feed_item.categories.each { |category| rss_item.categories.new_category.content = category }
50
- add_enclosure_from_url(feed_item.enclosure_url, rss_item) if config.attribute?(:enclosure)
50
+ attr_reader :config
51
51
 
52
- add_guid(feed_item, rss_item)
53
- end
52
+ def add_channel(channel_maker)
53
+ %i[language author title description link ttl].each do |attribute_name|
54
+ channel_maker.public_send("#{attribute_name}=", config.public_send(attribute_name))
55
+ end
54
56
 
55
- def add_enclosure_from_url(url, rss_item)
56
- content_type = MIME::Types.type_for(File.extname(url).delete('.'))
57
+ channel_maker.generator = "html2rss V. #{::Html2rss::VERSION}"
58
+ channel_maker.lastBuildDate = Time.now
59
+ end
57
60
 
58
- rss_item.enclosure.type = if content_type && content_type.first
59
- content_type.first.to_s
60
- else
61
- 'application/octet-stream'
62
- end
63
- rss_item.enclosure.length = 0
64
- rss_item.enclosure.url = url
61
+ def items
62
+ @items ||= Item.from_url(config.url, config)
65
63
  end
66
64
 
67
- def add_guid(feed_item, rss_item)
68
- rss_item.guid.content = Digest::SHA1.hexdigest(feed_item.title)
69
- rss_item.guid.isPermaLink = false
65
+ def add_item(item, item_maker)
66
+ item.available_attributes.each do |attribute_name|
67
+ item_maker.public_send("#{attribute_name}=", item.public_send(attribute_name))
68
+ end
69
+
70
+ self.class.add_categories(item.categories, item_maker)
71
+ self.class.add_enclosure_from_url(item.enclosure_url, item_maker) if item.enclosure?
72
+ self.class.add_guid(item, item_maker)
70
73
  end
71
74
  end
72
75
  end
@@ -23,15 +23,15 @@ module Html2rss
23
23
 
24
24
  attribute_options = config.attribute_options(method_name)
25
25
 
26
- extractor = ItemExtractors.get_extractor(attribute_options['extractor'])
26
+ extractor = ItemExtractors.get_extractor(attribute_options[:extractor])
27
27
  value = extractor.new(xml, attribute_options).get
28
28
 
29
- post_process(value, attribute_options.fetch('post_process', false))
29
+ post_process(value, attribute_options.fetch(:post_process, false))
30
30
  end
31
31
 
32
32
  def available_attributes
33
- @available_attributes ||= (%w[title link description author comments updated] &
34
- @config.attribute_names) - %w[categories enclosure]
33
+ @available_attributes ||= (%i[title link description author comments updated] &
34
+ @config.attribute_names) - %i[categories enclosure]
35
35
  end
36
36
 
37
37
  ##
@@ -45,17 +45,17 @@ module Html2rss
45
45
  ##
46
46
  # @return [Array]
47
47
  def categories
48
- categories = config.categories
49
- categories.map!(&method(:method_missing))
50
- categories.uniq!
51
- categories.keep_if { |category| category.to_s != '' }
48
+ config.category_selectors.map(&method(:method_missing))
49
+ end
50
+
51
+ def enclosure?
52
+ config.attribute?(:enclosure)
52
53
  end
53
54
 
54
55
  def enclosure_url
55
- enclosure = method_missing(:enclosure)
56
- return if enclosure.to_s == ''
56
+ enclosure = Html2rss::Utils.sanitize_url(method_missing(:enclosure))
57
57
 
58
- Html2rss::Utils.build_absolute_url_from_relative(enclosure, config.url).to_s
58
+ Html2rss::Utils.build_absolute_url_from_relative(enclosure, config.url).to_s if enclosure
59
59
  end
60
60
 
61
61
  ##
@@ -63,7 +63,9 @@ module Html2rss
63
63
  def self.from_url(url, config)
64
64
  body = get_body_from_url(url, config)
65
65
 
66
- Nokogiri.HTML(body).css(config.selector('items')).map { |xml_item| new xml_item, config }
66
+ Nokogiri.HTML(body).css(config.selector(:items))
67
+ .map { |xml_item| new xml_item, config }
68
+ .keep_if(&:valid?)
67
69
  end
68
70
 
69
71
  private
@@ -74,7 +76,7 @@ module Html2rss
74
76
  faraday.adapter Faraday.default_adapter
75
77
  end.get.body
76
78
 
77
- config.json? ? Html2rss::Utils.hash_to_xml(JSON.parse(body)) : body
79
+ config.json? ? Html2rss::Utils.object_to_xml(JSON.parse(body)) : body
78
80
  end
79
81
  private_class_method :get_body_from_url
80
82
 
@@ -84,7 +86,7 @@ module Html2rss
84
86
  return value unless post_process_options
85
87
 
86
88
  [post_process_options].flatten.each do |options|
87
- value = AttributePostProcessors.get_processor(options['name'])
89
+ value = AttributePostProcessors.get_processor(options[:name])
88
90
  .new(value, options: options, item: self, config: @config)
89
91
  .get
90
92
  end
@@ -15,7 +15,7 @@ module Html2rss
15
15
  ##
16
16
  # @return [Nokogiri::XML::Element]
17
17
  def self.element(xml, options)
18
- selector = options['selector']
18
+ selector = options[:selector]
19
19
  selector ? xml.css(selector) : xml
20
20
  end
21
21
  end
@@ -30,7 +30,7 @@ module Html2rss
30
30
  ##
31
31
  # @return [String]
32
32
  def get
33
- @element.attr(@options['attribute']).to_s
33
+ @element.attr(@options[:attribute]).to_s
34
34
  end
35
35
  end
36
36
  end
@@ -24,12 +24,12 @@ module Html2rss
24
24
  def initialize(xml, options)
25
25
  @options = options
26
26
  element = ItemExtractors.element(xml, options)
27
- @href = element.attr('href').to_s
27
+ @href = Html2rss::Utils.sanitize_url(element.attr('href'))
28
28
  end
29
29
 
30
30
  # @return [URI::HTTPS, URI::HTTP]
31
31
  def get
32
- Html2rss::Utils.build_absolute_url_from_relative(@href, @options['channel']['url'])
32
+ Html2rss::Utils.build_absolute_url_from_relative(@href, @options[:channel][:url])
33
33
  end
34
34
  end
35
35
  end
@@ -15,13 +15,13 @@ module Html2rss
15
15
  @options = options
16
16
  end
17
17
 
18
- # Returns what options['static'] holds.
18
+ # Returns what options[:static] holds.
19
19
  #
20
20
  # options = { static: 'Foobar' }
21
21
  # Static.new(xml, options).get
22
22
  # # => 'Foobar'
23
23
  def get
24
- @options['static']
24
+ @options[:static]
25
25
  end
26
26
  end
27
27
  end
@@ -1,6 +1,6 @@
1
1
  require 'active_support/core_ext/hash'
2
+ require 'addressable/uri'
2
3
  require 'builder'
3
- require 'hashie'
4
4
  require 'json'
5
5
  require 'nokogiri'
6
6
 
@@ -8,27 +8,20 @@ module Html2rss
8
8
  ##
9
9
  # The collecting tank for utility methods.
10
10
  module Utils
11
- ##
12
- # A Hash with indifferent access, build with {https://github.com/intridea/hashie Hashie}.
13
- class IndifferentAccessHash < Hash
14
- include Hashie::Extensions::MergeInitializer
15
- include Hashie::Extensions::IndifferentAccess
16
- end
17
-
18
- def self.build_absolute_url_from_relative(url, channel_url)
11
+ def self.build_absolute_url_from_relative(url, base_url)
19
12
  url = URI(url) if url.is_a?(String)
20
13
 
21
14
  return url if url.absolute?
22
15
 
23
- URI(channel_url).tap do |uri|
16
+ URI(base_url).tap do |uri|
24
17
  uri.path = url.path.to_s.start_with?('/') ? url.path : "/#{url.path}"
25
18
  uri.query = url.query
26
19
  uri.fragment = url.fragment if url.fragment
27
20
  end
28
21
  end
29
22
 
30
- def self.hash_to_xml(hash)
31
- hash.to_xml(skip_instruct: true, skip_types: true)
23
+ def self.object_to_xml(object)
24
+ object.to_xml(skip_instruct: true, skip_types: true)
32
25
  end
33
26
 
34
27
  def self.get_class_from_name(snake_cased_name, module_name)
@@ -36,5 +29,12 @@ module Html2rss
36
29
  class_name = ['Html2rss', module_name, camel_cased_name].join('::')
37
30
  Object.const_get(class_name)
38
31
  end
32
+
33
+ def self.sanitize_url(url)
34
+ squished_url = url.to_s.split(' ').join
35
+ return if squished_url.to_s == ''
36
+
37
+ Addressable::URI.parse(squished_url).normalize.to_s
38
+ end
39
39
  end
40
40
  end
@@ -1,3 +1,3 @@
1
1
  module Html2rss
2
- VERSION = '0.8.1'.freeze
2
+ VERSION = '0.8.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html2rss
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gil Desmarais
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-08 00:00:00.000000000 Z
11
+ date: 2019-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: addressable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.7'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: builder
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +80,6 @@ dependencies:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0.13'
69
- - !ruby/object:Gem::Dependency
70
- name: hashie
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '3.6'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '3.6'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: kramdown
85
85
  requirement: !ruby/object:Gem::Requirement