asciidoctor 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) Tom Preston-Werner
3
+ Copyright (c) Ryan Waldron
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,69 +1,150 @@
1
- RakeGem
2
- =======
1
+ Asciidoctor
2
+ ===========
3
3
 
4
- # DESCRIPTION
4
+ Asciidoctor is a pure-ruby processor for turning
5
+ [Asciidoc](http://www.methods.co.nz/asciidoc/index.html) documents
6
+ into HTML (and, eventually, other formats perhaps).
5
7
 
6
- Ever wanted to manage your RubyGem in a sane way without having to resort to
7
- external dependencies like Jeweler or Hoe? Ever thought that Rake and a hand
8
- crafted gemspec should be enough to deal with these problems? If so, then
9
- RakeGem is here to make your life awesome!
8
+ Currently, asciidoctor uses some simple built-in ERB templates to
9
+ style the output in a way tht roughly matches the default HTML output
10
+ of the native Python processor.
10
11
 
11
- RakeGem is not a library. It is just a few simple file templates that you can
12
- copy into your project and easily customize to match your specific needs. It
13
- ships with a few Rake tasks to help you keep your gemspec up-to-date, build
14
- a gem, and release your library and gem to the world.
12
+ Asciidoctor currently works with Ruby 1.8.7 and 1.9.3, though I don't
13
+ know of any reason it shouldn't work with more exotic Ruby versions,
14
+ and would welcome help in testing that out.
15
15
 
16
- RakeGem assumes you are using Git. This makes the Rake tasks easy to write. If
17
- you are using something else, you should be able to get RakeGem up and running
18
- with your system without too much editing.
16
+ The initial code on which asciidoctor is based was from the Git SCM
17
+ site repo, [gitscm-next](https://github.com/github/gitscm-next).
19
18
 
20
- The RakeGem tasks were inspired by the
21
- [Sinatra](http://github.com/sinatra/sinatra) project.
19
+ # Installation
22
20
 
23
- # INSTALLATION
21
+ NOTE: This gem is very immature, and as yet only supports a small
22
+ subset of Asciidoc features. Thus, you should only use it if you have
23
+ a high tolerance for bugs, failures, and generally bad and intemperate
24
+ behavior.
24
25
 
25
- Take a look at `Rakefile` and `NAME.gemspec`. For new projects, you can start
26
- with these files and edit a few lines to make them fit into your library. If
27
- you have an existing project, you'll probably want to take the RakeGem
28
- versions and copy any custom stuff from your existing Rakefile and gemspec
29
- into them. As long as you're careful, the rake tasks should keep working.
26
+ To install the gem:
30
27
 
31
- # ASSUMPTIONS
28
+ gem install 'asciidoctor'
32
29
 
33
- RakeGem makes a few assumptions. You will either need to satisfy these
34
- assumptions or modify the rake tasks to work with your setup.
30
+ Or if you prefer bundler:
35
31
 
36
- You should have a file named `lib/NAME.rb` (where NAME is the name of your
37
- library) that contains a version line. It should look something like this:
32
+ bundle install 'asciidoctor'
38
33
 
39
- module NAME
40
- VERSION = '0.1.0'
41
- end
42
-
43
- It is important that you use the constant `VERSION` and that it appear on a
44
- line by itself.
45
-
46
- # UPDATING THE VERSION
47
-
48
- In order to make a new release, you'll want to update the version. With
49
- RakeGem, you only need to do that in the `lib/NAME.rb` file. Everything else
50
- will use this find the canonical version of the library.
34
+ # Usage
51
35
 
52
- # TASKS
36
+ To render a file of Asciidoc-marked-up text to html
53
37
 
54
- RakeGem provides three rake tasks:
55
-
56
- `rake gemspec` will update your gemspec with the latest version (taken from
57
- the `lib/NAME.rb` file) and file list (as reported by `git ls-files`).
58
-
59
- `rake build` will update your gemspec, build your gemspec into a gem, and
60
- place it in the `pkg` directory.
61
-
62
- `rake release` will update your gemspec, build your gem, make a commit with
63
- the message `Release 0.1.0` (with the correct version, obviously), tag the
64
- commit with `v0.1.0` (again with the correct version), and push the `master`
65
- branch and new tag to `origin`.
38
+ lines = File.readlines("your_file.asc")
39
+ doc = Asciidoctor::Document.new(lines)
40
+ html = doc.render
41
+ File.open("your_file.html", "w+") do |file|
42
+ file.puts html
43
+ end
66
44
 
67
- Keep in mind that these are just simple Rake tasks and you can edit them
68
- however you please. Don't want to auto-commit or auto-push? Just delete those
69
- lines. You can bend RakeGem to your own needs. That's the whole point!
45
+ Render an Asciidoc-formatted string
46
+
47
+ doc = Asciidoctor::Document.new("*This* is it.")
48
+ puts doc.render
49
+
50
+ Asciidoctor allows you to override the default template used to render
51
+ almost any individual Asciidoc elements. If you provide a directory of
52
+ [Tilt](https://github.com/rtomayko/tilt)-compatible templates, named
53
+ in a way Asciidoctor can figure out which template goes with which
54
+ element, Asciidoctor will use the templates in this directory instead
55
+ of its built-in templates for any elements for which it finds a
56
+ matching template. It will use its default templates for everything
57
+ else.
58
+
59
+ doc = Asciidoctor::Document.new("*This* is it.", :template_dir => 'templates')
60
+ puts doc.render
61
+
62
+ The Document and Section templates should begin with `document.` and
63
+ `section.`, respectively. The file extension will depend on which
64
+ Tilt-compatible format you've chosen. For ERB, they would be
65
+ `document.html.erb` and `section.html.erb`, for instance.
66
+
67
+ Specific elements, like a Paragraph or Anchor, would begin with
68
+ `section_<element>.`. So to override the default Paragraph template
69
+ with an ERB template you'd put a file called
70
+ `section_paragraph.html.erb` in the template directory you pass in to
71
+ `Document.new`.
72
+
73
+ For more usage examples, see the test suite.
74
+
75
+ ## Contributing
76
+ In the spirit of [free software][free-sw], **everyone** is encouraged to help
77
+ improve this project.
78
+
79
+ [free-sw]: http://www.fsf.org/licensing/essays/free-sw.html
80
+
81
+ Here are some ways *you* can contribute:
82
+
83
+ * by using alpha, beta, and prerelease versions
84
+ * by reporting bugs
85
+ * by suggesting new features
86
+ * by writing or editing documentation
87
+ * by writing specifications
88
+ * by writing code (**no patch is too small**: fix typos, add comments, clean up
89
+ inconsistent whitespace)
90
+ * by refactoring code
91
+ * by fixing [issues][]
92
+ * by reviewing patches
93
+
94
+ [issues]: https://github.com/erebor/asciidoctor/issues
95
+
96
+ ## Submitting an Issue
97
+ We use the [GitHub issue tracker][issues] to track bugs and
98
+ features. Before submitting a bug report or feature request, check to
99
+ make sure it hasn't already been submitted. When submitting a bug
100
+ report, please include a [Gist][] that includes any details that may
101
+ help reproduce the bug, including your gem version, Ruby version, and
102
+ operating system.
103
+
104
+ Most importantly, since asciidoctor is a text processor, reproducing
105
+ most bugs requires that we have some snippet of text on which
106
+ asciidoctor exhibits the bad behavior.
107
+
108
+ An ideal bug report would include a pull request with failing
109
+ specs.
110
+
111
+ [gist]: https://gist.github.com/
112
+
113
+ ## Submitting a Pull Request
114
+ 1. [Fork the repository.][fork]
115
+ 2. [Create a topic branch.][branch]
116
+ 3. Add tests for your unimplemented feature or bug fix.
117
+ 4. Run `bundle exec rake`. If your tests pass, return to step 3.
118
+ 5. Implement your feature or bug fix.
119
+ 6. Run `bundle exec rake`. If your tests fail, return to step 5.
120
+ 7. Add documentation for your feature or bug fix.
121
+ 8. If your changes are not 100% documented, go back to step 7.
122
+ 9. Add, commit, and push your changes.
123
+ 10. [Submit a pull request.][pr]
124
+
125
+ [fork]: http://help.github.com/fork-a-repo/
126
+ [branch]: http://learn.github.com/p/branching.html
127
+ [pr]: http://help.github.com/send-pull-requests/
128
+
129
+ ## Supported Ruby Versions
130
+ This library aims to support the following Ruby implementations:
131
+
132
+ * Ruby 1.8.7
133
+ * Ruby 1.9.3
134
+
135
+ If something doesn't work on one of these interpreters, it should be
136
+ considered a bug.
137
+
138
+ If you would like this library to support another Ruby version, you
139
+ may volunteer to be a maintainer. Being a maintainer entails making
140
+ sure all tests run and pass on that implementation. When something
141
+ breaks on your implementation, you will be personally responsible for
142
+ providing patches in a timely fashion. If critical issues for a
143
+ particular implementation exist at the time of a major release,
144
+ support for that Ruby version may be dropped.
145
+
146
+ ## Copyright
147
+ Copyright (c) 2012 Ryan Waldron.
148
+ See [LICENSE][] for details.
149
+
150
+ [license]: https://github.com/erebor/asciidoctor/blob/master/LICENSE
data/asciidoctor.gemspec CHANGED
@@ -13,14 +13,14 @@ 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.1'
17
- s.date = '2012-06-14'
16
+ s.version = '0.0.2'
17
+ s.date = '2012-08-03'
18
18
  s.rubyforge_project = 'asciidoctor'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
21
21
  ## as you like.
22
22
  s.summary = "Pure Ruby Asciidoc to HTML rendering."
23
- s.description = "Render all the AsciiDocs! The time, she is now, for all good renders."
23
+ s.description = "A pure Ruby processor to turn Asciidoc-formatted documents into HTML (and, eventually, other formats perhaps)."
24
24
 
25
25
  ## List the primary authors. If there are a bunch of authors, it's probably
26
26
  ## better to set the email to an email list or something. If you don't have
@@ -44,13 +44,14 @@ Gem::Specification.new do |s|
44
44
  ## List your runtime dependencies here. Runtime dependencies are those
45
45
  ## that are needed for an end user to actually USE your code.
46
46
  s.add_dependency('json')
47
- s.add_dependency('nokogiri')
47
+ s.add_dependency('tilt')
48
48
 
49
49
  ## List your development dependencies here. Development dependencies are
50
50
  ## those that are only needed during development
51
51
  s.add_development_dependency('mocha')
52
52
  s.add_development_dependency('nokogiri')
53
53
  s.add_development_dependency('htmlentities')
54
+ s.add_development_dependency('pending')
54
55
 
55
56
  ## Leave this section as-is. It will be automatically generated from the
56
57
  ## contents of your Git repository via the gemspec task. DO NOT REMOVE
@@ -67,21 +68,26 @@ Gem::Specification.new do |s|
67
68
  lib/asciidoctor/debug.rb
68
69
  lib/asciidoctor/document.rb
69
70
  lib/asciidoctor/errors.rb
71
+ lib/asciidoctor/lexer.rb
70
72
  lib/asciidoctor/list_item.rb
73
+ lib/asciidoctor/reader.rb
71
74
  lib/asciidoctor/render_templates.rb
72
75
  lib/asciidoctor/renderer.rb
73
76
  lib/asciidoctor/section.rb
74
77
  lib/asciidoctor/string.rb
75
78
  lib/asciidoctor/version.rb
76
79
  noof.rb
80
+ test/attributes_test.rb
77
81
  test/document_test.rb
78
82
  test/fixtures/asciidoc.txt
79
83
  test/fixtures/asciidoc_index.txt
80
84
  test/fixtures/ascshort.txt
81
85
  test/fixtures/list_elements.asciidoc
82
86
  test/headers_test.rb
87
+ test/lexer_test.rb
83
88
  test/list_elements_test.rb
84
89
  test/paragraphs_test.rb
90
+ test/reader_test.rb
85
91
  test/test_helper.rb
86
92
  test/text_test.rb
87
93
  ]
data/lib/asciidoctor.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'cgi'
3
3
  require 'erb'
4
+ require 'tilt'
4
5
 
5
6
  $:.unshift(File.dirname(__FILE__))
6
7
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'vendor'))
@@ -40,6 +41,13 @@ module Asciidoctor
40
41
  # Foowhatevs [[Bar]]
41
42
  :anchor_embedded => /^(.*)\[\[([^\]]+)\]\]\s*$/,
