doc_repo 0.1.1 → 1.0.0.pre.beta.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 +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +4 -4
- data/CHANGELOG.md +47 -0
- data/Gemfile +5 -0
- data/README.md +282 -16
- data/benchmarks/digests.rb +55 -0
- data/doc_repo.gemspec +5 -5
- data/lib/doc_repo/configuration.rb +65 -4
- data/lib/doc_repo/doc.rb +84 -0
- data/lib/doc_repo/error.rb +14 -0
- data/lib/doc_repo/gateway_error.rb +37 -0
- data/lib/doc_repo/http_error.rb +32 -0
- data/lib/doc_repo/http_result.rb +29 -0
- data/lib/doc_repo/net_http_adapter.rb +203 -0
- data/lib/doc_repo/rails/legacy_versioned_cache.rb +19 -0
- data/lib/doc_repo/rails.rb +37 -0
- data/lib/doc_repo/redirect.rb +19 -0
- data/lib/doc_repo/repository.rb +72 -20
- data/lib/doc_repo/result_handler.rb +30 -0
- data/lib/doc_repo/version.rb +1 -1
- data/lib/doc_repo.rb +20 -17
- data/spec/doc_repo/configuration_spec.rb +86 -31
- data/spec/doc_repo/doc_spec.rb +442 -0
- data/spec/doc_repo/net_http_adapter_spec.rb +435 -0
- data/spec/doc_repo/repository_spec.rb +325 -13
- data/spec/doc_repo/result_handler_spec.rb +43 -0
- data/spec/doc_repo_spec.rb +25 -3
- data/spec/spec_helper.rb +88 -3
- data/spec/support/in_memory_cache.rb +33 -0
- metadata +33 -20
- data/lib/doc_repo/github_file.rb +0 -45
- data/lib/doc_repo/page.rb +0 -35
- data/lib/doc_repo/response.rb +0 -25
- data/spec/doc_repo/page_spec.rb +0 -44
- data/spec/doc_repo/response_spec.rb +0 -19
@@ -1,55 +1,110 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe DocRepo::Configuration do
|
4
4
|
|
5
|
-
|
5
|
+
shared_examples "has setting" do |setting_name|
|
6
|
+
it "allows configuring `#{setting_name}`" do
|
7
|
+
a_config = DocRepo::Configuration.new
|
8
|
+
expect {
|
9
|
+
a_config.public_send "#{setting_name}=", "Any Value"
|
10
|
+
}.to change(a_config, setting_name).to "Any Value"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "new configuration" do
|
6
15
|
subject(:default_config) { DocRepo::Configuration.new }
|
7
16
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
'DOC_REPO_REPONAME' => nil,
|
12
|
-
'DOC_REPO_BRANCH' => nil,
|
13
|
-
}
|
14
|
-
using_env(env, &example)
|
17
|
+
it "yields itself when given a block" do
|
18
|
+
a_config = DocRepo::Configuration.new { |c| c.repo = "Any Repo" }
|
19
|
+
expect(a_config.repo).to eq "Any Repo"
|
15
20
|
end
|
16
21
|
|
17
|
-
it "
|
18
|
-
expect(default_config.
|
22
|
+
it "defaults to the 'master' branch" do
|
23
|
+
expect(default_config.branch).to eq 'master'
|
19
24
|
end
|
20
25
|
|
21
|
-
it "
|
22
|
-
expect(default_config.
|
26
|
+
it "defaults to empty cache options" do
|
27
|
+
expect(default_config.cache_options).to eq({})
|
23
28
|
end
|
24
29
|
|
25
|
-
it "
|
26
|
-
expect(default_config.
|
30
|
+
it "defaults to a null cache store" do
|
31
|
+
expect(default_config.cache_store).to be DocRepo::NullCache.instance
|
32
|
+
end
|
33
|
+
|
34
|
+
it "defaults to markdown and HTML as documentation formats" do
|
35
|
+
expect(default_config.doc_formats).to match_array %w[
|
36
|
+
.md
|
37
|
+
.markdown
|
38
|
+
.htm
|
39
|
+
.html
|
40
|
+
]
|
27
41
|
end
|
28
|
-
end
|
29
42
|
|
30
|
-
|
31
|
-
|
43
|
+
it "defaults to a 'docs' root path" do
|
44
|
+
expect(default_config.doc_root).to eq 'docs'
|
45
|
+
end
|
32
46
|
|
33
|
-
|
34
|
-
|
35
|
-
'DOC_REPO_ORG' => 'the-silence',
|
36
|
-
'DOC_REPO_REPONAME' => 'falls',
|
37
|
-
'DOC_REPO_BRANCH' => 'ask_the_question',
|
38
|
-
}
|
39
|
-
using_env(env, &example)
|
47
|
+
it "defaults to '.md' for the fallback extension" do
|
48
|
+
expect(default_config.fallback_ext).to eq '.md'
|
40
49
|
end
|
41
50
|
|
42
|
-
it "
|
43
|
-
expect(
|
51
|
+
it "has no org set" do
|
52
|
+
expect(default_config.org).to be nil
|
44
53
|
end
|
45
54
|
|
46
|
-
it "
|
47
|
-
expect(
|
55
|
+
it "has no repo set" do
|
56
|
+
expect(default_config.repo).to be nil
|
48
57
|
end
|
49
58
|
|
50
|
-
it "
|
51
|
-
expect(
|
59
|
+
it "converting to a hash includes all settings" do
|
60
|
+
expect(default_config.to_h.keys).to match_array %i[
|
61
|
+
branch
|
62
|
+
cache_options
|
63
|
+
cache_store
|
64
|
+
doc_formats
|
65
|
+
doc_root
|
66
|
+
fallback_ext
|
67
|
+
org
|
68
|
+
repo
|
69
|
+
]
|
52
70
|
end
|
53
71
|
end
|
54
72
|
|
73
|
+
include_examples "has setting", :branch
|
74
|
+
include_examples "has setting", :cache_options
|
75
|
+
include_examples "has setting", :cache_store
|
76
|
+
include_examples "has setting", :doc_formats
|
77
|
+
include_examples "has setting", :doc_root
|
78
|
+
include_examples "has setting", :fallback_ext
|
79
|
+
include_examples "has setting", :org
|
80
|
+
include_examples "has setting", :repo
|
81
|
+
|
82
|
+
it "converting to a hash maps all settings to configured values" do
|
83
|
+
a_config = DocRepo::Configuration.new
|
84
|
+
a_config.branch = "Any Branch"
|
85
|
+
a_config.cache_options = "Any Cache Options"
|
86
|
+
a_config.cache_store = "Any Cache Store"
|
87
|
+
a_config.doc_formats = %w[ .any .formats ]
|
88
|
+
a_config.doc_root = "Any Doc Root"
|
89
|
+
a_config.fallback_ext = ".anything"
|
90
|
+
a_config.org = "Any Org"
|
91
|
+
a_config.repo = "Any Repo"
|
92
|
+
expect(a_config.to_h).to eq(
|
93
|
+
branch: "Any Branch",
|
94
|
+
cache_options: "Any Cache Options",
|
95
|
+
cache_store: "Any Cache Store",
|
96
|
+
doc_formats: %w[ .any .formats ],
|
97
|
+
doc_root: "Any Doc Root",
|
98
|
+
fallback_ext: ".anything",
|
99
|
+
org: "Any Org",
|
100
|
+
repo: "Any Repo",
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "doesn't allow creating new settings" do
|
105
|
+
expect {
|
106
|
+
DocRepo::Configuration.add_setting :new_setting
|
107
|
+
}.to raise_error NoMethodError
|
108
|
+
end
|
109
|
+
|
55
110
|
end
|
@@ -0,0 +1,442 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
RSpec.describe DocRepo::Doc do
|
5
|
+
|
6
|
+
context "a standard document", "with cachable content" do
|
7
|
+
subject(:a_document) {
|
8
|
+
DocRepo::Doc.new("/any/uri", any_http_ok_response)
|
9
|
+
}
|
10
|
+
|
11
|
+
let(:any_http_ok_response) {
|
12
|
+
instance_double("Net::HTTPOK", code: "200", body: "Any Content Body").tap { |dbl|
|
13
|
+
allow(dbl).to receive(:[]) { |key| response_cache_headers[key] }
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
let(:response_cache_headers) {
|
18
|
+
# Make string keys mutable to allow testing mutations
|
19
|
+
{
|
20
|
+
"Last-Modified" => String.new("Sat, 01 Jul 2017 18:18:33 GMT"),
|
21
|
+
"Content-Type" => String.new("text/plain"),
|
22
|
+
"Cache-Control" => String.new("max-age=300, private, must-revalidate"),
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
it "is not an error" do
|
27
|
+
expect(a_document).not_to be_an_error
|
28
|
+
end
|
29
|
+
|
30
|
+
it "is not missing" do
|
31
|
+
expect(a_document).not_to be_not_found
|
32
|
+
end
|
33
|
+
|
34
|
+
it "is not a redirect" do
|
35
|
+
expect(a_document).not_to be_a_redirect
|
36
|
+
end
|
37
|
+
|
38
|
+
it "is successful" do
|
39
|
+
expect(a_document).to be_a_success
|
40
|
+
end
|
41
|
+
|
42
|
+
it "has a numeric status code" do
|
43
|
+
expect(a_document.code).to eq 200
|
44
|
+
end
|
45
|
+
|
46
|
+
it "has a URI" do
|
47
|
+
expect(a_document.uri).to eq "/any/uri"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "sets the last modified time from the cache headers" do
|
51
|
+
modified_time = Time.gm(2017, 7, 1, 18, 18, 33)
|
52
|
+
expect(a_document.last_modified).to eq(modified_time).and be_frozen
|
53
|
+
expect(response_cache_headers["Last-Modified"]).not_to be_frozen
|
54
|
+
end
|
55
|
+
|
56
|
+
it "sets the content to the response body" do
|
57
|
+
expect(a_document.content).to eq "Any Content Body"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "sets the content type according to the associated header" do
|
61
|
+
expect(a_document.content_type).to eq "text/plain"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "uses the URI as the cache key" do
|
65
|
+
expect(a_document.cache_key).to eq "/any/uri"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "sets the cache version based on the raw content" do
|
69
|
+
content_version = Digest::SHA1.hexdigest("Any Content Body")
|
70
|
+
expect(a_document.cache_version).to eq(content_version).and be_frozen
|
71
|
+
end
|
72
|
+
|
73
|
+
it "has a convenience reader for a versioned cache key" do
|
74
|
+
content_version = Digest::SHA1.hexdigest("Any Content Body")
|
75
|
+
expect(a_document.cache_key_with_version).to eq "/any/uri-#{content_version}"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "allows access to the cache control settings" do
|
79
|
+
expect(a_document.cache_control).to eq "max-age=300, private, must-revalidate"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "a standard document", "with missing headers" do
|
84
|
+
subject(:uncachable_document) {
|
85
|
+
DocRepo::Doc.new("/any/uri", headerless_http_ok_response)
|
86
|
+
}
|
87
|
+
|
88
|
+
let(:headerless_http_ok_response) {
|
89
|
+
# Use either `:[] => nil` or `"[]" => nil` as `[]: nil` is invalid Ruby
|
90
|
+
instance_double(
|
91
|
+
"Net::HTTPOK",
|
92
|
+
"code" => "200",
|
93
|
+
"body" => nil,
|
94
|
+
"[]" => nil,
|
95
|
+
)
|
96
|
+
}
|
97
|
+
|
98
|
+
EMPTY_STRING_SHA1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
99
|
+
|
100
|
+
it "may not have a last modified timestamp", :aggregate_failures do
|
101
|
+
expect(uncachable_document.last_modified).to be nil
|
102
|
+
|
103
|
+
allow(headerless_http_ok_response).to receive(:[]) { |key|
|
104
|
+
"Last-Modified" == key ? "0" : nil
|
105
|
+
}
|
106
|
+
invalid_time = DocRepo::Doc.new("/any/uri", headerless_http_ok_response)
|
107
|
+
expect(invalid_time.last_modified).to be nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "may not have any content type" do
|
111
|
+
expect(uncachable_document.content_type).to be nil
|
112
|
+
end
|
113
|
+
|
114
|
+
it "always has a cache version" do
|
115
|
+
expect(uncachable_document.cache_version).to eq EMPTY_STRING_SHA1
|
116
|
+
end
|
117
|
+
|
118
|
+
it "has a convenience reader for a versioned cache key" do
|
119
|
+
expect(uncachable_document.cache_key_with_version).to eq "/any/uri-#{EMPTY_STRING_SHA1}"
|
120
|
+
end
|
121
|
+
|
122
|
+
it "may not have any cache control settings" do
|
123
|
+
expect(uncachable_document.cache_control).to be nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "converting markdown content to HTML" do
|
128
|
+
it "handles empty content" do
|
129
|
+
empty_content = OpenStruct.new(body: nil)
|
130
|
+
empty_doc = DocRepo::Doc.new("/any/uri", empty_content)
|
131
|
+
expect(empty_doc.to_html).to eq ""
|
132
|
+
end
|
133
|
+
|
134
|
+
it "does not parse emphasis inside of words" do
|
135
|
+
em_content = OpenStruct.new(body: <<~MARKDOWN)
|
136
|
+
_this is emphasis_
|
137
|
+
|
138
|
+
this_is_not
|
139
|
+
MARKDOWN
|
140
|
+
em_doc = DocRepo::Doc.new("/any/uri", em_content)
|
141
|
+
expect(em_doc.to_html).to eq <<~HTML
|
142
|
+
<p><em>this is emphasis</em></p>
|
143
|
+
|
144
|
+
<p>this_is_not</p>
|
145
|
+
HTML
|
146
|
+
end
|
147
|
+
|
148
|
+
it "parse tables" do
|
149
|
+
tables = OpenStruct.new(body: <<~MARKDOWN)
|
150
|
+
| Heading 1 | Heading 2 |
|
151
|
+
|-----------|-----------|
|
152
|
+
| Content A | Content B |
|
153
|
+
| Content C | Content D |
|
154
|
+
|
155
|
+
Heading 3 | Heading 4
|
156
|
+
-----------|-----------
|
157
|
+
Content E | Content F
|
158
|
+
Content G | Content H
|
159
|
+
|
160
|
+
| Left align | Right align | Center align |
|
161
|
+
|:-----------|------------:|:------------:|
|
162
|
+
| left | right | center |
|
163
|
+
| aligned | aligned | aligned |
|
164
|
+
MARKDOWN
|
165
|
+
table_doc = DocRepo::Doc.new("/any/uri", tables)
|
166
|
+
expect(table_doc.to_html).to eq <<~HTML
|
167
|
+
<table><thead>
|
168
|
+
<tr>
|
169
|
+
<th>Heading 1</th>
|
170
|
+
<th>Heading 2</th>
|
171
|
+
</tr>
|
172
|
+
</thead><tbody>
|
173
|
+
<tr>
|
174
|
+
<td>Content A</td>
|
175
|
+
<td>Content B</td>
|
176
|
+
</tr>
|
177
|
+
<tr>
|
178
|
+
<td>Content C</td>
|
179
|
+
<td>Content D</td>
|
180
|
+
</tr>
|
181
|
+
</tbody></table>
|
182
|
+
|
183
|
+
<table><thead>
|
184
|
+
<tr>
|
185
|
+
<th>Heading 3</th>
|
186
|
+
<th>Heading 4</th>
|
187
|
+
</tr>
|
188
|
+
</thead><tbody>
|
189
|
+
<tr>
|
190
|
+
<td>Content E</td>
|
191
|
+
<td>Content F</td>
|
192
|
+
</tr>
|
193
|
+
<tr>
|
194
|
+
<td>Content G</td>
|
195
|
+
<td>Content H</td>
|
196
|
+
</tr>
|
197
|
+
</tbody></table>
|
198
|
+
|
199
|
+
<table><thead>
|
200
|
+
<tr>
|
201
|
+
<th style="text-align: left">Left align</th>
|
202
|
+
<th style="text-align: right">Right align</th>
|
203
|
+
<th style="text-align: center">Center align</th>
|
204
|
+
</tr>
|
205
|
+
</thead><tbody>
|
206
|
+
<tr>
|
207
|
+
<td style="text-align: left">left</td>
|
208
|
+
<td style="text-align: right">right</td>
|
209
|
+
<td style="text-align: center">center</td>
|
210
|
+
</tr>
|
211
|
+
<tr>
|
212
|
+
<td style="text-align: left">aligned</td>
|
213
|
+
<td style="text-align: right">aligned</td>
|
214
|
+
<td style="text-align: center">aligned</td>
|
215
|
+
</tr>
|
216
|
+
</tbody></table>
|
217
|
+
HTML
|
218
|
+
end
|
219
|
+
|
220
|
+
it "supports fenced code blocks" do
|
221
|
+
fenced_code = OpenStruct.new(body: <<~MARKDOWN)
|
222
|
+
Plain Code Block:
|
223
|
+
|
224
|
+
```
|
225
|
+
plain = code
|
226
|
+
block { do_something }
|
227
|
+
```
|
228
|
+
|
229
|
+
Language Formatted Block:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
str = "tagged code"
|
233
|
+
# with coments
|
234
|
+
block { do_something }
|
235
|
+
```
|
236
|
+
|
237
|
+
Alternative Block Delimiter:
|
238
|
+
|
239
|
+
~~~js
|
240
|
+
alternative = { style: "javascript" }
|
241
|
+
~~~
|
242
|
+
|
243
|
+
End
|
244
|
+
MARKDOWN
|
245
|
+
code_doc = DocRepo::Doc.new("/any/uri", fenced_code)
|
246
|
+
expect(code_doc.to_html).to eq <<~HTML
|
247
|
+
<p>Plain Code Block:</p>
|
248
|
+
<div class="highlight"><pre><code class="language-" data-lang="">plain = code
|
249
|
+
block { do_something }
|
250
|
+
</code></pre></div>
|
251
|
+
<p>Language Formatted Block:</p>
|
252
|
+
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">str</span> <span class="o">=</span> <span class="s2">"tagged code"</span>
|
253
|
+
<span class="c1"># with coments</span>
|
254
|
+
<span class="n">block</span> <span class="p">{</span> <span class="n">do_something</span> <span class="p">}</span>
|
255
|
+
</code></pre></div>
|
256
|
+
<p>Alternative Block Delimiter:</p>
|
257
|
+
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">alternative</span> <span class="o">=</span> <span class="p">{</span> <span class="na">style</span><span class="p">:</span> <span class="s2">"javascript"</span> <span class="p">}</span>
|
258
|
+
</code></pre></div>
|
259
|
+
<p>End</p>
|
260
|
+
HTML
|
261
|
+
end
|
262
|
+
|
263
|
+
it "autolinks URLs" do
|
264
|
+
embedded_urls = OpenStruct.new(body: <<~MARKDOWN)
|
265
|
+
Many people use www.google.com to search. But they really should use
|
266
|
+
https://www.duckduckgo.com if they want some security and privacy.
|
267
|
+
|
268
|
+
Is it still common to use http://example.com? What about just example.com
|
269
|
+
|
270
|
+
And no one uses ftp://example.com any more.
|
271
|
+
MARKDOWN
|
272
|
+
linked_doc = DocRepo::Doc.new("/any/uri", embedded_urls)
|
273
|
+
expect(linked_doc.to_html).to eq <<~HTML
|
274
|
+
<p>Many people use <a href="http://www.google.com">www.google.com</a> to search. But they really should use
|
275
|
+
<a href="https://www.duckduckgo.com">https://www.duckduckgo.com</a> if they want some security and privacy.</p>
|
276
|
+
|
277
|
+
<p>Is it still common to use <a href="http://example.com">http://example.com</a>? What about just example.com</p>
|
278
|
+
|
279
|
+
<p>And no one uses <a href="ftp://example.com">ftp://example.com</a> any more.</p>
|
280
|
+
HTML
|
281
|
+
end
|
282
|
+
|
283
|
+
it "autolinks email addresses" do
|
284
|
+
embedded_email = OpenStruct.new(body: <<~MARKDOWN)
|
285
|
+
If you need some help just contant support@example.com.
|
286
|
+
MARKDOWN
|
287
|
+
mail_doc = DocRepo::Doc.new("/any/uri", embedded_email)
|
288
|
+
expect(mail_doc.to_html).to eq <<~HTML
|
289
|
+
<p>If you need some help just contant <a href="mailto:support@example.com">support@example.com</a>.</p>
|
290
|
+
HTML
|
291
|
+
end
|
292
|
+
|
293
|
+
it "supports styling strikethrough content" do
|
294
|
+
styled_content = OpenStruct.new(body: <<~MARKDOWN)
|
295
|
+
this is ~~good~~ bad
|
296
|
+
MARKDOWN
|
297
|
+
styled_doc = DocRepo::Doc.new("/any/uri", styled_content)
|
298
|
+
expect(styled_doc.to_html).to eq <<~HTML
|
299
|
+
<p>this is <del>good</del> bad</p>
|
300
|
+
HTML
|
301
|
+
end
|
302
|
+
|
303
|
+
it "supports styling superscript content" do
|
304
|
+
styled_content = OpenStruct.new(body: <<~MARKDOWN)
|
305
|
+
this is the 2^(nd) time
|
306
|
+
MARKDOWN
|
307
|
+
styled_doc = DocRepo::Doc.new("/any/uri", styled_content)
|
308
|
+
expect(styled_doc.to_html).to eq <<~HTML
|
309
|
+
<p>this is the 2<sup>nd</sup> time</p>
|
310
|
+
HTML
|
311
|
+
end
|
312
|
+
|
313
|
+
it "adds HTML anchors to headers" do
|
314
|
+
styled_content = OpenStruct.new(body: <<~MARKDOWN)
|
315
|
+
# Heading 1
|
316
|
+
|
317
|
+
Content A
|
318
|
+
|
319
|
+
## Sub-Heading 2
|
320
|
+
|
321
|
+
Content B
|
322
|
+
MARKDOWN
|
323
|
+
styled_doc = DocRepo::Doc.new("/any/uri", styled_content)
|
324
|
+
expect(styled_doc.to_html).to eq <<~HTML
|
325
|
+
<h1 id="heading-1">Heading 1</h1>
|
326
|
+
|
327
|
+
<p>Content A</p>
|
328
|
+
|
329
|
+
<h2 id="sub-heading-2">Sub-Heading 2</h2>
|
330
|
+
|
331
|
+
<p>Content B</p>
|
332
|
+
HTML
|
333
|
+
end
|
334
|
+
|
335
|
+
it "leaves markdown compliant HTML unchanged but may add whitespace" do
|
336
|
+
html_content = OpenStruct.new(body: <<~HTML)
|
337
|
+
<h1 id="heading-1">Heading 1</h1>
|
338
|
+
<p>Content A</p>
|
339
|
+
<p>this is <del>good</del> bad</p>
|
340
|
+
<p>If you need some help just contant <a href="mailto:support@example.com">support@example.com</a>.</p>
|
341
|
+
<p>Plain Code Block:</p>
|
342
|
+
<div class="highlight"><pre><code class="language-" data-lang="">plain = code
|
343
|
+
block { do_something }
|
344
|
+
</code></pre></div>
|
345
|
+
<p>Language Formatted Block:</p>
|
346
|
+
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">str</span> <span class="o">=</span> <span class="s2">"tagged code"</span>
|
347
|
+
<span class="c1"># with coments</span>
|
348
|
+
<span class="n">block</span> <span class="p">{</span> <span class="n">do_something</span> <span class="p">}</span>
|
349
|
+
</code></pre></div>
|
350
|
+
<p>Alternative Block Delimiter:</p>
|
351
|
+
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">alternative</span> <span class="o">=</span> <span class="p">{</span> <span class="na">style</span><span class="p">:</span> <span class="s2">"javascript"</span> <span class="p">}</span>
|
352
|
+
</code></pre></div>
|
353
|
+
<h2 id="sub-heading-2">Sub-Heading 2</h2>
|
354
|
+
<p>this is the 2<sup>nd</sup> time</p>
|
355
|
+
<h3>Sub-Sub-Heading 3</h3>
|
356
|
+
<p>Many people use <a href="http://www.google.com">www.google.com</a> to search. But they really should use
|
357
|
+
<a href="https://www.duckduckgo.com">https://www.duckduckgo.com</a> if they want some security and privacy.</p>
|
358
|
+
<p>And no one uses <a href="ftp://example.com">ftp://example.com</a> any more.</p>
|
359
|
+
<table><thead>
|
360
|
+
<tr>
|
361
|
+
<th style="text-align: left">Left align</th>
|
362
|
+
<th style="text-align: right">Right align</th>
|
363
|
+
<th style="text-align: center">Center align</th>
|
364
|
+
</tr>
|
365
|
+
</thead><tbody>
|
366
|
+
<tr>
|
367
|
+
<td style="text-align: left">left</td>
|
368
|
+
<td style="text-align: right">right</td>
|
369
|
+
<td style="text-align: center">center</td>
|
370
|
+
</tr>
|
371
|
+
<tr>
|
372
|
+
<td style="text-align: left">aligned</td>
|
373
|
+
<td style="text-align: right">aligned</td>
|
374
|
+
<td style="text-align: center">aligned</td>
|
375
|
+
</tr>
|
376
|
+
</tbody></table>
|
377
|
+
<p>Final Content</p>
|
378
|
+
HTML
|
379
|
+
html_doc = DocRepo::Doc.new("/any/uri", html_content)
|
380
|
+
expect(html_doc.to_html).to eq <<~HTML
|
381
|
+
<h1 id="heading-1">Heading 1</h1>
|
382
|
+
|
383
|
+
<p>Content A</p>
|
384
|
+
|
385
|
+
<p>this is <del>good</del> bad</p>
|
386
|
+
|
387
|
+
<p>If you need some help just contant <a href="mailto:support@example.com">support@example.com</a>.</p>
|
388
|
+
|
389
|
+
<p>Plain Code Block:</p>
|
390
|
+
|
391
|
+
<div class="highlight"><pre><code class="language-" data-lang="">plain = code
|
392
|
+
block { do_something }
|
393
|
+
</code></pre></div>
|
394
|
+
|
395
|
+
<p>Language Formatted Block:</p>
|
396
|
+
|
397
|
+
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">str</span> <span class="o">=</span> <span class="s2">"tagged code"</span>
|
398
|
+
<span class="c1"># with coments</span>
|
399
|
+
<span class="n">block</span> <span class="p">{</span> <span class="n">do_something</span> <span class="p">}</span>
|
400
|
+
</code></pre></div>
|
401
|
+
|
402
|
+
<p>Alternative Block Delimiter:</p>
|
403
|
+
|
404
|
+
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="nx">alternative</span> <span class="o">=</span> <span class="p">{</span> <span class="na">style</span><span class="p">:</span> <span class="s2">"javascript"</span> <span class="p">}</span>
|
405
|
+
</code></pre></div>
|
406
|
+
|
407
|
+
<h2 id="sub-heading-2">Sub-Heading 2</h2>
|
408
|
+
|
409
|
+
<p>this is the 2<sup>nd</sup> time</p>
|
410
|
+
|
411
|
+
<h3>Sub-Sub-Heading 3</h3>
|
412
|
+
|
413
|
+
<p>Many people use <a href="http://www.google.com">www.google.com</a> to search. But they really should use
|
414
|
+
<a href="https://www.duckduckgo.com">https://www.duckduckgo.com</a> if they want some security and privacy.</p>
|
415
|
+
|
416
|
+
<p>And no one uses <a href="ftp://example.com">ftp://example.com</a> any more.</p>
|
417
|
+
|
418
|
+
<table><thead>
|
419
|
+
<tr>
|
420
|
+
<th style="text-align: left">Left align</th>
|
421
|
+
<th style="text-align: right">Right align</th>
|
422
|
+
<th style="text-align: center">Center align</th>
|
423
|
+
</tr>
|
424
|
+
</thead><tbody>
|
425
|
+
<tr>
|
426
|
+
<td style="text-align: left">left</td>
|
427
|
+
<td style="text-align: right">right</td>
|
428
|
+
<td style="text-align: center">center</td>
|
429
|
+
</tr>
|
430
|
+
<tr>
|
431
|
+
<td style="text-align: left">aligned</td>
|
432
|
+
<td style="text-align: right">aligned</td>
|
433
|
+
<td style="text-align: center">aligned</td>
|
434
|
+
</tr>
|
435
|
+
</tbody></table>
|
436
|
+
|
437
|
+
<p>Final Content</p>
|
438
|
+
HTML
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
end
|