govspeak 6.5.0 → 6.5.5

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -2
  3. data/README.md +6 -5
  4. data/Rakefile +7 -4
  5. data/lib/govspeak.rb +116 -116
  6. data/lib/govspeak/header_extractor.rb +1 -1
  7. data/lib/govspeak/html_sanitizer.rb +12 -9
  8. data/lib/govspeak/kramdown_overrides.rb +2 -2
  9. data/lib/govspeak/link_extractor.rb +6 -6
  10. data/lib/govspeak/post_processor.rb +34 -14
  11. data/lib/govspeak/presenters/attachment_presenter.rb +39 -39
  12. data/lib/govspeak/presenters/contact_presenter.rb +2 -2
  13. data/lib/govspeak/presenters/h_card_presenter.rb +3 -3
  14. data/lib/govspeak/presenters/image_presenter.rb +4 -4
  15. data/lib/govspeak/structured_header_extractor.rb +2 -2
  16. data/lib/govspeak/version.rb +1 -1
  17. data/lib/kramdown/parser/govuk.rb +6 -7
  18. data/test/blockquote_extra_quote_remover_test.rb +24 -26
  19. data/test/govspeak_attachment_link_test.rb +0 -2
  20. data/test/govspeak_attachment_test.rb +0 -2
  21. data/test/govspeak_attachments_image_test.rb +12 -14
  22. data/test/govspeak_attachments_inline_test.rb +22 -24
  23. data/test/govspeak_button_test.rb +29 -31
  24. data/test/govspeak_contacts_test.rb +29 -31
  25. data/test/govspeak_extract_contact_content_ids_test.rb +1 -3
  26. data/test/govspeak_images_bang_test.rb +37 -39
  27. data/test/govspeak_images_test.rb +43 -45
  28. data/test/govspeak_link_extractor_test.rb +1 -1
  29. data/test/govspeak_link_test.rb +1 -3
  30. data/test/govspeak_structured_headers_test.rb +7 -6
  31. data/test/govspeak_table_with_headers_test.rb +68 -21
  32. data/test/govspeak_test.rb +98 -101
  33. data/test/govspeak_test_helper.rb +1 -1
  34. data/test/html_sanitizer_test.rb +17 -9
  35. data/test/html_validator_test.rb +2 -2
  36. data/test/presenters/h_card_presenter_test.rb +39 -41
  37. data/test/test_helper.rb +12 -8
  38. metadata +52 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 691092344fa56f8643bda4f29f8f0a18344515254b042fb15771375489395015
4
- data.tar.gz: 529021924ad18fccfabda572204e59b33867578e548816ab093e2d51b30e059f
3
+ metadata.gz: 99554d6b3b3fd3287b35eebe6ff4633d6e3df24f74bede69fd65c16a81a41584
4
+ data.tar.gz: 300af892bfebf34b74161432f49d93131bde2d533354fd2580204c3d341b8031
5
5
  SHA512:
