asciidoctor 0.0.9 → 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 might be problematic. Click here for more details.

Files changed (42) hide show
  1. data/README.asciidoc +163 -41
  2. data/Rakefile +3 -1
  3. data/asciidoctor.gemspec +13 -5
  4. data/bin/asciidoctor +6 -3
  5. data/bin/asciidoctor-safe +13 -0
  6. data/lib/asciidoctor.rb +237 -26
  7. data/lib/asciidoctor/abstract_node.rb +27 -17
  8. data/lib/asciidoctor/attribute_list.rb +6 -0
  9. data/lib/asciidoctor/backends/base_template.rb +3 -4
  10. data/lib/asciidoctor/backends/docbook45.rb +114 -55
  11. data/lib/asciidoctor/backends/html5.rb +173 -104
  12. data/lib/asciidoctor/cli/invoker.rb +105 -0
  13. data/lib/asciidoctor/cli/options.rb +146 -0
  14. data/lib/asciidoctor/document.rb +135 -35
  15. data/lib/asciidoctor/lexer.rb +86 -33
  16. data/lib/asciidoctor/list_item.rb +2 -2
  17. data/lib/asciidoctor/reader.rb +6 -7
  18. data/lib/asciidoctor/section.rb +17 -5
  19. data/lib/asciidoctor/substituters.rb +216 -97
  20. data/lib/asciidoctor/table.rb +9 -2
  21. data/lib/asciidoctor/version.rb +1 -1
  22. data/man/asciidoctor.1 +212 -0
  23. data/man/asciidoctor.ad +156 -0
  24. data/test/attributes_test.rb +108 -5
  25. data/test/blocks_test.rb +102 -15
  26. data/test/document_test.rb +214 -3
  27. data/test/fixtures/encoding.asciidoc +4 -0
  28. data/test/fixtures/sample.asciidoc +26 -0
  29. data/test/invoker_test.rb +254 -0
  30. data/test/lexer_test.rb +53 -0
  31. data/test/links_test.rb +30 -0
  32. data/test/lists_test.rb +648 -9
  33. data/test/options_test.rb +68 -0
  34. data/test/paragraphs_test.rb +65 -1
  35. data/test/reader_test.rb +18 -4
  36. data/test/{headers_test.rb → sections_test.rb} +237 -0
  37. data/test/substitutions_test.rb +247 -5
  38. data/test/tables_test.rb +22 -4
  39. data/test/test_helper.rb +47 -3
  40. data/test/text_test.rb +20 -4
  41. metadata +34 -6
  42. data/noof.rb +0 -16
@@ -1,46 +1,53 @@
1
- [float]
2
1
  Asciidoctor
3
2
  ===========
4
- :asciidoctor: http://github.com/erebor/asciidoctor
5
- :asciidoc: http://www.methods.co.nz/asciidoc/index.html
3
+ :asciidoctor: http://asciidoctor.org
4
+ :asciidoctor-source: http://github.com/asciidoctor/asciidoctor
5
+ :asciidoc: http://asciidoc.org
6
6
  :gitscm-next: https://github.com/github/gitscm-next
7
- :asciidoctorseed: https://github.com/github/gitscm-next/commits/master/lib/asciidoc.rb
8
- :templates: https://github.com/erebor/asciidoctor/blob/master/lib/asciidoctor/render_templates.rb
7
+ :asciidoctor-seed: https://github.com/github/gitscm-next/commits/master/lib/asciidoc.rb
8
+ :templates: https://github.com/asciidoctor/asciidoctor/blob/master/lib/asciidoctor/backends
9
9
  :tilt: https://github.com/rtomayko/tilt
10
10
  :freesoftware: http://www.fsf.org/licensing/essays/free-sw.html
11
- :issues: https://github.com/erebor/asciidoctor/issues
11
+ :issues: https://github.com/asciidoctor/asciidoctor/issues
12
12
  :gist: https://gist.github.com
13
13
  :fork: http://help.github.com/fork-a-repo/
14
14
  :branch: http://learn.github.com/p/branching.html
15
15
  :pr: http://help.github.com/send-pull-requests/
16
- :license: https://github.com/erebor/asciidoctor/blob/master/LICENSE
16
+ :license: https://github.com/asciidoctor/asciidoctor/blob/master/LICENSE
17
+ :idprefix:
17
18
 
18
- {asciidoctor}[Asciidoctor] is a pure-Ruby processor for turning
19
- {asciidoc}[AsciiDoc] documents or strings into HTML (and, eventually
20
- other formats as well...'stay tuned!').
19
+ {asciidoctor}[Asciidoctor] is a pure Ruby processor for converting
20
+ {asciidoc}[AsciiDoc] source files and strings into HTML 5, DocBook 4.5
21
+ and other formats. It's
22
+ http://rubygems.org/gems/asciidoctor[published as a RubyGem] and is
23
+ available under the MIT open source license.
21
24
 
22
- image::https://travis-ci.org/erebor/asciidoctor.png?branch=master["Build Status", link="https://travis-ci.org/erebor/asciidoctor"]
25
+ image::https://travis-ci.org/asciidoctor/asciidoctor.png?branch=master["Build Status", link="https://travis-ci.org/asciidoctor/asciidoctor"]
23
26
 
