asciidoctor 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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