42
43
 
44
+ # + Attribute values treat lines ending with ' +' as a continuation,
45
+ # not a line-break as elsewhere in the document, where this is
46
+ # a forced line break. This should be the same regexp as :line_break,
47
+ # below, but it gets its own entry because readability ftw, even
48
+ # though repeating regexps ftl.
49
+ :attr_continue => /(.*)(?:^|\s)\+$/,
50
+
43
51
  # [[[Foo]]] (does not suffer quite the same malady as :anchor, but almost. Allows [ but not ] in internal capture
44
52
  :biblio => /\[\[\[([^\]]+)\]\]\]/,
45
53
 
@@ -52,11 +60,6 @@ module Asciidoctor
52
60
  # // (and then whatever)
53
61
  :comment => /^\/\/\s/,
54
62
 
55
- # + Note that Asciidoc appears to allow continuations using + at
56
- # the end of the previous line and indenting
57
- # the following line (as in :lit_par)
58
- :continue => /^\+\s*$/,
59
-
60
63
  # foo:: || foo;;
61
64
  # Should be followed by a definition line, e.g.,
62
65
  # foo::
@@ -78,6 +81,23 @@ module Asciidoctor
78
81
  # ====== || ------ || ~~~~~~ || ^^^^^^ || ++++++
79
82
  :line => /^([=\-~^\+])+\s*$/,
