govspeak 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +7 -0
- data/Rakefile +15 -0
- data/lib/govspeak.rb +118 -0
- data/test/govspeak_test.rb +171 -0
- data/test/test_helper.rb +20 -0
- metadata +77 -0
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
Bundler::GemHelper.install_tasks
|
6
|
+
|
7
|
+
task :default => [:test_units]
|
8
|
+
|
9
|
+
desc "Run basic tests"
|
10
|
+
Rake::TestTask.new("test_units") { |t|
|
11
|
+
t.libs << "test"
|
12
|
+
t.pattern = 'test/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
t.warning = true
|
15
|
+
}
|
data/lib/govspeak.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
|
3
|
+
module Govspeak
|
4
|
+
|
5
|
+
class Document
|
6
|
+
|
7
|
+
@@extensions = []
|
8
|
+
|
9
|
+
def self.to_html(source, options = {})
|
10
|
+
new(source, options).to_html
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(source, options = {})
|
14
|
+
source ||= ""
|
15
|
+
options[:entity_output] ||= :symbolic
|
16
|
+
@doc = Kramdown::Document.new(preprocess(source), options)
|
17
|
+
super()
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_html
|
21
|
+
@doc.to_html
|
22
|
+
end
|
23
|
+
|
24
|
+
def preprocess(source)
|
25
|
+
@@extensions.each do |title,regexp,block|
|
26
|
+
source.gsub!(regexp) {|match|
|
27
|
+
block.call($1)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
source
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.extension(title, regexp = nil, &block)
|
34
|
+
regexp ||= %r${::#{title}}(.*?){:/#{title}}$m
|
35
|
+
@@extensions << [title, regexp, block]
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.surrounded_by(open, close=nil)
|
39
|
+
open = Regexp::escape(open)
|
40
|
+
if close
|
41
|
+
close = Regexp::escape(close)
|
42
|
+
%r+(?:\r|\n|^)#{open}(.*?)#{close}(\r|\n|$)?+m
|
43
|
+
else
|
44
|
+
%r+(?:\r|\n|^)#{open}(.*?)#{open}?(\r|\n|$)+m
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.wrap_with_div(class_name, character, parser=Kramdown::Document)
|
49
|
+
extension(class_name, surrounded_by(character)) { |body|
|
50
|
+
content = parser ? parser.new("#{body.strip}\n").to_html : body.strip
|
51
|
+
%{<div class="#{class_name}">\n#{content}</div>\n}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
extension('reverse') { |body|
|
56
|
+
body.reverse
|
57
|
+
}
|
58
|
+
|
59
|
+
extension('external', surrounded_by("x")) { |body|
|
60
|
+
Kramdown::Document.new("#{body.strip}{:rel='external'}").to_html
|
61
|
+
}
|
62
|
+
|
63
|
+
extension('informational', surrounded_by("^")) { |body|
|
64
|
+
%{\n\n<div class="application-notice info-notice">
|
65
|
+
#{Kramdown::Document.new(body.strip).to_html}</div>\n}
|
66
|
+
}
|
67
|
+
|
68
|
+
extension('important', surrounded_by("@")) { |body|
|
69
|
+
%{\n\n<h3 class="advisory"><span>#{body.strip}</span></h3>\n}
|
70
|
+
}
|
71
|
+
|
72
|
+
extension('helpful', surrounded_by("%")) { |body|
|
73
|
+
%{\n\n<div class="application-notice help-notice">\n<p>#{body.strip}</p>\n</div>\n}
|
74
|
+
}
|
75
|
+
|
76
|
+
extension('map_link', surrounded_by("((", "))")) { |body|
|
77
|
+
%{<div class="map"><iframe width="200" height="200" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="#{body.strip}&output=embed"></iframe><br /><small><a href="#{body.strip}">View Larger Map</a></small></div>}
|
78
|
+
}
|
79
|
+
|
80
|
+
wrap_with_div('summary', '$!')
|
81
|
+
wrap_with_div('form-download', '$D')
|
82
|
+
wrap_with_div('contact', '$C')
|
83
|
+
wrap_with_div('place', '$P', Govspeak::Document)
|
84
|
+
wrap_with_div('information', '$I', Govspeak::Document)
|
85
|
+
wrap_with_div('additional-information', '$AI')
|
86
|
+
wrap_with_div('example', '$E', Govspeak::Document)
|
87
|
+
|
88
|
+
extension('address', surrounded_by("$A")) { |body|
|
89
|
+
%{<div class="address vcard"><div class="adr org fn"><p>\n#{body.sub("\n", "").gsub("\n", "<br />")}\n</p></div></div>\n}
|
90
|
+
}
|
91
|
+
|
92
|
+
extension("numbered list", /((s\d+\.\s.*(?:\n|$))+)/) do |body|
|
93
|
+
steps ||= 0
|
94
|
+
body.gsub!(/s(\d+)\.\s(.*)(?:\n|$)/) do |b|
|
95
|
+
"<li>#{Kramdown::Document.new($2.strip).to_html}</li>\n"
|
96
|
+
end
|
97
|
+
%{<ol class="steps">\n#{body}</ol>}
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.devolved_options
|
101
|
+
{ 'scotland' => 'Scotland',
|
102
|
+
'england' => 'England',
|
103
|
+
'england-wales' => 'England and Wales',
|
104
|
+
'northern-ireland' => 'Northern Ireland',
|
105
|
+
'wales' => 'Wales',
|
106
|
+
'london' => 'London' }
|
107
|
+
end
|
108
|
+
|
109
|
+
devolved_options.each do |k,v|
|
110
|
+
extension("devolved-#{k}",/:#{k}:(.*?):#{k}:/m) do |body|
|
111
|
+
%{<div class="devolved-content #{k}">
|
112
|
+
<p class="devolved-header">This section applies to #{v}</p>
|
113
|
+
<div class="devolved-body">#{Kramdown::Document.new(body.strip).to_html}</div>
|
114
|
+
</div>\n}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'simplecov-rcov'
|
3
|
+
|
4
|
+
SimpleCov.start
|
5
|
+
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
|
6
|
+
|
7
|
+
require 'test_helper'
|
8
|
+
|
9
|
+
class GovspeakTest < Test::Unit::TestCase
|
10
|
+
|
11
|
+
test "simple smoke-test" do
|
12
|
+
rendered = Govspeak::Document.new("*this is markdown*").to_html
|
13
|
+
assert_equal "<p><em>this is markdown</em></p>\n", rendered
|
14
|
+
end
|
15
|
+
|
16
|
+
test "simple smoke-test for simplified API" do
|
17
|
+
rendered = Govspeak::Document.to_html("*this is markdown*")
|
18
|
+
assert_equal "<p><em>this is markdown</em></p>\n", rendered
|
19
|
+
end
|
20
|
+
|
21
|
+
test "simple block extension" do
|
22
|
+
rendered = Govspeak::Document.new("this \n{::reverse}\n*is*\n{:/reverse}\n markdown").to_html
|
23
|
+
assert_equal "<p>this </p>\n\n<p><em>si</em></p>\n\n<p>markdown</p>\n", rendered
|
24
|
+
end
|
25
|
+
|
26
|
+
test "govspark extensions" do
|
27
|
+
markdown_regression_tests = [
|
28
|
+
{
|
29
|
+
input: "^ I am very informational ^",
|
30
|
+
output: %{<div class="application-notice info-notice">
|
31
|
+
<p>I am very informational</p>
|
32
|
+
</div>}
|
33
|
+
}, {
|
34
|
+
input: "The following is very informational\n^ I am very informational ^",
|
35
|
+
output: %{<p>The following is very informational</p>
|
36
|
+
|
37
|
+
<div class="application-notice info-notice">
|
38
|
+
<p>I am very informational</p>
|
39
|
+
</div>}
|
40
|
+
}, {
|
41
|
+
input: "^ I am very informational",
|
42
|
+
output: %{<div class="application-notice info-notice">
|
43
|
+
<p>I am very informational</p>
|
44
|
+
</div>}
|
45
|
+
}, {
|
46
|
+
input: "@ I am very important @",
|
47
|
+
output: %{<h3 class="advisory"><span>I am very important</span></h3>}
|
48
|
+
}, {
|
49
|
+
input: "The following is very important
|
50
|
+
@ I am very important @",
|
51
|
+
output: %{<p>The following is very important</p>
|
52
|
+
|
53
|
+
<h3 class="advisory"><span>I am very important</span></h3>}
|
54
|
+
}, {
|
55
|
+
input: "% I am very helpful %",
|
56
|
+
output: %{<div class="application-notice help-notice">
|
57
|
+
<p>I am very helpful</p>
|
58
|
+
</div>}
|
59
|
+
}, {
|
60
|
+
input: "The following is very helpful\n% I am very helpful %",
|
61
|
+
output: %{<p>The following is very helpful</p>
|
62
|
+
|
63
|
+
<div class="application-notice help-notice">
|
64
|
+
<p>I am very helpful</p>
|
65
|
+
</div>}
|
66
|
+
}, {
|
67
|
+
input: "## Hello ##\n\n% I am very helpful %\r\n### Young Workers ###\n\n",
|
68
|
+
output: %{<h2 id="hello">Hello</h2>
|
69
|
+
|
70
|
+
<div class="application-notice help-notice">
|
71
|
+
<p>I am very helpful</p>
|
72
|
+
</div>
|
73
|
+
|
74
|
+
<h3 id="young-workers">Young Workers</h3>}
|
75
|
+
}, {
|
76
|
+
input: "% I am very helpful",
|
77
|
+
output: %{<div class="application-notice help-notice">
|
78
|
+
<p>I am very helpful</p>
|
79
|
+
</div>}
|
80
|
+
}, {
|
81
|
+
input: "This is a [link](http://www.google.com) isn't it?",
|
82
|
+
output: '<p>This is a <a href="http://www.google.com">link</a> isn’t it?</p>'
|
83
|
+
}, {
|
84
|
+
input: "This is a [link with an at sign in it](http://www.google.com/@dg/@this) isn't it?",
|
85
|
+
output: '<p>This is a <a href="http://www.google.com/@dg/@this">link with an at sign in it</a> isn’t it?</p>'
|
86
|
+
}, {
|
87
|
+
input: "HTML
|
88
|
+
|
89
|
+
*[HTML]: Hyper Text Markup Language",
|
90
|
+
output: %{<p><abbr title="Hyper Text Markup Language">HTML</abbr></p>}
|
91
|
+
}, {
|
92
|
+
input: "x[a link](http://rubyforge.org)x",
|
93
|
+
output: '<p><a href="http://rubyforge.org" rel="external">a link</a></p>'
|
94
|
+
}, {
|
95
|
+
input: "$!
|
96
|
+
rainbow
|
97
|
+
$!",
|
98
|
+
output: %{<div class="summary">
|
99
|
+
<p>rainbow</p>
|
100
|
+
</div>}
|
101
|
+
}, {
|
102
|
+
input: "$C help, send cake $C",
|
103
|
+
output: %{<div class="contact">
|
104
|
+
<p>help, send cake</p>
|
105
|
+
</div>}
|
106
|
+
}, {
|
107
|
+
input: "$A
|
108
|
+
street
|
109
|
+
road
|
110
|
+
$A",
|
111
|
+
output: %{<div class="address vcard"><div class="adr org fn"><p>
|
112
|
+
street<br />road<br />
|
113
|
+
</p></div></div>}
|
114
|
+
}, {
|
115
|
+
input: "$P
|
116
|
+
$I
|
117
|
+
help
|
118
|
+
$I
|
119
|
+
$P",
|
120
|
+
output: %{<div class="place">\n<div class="information">\n<p>help</p>\n</div>\n</div>}
|
121
|
+
}, {
|
122
|
+
input: "$D
|
123
|
+
can you tell me how to get to...
|
124
|
+
$D",
|
125
|
+
output: %{<div class="form-download">
|
126
|
+
<p>can you tell me how to get to…</p>
|
127
|
+
</div>}
|
128
|
+
}, {
|
129
|
+
input: "1. rod
|
130
|
+
2. jane
|
131
|
+
3. freddy",
|
132
|
+
output: "<ol>\n <li>rod</li>\n <li>jane</li>\n <li>freddy</li>\n</ol>"
|
133
|
+
}, {
|
134
|
+
input: "
|
135
|
+
((http://maps.google.co.uk/maps?q=Winkfield+Rd,+Windsor,+Berkshire+SL4+4AY&hl=en&sll=53.800651,-4.064941&sspn=17.759517,42.055664&vpsrc=0&z=14))
|
136
|
+
",
|
137
|
+
output: %{<div class="map"><iframe width="200" height="200" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://maps.google.co.uk/maps?q=Winkfield+Rd,+Windsor,+Berkshire+SL4+4AY&hl=en&sll=53.800651,-4.064941&sspn=17.759517,42.055664&vpsrc=0&z=14&output=embed"></iframe><br /><small><a href="http://maps.google.co.uk/maps?q=Winkfield+Rd,+Windsor,+Berkshire+SL4+4AY&hl=en&sll=53.800651,-4.064941&sspn=17.759517,42.055664&vpsrc=0&z=14">View Larger Map</a></small></div>}
|
138
|
+
}, {
|
139
|
+
input: "s1. zippy
|
140
|
+
s2. bungle
|
141
|
+
s3. george
|
142
|
+
",
|
143
|
+
output: %{<ol class="steps">
|
144
|
+
<li><p>zippy</p>\n</li>
|
145
|
+
<li><p>bungle</p>\n</li>
|
146
|
+
<li><p>george</p>\n</li>
|
147
|
+
</ol>}
|
148
|
+
}
|
149
|
+
]
|
150
|
+
|
151
|
+
markdown_regression_tests.each do |t|
|
152
|
+
rendered = Govspeak::Document.new(t[:input]).to_html
|
153
|
+
assert_equal t[:output].strip, rendered.strip
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
test "devolved markdown sections" do
|
159
|
+
input = ":scotland: I am very devolved \n and very scottish \n:scotland:"
|
160
|
+
output = '<div class="devolved-content scotland">
|
161
|
+
<p class="devolved-header">This section applies to Scotland</p>
|
162
|
+
<div class="devolved-body"><p>I am very devolved
|
163
|
+
and very scottish</p>
|
164
|
+
</div>
|
165
|
+
</div>
|
166
|
+
'
|
167
|
+
|
168
|
+
assert_equal output, Govspeak::Document.new(input).to_html
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$:.unshift(File.expand_path("../lib")) unless $:.include?(File.expand_path("../lib"))
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.setup :default, :development, :test
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
|
8
|
+
class Test::Unit::TestCase
|
9
|
+
class << self
|
10
|
+
def test(name, &block)
|
11
|
+
clean_name = name.gsub(/\s+/,'_')
|
12
|
+
method = "test_#{clean_name.gsub(/\s+/,'_')}".to_sym
|
13
|
+
already_defined = instance_method(method) rescue false
|
14
|
+
raise "#{method} exists" if already_defined
|
15
|
+
define_method(method, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'govspeak'
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: govspeak
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.4
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ben Griffiths
|
9
|
+
- James Stewart
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2011-11-01 00:00:00.000000000Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: kramdown
|
17
|
+
requirement: &70159122835620 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.13.3
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70159122835620
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rake
|
28
|
+
requirement: &70159122835160 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.8.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70159122835160
|
37
|
+
description: ! "A set of extensions to markdown layered on top of the kramdown \nlibrary
|
38
|
+
for use in the UK Government Single Domain project"
|
39
|
+
email:
|
40
|
+
- ben@alphagov.co.uk
|
41
|
+
- james.stewart@digital.cabinet-office.gov.uk
|
42
|
+
executables: []
|
43
|
+
extensions: []
|
44
|
+
extra_rdoc_files: []
|
45
|
+
files:
|
46
|
+
- lib/govspeak.rb
|
47
|
+
- Gemfile
|
48
|
+
- Rakefile
|
49
|
+
- test/govspeak_test.rb
|
50
|
+
- test/test_helper.rb
|
51
|
+
homepage: http://github.com/alphagov/govspeak
|
52
|
+
licenses: []
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.8.10
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Markup language for single domain
|
75
|
+
test_files:
|
76
|
+
- test/govspeak_test.rb
|
77
|
+
- test/test_helper.rb
|