asciidoctor 0.0.1 → 0.0.2

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.

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