80
83
 
84
+ # + From the Asciidoc User Guide: "A plus character preceded by at
85
+ # least one space character at the end of a non-blank line forces
86
+ # a line break. It generates a line break (br) tag for HTML outputs.
87
+ #
88
+ # This is the correct regexp to match what the User Guide actually
89
+ # says to do:
90
+ # :line_break => /^(.*(?:\S+)+.*)\s\+$/,
91
+ #
92
+ # But the regexp we're using (below), is what asciidoc *actually*
93
+ # does for HTML output, courtesy of the default html4.conf file (under
94
+ # the [replacements2] section).
95
+ #
96
+ # + (would not match because there's no space before +)
97
+ # + (would match and capture '')
98
+ # Foo + (would and capture 'Foo')
99
+ :line_break => /^(.*)\s\+$/,
100
+
81
101
  # ----
82
102
  :listing => /^\-{4,}\s*$/,
83
103
 
@@ -106,7 +126,7 @@ module Asciidoctor
106
126
  # ____
107
127
  :quote => /^_{4,}\s*$/,
108
128
 
109
- # ____
129
+ # ''''
110
130
  :ruler => /^'{3,}\s*$/,
111
131
 
112
132
  # ****
@@ -120,7 +140,7 @@ module Asciidoctor
120
140
  :title => /^\.([^\s\.].*)\s*$/,