24
- Asciidoctor uses simple built-in ERB templates to style the output in
25
- a way that roughly matches the default HTML output of the native
26
- Python processor. You can override this behavior by providing
27
- {tilt}[Tilt]-compatible templates. See the xref:usage[Usage section]
28
- for more details.
27
+ Asciidoctor uses a set of built-in ERB templates to render the document
28
+ to HTML 5 or DocBook 4.5. We've matched the rendered output as close as
29
+ possible to the default output of the native Python processor. You can
30
+ override this behavior by providing {tilt}[Tilt]-compatible templates.
31
+ See the xref:usage[Usage section] for more details.
29
32
 
30
- Asciidoctor currently works with Ruby 1.8.7 and 1.9.3, though I don't
31
- know of any reason it shouldn't work with more exotic Ruby versions,
32
- and would welcome help in testing that out.
33
+ Asciidoctor currently works (read as 'tested') with Ruby 1.8.7, Ruby
34
+ 1.9.3 and JRuby 1.7.2 (on Linux, Mac and Windows). We expect it will
35
+ work with other versions of Ruby as well and would welcome help in
36
+ testing it out.
33
37
 
34
- The initial code from which Asciidoctor started was from the
38
+ The initial code from which Asciidoctor started emerged from the
35
39
  {gitscm-next}[Git SCM site repo]. Refer to commit history of
36
- {asciidoctorseed}[asciidoc.rb] to view the initial contributions.
40
+ {asciidoctor-seed}[asciidoc.rb] to view the initial contributions and
41
+ individual contributors.
42
+
43
+ The source code can now be found in the {asciidoctor-source}[Asciidoctor
44
+ source repository] on GitHub.
37
45
 
38
46
  == Installation
39
47
 
