asciidoctor-include-ext 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of asciidoctor-include-ext might be problematic. Click here for more details.

@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3fd8f2f25f1005feb22f42516ca6333891f4cf0a
4
+ data.tar.gz: fb3082daf8722e5f568ae832b4e7390c495c71da
5
+ SHA512:
6
+ metadata.gz: 659a51ad942bdbc85faaf3f8db18ef80772afaea9461902450998cf391085a2de3747ad5fb399031444b3a2efcf47430990e5bb9298bb21b345eeb2d804ebb2c
7
+ data.tar.gz: 939b343e54c1a1e0150090d1428402a8ee4c98b792a68ec0e1dd2484b8c30c638fca08f39c894dcd112406010d78b1c88e46f18d19f775f19068af9751813b0a
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright 2017 Jakub Jirutka <jakub@jirutka.cz>.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ = Asciidoctor Include Extension
2
+ :source-language: shell
3
+ // custom
4
+ :gem-name: asciidoctor-include-ext
5
+ :gh-name: jirutka/{gem-name}
6
+ :gh-branch: master
7
+ :codacy-id: 45320444129044688ef6553821b083f1
8
+
9
+ ifdef::env-github[]
10
+ image:https://travis-ci.org/{gh-name}.svg?branch={gh-branch}[Build Status, link="https://travis-ci.org/{gh-name}"]
11
+ image:https://api.codacy.com/project/badge/Coverage/{codacy-id}["Test Coverage", link="https://www.codacy.com/app/{gh-name}"]
12
+ image:https://api.codacy.com/project/badge/Grade/{codacy-id}["Codacy Code quality", link="https://www.codacy.com/app/{gh-name}"]
13
+ image:https://img.shields.io/gem/v/{gem-name}.svg?style=flat[Gem Version, link="https://rubygems.org/gems/{gem-name}"]
14
+ image:https://img.shields.io/badge/yard-docs-blue.svg[Yard Docs, link="http://www.rubydoc.info/github/{gh-name}/{gh-branch}"]
15
+ endif::env-github[]
16
+
17
+
18
+ This project is a reimplementation of the http://asciidoctor.org[Asciidoctor]’s built-in (pre)processor for the http://asciidoctor.org/docs/user-manual/#include-directive[include::[\]] directive in extensible and more clean way.
19
+ It provides the same features, but you can easily adjust it or extend for your needs.
20
+ For example, you can change how it loads included files or add another ways how to select portions of the document to include.
21
+
22
+
23
+ == Why?
24
+
25
+ You may ask why I _reimplemented_ something that is already in the Asciidoctor core.
26
+
27
+ Well…
28
+ Code for decision if the include is allowed, parsing attributes for partial selection, reading the file to be included, filtering its content according to `lines` or `tags` attribute, handling errors… all of this is implemented directly in a single 210 lines long method https://github.com/asciidoctor/asciidoctor/blob/911d0bd509f369e9da15d2bb71f81aecb7c45fec/lib/asciidoctor/reader.rb#L824-L1034[Asciidoctor::Reader#preprocess_include_directive] with really horrible perl-like spaghetti code. :spaghetti: :hankey:
29
+
30
+ How can you adjust it or reuse outside of the Asciidoctor codebase?
31
+ For example, what if you can’t read documents directly from file system?
32
+ Then you’re out of luck.
33
+ There’s no way how to do that without reimplementing this whole mess on your own (monkey-patching `Kernel.open` and `File.file?` is not a sensible option…).
34
+
35
+ I wrote this extension to allow implementing a complete support of `include::[]` directive in GitLab.
36
+ And also to open doors for adding some custom _selectors_, e.g. selecting lines using regular expression in addition to ranges of line numbers and tags.
37
+
38
+
39
+ == Installation
40
+
41
+ To install (or update to the latest version):
42
+
43
+ [source, subs="+attributes"]
44
+ gem install {gem-name}
45
+
46
+ or to install the latest development version:
47
+
48
+ [source, subs="+attributes"]
49
+ gem install {gem-name} --pre
50
+
51
+
52
+ == Usage
53
+
54
+ Just `require '{gem-name}'`.
55
+ If you invoke Asciidoctor from command-line, use option `-r` to load the extension:
56
+
57
+ [source, subs="+attributes"]
58
+ asciidoctor -r {gem-name} README.adoc
59
+
60
+ If you don’t want the extension to be automatically registered in Asciidoctor, don’t _require_ `{gem-name}`, but `asciidoctor/include_ext/include_processor`.
61
+
62
+ IMPORTANT: Bundler automatically _requires_ all the specified gems.
63
+ To prevent it, use `gem '{gem-name}', require: false`.
64
+
65
+
66
+ == License
67
+
68
+ This project is licensed under http://opensource.org/licenses/MIT/[MIT License].
69
+ For the full text of the license, see the link:LICENSE[LICENSE] file.
@@ -0,0 +1,34 @@
1
+ require File.expand_path('../lib/asciidoctor/include_ext/version', __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'asciidoctor-include-ext'
5
+ s.version = Asciidoctor::IncludeExt::VERSION
6
+ s.author = 'Jakub Jirutka'
7
+ s.email = 'jakub@jirutka.cz'
8
+ s.homepage = 'https://github.com/jirutka/asciidoctor-include-ext'
9
+ s.license = 'MIT'
10
+
11
+ s.summary = "Asciidoctor's standard include::[] processor reimplemented as an extension"
12
+ s.description = <<EOF
13
+ This is a reimplementation of the Asciidoctor's built-in (pre)processor for the
14
+ include::[] directive in extensible and more clean way. It provides the same
15
+ features, but you can easily adjust it or extend for your needs. For example,
16
+ you can change how it loads included files or add another ways how to select
17
+ portions of the document to include.
18
+ EOF
19
+
20
+ s.files = Dir['lib/**/*', '*.gemspec', 'LICENSE*', 'README*']
21
+ s.has_rdoc = 'yard'
22
+
23
+ s.required_ruby_version = '>= 2.1'
24
+
25
+ s.add_runtime_dependency 'asciidoctor', '~> 1.5.6'
26
+
27
+ s.add_development_dependency 'corefines', '~> 1.11'
28
+ s.add_development_dependency 'kramdown', '~> 1.16'
29
+ s.add_development_dependency 'rake', '~> 12.0'
30
+ s.add_development_dependency 'rspec', '~> 3.7'
31
+ s.add_development_dependency 'rubocop', '~> 0.51.0'
32
+ s.add_development_dependency 'simplecov', '~> 0.15'
33
+ s.add_development_dependency 'yard', '~> 0.9'
34
+ end
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require 'asciidoctor/include_ext'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ require 'asciidoctor/extensions'
3
+ require 'asciidoctor/include_ext/include_processor'
4
+
5
+ Asciidoctor::Extensions.register do
6
+ include_processor Asciidoctor::IncludeExt::IncludeProcessor
7
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+ require 'logger'
3
+ require 'open-uri'
4
+
5
+ require 'asciidoctor/include_ext/version'
6
+ require 'asciidoctor/include_ext/reader_ext'
7
+ require 'asciidoctor/include_ext/lineno_lines_selector'
8
+ require 'asciidoctor/include_ext/tag_lines_selector'
9
+ require 'asciidoctor/extensions'
10
+
11
+ module Asciidoctor::IncludeExt
12
+ # Asciidoctor preprocessor for processing `include::<target>[]` directives
13
+ # in the source document.
14
+ #
15
+ # @see http://asciidoctor.org/docs/user-manual/#include-directive
16
+ class IncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
17
+
18
+ # @param selectors [Array<Class>] an array of selectors that can filter
19
+ # specified portions of the document to include
20
+ # (see <http://asciidoctor.org/docs/user-manual#include-partial>).
21
+ # @param logger [Logger] the logger to use for logging warning and errors
22
+ # from this object and selectors.
23
+ def initialize(selectors: [LinenoLinesSelector, TagLinesSelector],
24
+ logger: Logger.new(STDERR), **)
25
+ super
26
+ @selectors = selectors.dup.freeze
27
+ @logger = logger
28
+ end
29
+
30
+ # @param reader [Asciidoctor::Reader]
31
+ # @param target [String] name of the source file to include as specified
32
+ # in the target slot of the `include::[]` directive.
33
+ # @param attributes [Hash<String, String>] parsed attributes of the
34
+ # `include::[]` directive.
35
+ def process(_, reader, target, attributes)
36
+ unless include_allowed? target, reader
37
+ reader.replace_next_line("link:#{target}[]")
38
+ return
39
+ end
40
+
41
+ if (max_depth = reader.exceeded_max_depth?)
42
+ logger.error "#{reader.line_info}: maximum include depth of #{max_depth} exceeded"
43
+ return
44
+ end
45
+
46
+ unless (path = resolve_target_path(target, reader))
47
+ if attributes.key? 'optional-option'
48
+ reader.shift
49
+ else
50
+ logger.error "#{reader.line_info}: include target not found: #{target}"
51
+ unresolved_include!(target, reader)
52
+ end
53
+ return
54
+ end
55
+
56
+ selector = lines_selector_for(target, attributes)
57
+ begin
58
+ lines = read_lines(path, selector)
59
+ rescue => e # rubocop:disable RescueWithoutErrorClass
60
+ logger.error "#{reader.line_info}: failed to read include file: #{path}: #{e}"
61
+ unresolved_include!(target, reader)
62
+ return
63
+ end
64
+
65
+ if selector && selector.respond_to?(:first_included_lineno)
66
+ incl_offset = selector.first_included_lineno
67
+ end
68
+
69
+ unless lines.empty?
70
+ reader.push_include(lines, path, target, incl_offset || 1, attributes)
71
+ end
72
+ end
73
+
74
+ protected
75
+
76
+ attr_reader :logger
77
+
78
+ # @param target (see #process)
79
+ # @param reader (see #process)
80
+ # @return [Boolean] `true` if it's allowed to include the *target*,
81
+ # `false` otherwise.
82
+ def include_allowed?(target, reader)
83
+ doc = reader.document
84
+
85
+ return false if doc.safe >= ::Asciidoctor::SafeMode::SECURE
86
+ return false if doc.attributes.fetch('max-include-depth', 64).to_i < 1
87
+ return false if target_uri?(target) && !doc.attributes.key?('allow-uri-read')
88
+ true
89
+ end
90
+
91
+ # @param target (see #process)
92
+ # @param reader (see #process)
93
+ # @return [String, nil] file path or URI of the *target*, or `nil` if not found.
94
+ def resolve_target_path(target, reader)
95
+ return target if target_uri? target
96
+
97
+ # Include file is resolved relative to dir of the current include,
98
+ # or base_dir if within original docfile.
99
+ path = reader.document.normalize_system_path(target, reader.dir, nil,
100
+ target_name: 'include file')
101
+ path if ::File.file?(path)
102
+ end
103
+
104
+ # Reads the specified file as individual lines, filters them using the
105
+ # *selector* (if provided) and returns those lines in an array.
106
+ #
107
+ # @param filename [String] path of the file to be read.
108
+ # @param selector [#to_proc, nil] predicate to filter lines that should be
109
+ # included in the output. It must accept two arguments: line and
110
+ # the line number. If `nil` is given, all lines are passed.
111
+ # @return [Array<String>] an array of read lines.
112
+ def read_lines(filename, selector)
113
+ if selector
114
+ IO.foreach(filename).select.with_index(1, &selector)
115
+ else
116
+ open(filename, &:read)
117
+ end
118
+ end
119
+
120
+ # Finds and initializes a lines selector that can handle the specified include.
121
+ #
122
+ # @param target (see #process)
123
+ # @param attributes (see #process)
124
+ # @return [#to_proc, nil] an instance of lines selector, or `nil` if not found.
125
+ def lines_selector_for(target, attributes)
126
+ if (klass = @selectors.find { |s| s.handles? target, attributes })
127
+ klass.new(target, attributes, logger: logger)
128
+ end
129
+ end
130
+
131
+ # Replaces the include directive in ouput with a notice that it has not
132
+ # been resolved.
133
+ #
134
+ # @param target (see #process)
135
+ # @param reader (see #process)
136
+ def unresolved_include!(target, reader)
137
+ reader.replace_next_line("Unresolved directive in #{reader.path} - include::#{target}[]")
138
+ end
139
+
140
+ private
141
+
142
+ # @param target (see #process)
143
+ # @return [Boolean] `true` if the *target* is an URI, `false` otherwise.
144
+ def target_uri?(target)
145
+ ::Asciidoctor::Helpers.uriish?(target)
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+ require 'asciidoctor/include_ext/version'
3
+
4
+ module Asciidoctor::IncludeExt
5
+ # Lines selector that selects lines of the content to be included based on
6
+ # the specified ranges of line numbers.
7
+ #
8
+ # @note Instance of this class can be used only once, as a predicate to
9
+ # filter a single include directive.
10
+ #
11
+ # @example
12
+ # include::some-file.adoc[lines=1;3..4;6..-1]
13
+ #
14
+ # @example
15
+ # selector = LinenoLinesSelector.new("some-file.adoc", {"lines" => "1;3..4;6..-1"})
16
+ # IO.foreach(filename).select.with_index(1, &selector)
17
+ #
18
+ # @see http://asciidoctor.org/docs/user-manual#by-line-ranges
19
+ class LinenoLinesSelector
20
+
21
+ # @return [Integer, nil] 1-based line number of the first included line,
22
+ # or `nil` if none.
23
+ attr_reader :first_included_lineno
24
+
25
+ # @param attributes [Hash<String, String>] the attributes parsed from the
26
+ # `include::[]`s attributes slot.
27
+ # @return [Boolean] `true` if the *attributes* hash contains a key `"lines"`.
28
+ def self.handles?(_, attributes)
29
+ attributes.key? 'lines'
30
+ end
31
+
32
+ # @param attributes [Hash<String, String>] the attributes parsed from the
33
+ # `include::[]`s attributes slot. It must contain a key `"lines"`.
34
+ def initialize(_, attributes, **)
35
+ @ranges = parse_attribute(attributes['lines'])
36
+ @first_included_lineno = @ranges.last.first unless @ranges.empty?
37
+ end
38
+
39
+ # Returns `true` if the given line should be included, `false` otherwise.
40
+ #
41
+ # @note This method modifies state of this object. It's supposed to be
42
+ # called successively with each line of the content being included.
43
+ # See {LinenoLinesSelector example}.
44
+ #
45
+ # @param line_num [Integer] 1-based *line* number.
46
+ # @return [Boolean] `true` to select the *line*, or `false` to reject.
47
+ def include?(_, line_num)
48
+ return false if @ranges.empty?
49
+
50
+ ranges = @ranges
51
+ ranges.pop while !ranges.empty? && ranges.last.last < line_num
52
+ ranges.last.cover?(line_num) if !ranges.empty?
53
+ end
54
+
55
+ # @return [Proc] {#include?} method as a Proc.
56
+ def to_proc
57
+ method(:include?).to_proc
58
+ end
59
+
60
+ protected
61
+
62
+ # @param lines_def [String] a comma or semicolon separated numbers and
63
+ # and ranges (e.g. `1..2`) specifying lines to be selected, or rejected
64
+ # if prefixed with "!".
65
+ # @return [Array<Range>] an array of ranges sorted by the range begin in
66
+ # _descending_ order.
67
+ def parse_attribute(lines_def)
68
+ lines_def
69
+ .split(/[,;]/)
70
+ .map! { |line_def|
71
+ from, to = line_def.split('..', 2).map(&:to_i)
72
+ to ||= from
73
+ to = ::Float::INFINITY if to == -1
74
+ (from..to)
75
+ }.sort! do |a, b|
76
+ b.first <=> a.first
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ require 'asciidoctor/reader'
3
+
4
+ # Monkey-patch Reader to add #document.
5
+ class Asciidoctor::Reader
6
+ attr_reader :document
7
+ end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+ require 'logger'
3
+ require 'set'
4
+
5
+ require 'asciidoctor'
6
+ require 'asciidoctor/include_ext/version'
7
+
8
+ module Asciidoctor::IncludeExt
9
+ # Lines selector that selects lines of the content based on the specified tags.
10
+ #
11
+ # @note Instance of this class can be used only once, as a predicate to
12
+ # filter a single include directive.
13
+ #
14
+ # @example
15
+ # include::some-file.adoc[tags=snippets;!snippet-b]
16
+ # include::some-file.adoc[tag=snippets]
17
+ #
18
+ # @example
19
+ # selector = TagLinesSelector.new("some-file.adoc", {"tag" => "snippets"})
20
+ # IO.foreach(filename).select.with_index(1, &selector)
21
+ #
22
+ # @see http://asciidoctor.org/docs/user-manual#by-tagged-regions
23
+ class TagLinesSelector
24
+
25
+ # @return [Integer, nil] 1-based line number of the first included line,
26
+ # or `nil` if none.
27
+ attr_reader :first_included_lineno
28
+
29
+ # @param attributes [Hash<String, String>] the attributes parsed from the
30
+ # `include::[]`s attributes slot.
31
+ # @return [Boolean] `true` if the *attributes* hash contains a key `"tag"`
32
+ # or `"tags"`.
33
+ def self.handles?(_, attributes)
34
+ attributes.key?('tag') || attributes.key?('tags')
35
+ end
36
+
37
+ # @param target [String] name of the source file to include as specified
38
+ # in the target slot of the `include::[]` directive.
39
+ # @param attributes [Hash<String, String>] the attributes parsed from the
40
+ # `include::[]`s attributes slot. It must contain a key `"tag"` or `"tags"`.
41
+ # @param logger [Logger]
42
+ def initialize(target, attributes, logger: Logger.new(STDERR), **)
43
+ tag_flags =
44
+ if attributes.key? 'tag'
45
+ parse_attribute(attributes['tag'], true)
46
+ else
47
+ parse_attribute(attributes['tags'])
48
+ end
49
+
50
+ wildcard = tag_flags.delete('*')
51
+ if tag_flags.key? '**'
52
+ default_state = tag_flags.delete('**')
53
+ wildcard = default_state if wildcard.nil?
54
+ else
55
+ default_state = !tag_flags.value?(true)
56
+ end
57
+
58
+ if (circ_cmt = ::Asciidoctor::CIRCUMFIX_COMMENTS[File.extname(target)])
59
+ # Note: "\s" instead of more practical "\s+" is here for compatibility
60
+ # with Asciidoctor.
61
+ suffix_rx = "(?:\s#{::Regexp.escape(circ_cmt[:suffix])})?"
62
+ end
63
+
64
+ # "immutable"
65
+ @target = target
66
+ @logger = logger
67
+ @tag_flags = tag_flags.freeze
68
+ @wildcard = wildcard
69
+ @tag_directive_rx = /\b(?:tag|(end))::(\S+)\[\]#{suffix_rx}$/.freeze
70
+
71
+ # mutable (state variables)
72
+ @stack = [[nil, default_state]]
73
+ @state = default_state
74
+ @used_tags = ::Set.new
75
+ end
76
+
77
+ # Returns `true` if the given line should be included, `false` otherwise.
78
+ #
79
+ # @note This method modifies state of this object. It's supposed to be
80
+ # called successively with each line of the content being included.
81
+ # See {TagLinesSelector example}.
82
+ #
83
+ # @param line [String]
84
+ # @param line_num [Integer] 1-based *line* number.
85
+ # @return [Boolean] `true` to select the *line*, `false` to reject.
86
+ def include?(line, line_num)
87
+ tag_type, tag_name = parse_tag_directive(line)
88
+
89
+ case tag_type
90
+ when :start
91
+ enter_region!(tag_name, line_num)
92
+ false
93
+ when :end
94
+ exit_region!(tag_name, line_num)
95
+ false
96
+ when nil
97
+ if @state && @first_included_lineno.nil?
98
+ @first_included_lineno = line_num
99
+ end
100
+ @state
101
+ end
102
+ end
103
+
104
+ # @return [Proc] {#include?} method as a Proc.
105
+ def to_proc
106
+ method(:include?).to_proc
107
+ end
108
+
109
+ protected
110
+
111
+ attr_reader :logger, :target
112
+
113
+ # @return [String, nil] a name of the active tag (region), or `nil` if none.
114
+ def active_tag
115
+ @stack.last.first
116
+ end
117
+
118
+ # @param tag_name [String]
119
+ # @param _line_num [Integer]
120
+ def enter_region!(tag_name, _line_num)
121
+ if @tag_flags.key? tag_name
122
+ @used_tags << tag_name
123
+ @state = @tag_flags[tag_name]
124
+ @stack << [tag_name, @state]
125
+ elsif !@wildcard.nil?
126
+ @state = active_tag && !@state ? false : @wildcard
127
+ @stack << [tag_name, @state]
128
+ end
129
+ end
130
+
131
+ # @param tag_name [String]
132
+ # @param line_num [Integer]
133
+ def exit_region!(tag_name, line_num)
134
+ # valid end tag
135
+ if tag_name == active_tag
136
+ @stack.pop
137
+ @state = @stack.last[1]
138
+
139
+ # mismatched/unexpected end tag
140
+ elsif @tag_flags.key? tag_name
141
+ log_prefix = "#{target}: line #{line_num}"
142
+
143
+ if (idx = @stack.rindex { |key, _| key == tag_name })
144
+ @stack.delete_at(idx)
145
+ logger.warn "#{log_prefix}: mismatched end tag include: expected #{active_tag}, found #{tag_name}" # rubocop:disable LineLength
146
+ else
147
+ logger.warn "#{log_prefix}: unexpected end tag in include: #{tag_name}"
148
+ end
149
+ end
150
+ end
151
+
152
+ # Parses `tag::<name>[]` and `end::<name>[]` in the given *line*.
153
+ #
154
+ # @param line [String]
155
+ # @return [Array, nil] a tuple `[Symbol, String]` where the first item is
156
+ # `:start` or `:end` and the second is a tag name. If no tag is matched,
157
+ # then `nil` is returned.
158
+ def parse_tag_directive(line)
159
+ @tag_directive_rx.match(line) do |m|
160
+ [m[1].nil? ? :start : :end, m[2]]
161
+ end
162
+ end
163
+
164
+ # @param tags_def [String] a comma or semicolon separated names of tags to
165
+ # be selected, or rejected if prefixed with "!".
166
+ # @param single [Boolean] whether the *tags_def* should be parsed as
167
+ # a single tag name (i.e. without splitting on comma/semicolon).
168
+ # @return [Hash<String, Boolean>] a Hash with tag names as keys and boolean
169
+ # flags as values.
170
+ def parse_attribute(tags_def, single = false)
171
+ atoms = single ? [tags_def] : tags_def.split(/[,;]/)
172
+
173
+ atoms.each_with_object({}) do |atom, tags|
174
+ if atom.start_with? '!'
175
+ tags[atom[1..-1]] = false if atom != '!'
176
+ elsif !atom.empty?
177
+ tags[atom] = true
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module IncludeExt
5
+ # Version of the asciidoctor-include-ext gem.
6
+ VERSION = '0.1.0'.freeze
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asciidoctor-include-ext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jakub Jirutka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-12-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: asciidoctor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.5.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.5.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: corefines
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.11'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.11'
41
+ - !ruby/object:Gem::Dependency
42
+ name: kramdown
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '12.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '12.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.7'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.51.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.51.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.15'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.15'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.9'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.9'
125
+ description: |
126
+ This is a reimplementation of the Asciidoctor's built-in (pre)processor for the
127
+ include::[] directive in extensible and more clean way. It provides the same
128
+ features, but you can easily adjust it or extend for your needs. For example,
129
+ you can change how it loads included files or add another ways how to select
130
+ portions of the document to include.
131
+ email: jakub@jirutka.cz
132
+ executables: []
133
+ extensions: []
134
+ extra_rdoc_files: []
135
+ files:
136
+ - LICENSE
137
+ - README.adoc
138
+ - asciidoctor-include-ext.gemspec
139
+ - lib/asciidoctor-include-ext.rb
140
+ - lib/asciidoctor/include_ext.rb
141
+ - lib/asciidoctor/include_ext/include_processor.rb
142
+ - lib/asciidoctor/include_ext/lineno_lines_selector.rb
143
+ - lib/asciidoctor/include_ext/reader_ext.rb
144
+ - lib/asciidoctor/include_ext/tag_lines_selector.rb
145
+ - lib/asciidoctor/include_ext/version.rb
146
+ homepage: https://github.com/jirutka/asciidoctor-include-ext
147
+ licenses:
148
+ - MIT
149
+ metadata: {}
150
+ post_install_message:
151
+ rdoc_options: []
152
+ require_paths:
153
+ - lib
154
+ required_ruby_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '2.1'
159
+ required_rubygems_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ requirements: []
165
+ rubyforge_project:
166
+ rubygems_version: 2.6.11
167
+ signing_key:
168
+ specification_version: 4
169
+ summary: Asciidoctor's standard include::[] processor reimplemented as an extension
170
+ test_files: []