121
141
 
122
142
  # * Foo || - Foo
123
- :ulist => /^\s*([\*\-])\s+(.*)$/,
143
+ :ulist => /^ \s* (- | \*{1,5}) \s+ (.*) $/x,
124
144
 
125
145
  # [verse]
126
146
  :verse => /^\[verse\]\s*$/
@@ -139,11 +159,17 @@ module Asciidoctor
139
159
  'backtick' => '`'
140
160
  )
141
161
 
162
+ HTML_ELEMENTS = {
163
+ 'br-asciidoctor' => '<br/>'
164
+ }
165
+
142
166
  require 'asciidoctor/block'
143
167
  require 'asciidoctor/debug'
144
168
  require 'asciidoctor/document'
145
169
  require 'asciidoctor/errors'
170
+ require 'asciidoctor/lexer'
146
171
  require 'asciidoctor/list_item'
172
+ require 'asciidoctor/reader'
147
173
  require 'asciidoctor/render_templates'
148
174
  require 'asciidoctor/renderer'
149
175
  require 'asciidoctor/section'
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Examples
4
4
  #
5
- # block = Asciidoctor::Block.new(:paragraph, ["`This` is a <test>"])
5
+ # block = Asciidoctor::Block.new(document, :paragraph, ["`This` is a <test>"])
6
6
  # block.content
7
7
  # => ["<em>This</em> is a &lt;test&gt;"]
8
8
  class Asciidoctor::Block
@@ -18,6 +18,10 @@ class Asciidoctor::Block
18
18
  # Public: Get/Set the String section anchor name.
19
19
  attr_accessor :anchor
20
20
 
21
+ # Public: Get/Set the Integer block level (for nested elements, like
22
+ # list elements).
23
+ attr_accessor :level
24
+
21
25
  # Public: Get/Set the String block title.
22
26
  attr_accessor :title
23
27
 
@@ -29,6 +33,10 @@ class Asciidoctor::Block
29
33
  # parent - The parent Asciidoc Object.
30
34
  # context - The Symbol context name for the type of content.