40
- NOTE: This gem is very immature, and as yet only supports a small subset
41
- of AsciiDoc features (but it's getting better!). Thus, you should only
42
- use it if you have a high tolerance for bugs, failures, and generally
43
- bad and intemperate behavior.
48
+ NOTE: We are working hard to make Asciidoctor a drop-in replacement for
49
+ AsciiDoc. We're very close, with nearly 600 tests that ensure
50
+ compatibility. The march is on towards full compliance and beyond.
44
51
 
45
52
  To install the gem:
46
53
 
@@ -52,20 +59,91 @@ Or if you prefer bundler:
52
59
 
53
60
  == Usage
54
61
 
55
- To render a file containing AsciiDoc markup to HTML:
62
+ Asciidoctor has both a command line interface (CLI) and an API. The
63
+ CLI is a drop-in replacement for the `asciidoc.py` command from the
64
+ python implementation. The API is intended for integration with other
65
+ software projects and is suitable for server-side applications, such
66
+ as Rails, Sinatra and GitHub.
67
+
68
+ === Command line interface (CLI)
69
+
70
+ After installing the `asciidoctor` gem, the `asciidoctor` commandline
71
+ interface should be available on your PATH after installing the gem.
72
+ To invoke it, simply execute:
73
+
74
+ asciidoctor <asciidoc_file>
75
+
76
+ This will use the built-in defaults for options and create a new file
77
+ in the same directory as the input file, with the same base name, but
78
+ with the .html extention.
79
+
80
+ There are many other options available and full help is provided via:
81
+
82
+ asciidoctor --help
83
+
84
+ , or in the http://asciidoctor.org/man/asciidoctor[man page].
85
+
86
+ There is also an `asciidoctor-safe` command, which turns on safe mode
87
+ by default, preventing access to files outside the parent directory of
88
+ the source file. This mode is very similar to the safe mode of `asciidoc.py`.
89
+
90
+ === Ruby API
91
+
92
+ To use Asciidoctor in your application, you first need to require the
93
+ gem:
94
+
95
+ require 'asciidoctor'
96
+
97
+ With that in place, you can start processing AsciiDoc documents.
98
+
99
+ .Loading a document
100
+ To parse a file into an `Asciidoctor::Document` object:
56
101
 
57
- lines = File.readlines('your_file.asciidoc')
58
- doc = Asciidoctor::Document.new(lines)
59
- html = doc.render
60
- File.open('your_file.html', 'w+') do |file|
61
- file.puts html
62
- end
102
+ doc = Asciidoctor.load_file('your_file.asciidoc')
63
103
 
104
+ You can get information about the document:
105
+
106
+ puts doc.doctitle
107
+ puts doc.attributes
108
+
109
+ More than likely, you want to just render the document.
110
+
111
+ .Rendering files
112
+ To render a file containing AsciiDoc markup to HTML 5:
113
+
114
+ Asciidoctor.render_file('your_file.asciidoc', :in_place => true)
115
+
116
+ The command will output to the file `your_file.html` in the same
117
+ directory. You can render the file to DocBook 4.5 by setting the
118
+ `backend` attribute to 'docbook':
119
+
120
+ Asciidoctor.render_file('your_file.asciidoc', :in_place => true,
121
+ :attributes => {'backend' => 'docbook'})
122
+
123
+ The command will output to the file `your_file.xml` in the same
124
+ directory. (If you're on Linux, you can view the file using yelp).
125
+
126
+ .Rendering strings
64
127
  To render an AsciiDoc-formatted string:
65
128
 
66
- doc = Asciidoctor::Document.new("*This* is it.")
67
- puts doc.render
129
+ puts Asciidoctor.render('*This* is it.')
130
+
131
+ When rendering a string, the header and footer are excluded by default
132
+ to make Asciidoctor consistent with other lightweight markup engines
133
+ like Markdown. If you want the header and footer, just declare it as
134
+ an option:
135
+
136
+ puts Asciidoctor.render('*This* is it.', :header_footer => true)
137
+
138
+ Now you'll get a full HTML 5 file. As before, you can also produce
139
+ DocBook 4.5:
68
140
 
141
+ puts Asciidoctor.render('*This* is it.', :header_footer => true,
142
+ :attributes => {'backend' => 'docbook'})
143
+
144
+ If you don't like the output you see, you can change it. Any of it!
145
+
146
+ .Custom templates
69
147
  Asciidoctor allows you to override the {templates}[built-in templates]
70
148
  used to render almost any individual AsciiDoc element. If you provide a
71
149
  directory of {tilt}[Tilt]-compatible templates, named in such a way that
@@ -74,8 +152,8 @@ Asciidoctor will use the templates in this directory instead of its
74
152
  built-in templates for any elements for which it finds a matching
75
153
  template. It will fallback to its default templates for everything else.
76
154
 
77
- doc = Asciidoctor::Document.new("*This* is it.", :template_dir => 'templates')
78
- puts doc.render
155
+ puts Asciidoctor.render('*This* is it.', :header_footer => true,
156
+ :template_dir => 'templates')
79
157
 
80
158
  The Document and Section templates should begin with `document.` and
81
159
  `section.`, respectively. The file extension is used by Tilt to
@@ -90,7 +168,47 @@ template with an ERB template, put a file named
90
168
  `block_paragraph.html.erb` in the template directory you pass to the
91
169
  `Document` constructor using the `template_dir` option.
92
170
 
93
- For more usage examples, see the test suite.
171
+ For more usage examples, see the (massive) test suite.
172
+
173
+ == Differences from AsciiDoc
174
+
175
+ While Asciidoctor aims to be compliant with the AsciiDoc syntax, there are some differences which are important to keep in mind. In some cases, it's to enforce a rule we believe is too lax or ambiguous in AsciiDoc. In other cases, it's a tradeoff for speed, smarter processing or a feature we just haven't yet implemented. (You'll also notice that Asciidoctor is about 20x faster than AsciiDoc).
176
+
177
+ Here are the known cases where Asciidoctor differs from AsciiDoc:
178
+
179
+ * In Asciidoctor, safe mode is on by default when using the API (safe mode level SECURE),
180
+ * Asciidoctor safe mode is even more safe than AsciiDoc's safe mode
181
+ * Asciidoctor enforces symmetric block delimiters (the length of start and end delimiters for a block must match)
182
+ * Section title underlines must be within +/- 1 of the length of the title (AsciiDoc is +/- 3)
183
+ * Asciidoctor's default HTML backend matches AsciiDoc's HTML 5 backend (whereas XHTML 1.1 is the default HTML backend in AsciiDoc)
184
+ * Asciidoctor handles inline anchors more cleanly
185
+ ** AsciiDoc adds an `<a>` tag in the line and that markup gets caught in the generated id
186
+ ** Asciidoctor promotes the id of the anchor as the section id
187
+ * Asciidoctor strips XML entities from the section title before generating the id (makes for cleaner section ids)
188
+ * Asciidoctor use `<tt>` instead of `<span class="monospace">` around inline literal text in the HTML backend
189
+ * Asciidoctor is much more lenient about attribute list parsing (double quotes are rarely needed)
190
+ * Asciidoctor creates xref labels using the text from the linked section title when rendering HTML to match how DocBook works
191
+ * Asciidoctor allows commas to be used in xref labels, whereas AsciiDoc cuts off the label at the location of the first comma
192
+ * Asciidoctor removes indentation for non-literal paragraphs in a list item
193
+ ** In general, Asciidoctor handles whitespace much more intelligently
194
+ * In Asciidoctor, a ruler can have attributes
195
+ * Asciidoctor skips over line comments in tables, whereas AsciiDoc does not
196
+ * Asciidoctor uses its own API rather than a command line invocation to handle table cells that have AsciiDoc content
197
+ * Asciidoctor supports resolving variables from parent document in table cells with AsciiDoc content
198
+ * AsciiDoc doesn't carry over the doctype attribute passed from the commandline when rendering AsciiDoc content cells, whereas Asciidoctor does
199
+ * Asciidoctor strips the file extension from the target image when generating alt text if no alt text is provided
200
+ * Asciidoctor reifies the toc in the header of the document instead of relying on JavaScript to create it
201
+ * Asciidoctor is nice about using a section title syntax inside a delimited block by simply ignoring it (AsciiDoc issues warnings)
202
+ * Asciidoctor honors the alternate style name "discrete" for a floating title (i.e., [discrete])
203
+ * Asciidoctor supports syntax highlighting of listing or literal blocks that have the "source" style out of the box
204
+ ** Asciidoctor honors the source-highlighter values `coderay` and `highlightjs`, using CodeRay or highlight.js, respectively
205
+ ** Asciidoctor does not currently support Pygments for source highlighting
206
+ * Asciidoctor sets these additional intrinsic attributes
207
+ `asciidoctor`:: indicates Asciidoctor is being used; useful for conditional processing
208
+ `asciidoctor-version`:: indicates which version of Asciidoctor is in use
209
+ * Asciidoctor does not support deprecated tables (you don't want them anyway)
210
+
211
+ If there's a difference you don't see in this list, check the {issues}[issue tracker] to see if it's an outstanding feature, or file an issue to report the difference.
94
212
 
95
213
  == Contributing
96
214
 
@@ -104,8 +222,11 @@ Here are some ways *you* can contribute:
104
222
  * by suggesting new features
105
223
  * by writing or editing documentation
106
224
  * by writing specifications
107
- * by writing code ('No patch is too small.' Fix typos, add comments,
108
- clean up inconsistent whitespace, etc.)
225
+ * by writing code -- 'No patch is too small.'
226
+ ** fix typos
227
+ ** add comments
228
+ ** clean up inconsistent whitespace
229
+ ** write tests!
109
230
  * by refactoring code
110
231
  * by fixing {issues}[issues]
111
232
  * by reviewing patches
@@ -138,13 +259,14 @@ An ideal bug report would include a pull request with failing specs.
138
259
  . Add, commit, and push your changes.
139
260
  . {pr}[Submit a pull request].
140
261
 
141
-
142
262
  == Supported Ruby Versions
143
263
 
144
264
  This library aims to support the following Ruby implementations:
145
265
 
146
266
  * Ruby 1.8.7
147
267
  * Ruby 1.9.3
268
+ * JRuby 1.7.2
269
+ * Rubinius 1.2.4
148
270
 
149
271
  If something doesn't work on one of these interpreters, it should be
150
272
  considered a bug.
@@ -159,7 +281,7 @@ support for that Ruby version may be dropped.
159
281
 
160
282
  == Copyright
161
283
 
162
- Copyright (c) 2012 Ryan Waldron.
284
+ Copyright (C) 2012 Ryan Waldron.
163
285
  See {license}[LICENSE] for details.
164
286
 
165
287
  // vim: tw=72
data/Rakefile CHANGED
@@ -49,6 +49,7 @@ require 'rake/testtask'
49
49
  Rake::TestTask.new(:test) do |test|
50
50
  test.libs << 'lib' << 'test'
51
51
  test.pattern = 'test/**/*_test.rb'
52
+ test.warning = true
52
53
  test.verbose = true
53
54
  end
54
55
 
@@ -62,9 +63,10 @@ end
62
63
 
63
64
  begin
64
65
  require 'rdoc/task'
65
- Rake::RDocTask.new do |rdoc|
66
+ RDoc::Task.new do |rdoc|
66
67
  rdoc.rdoc_dir = 'rdoc'
67
68
  rdoc.title = "#{name} #{version}"
69
+ rdoc.markup = 'tomdoc' if rdoc.respond_to?(:markup)
68
70
  rdoc.rdoc_files.include('README*')
69
71
  rdoc.rdoc_files.include('lib/**/*.rb')
70
72
  end
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'asciidoctor'
16
- s.version = '0.0.9'
17
- s.date = '2013-01-16'
16
+ s.version = '0.1.0'
17
+ s.date = '2013-02-04'
18
18
  s.rubyforge_project = 'asciidoctor'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
27
27
  ## a custom homepage, consider using your GitHub URL or the like.
28
28
  s.authors = ["Ryan Waldron", "Dan Allen", "Jeremy McAnally"]
29
29
  s.email = 'rew@erebor.com'
30
- s.homepage = 'http://github.com/erebor/asciidoctor'
30
+ s.homepage = 'http://github.com/asciidoctor'
31
31
 
32
32
  ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
33
33
  ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
@@ -53,6 +53,7 @@ Gem::Specification.new do |s|
53
53
  s.add_development_dependency('nokogiri')
54
54
  s.add_development_dependency('pending')
55
55
  s.add_development_dependency('rake')
56
+ s.add_development_dependency('rdoc', '~> 3.12')
56
57
  s.add_development_dependency('tilt')
57
58
 
58
59
  ## Leave this section as-is. It will be automatically generated from the
@@ -66,6 +67,7 @@ Gem::Specification.new do |s|
66
67
  Rakefile
67
68
  asciidoctor.gemspec
68
69
  bin/asciidoctor
70
+ bin/asciidoctor-safe
69
71
  lib/asciidoctor.rb
70
72
  lib/asciidoctor/abstract_block.rb
71
73
  lib/asciidoctor/abstract_node.rb
@@ -75,6 +77,8 @@ Gem::Specification.new do |s|
75
77
  lib/asciidoctor/backends/html5.rb
76
78
  lib/asciidoctor/block.rb
77
79
  lib/asciidoctor/callouts.rb
80
+ lib/asciidoctor/cli/invoker.rb
81
+ lib/asciidoctor/cli/options.rb
78
82
  lib/asciidoctor/debug.rb
79
83
  lib/asciidoctor/document.rb
80
84
  lib/asciidoctor/errors.rb
@@ -87,7 +91,8 @@ Gem::Specification.new do |s|
87
91
  lib/asciidoctor/substituters.rb
88
92
  lib/asciidoctor/table.rb
89
93
  lib/asciidoctor/version.rb
90
- noof.rb
94
+ man/asciidoctor.1
95
+ man/asciidoctor.ad
91
96
  test/attributes_test.rb
92
97
  test/blocks_test.rb
93
98
  test/document_test.rb
@@ -98,15 +103,18 @@ Gem::Specification.new do |s|
98
103
  test/fixtures/encoding.asciidoc
99
104
  test/fixtures/include-file.asciidoc
100
105
  test/fixtures/list_elements.asciidoc
106
+ test/fixtures/sample.asciidoc
101
107
  test/fixtures/tip.gif
102
- test/headers_test.rb
108
+ test/invoker_test.rb
103
109
  test/lexer_test.rb
104
110
  test/links_test.rb
105
111
  test/lists_test.rb
112
+ test/options_test.rb
106
113
  test/paragraphs_test.rb
107
114
  test/preamble_test.rb
108
115
  test/reader_test.rb
109
116
  test/renderer_test.rb
117
+ test/sections_test.rb
110
118
  test/substitutions_test.rb
111
119
  test/tables_test.rb
112
120
  test/test_helper.rb
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $:.unshift File.dirname(__FILE__) + '/../lib'
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
4
 
5
5
  require 'asciidoctor'
6
- require 'asciidoctor/cli'
6
+ require 'asciidoctor/cli/options'
7
+ require 'asciidoctor/cli/invoker'
7
8
 
8
- Asciidoctor::Cli.new.run
9
+ invoker = Asciidoctor::Cli::Invoker.new(ARGV)
10
+ invoker.invoke!
11
+ exit invoker.code
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ require 'asciidoctor'
6
+ require 'asciidoctor/cli/options'
7
+ require 'asciidoctor/cli/invoker'
8
+
9
+ options = Asciidoctor::Cli::Options.parse! ARGV
10
+ options[:safe] = Asciidoctor::SafeMode::SAFE
11
+ invoker = Asciidoctor::Cli::Invoker.new(options)
12
+ invoker.invoke!
13
+ exit invoker.code
@@ -57,19 +57,29 @@ module Asciidoctor
57
57
  # the source file and disables any macro other than the include::[] macro.
58
58
  SAFE = 1;
59
59
 
60
- # A safe mode level that disallows the document from attempting to read files
61
- # from the file system and including the contents of them into the document.
62
- # This value disallows use of the include::[] macro and the embedding of
63
- # binary content (data uri), stylesheets and JavaScripts referenced by the
64
- # document. (Asciidoctor and trusted extensions may still be allowed to embed
65
- # trusted content into the document). Since Asciidoctor is aiming for wide
66
- # adoption, this value is the default and is recommended for server-side
67
- # deployments.
68
- SECURE = 10;
60
+ # A safe mode level that disallows the document from setting attributes
61
+ # that would affect the rendering of the document, in addition to all the
62
+ # security features of SafeMode::SAFE. For instance, this level disallows
63
+ # changing the backend or the source-highlighter using an attribute defined
64
+ # in the source document. This is the most fundamental level of security
65
+ # for server-side deployments (hence the name).
66
+ SERVER = 10;
67
+
68
+ # A safe mode level that disallows the document from attempting to read
69
+ # files from the file system and including the contents of them into the
70
+ # document, in additional to all the security features of SafeMode::SERVER.
71
+ # For instance, this level disallows use of the include::[] macro and the
72
+ # embedding of binary content (data uri), stylesheets and JavaScripts
73
+ # referenced by the document.(Asciidoctor and trusted extensions may still
74
+ # be allowed to embed trusted content into the document).
75
+ #
76
+ # Since Asciidoctor is aiming for wide adoption, this level is the default
77
+ # and is recommended for server-side deployments.
78
+ SECURE = 20;
69
79
 
70
80
  # A planned safe mode level that disallows the use of passthrough macros and
71
81
  # prevents the document from setting any known attributes, in addition to all
72
- # the security features of SafeMode::SECURE
82
+ # the security features of SafeMode::SECURE.
73
83
  #
74
84
  # Please note that this level is not currently implemented (and therefore not
75
85
  # enforced)!
@@ -81,14 +91,28 @@ module Asciidoctor
81
91
  # Can influence markup generated by render templates
82
92
  DEFAULT_DOCTYPE = 'article'
83
93
 
84
- # Backend determines the format of the rendered output, default to html5
94
+ # The backend determines the format of the rendered output, default to html5
85
95
  DEFAULT_BACKEND = 'html5'
86
96
 
97
+ # Pointers to the preferred version for a given backend.
98
+ BACKEND_ALIASES = {
99
+ 'html' => 'html5',
100
+ 'docbook' => 'docbook45'
101
+ }
102
+
87
103
  # Default page widths for calculating absolute widths
88
104
  DEFAULT_PAGE_WIDTHS = {
89
105
  'docbook' => 425
90
106
  }
91
107
 
108
+ # Default extensions for the respective base backends
109
+ DEFAULT_EXTENSIONS = {
110
+ 'html' => '.html',
111
+ 'docbook' => '.xml',
112
+ 'asciidoc' => '.ad',
113
+ 'markdown' => '.md'
114
+ }
115
+
92
116
  LIST_CONTEXTS = [:ulist, :olist, :dlist, :colist]
93
117
 
94
118
  NESTABLE_LIST_CONTEXTS = [:ulist, :olist, :dlist]
@@ -109,6 +133,13 @@ module Asciidoctor
109
133
 
110
134
  LINE_FEED_ENTITY = '&#10;' # or &#x0A;
111
135
 
136
+ # The following pattern, which appears frequently, captures the contents between square brackets,
137
+ # ignoring escaped closing brackets (closing brackets prefixed with a backslash '\' character)
138
+ #
139
+ # Pattern:
140
+ # (?:\[((?:\\\]|[^\]])*?)\])
141
+ # Matches:
142
+ # [enclosed text here] or [enclosed [text\] here]
112
143
  REGEXP = {
113
144
  # [[Foo]]
114
145
  :anchor => /^\[\[([^\[\]]+)\]\]\s*$/,
@@ -159,14 +190,15 @@ module Asciidoctor
159
190
 
160
191
  # attribute reference
161
192
  # {foo}
162
- :attr_ref => /(\\?)\{(\w|\w[\w\-]*\w)(\\?)\}/,
193
+ # {counter:pcount:1}
194
+ :attr_ref => /(\\?)\{(\w|\w[\w\-:]*\w)(\\?)\}/,
163
195
 
164
196
  # The author info line the appears immediately following the document title
165
197
  # John Doe <john@anonymous.com>
166
- :author_info => /^\s*([\w\-]+)(?: +([\w\-]+))?(?: +([\w\-]+))?(?: +<([^>]+)>)?\s*$/,
198
+ :author_info => /^\s*(\w[\w\-'\.]*)(?: +(\w[\w\-'\.]*))?(?: +(\w[\w\-'\.]*))?(?: +<([^>]+)>)?\s*$/,
167
199
 
168
- # [[[Foo]]] (does not suffer quite the same malady as :anchor, but almost. Allows [ but not ] in internal capture
169
- :biblio => /\[\[\[([^\[\]]+)\]\]\]/,
200
+ # [[[Foo]]] (anywhere inline)
201
+ :biblio_macro => /\\?\[\[\[([\w:][\w:\.-]*?)\]\]\]/,
170
202
 
171
203
  # callout reference inside literal text
172
204
  # <1>
@@ -186,6 +218,11 @@ module Asciidoctor
186
218
  # // (and then whatever)
187
219
  :comment => %r{^//([^/].*|)$},
188
220
 
221
+ # one,two
222
+ # one, two
223
+ # one , two
224
+ :csv_delimiter => /[[:space:]]*,[[:space:]]*/,
225
+
189
226
  # 29
190
227
  :digits => /^\d+$/,
191
228
 
@@ -208,12 +245,25 @@ module Asciidoctor
208
245
  # ====
209
246
  :example => /^={4,}\s*$/,
210
247
 
248
+ # footnote:[text]
249
+ # footnoteref:[id,text]
250
+ # footnoteref:[id]
251
+ :footnote_macro => /\\?(footnote|footnoteref):\[((?:\\\]|[^\]])*?)\]/m,
252
+
211
253
  # image::filename.png[Caption]
212
- :image_blk => /^image::(\S+?)\[(.*?)\]$/,
254
+ :image_blk => /^image::(\S+?)\[(.*?)\]\s*$/,
213
255
 
214
- # image:filename.png[Alt]
256
+ # image:filename.png[Alt Text]
215
257
  :image_macro => /\\?image:([^\[]+)(?:\[([^\]]*)\])/,
216
258
 
259
+ # indexterm:[Tigers,Big cats]
260
+ # (((Tigers,Big cats)))
261
+ :indexterm_macro => /\\?(?:indexterm:(?:\[((?:\\\]|[^\]])*?)\])|\(\(\((.*?)\)\)\)(?!\)))/m,
262
+
263
+ # indexterm2:[Tigers]
264
+ # ((Tigers))
265
+ :indexterm2_macro => /\\?(?:indexterm2:(?:\[((?:\\\]|[^\]])*?)\])|\(\((.*?)\)\)(?!\)))/m,
266
+
217
267
  # whitespace at the beginning of the line