6
- metadata.gz: a870b551730a2a07f5a85bdb06df18b56018f3a700d21469d8c1804fe51d044ae7beb5455a8d1e332f44e003ed2d6231eb9f36fd72b0578de19cc408973074f0
7
- data.tar.gz: d0b4ca4cf824216c139094d33fdd1a9ddf98800db9aa94b077b454cfce35e98713b1b6e850c63817242f5cc3e381aaa9633062d1b01c3a7450ec6a64876632ee
6
+ metadata.gz: 033a7f0ac2134f8a7912fbb38033a07b8f51370d5631b1e6342a7b04d451b50540fc3874c5b3153af4a18b8ce892fa9f16d24ee6909ba339d2888423ea577199
7
+ data.tar.gz: df16ff9574a2b759b0bb75e53475e08b7164166af97e28d900ed1f44407826d4156ec7441bb07363362740542f698244dc78a712f4b4c1b59e9570ec598685e5
@@ -1,12 +1,34 @@
1
+ ## 6.5.5
2
+
3
+ * Prevent links in table headers being stripped (PR#187)
4
+
5
+ ## 6.5.4
6
+
7
+ * Require Sanitize to be at least 5.2.1 due to https://nvd.nist.gov/vuln/detail/CVE-2020-4054
8
+
9
+ ## 6.5.3
10
+
11
+ * Use button component for buttons (PR#176)
12
+
13
+ ## 6.5.2
14
+
15
+ * Allow `data` attributes on `div` tags (PR#173)
16
+
17
+ ## 6.5.1
18
+
19
+ * Change unicode testing characters after external gem change
20
+ * Move from govuk-lint to rubocop-govuk
21
+ * Allow version 6 of actionview
22
+
1
23
  ## 6.5.0
2
24
 
3
25
  * Allow data attributes on links
4
26
 
5
27
  ## 6.4.0
6
28
 
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)
29
+ * 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
30
 
9
- ## 6.3.0
31
+ ## 6.3.0
10
32
 
11
33
  * Unicode characters forbidden in HTML are stripped from input
12
34
  * Validation is now more lenient for HTML input
data/README.md CHANGED
@@ -619,8 +619,7 @@ will output
619
619
 
620
620
  An accessible way to add button links into content, that can also allow cross domain tracking with [Google Analytics](https://support.google.com/analytics/answer/7372977?hl=en)
621
621
 
622
- This button component is [extended from static](http://govuk-static.herokuapp.com/component-guide/button) for [use in govspeak](http://govuk-static.herokuapp.com/component-guide/govspeak/button)
623
- Note: Ideally we'd use the original component directly but this currently isnt possible
622
+ This button component uses the component from the [components gem](https://components.publishing.service.gov.uk/component-guide/button) for use in govspeak.
624
623
 
625
624
  You must use the [link](https://daringfireball.net/projects/markdown/syntax#link) syntax within the button tags.
626
625
 
@@ -635,7 +634,7 @@ To get the most basic button.
635
634
  which outputs
636
635
 
637
636
  ```html
638
- <a role="button" class="button" href="https://gov.uk/random">
637
+ <a role="button" class="gem-c-button govuk-button" href="https://gov.uk/random">
639
638
  Continue
640
639
  </a>
641
640
  ```
@@ -649,8 +648,9 @@ To turn a button into a ['Start now' button](https://www.gov.uk/service-manual/d
649
648
  which outputs
650
649
 
651
650
  ```html
652
- <a role="button" class="button button-start" href="https://gov.uk/random">
651
+ <a role="button" class="gem-c-button govuk-button govuk-button--start" href="https://gov.uk/random">
653
652
  Start Now
653
+ <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg>
654
654
  </a>
655
655
  ```
656
656
 
@@ -667,12 +667,13 @@ which outputs
667
667
  ```html
668
668
  <a
669
669
  role="button"
670
- class="button button-start"
670
+ class="gem-c-button govuk-button govuk-button--start"
671
671
  href="https://example.com/external-service/start-now"
672
672
  data-module="cross-domain-tracking"
673
673
  data-tracking-code="UA-XXXXXX-Y"
674
674
  data-tracking-name="govspeakButtonTracker"
675
675
  >
676
676
  Start Now
677
+ <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg>
677
678
  </a>
678
679
  ```
data/Rakefile CHANGED
@@ -1,15 +1,18 @@
1
1
  require "rake"
2
2
  require "rake/testtask"
3
+ require "rubocop/rake_task"
3
4
  require "bundler"
4
5
 
5
6
  Bundler::GemHelper.install_tasks
6
7
 
8
+ RuboCop::RakeTask.new
9
+
7
10
  desc "Run basic tests"
8
- Rake::TestTask.new("test") { |t|
11
+ Rake::TestTask.new("test") do |t|
9
12
  t.libs << "test"
10
- t.pattern = 'test/*_test.rb'
13
+ t.pattern = "test/*_test.rb"
11
14
  t.verbose = true
12
15
  t.warning = true
13
- }
16
+ end
14
17
 
15
- task default: [:test]
18
+ task default: %i[test rubocop]
@@ -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 = {})
@@ -108,9 +108,9 @@ module Govspeak
108
108
  source = Govspeak::BlockquoteExtraQuoteRemover.remove(source)
109
109
  source = remove_forbidden_characters(source)
110
110
  self.class.extensions.each do |_, regexp, block|
111
- source.gsub!(regexp) {
111
+ source.gsub!(regexp) do
112
112
  instance_exec(*Regexp.last_match.captures, &block)
113
- }
113
+ end
114
114
  end
115
115
  source
116
116
  end
@@ -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)
@@ -127,27 +127,27 @@ module Govspeak
127
127
  end
128
128
 
129
129
  def self.surrounded_by(open, close = nil)
130
- open = Regexp::escape(open)
130
+ open = Regexp.escape(open)
131
131
  if close
132
- close = Regexp::escape(close)
133
- %r+(?:\r|\n|^)#{open}(.*?)#{close} *(\r|\n|$)?+m
132
+ close = Regexp.escape(close)
133
+ %r{(?:\r|\n|^)#{open}(.*?)#{close} *(\r|\n|$)?}m
134
134
  else
135
- %r+(?:\r|\n|^)#{open}(.*?)#{open}? *(\r|\n|$)+m
135
+ %r{(?:\r|\n|^)#{open}(.*?)#{open}? *(\r|\n|$)}m
136
136
  end
137
137
  end
138
138
 
139
139
  def self.wrap_with_div(class_name, character, parser = Kramdown::Document)
140
- extension(class_name, surrounded_by(character)) { |body|
140
+ extension(class_name, surrounded_by(character)) do |body|
141
141
  content = parser ? parser.new("#{body.strip}\n").to_html : body.strip
142
- %{\n<div class="#{class_name}">\n#{content}</div>\n}
143
- }
142
+ %(\n<div class="#{class_name}">\n#{content}</div>\n)
143
+ end
144
144
  end
145
145
 
146
146
  def insert_strong_inside_p(body, parser = Govspeak::Document)
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
@@ -160,11 +160,11 @@ module Govspeak
160
160
  \s* # any whitespace between opening bracket and link
161
161
  {\/button} # match ending bracket
162
162
  (?:\r|\n|$) # non-capturing match to make sure end of line and linebreak
163
- }x) { |attributes, text, href|
164
- button_classes = "button"
165
- button_classes << " button-start" if attributes =~ /start/
163
+ }x) do |attributes, text, href|
164
+ button_classes = "govuk-button"
166
165
  /cross-domain-tracking:(?<cross_domain_tracking>.[^\s*]+)/ =~ attributes
167
166
  data_attribute = ""
167
+ data_attribute << " data-start='true'" if attributes =~ /start/
168
168
  if cross_domain_tracking
169
169
  data_attribute << " data-module='cross-domain-tracking'"
170
170
  data_attribute << " data-tracking-code='#{cross_domain_tracking.strip}'"
@@ -173,54 +173,54 @@ module Govspeak
173
173
  text = text.strip
174
174
  href = href.strip
175
175
 
176
- %{\n<a role="button" class="#{button_classes}" href="#{href}" #{data_attribute}>#{text}</a>\n}
177
- }
176
+ %(\n<a role="button" class="#{button_classes}" href="#{href}" #{data_attribute}>#{text}</a>\n)
177
+ end
178
178
 
179
- extension('highlight-answer') { |body|
180
- %{\n\n<div class="highlight-answer">
181
- #{Govspeak::Document.new(body.strip).to_html}</div>\n}
182
- }
179
+ extension("highlight-answer") do |body|
180
+ %(\n\n<div class="highlight-answer">
181
+ #{Govspeak::Document.new(body.strip).to_html}</div>\n)
182
+ end
183
183
 
184
- extension('stat-headline', %r${stat-headline}(.*?){/stat-headline}$m) { |body|
185
- %{\n\n<aside class="stat-headline">
186
- #{Govspeak::Document.new(body.strip).to_html}</aside>\n}
187
- }
184
+ extension("stat-headline", %r${stat-headline}(.*?){/stat-headline}$m) do |body|
185
+ %(\n\n<aside class="stat-headline">
186
+ #{Govspeak::Document.new(body.strip).to_html}</aside>\n)
187
+ end
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")) do |body|
191
191
  Kramdown::Document.new("[#{body.strip}){:rel='external'}").to_html
192
- }
192
+ end
193
193
 
194
- extension('informational', surrounded_by("^")) { |body|
195
- %{\n\n<div role="note" aria-label="Information" class="application-notice info-notice">
196
- #{Govspeak::Document.new(body.strip).to_html}</div>\n}
197
- }
194
+ extension("informational", surrounded_by("^")) do |body|
195
+ %(\n\n<div role="note" aria-label="Information" class="application-notice info-notice">
196
+ #{Govspeak::Document.new(body.strip).to_html}</div>\n)
197
+ end
198
198
 
199
- extension('important', surrounded_by("@")) { |body|
200
- %{\n\n<div role="note" aria-label="Important" class="advisory">#{insert_strong_inside_p(body)}</div>\n}
201
- }
199
+ extension("important", surrounded_by("@")) do |body|
200
+ %(\n\n<div role="note" aria-label="Important" class="advisory">#{insert_strong_inside_p(body)}</div>\n)
201
+ end
202
202
 
203
- extension('helpful', surrounded_by("%")) { |body|
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
- }
203
+ extension("helpful", surrounded_by("%")) do |body|
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
+ end
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',
215
- stacked,
216
- compact,
217
- negative,
218
- '.mc-auto-outdent',
219
- '}'
220
- ].join(' ')
213
+ "{:",
214
+ ".js-barchart-table",
215
+ stacked,
216
+ compact,
217
+ negative,
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,22 +228,22 @@ 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
 
235
235
  attachment = AttachmentPresenter.new(attachment)
236
236
 
237
- span_id = attachment.id ? %{ id="attachment_#{attachment.id}"} : ""
237
+ span_id = attachment.id ? %( id="attachment_#{attachment.id}") : ""
238
238
  # new lines inside our title cause problems with govspeak rendering as this is expected to be on one line.
239
239
  title = (attachment.title || "").tr("\n", " ")
240
240
  link = attachment.link(title, attachment.url)
241
241
  attributes = attachment.attachment_attributes.empty? ? "" : " (#{attachment.attachment_attributes})"
242
- %{<span#{span_id} class="attachment-inline">#{link}#{attributes}</span>}
242
+ %(<span#{span_id} class="attachment-inline">#{link}#{attributes}</span>)
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
 
@@ -261,52 +261,52 @@ module Govspeak
261
261
  #
262
262
  # This issue is not considered a bug by kramdown: https://github.com/gettalong/kramdown/issues/191
263
263
  def render_image(image)
264
- id_attr = image.id ? %{ id="attachment_#{image.id}"} : ""
264
+ id_attr = image.id ? %( id="attachment_#{image.id}") : ""
265
265
  lines = []
266
- lines << %{<figure#{id_attr} class="image embedded">}
267
- lines << %{<div class="img"><img src="#{encode(image.url)}" alt="#{encode(image.alt_text)}"></div>}
266
+ lines << %(<figure#{id_attr} class="image embedded">)
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|
283
- %{\n<div class="address"><div class="adr org fn"><p>\n#{body.sub("\n", '').gsub("\n", '<br />')}\n</p></div></div>\n}
284
- }
282
+ extension("address", surrounded_by("$A")) do |body|
283
+ %(\n<div class="address"><div class="adr org fn"><p>\n#{body.sub("\n", '').gsub("\n", '<br />')}\n</p></div></div>\n)
284
+ end
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
295
295
 
296
296
  extension("numbered list", /^[ \t]*((s\d+\.\s.*(?:\n|$))+)/) do |body|
297
297
  body.gsub!(/s(\d+)\.\s(.*)(?:\n|$)/) do
298
- "<li>#{Govspeak::Document.new($2.strip).to_html}</li>\n"
298
+ "<li>#{Govspeak::Document.new(Regexp.last_match(2).strip).to_html}</li>\n"
299
299
  end
300
- %{<ol class="steps">\n#{body}</ol>}
300
+ %(<ol class="steps">\n#{body}</ol>)
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,31 +344,31 @@ 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
- %{<govspeak-embed-attachment id="#{attachment_id}"></govspeak-embed-attachment>}
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
- %{<govspeak-embed-attachment-link id="#{attachment_id}"></govspeak-embed-attachment-link>}
371
+ %(<govspeak-embed-attachment-link id="#{attachment_id}"></govspeak-embed-attachment-link>)
372
372
  end
373
373
 
374
374
  private
@@ -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
  )