31
35
  # buffer - The Array buffer of source data.
36
+
37
+ # TODO: Don't really need the parent, just the document (for access
38
+ # both to its renderer, as well as its references and other defined
39
+ # elements). Would probably be better to pass in just the document.
32
40
  def initialize(parent, context, buffer=nil)
33
41
  @parent = parent
34
42
  @context = context
@@ -39,13 +47,14 @@ class Asciidoctor::Block
39
47
 
40
48
  # Public: Get the Asciidoctor::Document instance to which this Block belongs
41
49
  def document
42
- @parent.is_a?(Asciidoctor::Document) ? @parent : @parent.document
50
+ return @document if @document
51
+ @document = (@parent.is_a?(Asciidoctor::Document) ? @parent : @parent.document)
43
52
  end
44
53
 
45
54
  # Public: Get the Asciidoctor::Renderer instance being used for the ancestor
46
55
  # Asciidoctor::Document instance.
47
56
  def renderer
48
- @parent.renderer
57
+ document.renderer
49
58
  end
50
59
 
51
60
  # Public: Get the rendered String content for this Block. If the block
@@ -59,21 +68,69 @@ class Asciidoctor::Block
59
68
  renderer.render("section_#{context}", self)
60
69
  end
61
70
 
71
+ def splain(parent_level = 0)
72
+ parent_level += 1
73
+ Asciidoctor.puts_indented(parent_level, "Block title: #{title}") unless self.title.nil?
74
+ Asciidoctor.puts_indented(parent_level, "Block anchor: #{anchor}") unless self.anchor.nil?
75
+ Asciidoctor.puts_indented(parent_level, "Block caption: #{caption}") unless self.caption.nil?
76
+ Asciidoctor.puts_indented(parent_level, "Block level: #{level}") unless self.level.nil?
77
+ Asciidoctor.puts_indented(parent_level, "Block context: #{context}") unless self.context.nil?
78
+
79
+ Asciidoctor.puts_indented(parent_level, "Blocks: #{@blocks.count}")
80
+
81
+ if buffer.is_a? Enumerable
82
+ buffer.each_with_index do |buf, i|
83
+ Asciidoctor.puts_indented(parent_level, "v" * (60 - parent_level*2))
84
+ Asciidoctor.puts_indented(parent_level, "Buffer ##{i} is a #{buf.class}")
85
+ Asciidoctor.puts_indented(parent_level, "Name is #{buf.name rescue 'n/a'}")
86
+
87
+ if buf.respond_to? :splain
88
+ buf.splain(parent_level)
89
+ else
90
+ Asciidoctor.puts_indented(parent_level, "Buffer: #{buf}")
91
+ end
92
+ Asciidoctor.puts_indented(parent_level, "^" * (60 - parent_level*2))
93
+ end
94
+ else
95
+ if buffer.respond_to? :splain
96
+ buffer.splain(parent_level)
97
+ else
98
+ Asciidoctor.puts_indented(parent_level, "Buffer: #{@buffer}")
99
+ end
100
+ end
101
+
102
+ @blocks.each_with_index do |block, i|
103
+ Asciidoctor.puts_indented(parent_level, "v" * (60 - parent_level*2))
104
+ Asciidoctor.puts_indented(parent_level, "Block ##{i} is a #{block.class}")
105
+ Asciidoctor.puts_indented(parent_level, "Name is #{block.name rescue 'n/a'}")
106
+
107
+ block.splain(parent_level) if block.respond_to? :splain
108
+ Asciidoctor.puts_indented(parent_level, "^" * (60 - parent_level*2))
109
+ end
110
+ nil
111
+ end
112
+
62
113
  # Public: Get an HTML-ified version of the source buffer, with special
63
114
  # Asciidoc characters and entities converted to their HTML equivalents.
64
115
  #
65
116
  # Examples
66
117
  #
67
- # block = Asciidoctor::Block.new(:paragraph, ['`This` is what happens when you <meet> a stranger in the <alps>!'])
118
+ # doc = Asciidoctor::Document.new([])
119
+ # block = Asciidoctor::Block.new(doc, :paragraph,
120
+ # ['`This` is what happens when you <meet> a stranger in the <alps>!'])
68
121
  # block.content
69
122
  # => ["<em>This</em> is what happens when you &lt;meet&gt; a stranger in the &lt;alps&gt;!"]