218
268
  :leading_blanks => /^([[:blank:]]*)/,
219
269
 
@@ -228,11 +278,11 @@ module Asciidoctor
228
278
 
229
279
  # inline link and some inline link macro
230
280
  # FIXME revisit!
231
- :link_inline => %r{(^|link:|\s|>|&lt;|[\(\)\]])(\\?https?://[^\[ ]*[^\. \)\[])(?:\[((?:\\\]|[^\]])*?)\])?},
281
+ :link_inline => %r{(^|link:|\s|>|&lt;|[\(\)\[\]])(\\?https?://[^\s\[<]*[^\s\.\)\[<])(?:\[((?:\\\]|[^\]])*?)\])?},
232
282
 
233
283
  # inline link macro
234
284
  # link:path[label]
235
- :link_macro => /\\?link:([^\[ ]+)(?:\[((?:\\\]|[^\]])*?)\])/,
285
+ :link_macro => /\\?link:([^\s\[]+)(?:\[((?:\\\]|[^\]])*?)\])/,
236
286
 
237
287
  # ----
238
288
  :listing => /^\-{4,}\s*$/,
@@ -328,8 +378,8 @@ module Asciidoctor
328
378
  #
329
379
  # match[1] is the delimiter, whose length determines the level
330
380
  # match[2] is the title itself
331
- # match[3] is an optional repeat of the delimiter, which is dropped
332
- :section_title => /^(={1,5})\s+(\S.*?)\s*(?:\[\[([^\[]+)\]\]\s*)?(\s\1)?$/,
381
+ # match[3] is an inline anchor, which becomes the section id
382
+ :section_title => /^(={1,5})\s+(\S.*?)\s*(?:\[\[([^\[]+)\]\]\s*)?(?:\s\1)?$/,
333
383
 
334
384
  # does not begin with a dot and has at least one alphanumeric character
335
385
  :section_name => /^((?=.*\w+.*)[^\.].*?)\s*$/,
@@ -458,7 +508,7 @@ module Asciidoctor
458
508
  # (TM)
459
509
  [/(^|[^\\])\(TM\)/, '\1&#8482;'],
460
510
  # foo -- bar
461
- [/ -- /, '&#8201;&#8212;&#8201;'],
511
+ [/(^|\n| )-- /, '&#8201;&#8212;&#8201;'],
462
512
  # foo--bar
463
513
  [/(\w)--(?=\w)/, '\1&#8212;'],
464
514
  # ellipsis
@@ -467,31 +517,192 @@ module Asciidoctor
467
517
  [/(\w)'(\w)/, '\1&#8217;\2'],
468
518
  # escaped single quotes
469
519
  [/(\w)\\'(\w)/, '\1\'\2'],
520
+ # right arrow ->
521
+ [/(^|[^\\])-&gt;/, '\1&#8594;'],
522
+ # right double arrow =>
523
+ [/(^|[^\\])=&gt;/, '\1&#8658;'],
524
+ # left arrow <-
525
+ [/(^|[^\\])&lt;-/, '\1&#8592;'],
526
+ # right left arrow <=
527
+ [/(^|[^\\])&lt;=/, '\1&#8656;'],
470
528
  # and so on...
471
529
 
472
530
  # restore entities; TODO needs cleanup
473
- [/&amp;(#[a-z0-9]+;)/i, '&\1']
531
+ [/(^|[^\\])&amp;(#[a-z0-9]+;)/i, '\1&\2']
474
532
  ]
475
533
 
534
+ # Public: Parse the AsciiDoc source input into an Asciidoctor::Document
535
+ #
536
+ # Accepts input as an IO (or StringIO), String or String Array object. If the
537
+ # input is a File, information about the file is stored in attributes on the
538
+ # Document object.
539
+ #
540
+ # input - the AsciiDoc source as a IO, String or Array.
541
+ # options - a Hash of options to control processing (default: {})
542
+ # see Asciidoctor::Document#initialize for details
543
+ # block - a callback block for handling include::[] directives
544
+ #
545
+ # returns the Asciidoctor::Document
546
+ def self.load(input, options = {}, &block)
547
+ lines = nil
548
+ if input.is_a?(File)
549
+ options[:attributes] ||= {}
550
+ attrs = options[:attributes]
551
+ lines = input.readlines
552
+ input_mtime = input.mtime
553
+ input_path = File.expand_path(input.path)
554
+ # hold off on setting infile and indir until we get a better sense of their purpose
555
+ attrs['docfile'] = input_path
556
+ attrs['docdir'] = File.dirname(input_path)
557
+ attrs['docname'] = File.basename(input_path, File.extname(input_path))
558
+ attrs['docdate'] = input_mtime.strftime('%Y-%m-%d')
559
+ attrs['doctime'] = input_mtime.strftime('%H:%M:%S %Z')
560
+ attrs['docdatetime'] = [attrs['docdate'], attrs['doctime']] * ' '
561
+ elsif input.respond_to?(:readlines)
562
+ input.rewind rescue nil
563
+ lines = input.readlines
564
+ elsif input.is_a?(String)
565
+ lines = input.lines.entries
566
+ elsif input.is_a?(Array)
567
+ lines = input.dup
568
+ else
569
+ raise "Unsupported input type: #{input.class}"
570
+ end
571
+
572
+ Document.new(lines, options, &block)
573
+ end
574
+
575
+ # Public: Parse the contents of the AsciiDoc source file into an Asciidoctor::Document
576
+ #
577
+ # Accepts input as an IO, String or String Array object. If the
578
+ # input is a File, information about the file is stored in
579
+ # attributes on the Document.
580
+ #
581
+ # input - the String AsciiDoc source filename
582
+ # options - a Hash of options to control processing (default: {})
583
+ # see Asciidoctor::Document#initialize for details
584
+ # block - a callback block for handling include::[] directives
585
+ #
586
+ # returns the Asciidoctor::Document
587
+ def self.load_file(filename, options = {}, &block)
588
+ Asciidoctor.load(File.new(filename), options, &block)
589
+ end
590
+
591
+ # Public: Parse the AsciiDoc source input into an Asciidoctor::Document and render it
592
+ # to the specified backend format
593
+ #
594
+ # Accepts input as an IO, String or String Array object. If the
595
+ # input is a File, information about the file is stored in
596
+ # attributes on the Document.
597
+ #
598
+ # If the :in_place option is true, and the input is a File, the output is
599
+ # written to a file adjacent to the input file, having an extension that
600
+ # corresponds to the backend format. Otherwise, if the :to_file option is
601
+ # specified, the file is written to that file. If :to_file is not an absolute
602
+ # path, it is resolved relative to :to_dir, if given, otherwise the
603
+ # Document#base_dir. If the target directory does not exist, it will not be
604
+ # created unless the :mkdirs option is set to true. If the file cannot be
605
+ # written because the target directory does not exist, or because it falls
606
+ # outside of the Document#base_dir in safe mode, an IOError is raised.
607
+ #
608
+ # If the output is going to be written to a file, the header and footer are
609
+ # rendered unless specified otherwise (writing to a file implies creating a
610
+ # standalone document). Otherwise, the header and footer are not rendered by
611
+ # default and the rendered output is returned.
612
+ #
613
+ # input - the String AsciiDoc source filename
614
+ # options - a Hash of options to control processing (default: {})
615
+ # see Asciidoctor::Document#initialize for details
616
+ # block - a callback block for handling include::[] directives
617
+ #
618
+ # returns nothing if the rendered output String is written to a file,
619
+ # otherwise the rendered output String is returned
620
+ def self.render(input, options = {}, &block)
621
+ in_place = options.delete(:in_place) || false
622
+ to_file = options.delete(:to_file)
623
+ to_dir = options.delete(:to_dir)
624
+ mkdirs = options.delete(:mkdirs) || false
625
+
626
+ write_in_place = in_place && input.is_a?(File)
627
+ write_to_target = to_file || to_dir
628
+
629
+ raise ArgumentError, ':in_place with input file must not accompany :to_dir or :to_file' if write_in_place && write_to_target
630
+
631
+ if !options.has_key?(:header_footer) && (write_in_place || write_to_target)
632
+ options[:header_footer] = true
633
+ end
634
+
635
+ doc = Asciidoctor.load(input, options, &block)
636
+
637
+ if write_in_place
638
+ to_file = File.join(File.dirname(input.path), "#{doc.attributes['docname']}#{doc.attributes['outfilesuffix']}")
639
+ elsif write_to_target
640
+ if to_dir
641
+ to_dir = doc.normalize_asset_path(to_dir, 'to_dir', false)
642
+ if to_file
643
+ # normalize again, to_file could have dirty bits
644
+ to_file = doc.normalize_asset_path(File.expand_path(to_file, to_dir), 'to_file', false)
645
+ # reestablish to_dir as the final target directory (in the case to_file had directory segments)
646
+ to_dir = File.dirname(to_file)
647
+ else
648
+ to_file = File.join(to_dir, "#{doc.attributes['docname']}#{doc.attributes['outfilesuffix']}")
649
+ end
650
+ elsif to_file
651
+ to_file = doc.normalize_asset_path(to_file, 'to_file', false)
652
+ to_dir = File.dirname(to_file)
653
+ end
654
+
655
+ if !File.directory? to_dir
656
+ if mkdirs
657
+ require_library 'fileutils'
658
+ FileUtils.mkdir_p to_dir
659
+ else
660
+ raise IOError, "target directory does not exist: #{to_dir}"
661
+ end
662
+ end
663
+ end
664
+
665
+ if to_file
666
+ File.open(to_file, 'w') {|file| file.write doc.render }
667
+ nil
668
+ else
669
+ doc.render
670
+ end
671
+ end
672
+
673
+ # Public: Parse the contents of the AsciiDoc source file into an Asciidoctor::Document
674
+ # and render it to the specified backend format
675
+ #
676
+ # input - the String AsciiDoc source filename
677
+ # options - a Hash of options to control processing (default: {})
678
+ # see Asciidoctor::Document#initialize for details
679
+ # block - a callback block for handling include::[] directives
680
+ #
681
+ # returns nothing if the rendered output String is written to a file,
682
+ # otherwise the rendered output String is returned
683
+ def self.render_file(filename, options = {}, &block)
684
+ Asciidoctor.render(File.new(filename), options, &block)
685
+ end
686
+
476
687
  # Internal: Prior to invoking Kernel#require, issues a warning urging a
477
688
  # manual require if running in a threaded environment.
478
689
  #
479
690
  # name - the String name of the library to require.
480
691
  #
481
- # returns nothing
692
+ # returns false if the library is detected on the load path or the return
693
+ # value of delegating to Kernel#require
482
694
  def self.require_library(name)
483
695
  if Thread.list.size > 1
484
696
  main_script = "#{name}.rb"
485
697
  main_script_path_segment = "/#{name}.rb"
486
698
  if !$LOADED_FEATURES.detect {|p| p == main_script || p.end_with?(main_script_path_segment) }.nil?
487
- return
699
+ return false
488
700
  else
489
701
  warn "WARN: asciidoctor is autoloading '#{name}' in threaded environment. " +
490
702
  "The use of an explicit require '#{name}' statement is recommended."
491
703
  end
492
704
  end
493
705
  require name
494
- nil
495
706
  end
496
707
 
497
708
  # modules