lib/asciidoctor/block.rb in asciidoctor-0.0.7 vs lib/asciidoctor/block.rb in asciidoctor-0.0.9
- old
+ new
@@ -3,109 +3,58 @@
# Examples
#
# block = Asciidoctor::Block.new(document, :paragraph, ["`This` is a <test>"])
# block.content
# => ["<em>This</em> is a <test>"]
-class Asciidoctor::Block
- # Public: Get the Symbol context for this section block.
- attr_reader :context
+class Asciidoctor::Block < Asciidoctor::AbstractBlock
# Public: Create alias for context to be consistent w/ AsciiDoc
alias :blockname :context
- # Public: Get the Hash of attributes for this block
- attr_reader :attributes
-
- # Public: Get the Array of sub-blocks for this section block.
- attr_reader :blocks
-
# Public: Get/Set the original Array content for this section block.
attr_accessor :buffer
- # Public: Get/Set the String section anchor name.
- attr_accessor :anchor
- alias :id :anchor
-
- # Public: Get/Set the Integer block level (for nested elements, like
- # list elements).
- attr_accessor :level
-
- # Public: Get/Set the String block title.
- attr_accessor :title
-
- # Public: Get/Set the String block caption.
+ # Public: Get/Set the caption for this block
attr_accessor :caption
# Public: Initialize an Asciidoctor::Block object.
#
# parent - The parent Asciidoc Object.
# context - The Symbol context name for the type of content.
- # buffer - The Array buffer of source data.
+ # buffer - The Array buffer of source data (default: nil).
- # TODO: Don't really need the parent, just the document (for access
- # both to its renderer, as well as its references and other defined
- # elements). Would probably be better to pass in just the document.
- def initialize(parent, context, buffer=nil)
- @parent = parent
- @context = context
+ def initialize(parent, context, buffer = nil)
+ super(parent, context)
@buffer = buffer
- @attributes = {}
- @blocks = []
end
- # Public: Get the Asciidoctor::Document instance to which this Block belongs
- def document
- return @document if @document
- @document = (@parent.is_a?(Asciidoctor::Document) ? @parent : @parent.document)
- end
-
- def attr(name, default = nil)
- default.nil? ? @attributes.fetch(name.to_s, self.document.attr(name)) :
- @attributes.fetch(name.to_s, self.document.attr(name, default))
- end
-
- def attr?(name)
- @attributes.has_key?(name.to_s) || self.document.attr?(name)
- end
-
- def update_attributes(attributes)
- @attributes.update(attributes)
- end
-
- # Public: Get the Asciidoctor::Renderer instance being used for the ancestor
- # Asciidoctor::Document instance.
- def renderer
- # wouldn't @parent.renderer work here? I believe so
- document.renderer
- end
-
# Public: Get the rendered String content for this Block. If the block
# has child blocks, the content method should cause them to be
# rendered and returned as content that can be included in the
# parent block's template.
def render
- Asciidoctor.debug "Now attempting to render for #{context} my own bad #{self}"
- Asciidoctor.debug "Parent is #{@parent}"
- Asciidoctor.debug "Renderer is #{renderer}"
- renderer.render("section_#{context}", self)
+ Asciidoctor.debug { "Now rendering #{@context} block for #{self}" }
+ out = renderer.render("block_#{@context}", self)
+ @document.callouts.next_list if @context == :colist
+ out
end
def splain(parent_level = 0)
parent_level += 1
+ Asciidoctor.puts_indented(parent_level, "Block id: #{id}") unless self.id.nil?
Asciidoctor.puts_indented(parent_level, "Block title: #{title}") unless self.title.nil?
- Asciidoctor.puts_indented(parent_level, "Block anchor: #{anchor}") unless self.anchor.nil?
Asciidoctor.puts_indented(parent_level, "Block caption: #{caption}") unless self.caption.nil?
Asciidoctor.puts_indented(parent_level, "Block level: #{level}") unless self.level.nil?
Asciidoctor.puts_indented(parent_level, "Block context: #{context}") unless self.context.nil?
Asciidoctor.puts_indented(parent_level, "Blocks: #{@blocks.count}")
if buffer.is_a? Enumerable
buffer.each_with_index do |buf, i|
Asciidoctor.puts_indented(parent_level, "v" * (60 - parent_level*2))
Asciidoctor.puts_indented(parent_level, "Buffer ##{i} is a #{buf.class}")
- Asciidoctor.puts_indented(parent_level, "Name is #{buf.name rescue 'n/a'}")
+ Asciidoctor.puts_indented(parent_level, "Name is #{buf.title rescue 'n/a'}")
if buf.respond_to? :splain
buf.splain(parent_level)
else
Asciidoctor.puts_indented(parent_level, "Buffer: #{buf}")
@@ -121,228 +70,52 @@
end
@blocks.each_with_index do |block, i|
Asciidoctor.puts_indented(parent_level, "v" * (60 - parent_level*2))
Asciidoctor.puts_indented(parent_level, "Block ##{i} is a #{block.class}")
- Asciidoctor.puts_indented(parent_level, "Name is #{block.name rescue 'n/a'}")
+ Asciidoctor.puts_indented(parent_level, "Name is #{block.title rescue 'n/a'}")
block.splain(parent_level) if block.respond_to? :splain
Asciidoctor.puts_indented(parent_level, "^" * (60 - parent_level*2))
end
+
nil
end
# Public: Get an HTML-ified version of the source buffer, with special
# Asciidoc characters and entities converted to their HTML equivalents.
#
# Examples
#
- # doc = Asciidoctor::Document.new([])
+ # doc = Asciidoctor::Document.new
# block = Asciidoctor::Block.new(doc, :paragraph,
# ['`This` is what happens when you <meet> a stranger in the <alps>!'])
# block.content
# => ["<em>This</em> is what happens when you <meet> a stranger in the <alps>!"]
- #
- # TODO:
- # * forced line breaks (partly done, at least in regular paragraphs)
- # * bold, mono
- # * double/single quotes
- # * super/sub script
def content
- #Asciidoctor.debug "For the record, buffer is:"
- #Asciidoctor.debug @buffer.inspect
-
case @context
- when :preamble, :oblock, :example, :sidebar
- blocks.map{|block| block.render}.join
- when :colist
- @buffer.map do |li|
- htmlify(li.text) + li.blocks.map{|block| block.render}.join
- end
- # lists get iterated in template
+ when :preamble, :open, :example, :sidebar
+ @blocks.map {|b| b.render }.join
+ # lists get iterated in the template (for now)
# list items recurse into this block when their text and content methods are called
- when :ulist, :olist, :dlist
+ when :ulist, :olist, :dlist, :colist
@buffer
- when :listing
- sub_special_chars(@buffer.join).gsub(/<(\d+)>/, '<b>\1</b>')
- when :literal
- sub_special_chars(@buffer.join)
+ when :listing, :literal
+ apply_literal_subs(@buffer)
+ when :pass
+ apply_passthrough_subs(@buffer)
when :quote, :verse, :admonition
if !@buffer.nil?
- htmlify(sub_attributes(@buffer).map{ |l| l.strip }.join( "\n" ))
+ apply_normal_subs(@buffer)
else
- blocks.map{|block| block.render}.join
+ @blocks.map {|b| b.render }.join
end
else
- lines = sub_attributes(@buffer).map do |line|
- line.strip
- line.gsub(Asciidoctor::REGEXP[:line_break], '\1{br-asciidoctor}')
- end
- lines = htmlify( lines.join )
- sub_html_attributes(lines) # got to clean up the br-asciidoctor line-break
+ apply_normal_subs(@buffer)
end
end
- # Attribute substitution
- #
- # TODO: Tom all the docs
- def sub_attributes(lines)
- Asciidoctor.debug "Entering #{__method__} from #{caller[0]}"
- if lines.is_a? String
- return_string = true
- lines = Array(lines)
- end
-
- result = lines.map do |line|
- Asciidoctor.debug "#{__method__} -> Processing line: #{line}"
- f = sub_special_chars(line)
- # gsub! doesn't have lookbehind, so we have to capture and re-insert
- f = f.gsub(/ (^|[^\\]) \{ (\w([\w\-_]+)?\w) \} /x) do
- if self.document.attributes.has_key?($2)
- # Substitute from user attributes first
- $1 + self.document.attributes[$2]
- elsif Asciidoctor::INTRINSICS.has_key?($2)
- # Then do intrinsics
- $1 + Asciidoctor::INTRINSICS[$2]
- elsif Asciidoctor::HTML_ELEMENTS.has_key?($2)
- $1 + Asciidoctor::HTML_ELEMENTS[$2]
- else
- Asciidoctor.debug "Bailing on key: #{$2}"
- # delete the line if it has a bad attribute
- # TODO: According to AsciiDoc, we're supposed to delete any line
- # containing a bad attribute. Eek! Can't do that here via gsub!.
- # (See `subs_attrs` function in asciidoc.py for many gory details.)
- "{ZZZZZ}"
- end
- end
- Asciidoctor.debug "#{__method__} -> Processed line: #{f}"
- f
- end
- #Asciidoctor.debug "#{__method__} -> result looks like #{result.inspect}"
- result.reject! {|l| l =~ /\{ZZZZZ\}/}
-
- if return_string
- result = result.join
- end
- result
+ def to_s
+ "#{super.to_s} - #@context [blocks:#{(@blocks || []).size}]"
end
-
- def sub_html_attributes(lines)
- Asciidoctor.debug "Entering #{__method__} from #{caller[0]}"
- if lines.is_a? String
- return_string = true
- lines = Array(lines)
- end
-
- result = lines.map do |line|
- Asciidoctor.debug "#{__method__} -> Processing line: #{line}"
- # gsub! doesn't have lookbehind, so we have to capture and re-insert
- line.gsub(/ (^|[^\\]) \{ (\w[\w\-_]+\w) \} /x) do
- if Asciidoctor::HTML_ELEMENTS.has_key?($2)
- $1 + Asciidoctor::HTML_ELEMENTS[$2]
- else
- $1 + "{#{$2}}"
- end
- end
- end
- #Asciidoctor.debug "#{__method__} -> result looks like #{result.inspect}"
- result.reject! {|l| l =~ /\{ZZZZZ\}/}
-
- if return_string
- result = result.join
- end
- result
- end
-
- # Public: Append a sub-block to this section block
- #
- # block - The new sub-block.
- #
- # block = Block.new(parent, :preamble)
- #
- # block << Block.new(block, :paragraph, 'p1')
- # block << Block.new(block, :paragraph, 'p2')
- # block.blocks
- # => ["p1", "p2"]
- def <<(block)
- @blocks << block
- end
-
- private
-
- # Private: Return a String HTML version of the source string, with
- # Asciidoc characters converted and HTML entities escaped.
- #
- # string - The String source string in Asciidoc format.
- #
- # Examples
- #
- # asciidoc_string = "Make 'this' <emphasized>"
- # htmlify(asciidoc_string)
- # => "Make <em>this</em> <emphasized>"
- def htmlify(string)
- unless string.nil?
- html = string.dup
-
- # Convert reference links to "link:" asciidoc for later HTMLification.
- # This ensures that eg. "<<some reference>>" is turned into a link but
- # "`<<<<<` and `>>>>>` are conflict markers" is not. This is much
- # easier before the HTML is escaped and <> are turned into entities.
- html.gsub!( /(^|[^<])<<([^<>,]+)(,([^>]*))?>>/ ) { "#{$1}link:##{$2}[" + ($4.nil? ? document.references[$2] : $4).to_s + "]" }
-
- # Do the same with URLs
- html.gsub!( /(^|[^(`|link:)])(https?:\/\/[^\[ ]+)(\[+[^\]]*\]+)?/ ) do
- pre = $1
- url = $2
- link = ( $3 || $2 ).gsub( /(^\[|\]$)/,'' )
- link = url if link.empty?
-
- "#{pre}link:#{url}[#{link}]"
- end
-
- html.gsub!(Asciidoctor::REGEXP[:biblio], '<a name="\1">[\1]</a>')
- html.gsub!(Asciidoctor::REGEXP[:ruler], "<hr>\n")
- html.gsub!(/``([^`']*)''/m, '“\1”')
- html.gsub!(/(?:\s|^)`([^`']*)'/m, '‘\1’')
-
- # TODO: This text thus quoted is supposed to be rendered as an
- # "inline literal passthrough", meaning that it is rendered
- # in a monospace font, but also doesn't go through any further
- # text substitution, except for special character substitution.
- # So we need to technically pull this text out, sha it and store
- # a marker and replace it after the other gsub!s are done in here.
- # See: http://www.methods.co.nz/asciidoc/userguide.html#X80
- html.gsub!(/`([^`]+)`/m) { "<tt>#{$1.gsub( '*', '{asterisk}' ).gsub( '\'', '{apostrophe}' )}</tt>" }
- html.gsub!(/([\s\W])#(.+?)#([\s\W])/, '\1\2\3')
-
- # "Unconstrained" quotes
- html.gsub!(/\_\_([^\_]+)\_\_/m, '<em>\1</em>')
- html.gsub!(/\*\*([^\*]+)\*\*/m, '<strong>\1</strong>')
- html.gsub!(/\+\+([^\+]+)\+\+/m, '<tt>\1</tt>')
- html.gsub!(/\^\^([^\^]+)\^\^/m, '<sup>\1</sup>')
- html.gsub!(/\~\~([^\~]+)\~\~/m, '<sub>\1</sub>')
-
- # "Constrained" quotes, which must be bounded by white space or
- # common punctuation characters
- html.gsub!(/(^|\s|\W)\*([^\*]+)\*(\s|\W|$)/m, '\1<strong>\2</strong>\3')
- html.gsub!(/(^|\s|\W)'(.+?)'(\s|\W|$)/m, '\1<em>\2</em>\3')
- # restore escaped single quotes after processing emphasis
- html.gsub!(/(\w)\\'(\w)/, '\1\'\2')
- html.gsub!(/(^|\s|\W)_([^_]+)_(\s|\W|$)/m, '\1<em>\2</em>\3')
- html.gsub!(/(^|\s|\W)\+([^\+]+)\+(\s|\W|$)/m, '\1<tt>\2</tt>\3')
- html.gsub!(/(^|\s|\W)\^([^\^]+)\^(\s|\W|$)/m, '\1<sup>\2</sup>\3')
- html.gsub!(/(^|\s|\W)\~([^\~]+)\~(\s|\W|$)/m, '\1<sub>\2</sub>\3')
-
- html.gsub!(/\\([\{\}\-])/, '\1')
- html.gsub!(/linkgit:([^\]]+)\[(\d+)\]/, '<a href="\1.html">\1(\2)</a>')
- html.gsub!(/link:([^\[]+)(\[+[^\]]*\]+)/ ) { "<a href=\"#{$1}\">#{$2.gsub( /(^\[|\]$)/,'' )}</a>" }
- html.gsub!(Asciidoctor::REGEXP[:line_break], '\1<br/>')
- html
- end
- end
-
- def sub_special_chars(str)
- str.gsub(/[#{Asciidoctor::SPECIAL_CHARS.keys.join}]/) {|match| Asciidoctor::SPECIAL_CHARS[match] }
- end
- # end private
end