70
123
  #
71
124
  # TODO:
72
- # * forced line breaks
125
+ # * forced line breaks (partly done, at least in regular paragraphs)
73
126
  # * bold, mono
74
127
  # * double/single quotes
75
128
  # * super/sub script
76
129
  def content
130
+
131
+ Asciidoctor.debug "For the record, buffer is:"
132
+ Asciidoctor.debug @buffer.inspect
133
+
77
134
  case @context
78
135
  when :dlist
79
136
  @buffer.map do |dt, dd|
@@ -93,21 +150,106 @@ class Asciidoctor::Block
93
150
  end
94
151
  when :oblock, :quote
95
152
  blocks.map{|block| block.render}.join
96
- when :olist, :ulist, :colist
153
+ when :olist, :colist
97
154
  @buffer.map do |li|
98
155
  htmlify(li.content) + li.blocks.map{|block| block.render}.join
99
156
  end
157
+ when :ulist
158
+ @buffer.map do |element|
159
+ if element.is_a? Asciidoctor::ListItem
160
+ element.content = sub_attributes(element.content)
161
+ end
162
+ # TODO - not sure why tests work the same whether or not this is commented out.
163
+ # I think that I am likely not yet testing unordered list items with no block
164
+ # content. Still and all, it seems like this should be all done by list_item.render .
165
+ element.render # + element.blocks.map{|block| block.render}.join
166
+ end
100
167
  when :listing
101
168
  @buffer.map{|l| CGI.escapeHTML(l).gsub(/(<\d+>)/,'<b>\1</b>')}.join
102
169
  when :literal
103
170
  htmlify( @buffer.join.gsub( '*', '{asterisk}' ).gsub( '\'', '{apostrophe}' ))
104
171
  when :verse
105
- htmlify( @buffer.map{ |l| l.strip }.join( "\n" ) )
172
+ htmlify( sub_attributes(@buffer).map{ |l| l.strip }.join( "\n" ) )
106
173
  else
107
- htmlify( @buffer.map{ |l| l.lstrip }.join )
174
+ lines = sub_attributes(@buffer).map do |line|
175
+ line.strip
176
+ line.gsub(Asciidoctor::REGEXP[:line_break], '\1{br-asciidoctor}')
177
+ end
178
+ lines = htmlify( lines.join )
179
+ sub_html_attributes(lines) # got to clean up the br-asciidoctor line-break
108
180
  end
109
181
  end
110
182
 
183
+ # Attribute substitution
184
+ #
185
+ # TODO: Tom all the docs
186
+ def sub_attributes(lines)
187
+ Asciidoctor.debug "Entering #{__method__} from #{caller[0]}"
188
+ if lines.is_a? String
189
+ return_string = true
190
+ lines = Array(lines)
191
+ end
192
+
193
+ result = lines.map do |line|
194
+ Asciidoctor.debug "#{__method__} -> Processing line: #{line}"
195
+ # gsub! doesn't have lookbehind, so we have to capture and re-insert
196
+ f = line.gsub(/ (^|[^\\]) \{ (\w[\w\-_]+\w) \} /x) do
197
+ if self.document.defines.has_key?($2)
198
+ # Substitute from user defines first
199
+ $1 + self.document.defines[$2]
200
+ elsif Asciidoctor::INTRINSICS.has_key?($2)
201
+ # Then do intrinsics
202
+ $1 + Asciidoctor::INTRINSICS[$2]
203
+ elsif Asciidoctor::HTML_ELEMENTS.has_key?($2)
204
+ $1 + Asciidoctor::HTML_ELEMENTS[$2]
205
+ else
206
+ Asciidoctor.debug "Bailing on key: #{$2}"
207
+ # delete the line if it has a bad attribute
208
+ # TODO: According to AsciiDoc, we're supposed to delete any line
209
+ # containing a bad attribute. Eek! Can't do that here via gsub!.
210
+ # (See `subs_attrs` function in asciidoc.py for many gory details.)
211
+ "{ZZZZZ}"
212
+ end
213
+ end
214
+ Asciidoctor.debug "#{__method__} -> Processed line: #{f}"
215
+ f
216
+ end
217
+ Asciidoctor.debug "#{__method__} -> result looks like #{result.inspect}"
218
+ result.reject! {|l| l =~ /\{ZZZZZ\}/}
219
+
220
+ if return_string
221
+ result = result.join
222
+ end
223
+ result
224
+ end
225
+
226
+ def sub_html_attributes(lines)
227
+ Asciidoctor.debug "Entering #{__method__} from #{caller[0]}"
228
+ if lines.is_a? String
229
+ return_string = true
230
+ lines = Array(lines)
231
+ end
232
+
233
+ result = lines.map do |line|
234
+ Asciidoctor.debug "#{__method__} -> Processing line: #{line}"
235
+ # gsub! doesn't have lookbehind, so we have to capture and re-insert
236
+ line.gsub(/ (^|[^\\]) \{ (\w[\w\-_]+\w) \} /x) do
237
+ if Asciidoctor::HTML_ELEMENTS.has_key?($2)
238
+ $1 + Asciidoctor::HTML_ELEMENTS[$2]
239
+ else
240
+ $1 + "{#{$2}}"
241
+ end
242
+ end
243
+ end
244
+ Asciidoctor.debug "#{__method__} -> result looks like #{result.inspect}"
245
+ result.reject! {|l| l =~ /\{ZZZZZ\}/}
246
+
247
+ if return_string
248
+ result = result.join
249
+ end
250
+ result
251
+ end
252
+
111
253
  private
