govspeak 10.6.5 → 10.8.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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +30 -2
- data/lib/govspeak/header_extractor.rb +6 -2
- data/lib/govspeak/post_processor.rb +38 -0
- data/lib/govspeak/structured_header_extractor.rb +9 -0
- data/lib/govspeak/version.rb +1 -1
- data/lib/govspeak.rb +3 -2
- data/test/govspeak_structured_headers_test.rb +51 -2
- data/test/govspeak_test.rb +44 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0920f169885278f664642da1cb6d8441a856b175779b4ad701aa966051644d25'
|
|
4
|
+
data.tar.gz: f0924a2e6574dc0b8c79ca819195368696b20b3c1e1943c3db283b98d3fada34
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 75028eeb6446acc724c97b76f8f1ccbc04447e21c2016b89abfdb4154e18bea563b5176cb5ba014ef7c60579e07311ecae50a669999f4502253ce4951c25e810
|
|
7
|
+
data.tar.gz: 884b2da2acb61aaa721201b80c67d40d57a2cc0ce517b1ff15114d8e530f37de35ab11473b4dca946ad34c8537e14eaaae9f7bc57d629228565f8f06cae4285c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 10.8.0
|
|
4
|
+
|
|
5
|
+
* feature: Allow callers to specify which headers will be auto-numbered [PR #451](https://github.com/alphagov/govspeak/pull/451)
|
|
6
|
+
|
|
7
|
+
## 10.7.0
|
|
8
|
+
|
|
9
|
+
* feature: Add auto-numbered headers option [PR #449](https://github.com/alphagov/govspeak/pull/449)
|
|
10
|
+
* fix: When finding/returning headers, filter links from header titles [PR #439](https://github.com/alphagov/govspeak/pull/439)
|
|
11
|
+
|
|
3
12
|
## 10.6.5
|
|
4
13
|
|
|
5
14
|
* Update dependencies
|
data/README.md
CHANGED
|
@@ -22,7 +22,7 @@ then create a new document
|
|
|
22
22
|
|
|
23
23
|
Some additional steps or considerations are needed to ensure changes to govspeak cascade across GOV.UK in a holistic way.
|
|
24
24
|
|
|
25
|
-
Once govspeak has been updated and version incremented then:
|
|
25
|
+
Once govspeak has been updated and version incremented then:
|
|
26
26
|
- [`govuk_publishing_components` govspeak](https://components.publishing.service.gov.uk/component-guide/govspeak) will also need updating to reflect your most recent change.
|
|
27
27
|
- [Publishing apps](https://docs.publishing.service.gov.uk/apps.html) (including but not limited to [content-publisher](https://github.com/alphagov/content-publisher) & [whitehall](https://github.com/alphagov/whitehall)) also use govspeak, these apps will need to be released with the new govspeak version present.
|
|
28
28
|
|
|
@@ -30,7 +30,7 @@ Also, consider if:
|
|
|
30
30
|
- [whitehall](https://github.com/alphagov/whitehall) needs updating (as custom govspeak changes are present)
|
|
31
31
|
- [govspeak-preview](https://github.com/alphagov/govspeak-preview) needs updating
|
|
32
32
|
|
|
33
|
-
Any pages that use govspeak to generate Content will need to *republished* in order for the new changes to be reflected.
|
|
33
|
+
Any pages that use govspeak to generate Content will need to be *republished* in order for the new changes to be reflected.
|
|
34
34
|
|
|
35
35
|
- Data Labs can help identify which pages need updating by [submitting a request](https://gov-uk.atlassian.net/wiki/spaces/GOVUK/pages/1860075525/GOV.UK+Data+Labs#Submitting-a-data-science-request) and [#govuk-2ndline](https://docs.publishing.service.gov.uk/manual/2nd-line.html) can help with republishing
|
|
36
36
|
|
|
@@ -48,6 +48,34 @@ with understanding how the content transforms from source through:
|
|
|
48
48
|
|
|
49
49
|
In addition to the [standard Markdown syntax](http://daringfireball.net/projects/markdown/syntax "Markdown syntax"), we have added our own extensions.
|
|
50
50
|
|
|
51
|
+
## Autonumbered headers
|
|
52
|
+
|
|
53
|
+
This extension is off by default, can be turned on with
|
|
54
|
+
|
|
55
|
+
doc = Govspeak::Document.new "## Header\n### Sub-header\n#### Sub-sub-header", auto_numbered_headers: true
|
|
56
|
+
|
|
57
|
+
Creates automatically numbered headers
|
|
58
|
+
|
|
59
|
+
```html
|
|
60
|
+
<h2>1 Header</h2>
|
|
61
|
+
<h3>1.1 Sub-header</h3>
|
|
62
|
+
<h4>1.1.1 Sub-sub-header</h4>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
By default the numbering scheme will work for all headers apart from H1s, if you want to
|
|
66
|
+
restrict this you can specify the levels you want in an array (default value is [2,3,4,5,6])
|
|
67
|
+
|
|
68
|
+
doc = Govspeak::Document.new "## Header\n### Sub-header\n#### Sub-sub-header", auto_numbered_headers: true, auto_numbered_header_levels: [2,3]
|
|
69
|
+
|
|
70
|
+
Creates automatically numbered headers
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<h2>1 Header</h2>
|
|
74
|
+
<h3>1.1 Sub-header</h3>
|
|
75
|
+
<h4>Sub-sub-header</h4>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
|
|
51
79
|
## Callouts
|
|
52
80
|
|
|
53
81
|
### Information callouts
|
|
@@ -20,11 +20,15 @@ module Govspeak
|
|
|
20
20
|
private
|
|
21
21
|
|
|
22
22
|
def id(element)
|
|
23
|
-
element.attr.fetch("id", generate_id(element
|
|
23
|
+
element.attr.fetch("id", generate_id(text_with_links(element)))
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def build_header(element)
|
|
27
|
-
Header.new(element
|
|
27
|
+
Header.new(text_with_links(element), element.options[:level], id(element))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def text_with_links(element)
|
|
31
|
+
element.options[:raw_text].gsub(/\[(.+)\]\((.*)\)/, '\1')
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def find_headers(parent)
|
|
@@ -160,6 +160,44 @@ module Govspeak
|
|
|
160
160
|
end
|
|
161
161
|
end
|
|
162
162
|
|
|
163
|
+
extension("use auto-numbered headers") do |document|
|
|
164
|
+
if govspeak_document.auto_numbered_headers
|
|
165
|
+
h2, h3, h4, h5, h6 = 0, 0, 0, 0, 0, 0
|
|
166
|
+
|
|
167
|
+
selector = govspeak_document.auto_numbered_header_levels.map { |i| "h#{i}" }.join(",")
|
|
168
|
+
|
|
169
|
+
document.css(selector).map do |el|
|
|
170
|
+
case el.name
|
|
171
|
+
when "h2"
|
|
172
|
+
h2 += 1
|
|
173
|
+
h3 = 0
|
|
174
|
+
h4 = 0
|
|
175
|
+
h5 = 0
|
|
176
|
+
h6 = 0
|
|
177
|
+
el.inner_html = "#{h2}. #{el.inner_html}"
|
|
178
|
+
when "h3"
|
|
179
|
+
h3 += 1
|
|
180
|
+
h4 = 0
|
|
181
|
+
h5 = 0
|
|
182
|
+
h6 = 0
|
|
183
|
+
el.inner_html = "#{h2}.#{h3} #{el.inner_html}"
|
|
184
|
+
when "h4"
|
|
185
|
+
h4 += 1
|
|
186
|
+
h5 = 0
|
|
187
|
+
h6 = 0
|
|
188
|
+
el.inner_html = "#{h2}.#{h3}.#{h4} #{el.inner_html}"
|
|
189
|
+
when "h5"
|
|
190
|
+
h5 += 1
|
|
191
|
+
h6 = 0
|
|
192
|
+
el.inner_html = "#{h2}.#{h3}.#{h4}.#{h5} #{el.inner_html}"
|
|
193
|
+
when "h6"
|
|
194
|
+
h6 += 1
|
|
195
|
+
el.inner_html = "#{h2}.#{h3}.#{h4}.#{h5}.#{h6} #{el.inner_html}"
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
163
201
|
attr_reader :input, :govspeak_document
|
|
164
202
|
|
|
165
203
|
def initialize(html, govspeak_document)
|
|
@@ -41,6 +41,8 @@ module Govspeak
|
|
|
41
41
|
stack.push(header)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
add_auto_numbering(structured_headers, doc.auto_numbered_header_levels) if doc.auto_numbered_headers
|
|
45
|
+
|
|
44
46
|
structured_headers
|
|
45
47
|
end
|
|
46
48
|
|
|
@@ -96,6 +98,13 @@ module Govspeak
|
|
|
96
98
|
@stack = []
|
|
97
99
|
end
|
|
98
100
|
|
|
101
|
+
def add_auto_numbering(structured_headers, levels, prefix: "")
|
|
102
|
+
structured_headers.each.with_index(1) do |header, index|
|
|
103
|
+
header[:text] = "#{prefix}#{index}#{'.' if prefix == ''} #{header[:text]}" if levels.include?(header[:level])
|
|
104
|
+
add_auto_numbering(header[:headers], levels, prefix: "#{prefix}#{index}.")
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
99
108
|
private
|
|
100
109
|
|
|
101
110
|
attr_reader :doc, :stack, :structured_headers
|
data/lib/govspeak/version.rb
CHANGED
data/lib/govspeak.rb
CHANGED
|
@@ -38,7 +38,7 @@ module Govspeak
|
|
|
38
38
|
@extensions = []
|
|
39
39
|
|
|
40
40
|
attr_accessor :images
|
|
41
|
-
attr_reader :attachments, :contacts, :links, :locale, :log_snapshots
|
|
41
|
+
attr_reader :attachments, :auto_numbered_headers, :auto_numbered_header_levels, :contacts, :links, :locale, :log_snapshots
|
|
42
42
|
|
|
43
43
|
def self.to_html(source, options = {})
|
|
44
44
|
new(source, options).to_html
|
|
@@ -55,11 +55,12 @@ module Govspeak
|
|
|
55
55
|
@log_snapshots = options.fetch(:log_snapshots, false)
|
|
56
56
|
log_snapshot("options", options)
|
|
57
57
|
log_snapshot("source", @source)
|
|
58
|
-
|
|
59
58
|
@images = options.delete(:images) || []
|
|
60
59
|
@allowed_elements = options.delete(:allowed_elements) || []
|
|
61
60
|
@allowed_image_hosts = options.delete(:allowed_image_hosts) || []
|
|
62
61
|
@attachments = Array.wrap(options.delete(:attachments))
|
|
62
|
+
@auto_numbered_headers = options.fetch(:auto_numbered_headers, false)
|
|
63
|
+
@auto_numbered_header_levels = options.delete(:auto_numbered_header_levels) || [2, 3, 4, 5, 6]
|
|
63
64
|
@links = Array.wrap(options.delete(:links))
|
|
64
65
|
@contacts = Array.wrap(options.delete(:contacts))
|
|
65
66
|
@locale = options.fetch(:locale, "en")
|
|
@@ -21,14 +21,16 @@ class GovspeakStructuredHeadersTest < Minitest::Test
|
|
|
21
21
|
|
|
22
22
|
### Sub heading 4.1
|
|
23
23
|
|
|
24
|
-
#### Sub heading 4.1.1
|
|
24
|
+
#### Sub sub heading 4.1.1
|
|
25
25
|
|
|
26
|
-
##### Sub heading 4.1.1.1
|
|
26
|
+
##### Sub sub sub heading 4.1.1.1
|
|
27
27
|
|
|
28
28
|
### Sub heading 4.2
|
|
29
29
|
|
|
30
30
|
## Heading 5
|
|
31
31
|
|
|
32
|
+
### [Sub heading 5.1](https://www.example.com)
|
|
33
|
+
|
|
32
34
|
)
|
|
33
35
|
end
|
|
34
36
|
|
|
@@ -67,6 +69,11 @@ class GovspeakStructuredHeadersTest < Minitest::Test
|
|
|
67
69
|
assert_equal "Sub heading 4.2", structured_headers[3].headers[1].text
|
|
68
70
|
end
|
|
69
71
|
|
|
72
|
+
test "headers that are links are based on the link text not the link" do
|
|
73
|
+
assert_equal "Sub heading 5.1", structured_headers[4].headers[0].text
|
|
74
|
+
assert_equal "sub-heading-51", structured_headers[4].headers[0].id
|
|
75
|
+
end
|
|
76
|
+
|
|
70
77
|
test "structured headers serialize to hashes recursively serializing sub headers" do
|
|
71
78
|
serialized_headers = structured_headers[1].to_h
|
|
72
79
|
|
|
@@ -138,4 +145,46 @@ class GovspeakStructuredHeadersTest < Minitest::Test
|
|
|
138
145
|
test "document with single h1 produces no headers" do
|
|
139
146
|
assert_equal [], Govspeak::Document.new("# Heading\n").structured_headers
|
|
140
147
|
end
|
|
148
|
+
|
|
149
|
+
test "auto-numbered headers are generated when the option is set on the document" do
|
|
150
|
+
doc = Govspeak::Document.new(document_body, auto_numbered_headers: true)
|
|
151
|
+
|
|
152
|
+
headers = doc.structured_headers
|
|
153
|
+
|
|
154
|
+
assert_equal "1. Heading 1", headers[0][:text]
|
|
155
|
+
assert_equal "2. Heading 2", headers[1][:text]
|
|
156
|
+
assert_equal "2.1 Sub heading 2.1", headers[1][:headers][0][:text]
|
|
157
|
+
assert_equal "2.2 Sub heading 2.2", headers[1][:headers][1][:text]
|
|
158
|
+
assert_equal "2.2.1 Sub sub heading 2.2.1", headers[1][:headers][1][:headers][0][:text]
|
|
159
|
+
assert_equal "2.3 Sub heading 2.3", headers[1][:headers][2][:text]
|
|
160
|
+
assert_equal "3. Heading 3", headers[2][:text]
|
|
161
|
+
assert_equal "4. Heading 4", headers[3][:text]
|
|
162
|
+
assert_equal "4.1 Sub heading 4.1", headers[3][:headers][0][:text]
|
|
163
|
+
assert_equal "4.1.1 Sub sub heading 4.1.1", headers[3][:headers][0][:headers][0][:text]
|
|
164
|
+
assert_equal "4.1.1.1 Sub sub sub heading 4.1.1.1", headers[3][:headers][0][:headers][0][:headers][0][:text]
|
|
165
|
+
assert_equal "4.2 Sub heading 4.2", headers[3][:headers][1][:text]
|
|
166
|
+
assert_equal "5. Heading 5", headers[4][:text]
|
|
167
|
+
assert_equal "5.1 Sub heading 5.1", headers[4][:headers][0][:text]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
test "auto-numbered headers are restricted to appropriate levels when the option is set on the document" do
|
|
171
|
+
doc = Govspeak::Document.new(document_body, auto_numbered_headers: true, auto_numbered_header_levels: [2, 3])
|
|
172
|
+
|
|
173
|
+
headers = doc.structured_headers
|
|
174
|
+
|
|
175
|
+
assert_equal "1. Heading 1", headers[0][:text]
|
|
176
|
+
assert_equal "2. Heading 2", headers[1][:text]
|
|
177
|
+
assert_equal "2.1 Sub heading 2.1", headers[1][:headers][0][:text]
|
|
178
|
+
assert_equal "2.2 Sub heading 2.2", headers[1][:headers][1][:text]
|
|
179
|
+
assert_equal "Sub sub heading 2.2.1", headers[1][:headers][1][:headers][0][:text]
|
|
180
|
+
assert_equal "2.3 Sub heading 2.3", headers[1][:headers][2][:text]
|
|
181
|
+
assert_equal "3. Heading 3", headers[2][:text]
|
|
182
|
+
assert_equal "4. Heading 4", headers[3][:text]
|
|
183
|
+
assert_equal "4.1 Sub heading 4.1", headers[3][:headers][0][:text]
|
|
184
|
+
assert_equal "Sub sub heading 4.1.1", headers[3][:headers][0][:headers][0][:text]
|
|
185
|
+
assert_equal "Sub sub sub heading 4.1.1.1", headers[3][:headers][0][:headers][0][:headers][0][:text]
|
|
186
|
+
assert_equal "4.2 Sub heading 4.2", headers[3][:headers][1][:text]
|
|
187
|
+
assert_equal "5. Heading 5", headers[4][:text]
|
|
188
|
+
assert_equal "5.1 Sub heading 5.1", headers[4][:headers][0][:text]
|
|
189
|
+
end
|
|
141
190
|
end
|
data/test/govspeak_test.rb
CHANGED
|
@@ -99,6 +99,50 @@ class GovspeakTest < Minitest::Test
|
|
|
99
99
|
assert_equal "foo bar baz", doc.to_text
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
+
test "adds auto-numbered headings when the auto_numbered_headings option is on" do
|
|
103
|
+
input = %(
|
|
104
|
+
## H2 One
|
|
105
|
+
|
|
106
|
+
### H3 One
|
|
107
|
+
|
|
108
|
+
### H3 Two
|
|
109
|
+
|
|
110
|
+
## H2 Two
|
|
111
|
+
|
|
112
|
+
### H3 Three
|
|
113
|
+
|
|
114
|
+
#### H4 One
|
|
115
|
+
|
|
116
|
+
##### H5 One
|
|
117
|
+
|
|
118
|
+
###### H6 One
|
|
119
|
+
)
|
|
120
|
+
doc = Govspeak::Document.new(input, auto_numbered_headers: true)
|
|
121
|
+
assert_equal %(\n<h2 id="h2-one">1. H2 One</h2>\n\n<h3 id="h3-one">1.1 H3 One</h3>\n\n<h3 id="h3-two">1.2 H3 Two</h3>\n\n<h2 id="h2-two">2. H2 Two</h2>\n\n<h3 id="h3-three">2.1 H3 Three</h3>\n\n<h4 id="h4-one">2.1.1 H4 One</h4>\n\n<h5 id="h5-one">2.1.1.1 H5 One</h5>\n\n<h6 id="h6-one">2.1.1.1.1 H6 One</h6>\n), doc.to_html
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
test "restricts auto-numbered headings to specified levels when the auto_numbered_heading_levels option is set" do
|
|
125
|
+
input = %(
|
|
126
|
+
## H2 One
|
|
127
|
+
|
|
128
|
+
### H3 One
|
|
129
|
+
|
|
130
|
+
### H3 Two
|
|
131
|
+
|
|
132
|
+
## H2 Two
|
|
133
|
+
|
|
134
|
+
### H3 Three
|
|
135
|
+
|
|
136
|
+
#### H4 One
|
|
137
|
+
|
|
138
|
+
##### H5 One
|
|
139
|
+
|
|
140
|
+
###### H6 One
|
|
141
|
+
)
|
|
142
|
+
doc = Govspeak::Document.new(input, auto_numbered_headers: true, auto_numbered_header_levels: [2, 3])
|
|
143
|
+
assert_equal %(\n<h2 id="h2-one">1. H2 One</h2>\n\n<h3 id="h3-one">1.1 H3 One</h3>\n\n<h3 id="h3-two">1.2 H3 Two</h3>\n\n<h2 id="h2-two">2. H2 Two</h2>\n\n<h3 id="h3-three">2.1 H3 Three</h3>\n\n<h4 id="h4-one">H4 One</h4>\n\n<h5 id="h5-one">H5 One</h5>\n\n<h6 id="h6-one">H6 One</h6>\n), doc.to_html
|
|
144
|
+
end
|
|
145
|
+
|
|
102
146
|
test "trailing space after the address should not prevent parsing" do
|
|
103
147
|
input = %($A
|
|
104
148
|
123 Test Street
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: govspeak
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 10.
|
|
4
|
+
version: 10.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GOV.UK Dev
|
|
@@ -18,7 +18,7 @@ dependencies:
|
|
|
18
18
|
version: '6'
|
|
19
19
|
- - "<"
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: 8.
|
|
21
|
+
version: 8.1.2
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -28,7 +28,7 @@ dependencies:
|
|
|
28
28
|
version: '6'
|
|
29
29
|
- - "<"
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
|
-
version: 8.
|
|
31
|
+
version: 8.1.2
|
|
32
32
|
- !ruby/object:Gem::Dependency
|
|
33
33
|
name: addressable
|
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|