jekyll-asciidoc 2.0.1 → 2.1.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.adoc +27 -8
- data/Gemfile +13 -3
- data/LICENSE.adoc +1 -1
- data/README.adoc +409 -103
- data/jekyll-asciidoc.gemspec +6 -7
- data/lib/jekyll-asciidoc/compat.rb +4 -3
- data/lib/jekyll-asciidoc/converter.rb +50 -30
- data/lib/jekyll-asciidoc/filters.rb +21 -1
- data/lib/jekyll-asciidoc/integrator.rb +42 -34
- data/lib/jekyll-asciidoc/mixins.rb +6 -0
- data/lib/jekyll-asciidoc/version.rb +1 -1
- data/spec/fixtures/basic_site/docid.adoc +4 -0
- data/spec/fixtures/basic_site/section-with-id-and-role.adoc +6 -0
- data/spec/fixtures/imagesdir_relative_to_root/_config.yml +1 -1
- data/spec/fixtures/{include_relative_to_doc → include_relative_to_docdir}/_config.yml +0 -0
- data/spec/fixtures/{include_relative_to_doc → include_relative_to_docdir}/_layouts/default.html +0 -0
- data/spec/fixtures/{include_relative_to_doc → include_relative_to_docdir}/about/_people.adoc +0 -0
- data/spec/fixtures/{include_relative_to_doc → include_relative_to_docdir}/about/index.adoc +0 -0
- data/spec/fixtures/include_relative_to_root/source/_config.yml +2 -0
- data/spec/fixtures/include_relative_to_root/source/_layouts/default.html +11 -0
- data/spec/fixtures/include_relative_to_root/source/about/_people.adoc +2 -0
- data/spec/fixtures/include_relative_to_root/source/about/index.adoc +13 -0
- data/spec/fixtures/tocify_filter/_config.yml +2 -0
- data/spec/fixtures/tocify_filter/_layouts/default.html +15 -0
- data/spec/fixtures/tocify_filter/index.adoc +25 -0
- data/spec/fixtures/with_posts/_config.yml +4 -0
- data/spec/fixtures/with_posts/_layouts/post.html +8 -0
- data/spec/fixtures/with_posts/_posts/2016-02-02-post-with-singular-vars.adoc +7 -0
- data/spec/fixtures/with_posts/_posts/2016-06-15-post-with-date.adoc +4 -0
- data/spec/fixtures/with_posts/_posts/2016-07-15-post-with-date-and-tz.adoc +4 -0
- data/spec/fixtures/with_posts/_posts/2016-07-20-post-with-date-in-revision-line.adoc +6 -0
- data/spec/fixtures/xhtml_syntax/images/sunset.jpg +0 -0
- data/spec/jekyll-asciidoc_spec.rb +320 -127
- data/spec/spec_helper.rb +4 -0
- metadata +41 -15
data/jekyll-asciidoc.gemspec
CHANGED
@@ -3,12 +3,13 @@ require File.expand_path '../lib/jekyll-asciidoc/version', __FILE__
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'jekyll-asciidoc'
|
5
5
|
s.version = Jekyll::AsciiDoc::VERSION
|
6
|
-
s.summary = 'A Jekyll plugin that converts AsciiDoc source files in your site to HTML pages using Asciidoctor.'
|
7
|
-
s.description = 'A Jekyll plugin that converts AsciiDoc source files in your site to HTML pages using Asciidoctor.'
|
6
|
+
s.summary = 'A Jekyll plugin that converts the AsciiDoc source files in your site to HTML pages using Asciidoctor.'
|
7
|
+
s.description = 'A Jekyll plugin that converts the AsciiDoc source files in your site to HTML pages using Asciidoctor.'
|
8
8
|
s.authors = ['Dan Allen', 'Paul Rayner']
|
9
9
|
s.email = ['dan.j.allen@gmail.com']
|
10
10
|
s.homepage = 'https://github.com/asciidoctor/jekyll-asciidoc'
|
11
11
|
s.license = 'MIT'
|
12
|
+
s.required_ruby_version = '>= 1.9.3'
|
12
13
|
|
13
14
|
files = begin
|
14
15
|
output = IO.popen('git ls-files -z', err: File::NULL) {|io| io.read }.split %(\0)
|
@@ -16,9 +17,9 @@ Gem::Specification.new do |s|
|
|
16
17
|
rescue
|
17
18
|
Dir['**/*']
|
18
19
|
end
|
19
|
-
s.files = files.grep /^(?:lib\/.+|Gemfile|Rakefile|(CHANGELOG|LICENSE|README)\.adoc|#{s.name}\.gemspec)$/
|
20
|
-
s.test_files = files.grep /^spec\//
|
21
|
-
|
20
|
+
s.files = files.grep %r/^(?:lib\/.+|Gemfile|Rakefile|(?:CHANGELOG|LICENSE|README)\.adoc|#{s.name}\.gemspec)$/
|
21
|
+
s.test_files = files.grep %r/^spec\//
|
22
|
+
|
22
23
|
s.require_paths = ['lib']
|
23
24
|
|
24
25
|
s.add_runtime_dependency 'asciidoctor', '>= 1.5.0'
|
@@ -26,6 +27,4 @@ Gem::Specification.new do |s|
|
|
26
27
|
|
27
28
|
s.add_development_dependency 'rake'
|
28
29
|
s.add_development_dependency 'rspec', '~> 3.5.0'
|
29
|
-
# enable pygments.rb dependency here once https://github.com/tmm1/pygments.rb/pull/162 is merged & released
|
30
|
-
#s.add_development_dependency 'pygments.rb', '~> 0.6.3'
|
31
30
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Jekyll
|
2
2
|
module AsciiDoc
|
3
|
-
Jekyll3Compatible = (::Gem::Version.new ::Jekyll::VERSION) >= (::Gem::Version.new '3.0.0')
|
3
|
+
Jekyll3Compatible = (jekyll_version = ::Gem::Version.new ::Jekyll::VERSION) >= (::Gem::Version.new '3.0.0')
|
4
|
+
Jekyll3_1 = (::Gem::Requirement.new '~> 3.1.0').satisfied_by? jekyll_version
|
4
5
|
end
|
5
6
|
end
|
6
7
|
|
@@ -9,11 +10,11 @@ module Jekyll
|
|
9
10
|
# Backport {::Jekyll::Site#find_converter_instance} to Jekyll 2.
|
10
11
|
def find_converter_instance type
|
11
12
|
converters.find {|candidate| type === candidate } || (raise %(No Converters found for #{type}))
|
12
|
-
end unless
|
13
|
+
end unless method_defined? :find_converter_instance
|
13
14
|
|
14
15
|
# Introduce complement to {::Jekyll::Site#find_converter_instance} for generators.
|
15
16
|
def find_generator_instance type
|
16
17
|
generators.find {|candidate| type === candidate } || (raise %(No Generators found for #{type}))
|
17
|
-
end unless
|
18
|
+
end unless method_defined? :find_generator_instance
|
18
19
|
end
|
19
20
|
end
|
@@ -34,7 +34,7 @@ module Jekyll
|
|
34
34
|
def initialize config
|
35
35
|
@config = config
|
36
36
|
@logger = ::Jekyll.logger
|
37
|
-
@
|
37
|
+
@page_context = {}
|
38
38
|
@setup = false
|
39
39
|
|
40
40
|
# NOTE jekyll-watch reinitializes plugins using a shallow clone of config, so no need to reconfigure
|
@@ -100,10 +100,10 @@ module Jekyll
|
|
100
100
|
'site-baseurl' => config['baseurl'],
|
101
101
|
'site-url' => config['url']
|
102
102
|
}
|
103
|
-
attrs = asciidoctor_config[:attributes] =
|
103
|
+
attrs = asciidoctor_config[:attributes] = assemble_attributes asciidoctor_config[:attributes],
|
104
104
|
((site_attributes.merge ImplicitAttributes).merge DefaultAttributes)
|
105
105
|
if (imagesdir = attrs['imagesdir']) && !(attrs.key? 'imagesoutdir') && (imagesdir.start_with? '/')
|
106
|
-
attrs['imagesoutdir'] = ::File.join dest, imagesdir
|
106
|
+
attrs['imagesoutdir'] = ::File.join dest, (imagesdir.chomp '@')
|
107
107
|
end
|
108
108
|
asciidoctor_config.extend Configured
|
109
109
|
end
|
@@ -151,47 +151,47 @@ module Jekyll
|
|
151
151
|
end
|
152
152
|
|
153
153
|
def before_render document, payload
|
154
|
-
|
154
|
+
# NOTE Jekyll 3.1 incorrectly mapped the page payload to document.data instead of payload['page']
|
155
|
+
@page_context[:data] = ::Jekyll::AsciiDoc::Jekyll3_1 ? document.data : payload['page']
|
156
|
+
record_paths document
|
155
157
|
end
|
156
158
|
|
157
159
|
def after_render document
|
158
|
-
|
160
|
+
@page_context.clear
|
159
161
|
end
|
160
162
|
|
161
|
-
def
|
162
|
-
@
|
163
|
+
def record_paths document, opts = {}
|
164
|
+
@page_context[:paths] = paths = {
|
163
165
|
'docfile' => (docfile = ::File.join document.site.source, document.relative_path),
|
164
166
|
'docdir' => (::File.dirname docfile),
|
165
167
|
'docname' => (::File.basename docfile, (::File.extname docfile))
|
166
168
|
}
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
})
|
173
|
-
end
|
169
|
+
paths.update({
|
170
|
+
'outfile' => (outfile = document.destination document.site.dest),
|
171
|
+
'outdir' => (::File.dirname outfile),
|
172
|
+
'outpath' => document.url
|
173
|
+
}) unless opts[:source_only]
|
174
174
|
end
|
175
175
|
|
176
|
-
def
|
177
|
-
@
|
176
|
+
def clear_paths
|
177
|
+
@page_context.delete :paths
|
178
178
|
end
|
179
179
|
|
180
180
|
def load_header document
|
181
181
|
setup
|
182
|
-
|
182
|
+
record_paths document, source_only: true if defined? ::Jekyll::Hooks
|
183
183
|
# NOTE merely an optimization; if this doesn't match, the header still gets isolated by the processor
|
184
184
|
header = (document.content.split HeaderBoundaryRx, 2)[0]
|
185
185
|
case @asciidoc_config['processor']
|
186
186
|
when 'asciidoctor'
|
187
187
|
opts = @asciidoctor_config.merge parse_header_only: true
|
188
|
-
if @
|
188
|
+
if (paths = @page_context[:paths])
|
189
189
|
if opts[:base_dir] == :docdir
|
190
|
-
opts[:base_dir] =
|
190
|
+
opts[:base_dir] = paths['docdir'] # NOTE this assignment happens inside the processor anyway
|
191
191
|
else
|
192
|
-
|
192
|
+
paths.delete 'docdir'
|
193
193
|
end
|
194
|
-
opts[:attributes] = opts[:attributes].merge
|
194
|
+
opts[:attributes] = opts[:attributes].merge paths
|
195
195
|
end
|
196
196
|
# NOTE return instance even if header is empty since attributes may be inherited from config
|
197
197
|
doc = ::Asciidoctor.load header, opts
|
@@ -199,7 +199,7 @@ module Jekyll
|
|
199
199
|
@logger.warn MessageTopic, %(Unknown AsciiDoc processor: #{@asciidoc_config['processor']}. Cannot load document header.)
|
200
200
|
doc = nil
|
201
201
|
end
|
202
|
-
|
202
|
+
clear_paths if defined? ::Jekyll::Hooks
|
203
203
|
doc
|
204
204
|
end
|
205
205
|
|
@@ -212,15 +212,18 @@ module Jekyll
|
|
212
212
|
case @asciidoc_config['processor']
|
213
213
|
when 'asciidoctor'
|
214
214
|
opts = @asciidoctor_config.merge header_footer: standalone
|
215
|
-
if @
|
215
|
+
if (paths = @page_context[:paths])
|
216
216
|
if opts[:base_dir] == :docdir
|
217
|
-
opts[:base_dir] =
|
217
|
+
opts[:base_dir] = paths['docdir'] # NOTE this assignment happens inside the processor anyway
|
218
218
|
else
|
219
|
-
|
219
|
+
paths.delete 'docdir'
|
220
220
|
end
|
221
|
-
opts[:attributes] = opts[:attributes].merge
|
221
|
+
opts[:attributes] = opts[:attributes].merge paths
|
222
|
+
# for auto-extracted excerpt, paths are't available since hooks don't get triggered
|
223
|
+
elsif opts[:base_dir] == :docdir
|
224
|
+
opts.delete :base_dir
|
222
225
|
end
|
223
|
-
::Asciidoctor.
|
226
|
+
((@page_context[:data] || {})['document'] = ::Asciidoctor.load content, opts).extend(Liquidable).convert
|
224
227
|
else
|
225
228
|
@logger.warn MessageTopic, %(Unknown AsciiDoc processor: #{@asciidoc_config['processor']}. Passing through unparsed content.)
|
226
229
|
content
|
@@ -233,7 +236,7 @@ module Jekyll
|
|
233
236
|
hash.each_with_object({}) {|(key, val), accum| accum[key.to_sym] = val }
|
234
237
|
end
|
235
238
|
|
236
|
-
def
|
239
|
+
def assemble_attributes attrs, initial = {}
|
237
240
|
if (is_array = ::Array === attrs) || ::Hash === attrs
|
238
241
|
attrs.each_with_object(initial) {|entry, new_attrs|
|
239
242
|
key, val = is_array ? ((entry.split '=', 2) + ['', ''])[0..1] : entry
|
@@ -241,8 +244,25 @@ module Jekyll
|
|
241
244
|
new_attrs[key[1..-1]] = nil
|
242
245
|
elsif key.end_with? '!'
|
243
246
|
new_attrs[key.chop] = nil
|
247
|
+
# we're reserving -name to mean "unset implicit value but allow doc to override"
|
248
|
+
elsif key.start_with? '-'
|
249
|
+
new_attrs.delete key[1..-1]
|
244
250
|
else
|
245
|
-
new_attrs[key] =
|
251
|
+
new_attrs[key] = if val
|
252
|
+
case val
|
253
|
+
when ::String
|
254
|
+
resolve_attribute_refs val, new_attrs
|
255
|
+
when ::Numeric
|
256
|
+
val.to_s
|
257
|
+
when true
|
258
|
+
''
|
259
|
+
else
|
260
|
+
val
|
261
|
+
end
|
262
|
+
else
|
263
|
+
# we may preserve false in the future to mean "unset implicit value but allow doc to override"
|
264
|
+
nil
|
265
|
+
end
|
246
266
|
end
|
247
267
|
}
|
248
268
|
else
|
@@ -254,7 +274,7 @@ module Jekyll
|
|
254
274
|
if text.empty?
|
255
275
|
text
|
256
276
|
elsif text.include? '{'
|
257
|
-
text.gsub(AttributeReferenceRx) { (
|
277
|
+
text.gsub(AttributeReferenceRx) { ($&.start_with? '\\') ? $&[1..-1] : ((attrs.fetch $1, $&).to_s.chomp '@') }
|
258
278
|
else
|
259
279
|
text
|
260
280
|
end
|
@@ -6,11 +6,31 @@ module Jekyll
|
|
6
6
|
# input - The AsciiDoc String to convert.
|
7
7
|
# doctype - The target AsciiDoc doctype (optional, default: nil).
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# {{ page.excerpt | asciidocify: 'inline' }}
|
12
|
+
#
|
13
|
+
# Returns the converted result as an HTML-formatted String.
|
10
14
|
def asciidocify input, doctype = nil
|
11
15
|
(@context.registers[:cached_asciidoc_converter] ||= (Converter.get_instance @context.registers[:site]))
|
12
16
|
.convert(doctype ? %(:doctype: #{doctype}#{Utils::NewLine}#{input}) : (input || ''))
|
13
17
|
end
|
18
|
+
|
19
|
+
# A Liquid filter for generating a table of contents in HTML from a parsed AsciiDoc document.
|
20
|
+
#
|
21
|
+
# document - The parsed AsciiDoc document from which to generate a table of contents in HTML.
|
22
|
+
# levels - The max section depth to include (optional, default: value of toclevels document attribute).
|
23
|
+
#
|
24
|
+
# Examples
|
25
|
+
#
|
26
|
+
# {{ page.document | tocify_asciidoc: 3 }}
|
27
|
+
#
|
28
|
+
# Returns the table of contents as an HTML-formatted String.
|
29
|
+
def tocify_asciidoc document, levels = nil
|
30
|
+
if ::Asciidoctor::Document === document
|
31
|
+
document.converter.convert document, 'outline', toclevels: (levels.nil_or_empty? ? nil : levels.to_i)
|
32
|
+
end
|
33
|
+
end
|
14
34
|
end
|
15
35
|
|
16
36
|
::Liquid::Template.register_filter Filters
|
@@ -14,8 +14,8 @@ module Jekyll
|
|
14
14
|
site.find_generator_instance self
|
15
15
|
end
|
16
16
|
|
17
|
-
# This method is triggered each time the site is generated, including after any file has changed when
|
18
|
-
#
|
17
|
+
# This method is triggered each time the site is generated, including after any file has changed when running in
|
18
|
+
# watch mode (regardless of incremental setting).
|
19
19
|
def generate site
|
20
20
|
@converter = converter = (Converter.get_instance site).setup
|
21
21
|
|
@@ -47,47 +47,59 @@ module Jekyll
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
# Integrate the page-related attributes from the AsciiDoc document header
|
51
|
-
#
|
52
|
-
# or {::Jekyll::Document}.
|
50
|
+
# Integrate the page-related attributes from the AsciiDoc document header into the data Array of the specified
|
51
|
+
# {::Jekyll::Page}, {::Jekyll::Post} or {::Jekyll::Document}.
|
53
52
|
#
|
54
53
|
# document - the Page, Post or Document instance to integrate.
|
55
|
-
# collection_name - the String name of the collection to which this
|
56
|
-
# document belongs (optional, default: nil).
|
54
|
+
# collection_name - the String name of the collection to which this document belongs (optional, default: nil).
|
57
55
|
#
|
58
56
|
# Returns a [Boolean] indicating whether the document should be published.
|
59
57
|
def integrate document, collection_name = nil
|
60
|
-
document.
|
61
|
-
document.content = [%(:#{@page_attr_prefix}layout: _auto), document.content] * NewLine unless
|
62
|
-
return unless (doc = @converter.load_header document)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
58
|
+
data = document.data
|
59
|
+
document.content = [%(:#{@page_attr_prefix}layout: _auto), document.content] * NewLine unless data.key? 'layout'
|
60
|
+
return true unless (doc = @converter.load_header document)
|
61
|
+
|
62
|
+
# NOTE id is already reserved in Jekyll for another purpose, so we'll map id to docid instead
|
63
|
+
data['docid'] = doc.id if doc.id
|
64
|
+
data['title'] = doc.doctitle if doc.header?
|
65
|
+
data['author'] = doc.author if doc.author
|
66
|
+
if collection_name == 'posts' && (doc.attr? 'revdate')
|
67
|
+
data['date'] = ::Jekyll::Utils.parse_date doc.revdate,
|
68
|
+
%(Document '#{document.relative_path}' does not have a valid revdate in the AsciiDoc header.)
|
69
|
+
# NOTE Jekyll 2.3 requires date field to be set explicitly
|
70
|
+
document.date = data['date'] if document.respond_to? :date=
|
71
|
+
end
|
67
72
|
|
68
|
-
no_prefix = (prefix_size = @page_attr_prefix.length)
|
69
|
-
unless (
|
70
|
-
.each_with_object({}) {|(key, val), accum|
|
73
|
+
no_prefix = (prefix_size = @page_attr_prefix.length) == 0
|
74
|
+
unless (adoc_data = doc.attributes.each_with_object({}) {|(key, val), accum|
|
71
75
|
if no_prefix || ((key.start_with? @page_attr_prefix) && key = key[prefix_size..-1])
|
72
76
|
accum[key] = ::String === val ? (parse_yaml_value val) : val
|
73
77
|
end
|
74
78
|
}).empty?
|
75
|
-
|
79
|
+
data.update adoc_data
|
76
80
|
end
|
77
81
|
|
78
|
-
|
82
|
+
{ 'category' => 'categories', 'tag' => 'tags' }.each do |sole_key, coll_key|
|
83
|
+
if (sole_val = data.delete sole_key) &&
|
84
|
+
!((coll_val = (data[coll_key] ||= [])).include? sole_val)
|
85
|
+
coll_val << sole_val
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
case data['layout']
|
79
90
|
when nil
|
80
|
-
document.content = %(#{StandaloneOptionLine}#{document.content}) unless
|
91
|
+
document.content = %(#{StandaloneOptionLine}#{document.content}) unless data.key? 'layout'
|
81
92
|
when '', '_auto'
|
82
93
|
layout = collection_name ? (collection_name.chomp 's') : 'page'
|
83
|
-
|
94
|
+
data['layout'] = (document.site.layouts.key? layout) ? layout : 'default'
|
84
95
|
when false
|
85
|
-
|
96
|
+
data.delete 'layout'
|
86
97
|
document.content = %(#{StandaloneOptionLine}#{document.content})
|
87
98
|
end
|
88
99
|
|
89
|
-
document.extend
|
90
|
-
document.data
|
100
|
+
document.extend Document
|
101
|
+
document.extend NoLiquid unless data['liquid']
|
102
|
+
data.fetch 'published', true
|
91
103
|
end
|
92
104
|
|
93
105
|
def generate_pygments_stylesheet site, attrs
|
@@ -114,26 +126,22 @@ module Jekyll
|
|
114
126
|
|
115
127
|
private
|
116
128
|
|
117
|
-
# Parse the specified value as though it is a single-line value part of a
|
118
|
-
# YAML key/value pair.
|
129
|
+
# Parse the specified value as though it is a single-line value part of a YAML key/value pair.
|
119
130
|
#
|
120
|
-
# Attempt to parse the specified String value as though it is a
|
121
|
-
#
|
122
|
-
# parse
|
123
|
-
# quotes in the value) and parse it as a character sequence. If the value
|
124
|
-
# is empty, return an empty String.
|
131
|
+
# Attempt to parse the specified String value as though it is a single-line value part of a YAML key/value pair.
|
132
|
+
# If the value fails to parse, wrap the value in single quotes (after escaping any single quotes in the value) and
|
133
|
+
# parse it as a character sequence. If the value is empty, return an empty String.
|
125
134
|
#
|
126
135
|
# val - The String value to parse.
|
127
136
|
#
|
128
|
-
# Returns an [Object] parsed from the string-based YAML value or empty
|
129
|
-
# [String] if the specified value is empty.
|
137
|
+
# Returns an [Object] parsed from the string-based YAML value or empty [String] if the specified value is empty.
|
130
138
|
def parse_yaml_value val
|
131
139
|
if val.empty?
|
132
140
|
''
|
133
141
|
else
|
134
142
|
begin
|
135
143
|
::SafeYAML.load %(--- #{val})
|
136
|
-
rescue
|
144
|
+
rescue ::StandardError, ::SyntaxError
|
137
145
|
val = val.gsub '\'', '\'\'' if val.include? '\''
|
138
146
|
::SafeYAML.load %(--- \'#{val}\')
|
139
147
|
end
|
File without changes
|
data/spec/fixtures/{include_relative_to_doc → include_relative_to_docdir}/_layouts/default.html
RENAMED
File without changes
|
data/spec/fixtures/{include_relative_to_doc → include_relative_to_docdir}/about/_people.adoc
RENAMED
File without changes
|
File without changes
|