112
254
 
113
255
  # Private: Return a String HTML version of the source string, with
@@ -143,8 +285,16 @@ class Asciidoctor::Block
143
285
  html = CGI.escapeHTML(html)
144
286
  html.gsub!(Asciidoctor::REGEXP[:biblio], '<a name="\1">[\1]</a>')
145
287
  html.gsub!(Asciidoctor::REGEXP[:ruler], '<hr>\n')
146
- html.gsub!(/``(.*?)''/m, '&ldquo;\1&rdquo;')
147
- html.gsub!(/`(.*?)'/m, '&lsquo;\1&rsquo;')
288
+ html.gsub!(/``([^`']*)''/m, '&ldquo;\1&rdquo;')
289
+ html.gsub!(/(?:\s|^)`([^`']*)'/m, '&lsquo;\1&rsquo;')
290
+
291
+ # TODO: This text thus quoted is supposed to be rendered as an
292
+ # "inline literal passthrough", meaning that it is rendered
293
+ # in a monospace font, but also doesn't go through any further
294
+ # text substitution, except for special character substitution.
295
+ # So we need to technically pull this text out, sha it and store
296
+ # a marker and replace it after the other gsub!s are done in here.
297
+ # See: http://www.methods.co.nz/asciidoc/userguide.html#X80
148
298
  html.gsub!(/`([^`]+)`/m) { "<tt>#{$1.gsub( '*', '{asterisk}' ).gsub( '\'', '{apostrophe}' )}</tt>" }
149
299
  html.gsub!(/([\s\W])#(.+?)#([\s\W])/, '\1\2\3')
150
300
 
@@ -164,23 +314,10 @@ class Asciidoctor::Block
164
314
  html.gsub!(/([\s\W])\^([^\^]+)\^([\s\W])/m, '\1<sup>\2</sup>\3')
165
315
  html.gsub!(/([\s\W])\~([^\~]+)\~([\s\W])/m, '\1<sub>\2</sub>\3')
166
316
 
167
- # Don't have lookbehind so have to capture and re-insert
168
- html.gsub!(/(^|[^\\])\{(\w[\w\-]+\w)\}/) do
169
- if self.document.defines.has_key?($2)
170
- # Substitute from user defines first
171
- $1 + self.document.defines[$2]
172
- elsif Asciidoctor::INTRINSICS.has_key?($2)
173
- # Then do intrinsics
174
- $1 + Asciidoctor::INTRINSICS[$2]
175
- else
176
- # leave everything else alone
177
- "#{$1}{#{$2}}"
178
- end
179
- end
180
-
181
317
  html.gsub!(/\\([\{\}\-])/, '\1')
182
318
  html.gsub!(/linkgit:([^\]]+)\[(\d+)\]/, '<a href="\1.html">\1(\2)</a>')
183
319
  html.gsub!(/link:([^\[]+)(\[+[^\]]*\]+)/ ) { "<a href=\"#{$1}\">#{$2.gsub( /(^\[|\]$)/,'' )}</a>" }
320
+ html.gsub!(Asciidoctor::REGEXP[:line_break], '\1<br/>')
184
321
  html
185
322
  end
186
323
  end