govspeak 6.5.0 → 6.5.1

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: 691092344fa56f8643bda4f29f8f0a18344515254b042fb15771375489395015
4
- data.tar.gz: 529021924ad18fccfabda572204e59b33867578e548816ab093e2d51b30e059f
3
+ metadata.gz: d1153c71bd7cd224750aa162c1ea63c89a902309cd08238a888d07a60f079d89
4
+ data.tar.gz: a7efca4529a1c6017224a77965e45994d30eba3a3e05f6d209dadff85a516cd9
5
5
  SHA512:
6
- metadata.gz: a870b551730a2a07f5a85bdb06df18b56018f3a700d21469d8c1804fe51d044ae7beb5455a8d1e332f44e003ed2d6231eb9f36fd72b0578de19cc408973074f0
7
- data.tar.gz: d0b4ca4cf824216c139094d33fdd1a9ddf98800db9aa94b077b454cfce35e98713b1b6e850c63817242f5cc3e381aaa9633062d1b01c3a7450ec6a64876632ee
6
+ metadata.gz: 33209bc51e340ccc5a2a0dc3b43f887eddbd464b687232fb4a17c6c34ae0a3097321f7f51da3ba17762e6ad1307424204872c3374dfa99eeb0100992641f4911
7
+ data.tar.gz: ab00d13be257f7730b4b7c2a858a9a9eba3802148dfc851f60fdf91eb65acdb80510a5c67a1e599f2cedbf945502cf29d6567526d695872118025ebb384318f9
data/CHANGELOG.md CHANGED
@@ -1,12 +1,17 @@
1
+ ## 6.5.1
2
+ * Change unicode testing characters after external gem change
3
+ * Move from govuk-lint to rubocop-govuk
4
+ * Allow version 6 of actionview
5
+
1
6
  ## 6.5.0
2
7
 
3
8
  * Allow data attributes on links
4
9
 
5
10
  ## 6.4.0
6
11
 
7
- * Add table heading syntax that allows a table cell outside of `thead` to be marked as a table heading with a scope of row. (PR#161)
12
+ * Add table heading syntax that allows a table cell outside of `thead` to be marked as a table heading with a scope of row. (PR#161)
8
13
 
9
- ## 6.3.0
14
+ ## 6.3.0
10
15
 
11
16
  * Unicode characters forbidden in HTML are stripped from input
12
17
  * Validation is now more lenient for HTML input
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ Bundler::GemHelper.install_tasks
7
7
  desc "Run basic tests"
8
8
  Rake::TestTask.new("test") { |t|
9
9
  t.libs << "test"
10
- t.pattern = 'test/*_test.rb'
10
+ t.pattern = "test/*_test.rb"
11
11
  t.verbose = true
12
12
  t.warning = true
13
13
  }
data/lib/govspeak.rb CHANGED
@@ -1,32 +1,32 @@
1
- require 'active_support/core_ext/hash'
2
- require 'active_support/core_ext/array'
3
- require 'erb'
4
- require 'govuk_publishing_components'
5
- require 'htmlentities'
6
- require 'kramdown'
7
- require 'kramdown/parser/govuk'
8
- require 'nokogiri'
9
- require 'nokogumbo'
10
- require 'rinku'
11
- require 'sanitize'
12
- require 'govspeak/header_extractor'
13
- require 'govspeak/structured_header_extractor'
14
- require 'govspeak/html_validator'
15
- require 'govspeak/html_sanitizer'
16
- require 'govspeak/kramdown_overrides'
17
- require 'govspeak/blockquote_extra_quote_remover'
18
- require 'govspeak/post_processor'
19
- require 'govspeak/link_extractor'
20
- require 'govspeak/template_renderer'
21
- require 'govspeak/presenters/attachment_presenter'
22
- require 'govspeak/presenters/contact_presenter'
23
- require 'govspeak/presenters/h_card_presenter'
24
- require 'govspeak/presenters/image_presenter'
25
- require 'govspeak/presenters/attachment_image_presenter'
1
+ require "active_support/core_ext/hash"
2
+ require "active_support/core_ext/array"
3
+ require "erb"
4
+ require "govuk_publishing_components"
5
+ require "htmlentities"
6
+ require "kramdown"
7
+ require "kramdown/parser/govuk"
8
+ require "nokogiri"
9
+ require "nokogumbo"
10
+ require "rinku"
11
+ require "sanitize"
12
+ require "govspeak/header_extractor"
13
+ require "govspeak/structured_header_extractor"
14
+ require "govspeak/html_validator"
15
+ require "govspeak/html_sanitizer"
16
+ require "govspeak/kramdown_overrides"
17
+ require "govspeak/blockquote_extra_quote_remover"
18
+ require "govspeak/post_processor"
19
+ require "govspeak/link_extractor"
20
+ require "govspeak/template_renderer"
21
+ require "govspeak/presenters/attachment_presenter"
22
+ require "govspeak/presenters/contact_presenter"
23
+ require "govspeak/presenters/h_card_presenter"
24
+ require "govspeak/presenters/image_presenter"
25
+ require "govspeak/presenters/attachment_image_presenter"
26
26
 
27
27
  module Govspeak
28
28
  def self.root
29
- File.expand_path('..', File.dirname(__FILE__))
29
+ File.expand_path("..", File.dirname(__FILE__))
30
30
  end
31
31
 
32
32
  class Document
@@ -44,8 +44,8 @@ module Govspeak
44
44
  new(source, options).to_html
45
45
  end
46
46
 
47
- def self.extensions
48
- @extensions
47
+ class << self
48
+ attr_reader :extensions
49
49
  end
50
50
 
51
51
  def initialize(source, options = {})
@@ -118,7 +118,7 @@ module Govspeak
118
118
  def remove_forbidden_characters(source)
119
119
  # These are characters that are not deemed not suitable for
120
120
  # markup: https://www.w3.org/TR/unicode-xml/#Charlist
121
- source.gsub(Sanitize::REGEX_UNSUITABLE_CHARS, '')
121
+ source.gsub(Sanitize::REGEX_UNSUITABLE_CHARS, "")
122
122
  end
123
123
 
124
124
  def self.extension(title, regexp = nil, &block)
@@ -147,7 +147,7 @@ module Govspeak
147
147
  parser.new(body.strip).to_html.sub(/^<p>(.*)<\/p>$/, "<p><strong>\\1</strong></p>")
148
148
  end
149
149
 
150
- extension('button', %r{
150
+ extension("button", %r{
151
151
  (?:\r|\n|^) # non-capturing match to make sure start of line and linebreak
152
152
  {button(.*?)} # match opening bracket and capture attributes
153
153
  \s* # any whitespace between opening bracket and link
@@ -176,51 +176,51 @@ module Govspeak
176
176
  %{\n<a role="button" class="#{button_classes}" href="#{href}" #{data_attribute}>#{text}</a>\n}
177
177
  }
178
178
 
179
- extension('highlight-answer') { |body|
179
+ extension("highlight-answer") { |body|
180
180
  %{\n\n<div class="highlight-answer">
181
181
  #{Govspeak::Document.new(body.strip).to_html}</div>\n}
182
182
  }
183
183
 
184
- extension('stat-headline', %r${stat-headline}(.*?){/stat-headline}$m) { |body|
184
+ extension("stat-headline", %r${stat-headline}(.*?){/stat-headline}$m) { |body|
185
185
  %{\n\n<aside class="stat-headline">
186
186
  #{Govspeak::Document.new(body.strip).to_html}</aside>\n}
187
187
  }
188
188
 
189
189
  # FIXME: these surrounded_by arguments look dodgy
190
- extension('external', surrounded_by("x[", ")x")) { |body|
190
+ extension("external", surrounded_by("x[", ")x")) { |body|
191
191
  Kramdown::Document.new("[#{body.strip}){:rel='external'}").to_html
192
192
  }
193
193
 
194
- extension('informational', surrounded_by("^")) { |body|
194
+ extension("informational", surrounded_by("^")) { |body|
195
195
  %{\n\n<div role="note" aria-label="Information" class="application-notice info-notice">
196
196
  #{Govspeak::Document.new(body.strip).to_html}</div>\n}
197
197
  }
198
198
 
199
- extension('important', surrounded_by("@")) { |body|
199
+ extension("important", surrounded_by("@")) { |body|
200
200
  %{\n\n<div role="note" aria-label="Important" class="advisory">#{insert_strong_inside_p(body)}</div>\n}
201
201
  }
202
202
 
203
- extension('helpful', surrounded_by("%")) { |body|
203
+ extension("helpful", surrounded_by("%")) { |body|
204
204
  %{\n\n<div role="note" aria-label="Warning" class="application-notice help-notice">\n#{Govspeak::Document.new(body.strip).to_html}</div>\n}
205
205
  }
206
206
 
207
- extension('barchart', /{barchart(.*?)}/) do |captures|
208
- stacked = '.mc-stacked' if captures.include? 'stacked'
209
- compact = '.compact' if captures.include? 'compact'
210
- negative = '.mc-negative' if captures.include? 'negative'
207
+ extension("barchart", /{barchart(.*?)}/) do |captures|
208
+ stacked = ".mc-stacked" if captures.include? "stacked"
209
+ compact = ".compact" if captures.include? "compact"
210
+ negative = ".mc-negative" if captures.include? "negative"
211
211
 
212
212
  [
213
- '{:',
214
- '.js-barchart-table',
213
+ "{:",
214
+ ".js-barchart-table",
215
215
  stacked,
216
216
  compact,
217
217
  negative,
218
- '.mc-auto-outdent',
219
- '}'
220
- ].join(' ')
218
+ ".mc-auto-outdent",
219
+ "}",
220
+ ].join(" ")
221
221
  end
222
222
 
223
- extension('attached-image', /^!!([0-9]+)/) do |image_number|
223
+ extension("attached-image", /^!!([0-9]+)/) do |image_number|
224
224
  image = images[image_number.to_i - 1]
225
225
  next "" unless image
226
226
 
@@ -228,7 +228,7 @@ module Govspeak
228
228
  end
229
229
 
230
230
  # DEPRECATED: use 'AttachmentLink:attachment-id' instead
231
- extension('embed attachment inline', /\[embed:attachments:inline:\s*(.*?)\s*\]/) do |content_id|
231
+ extension("embed attachment inline", /\[embed:attachments:inline:\s*(.*?)\s*\]/) do |content_id|
232
232
  attachment = attachments.detect { |a| a[:content_id] == content_id }
233
233
  next "" unless attachment
234
234
 
@@ -243,7 +243,7 @@ module Govspeak
243
243
  end
244
244
 
245
245
  # DEPRECATED: use 'Image:image-id' instead
246
- extension('attachment image', /\[embed:attachments:image:\s*(.*?)\s*\]/) do |content_id|
246
+ extension("attachment image", /\[embed:attachments:image:\s*(.*?)\s*\]/) do |content_id|
247
247
  attachment = attachments.detect { |a| a[:content_id] == content_id }
248
248
  next "" unless attachment
249
249
 
@@ -266,29 +266,29 @@ module Govspeak
266
266
  lines << %{<figure#{id_attr} class="image embedded">}
267
267
  lines << %{<div class="img"><img src="#{encode(image.url)}" alt="#{encode(image.alt_text)}"></div>}
268
268
  lines << image.figcaption_html if image.figcaption?
269
- lines << '</figure>'
269
+ lines << "</figure>"
270
270
  lines.join
271
271
  end
272
272
 
273
- wrap_with_div('summary', '$!')
274
- wrap_with_div('form-download', '$D')
275
- wrap_with_div('contact', '$C')
276
- wrap_with_div('place', '$P', Govspeak::Document)
277
- wrap_with_div('information', '$I', Govspeak::Document)
278
- wrap_with_div('additional-information', '$AI')
279
- wrap_with_div('example', '$E', Govspeak::Document)
280
- wrap_with_div('call-to-action', '$CTA', Govspeak::Document)
273
+ wrap_with_div("summary", "$!")
274
+ wrap_with_div("form-download", "$D")
275
+ wrap_with_div("contact", "$C")
276
+ wrap_with_div("place", "$P", Govspeak::Document)
277
+ wrap_with_div("information", "$I", Govspeak::Document)
278
+ wrap_with_div("additional-information", "$AI")
279
+ wrap_with_div("example", "$E", Govspeak::Document)
280
+ wrap_with_div("call-to-action", "$CTA", Govspeak::Document)
281
281
 
282
- extension('address', surrounded_by("$A")) { |body|
282
+ extension("address", surrounded_by("$A")) { |body|
283
283
  %{\n<div class="address"><div class="adr org fn"><p>\n#{body.sub("\n", '').gsub("\n", '<br />')}\n</p></div></div>\n}
284
284
  }
285
285
 
286
286
  extension("legislative list", /#{NEW_PARAGRAPH_LOOKBEHIND}\$LegislativeList\s*$(.*?)\$EndLegislativeList/m) do |body|
287
287
  Govspeak::KramdownOverrides.with_kramdown_ordered_lists_disabled do
288
288
  Kramdown::Document.new(body.strip).to_html.tap do |doc|
289
- doc.gsub!('<ul>', '<ol>')
290
- doc.gsub!('</ul>', '</ol>')
291
- doc.sub!('<ol>', '<ol class="legislative-list">')
289
+ doc.gsub!("<ul>", "<ol>")
290
+ doc.gsub!("</ul>", "</ol>")
291
+ doc.sub!("<ol>", '<ol class="legislative-list">')
292
292
  end
293
293
  end
294
294
  end
@@ -301,12 +301,12 @@ module Govspeak
301
301
  end
302
302
 
303
303
  def self.devolved_options
304
- { 'scotland' => 'Scotland',
305
- 'england' => 'England',
306
- 'england-wales' => 'England and Wales',
307
- 'northern-ireland' => 'Northern Ireland',
308
- 'wales' => 'Wales',
309
- 'london' => 'London' }
304
+ { "scotland" => "Scotland",
305
+ "england" => "England",
306
+ "england-wales" => "England and Wales",
307
+ "northern-ireland" => "Northern Ireland",
308
+ "wales" => "Wales",
309
+ "london" => "London" }
310
310
  end
311
311
 
312
312
  devolved_options.each do |k, v|
@@ -333,7 +333,7 @@ module Govspeak
333
333
  end
334
334
  end
335
335
 
336
- extension('embed link', /\[embed:link:\s*(.*?)\s*\]/) do |content_id|
336
+ extension("embed link", /\[embed:link:\s*(.*?)\s*\]/) do |content_id|
337
337
  link = links.detect { |l| l[:content_id] == content_id }
338
338
  next "" unless link
339
339
 
@@ -344,28 +344,28 @@ module Govspeak
344
344
  end
345
345
  end
346
346
 
347
- extension('Contact', /\[Contact:\s*(.*?)\s*\]/) do |content_id|
347
+ extension("Contact", /\[Contact:\s*(.*?)\s*\]/) do |content_id|
348
348
  contact = contacts.detect { |c| c[:content_id] == content_id }
349
349
  next "" unless contact
350
350
 
351
- renderer = TemplateRenderer.new('contact.html.erb', locale)
351
+ renderer = TemplateRenderer.new("contact.html.erb", locale)
352
352
  renderer.render(contact: ContactPresenter.new(contact))
353
353
  end
354
354
 
355
- extension('Image', /#{NEW_PARAGRAPH_LOOKBEHIND}\[Image:\s*(.*?)\s*\]/) do |image_id|
355
+ extension("Image", /#{NEW_PARAGRAPH_LOOKBEHIND}\[Image:\s*(.*?)\s*\]/) do |image_id|
356
356
  image = images.detect { |c| c.is_a?(Hash) && c[:id] == image_id }
357
357
  next "" unless image
358
358
 
359
359
  render_image(ImagePresenter.new(image))
360
360
  end
361
361
 
362
- extension('Attachment', /#{NEW_PARAGRAPH_LOOKBEHIND}\[Attachment:\s*(.*?)\s*\]/) do |attachment_id|
362
+ extension("Attachment", /#{NEW_PARAGRAPH_LOOKBEHIND}\[Attachment:\s*(.*?)\s*\]/) do |attachment_id|
363
363
  next "" if attachments.none? { |a| a[:id] == attachment_id }
364
364
 
365
365
  %{<govspeak-embed-attachment id="#{attachment_id}"></govspeak-embed-attachment>}
366
366
  end
367
367
 
368
- extension('AttachmentLink', /\[AttachmentLink:\s*(.*?)\s*\]/) do |attachment_id|
368
+ extension("AttachmentLink", /\[AttachmentLink:\s*(.*?)\s*\]/) do |attachment_id|
369
369
  next "" if attachments.none? { |a| a[:id] == attachment_id }
370
370
 
371
371
  %{<govspeak-embed-attachment-link id="#{attachment_id}"></govspeak-embed-attachment-link>}
@@ -384,5 +384,5 @@ module Govspeak
384
384
  end
385
385
 
386
386
  I18n.load_path.unshift(
387
- *Dir.glob(File.expand_path('locales/*.yml', Govspeak.root))
387
+ *Dir.glob(File.expand_path("locales/*.yml", Govspeak.root)),
388
388
  )
@@ -20,7 +20,7 @@ module Govspeak
20
20
  private
21
21
 
22
22
  def id(element)
23
- element.attr.fetch('id', generate_id(element.options[:raw_text]))
23
+ element.attr.fetch("id", generate_id(element.options[:raw_text]))
24
24
  end
25
25
 
26
26
  def build_header(element)
@@ -1,4 +1,4 @@
1
- require 'addressable/uri'
1
+ require "addressable/uri"
2
2
 
3
3
  class Govspeak::HtmlSanitizer
4
4
  class ImageSourceWhitelister
@@ -10,7 +10,7 @@ class Govspeak::HtmlSanitizer
10
10
  return unless sanitize_context[:node_name] == "img"
11
11
 
12
12
  node = sanitize_context[:node]
13
- image_uri = Addressable::URI.parse(node['src'])
13
+ image_uri = Addressable::URI.parse(node["src"])
14
14
  unless image_uri.relative? || @allowed_image_hosts.include?(image_uri.host)
15
15
  node.unlink # the node isn't sanitary. Remove it from the document.
16
16
  end
@@ -25,8 +25,8 @@ class Govspeak::HtmlSanitizer
25
25
 
26
26
  # Kramdown uses text-align to allow table cells to be aligned
27
27
  # http://kramdown.gettalong.org/quickref.html#tables
28
- if invalid_style_attribute?(node['style'])
29
- node.remove_attribute('style')
28
+ if invalid_style_attribute?(node["style"])
29
+ node.remove_attribute("style")
30
30
  end
31
31
  end
32
32
 
@@ -58,7 +58,7 @@ class Govspeak::HtmlSanitizer
58
58
  "th" => Sanitize::Config::RELAXED[:attributes]["th"] + %w[style],
59
59
  "td" => Sanitize::Config::RELAXED[:attributes]["td"] + %w[style],
60
60
  "govspeak-embed-attachment" => %w[content-id],
61
- }
61
+ },
62
62
  )
63
63
  end
64
64
  end
@@ -20,8 +20,8 @@ module Govspeak
20
20
  end
21
21
 
22
22
  def extract_href_from_link(link)
23
- href = link['href'] || ''
24
- if website_root && href.start_with?('/')
23
+ href = link["href"] || ""
24
+ if website_root && href.start_with?("/")
25
25
  "#{website_root}#{href}"
26
26
  else
27
27
  href
@@ -29,7 +29,7 @@ module Govspeak
29
29
  end
30
30
 
31
31
  def document_anchors
32
- processed_govspeak.css('a[href]').css('a:not([href^="mailto"])').css('a:not([href^="#"])')
32
+ processed_govspeak.css("a[href]").css('a:not([href^="mailto"])').css('a:not([href^="#"])')
33
33
  end
34
34
 
35
35
  def processed_govspeak
@@ -2,8 +2,8 @@ module Govspeak
2
2
  class PostProcessor
3
3
  @extensions = []
4
4
 
5
- def self.extensions
6
- @extensions
5
+ class << self
6
+ attr_reader :extensions
7
7
  end
8
8
 
9
9
  def self.process(html, govspeak_document)
@@ -38,11 +38,11 @@ module Govspeak
38
38
  el.children = xml
39
39
  .gsub(
40
40
  %r{&lt;(div class="img")&gt;(.*?)&lt;(/div)&gt;},
41
- "<\\1>\\2<\\3>"
41
+ "<\\1>\\2<\\3>",
42
42
  )
43
43
  .gsub(
44
44
  %r{&lt;(figcaption)&gt;(.*?)&lt;(/figcaption&)gt;},
45
- "<\\1>\\2<\\3>"
45
+ "<\\1>\\2<\\3>",
46
46
  )
47
47
  end
48
48
  end
@@ -59,7 +59,7 @@ module Govspeak
59
59
  attachment_html = GovukPublishingComponents.render(
60
60
  "govuk_publishing_components/components/attachment",
61
61
  attachment: attachment,
62
- locale: govspeak_document.locale
62
+ locale: govspeak_document.locale,
63
63
  )
64
64
  el.swap(attachment_html)
65
65
  end
@@ -77,7 +77,7 @@ module Govspeak
77
77
  attachment_html = GovukPublishingComponents.render(
78
78
  "govuk_publishing_components/components/attachment_link",
79
79
  attachment: attachment,
80
- locale: govspeak_document.locale
80
+ locale: govspeak_document.locale,
81
81
  )
82
82
  el.swap(attachment_html)
83
83
  end
@@ -85,17 +85,17 @@ module Govspeak
85
85
 
86
86
  extension("Add table headers and row / column scopes") do |document|
87
87
  document.css("thead th").map do |el|
88
- el.content = el.content.gsub(/^# /, '')
89
- el.content = el.content.gsub(/[[:space:]]/, '') if el.content.blank? # Removes a strange whitespace in the cell if the cell is already blank.
90
- el.name = 'td' if el.content.blank? # This prevents a `th` with nothing inside it; a `td` is preferable.
88
+ el.content = el.content.gsub(/^# /, "")
89
+ el.content = el.content.gsub(/[[:space:]]/, "") if el.content.blank? # Removes a strange whitespace in the cell if the cell is already blank.
90
+ el.name = "td" if el.content.blank? # This prevents a `th` with nothing inside it; a `td` is preferable.
91
91
  el[:scope] = "col" if el.content.present? # `scope` shouldn't be used if there's nothing in the table heading.
92
92
  end
93
93
 
94
94
  document.css(":not(thead) tr td:first-child").map do |el|
95
95
  if el.content.match?(/^#($|\s.*$)/)
96
- el.content = el.content.gsub(/^#($|\s)/, '') # Replace '# ' and '#', but not '#Word'.
97
- el.name = 'th' if el.content.present? # This also prevents a `th` with nothing inside it; a `td` is preferable.
98
- el[:scope] = 'row' if el.content.present? # `scope` shouldn't be used if there's nothing in the table heading.
96
+ el.content = el.content.gsub(/^#($|\s)/, "") # Replace '# ' and '#', but not '#Word'.
97
+ el.name = "th" if el.content.present? # This also prevents a `th` with nothing inside it; a `td` is preferable.
98
+ el[:scope] = "row" if el.content.present? # `scope` shouldn't be used if there's nothing in the table heading.
99
99
  end
100
100
  end
101
101
  end