asciidoctor 0.0.7 → 0.0.9
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/Gemfile +2 -0
- data/README.asciidoc +35 -26
- data/Rakefile +9 -6
- data/asciidoctor.gemspec +27 -8
- data/bin/asciidoctor +1 -1
- data/lib/asciidoctor.rb +351 -63
- data/lib/asciidoctor/abstract_block.rb +218 -0
- data/lib/asciidoctor/abstract_node.rb +249 -0
- data/lib/asciidoctor/attribute_list.rb +211 -0
- data/lib/asciidoctor/backends/base_template.rb +99 -0
- data/lib/asciidoctor/backends/docbook45.rb +510 -0
- data/lib/asciidoctor/backends/html5.rb +585 -0
- data/lib/asciidoctor/block.rb +27 -254
- data/lib/asciidoctor/callouts.rb +117 -0
- data/lib/asciidoctor/debug.rb +7 -4
- data/lib/asciidoctor/document.rb +229 -77
- data/lib/asciidoctor/inline.rb +29 -0
- data/lib/asciidoctor/lexer.rb +1330 -502
- data/lib/asciidoctor/list_item.rb +33 -34
- data/lib/asciidoctor/reader.rb +305 -142
- data/lib/asciidoctor/renderer.rb +115 -19
- data/lib/asciidoctor/section.rb +100 -189
- data/lib/asciidoctor/substituters.rb +468 -0
- data/lib/asciidoctor/table.rb +499 -0
- data/lib/asciidoctor/version.rb +1 -1
- data/test/attributes_test.rb +301 -87
- data/test/blocks_test.rb +568 -0
- data/test/document_test.rb +221 -24
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +1 -0
- data/test/fixtures/include-file.asciidoc +1 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/headers_test.rb +411 -43
- data/test/lexer_test.rb +265 -45
- data/test/links_test.rb +144 -3
- data/test/lists_test.rb +2252 -74
- data/test/paragraphs_test.rb +21 -30
- data/test/preamble_test.rb +24 -0
- data/test/reader_test.rb +248 -12
- data/test/renderer_test.rb +22 -0
- data/test/substitutions_test.rb +414 -0
- data/test/tables_test.rb +484 -0
- data/test/test_helper.rb +70 -6
- data/test/text_test.rb +30 -6
- metadata +64 -10
- data/lib/asciidoctor/render_templates.rb +0 -317
- data/lib/asciidoctor/string.rb +0 -12
data/lib/asciidoctor/renderer.rb
CHANGED
@@ -1,37 +1,61 @@
|
|
1
1
|
# Public: Methods for rendering Asciidoc Documents, Sections, and Blocks
|
2
|
-
# using
|
2
|
+
# using eRuby templates.
|
3
3
|
class Asciidoctor::Renderer
|
4
|
+
attr_reader :compact
|
5
|
+
|
4
6
|
# Public: Initialize an Asciidoctor::Renderer object.
|
5
7
|
#
|
6
8
|
def initialize(options={})
|
7
9
|
@debug = !!options[:debug]
|
8
10
|
|
9
11
|
@views = {}
|
12
|
+
@compact = options[:compact]
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
backend = options[:backend]
|
15
|
+
case backend
|
16
|
+
when 'html5', 'docbook45'
|
17
|
+
eruby = load_eruby options[:eruby]
|
18
|
+
#Asciidoctor.require_library 'asciidoctor/backends/' + backend
|
19
|
+
require 'asciidoctor/backends/' + backend
|
20
|
+
# Load up all the template classes that we know how to render for this backend
|
21
|
+
Asciidoctor::BaseTemplate.template_classes.each do |tc|
|
22
|
+
if tc.to_s.downcase.include?('::' + backend + '::') # optimization
|
23
|
+
view_name, view_backend = self.class.extract_view_mapping(tc)
|
24
|
+
if view_backend == backend
|
25
|
+
@views[view_name] = tc.new(view_name, eruby)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
Asciidoctor.debug { "No built-in templates for backend: #{backend}" }
|
15
31
|
end
|
16
32
|
|
17
33
|
# If user passed in a template dir, let them override our base templates
|
18
34
|
if template_dir = options.delete(:template_dir)
|
19
|
-
Asciidoctor.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
35
|
+
Asciidoctor.require_library 'tilt'
|
36
|
+
|
37
|
+
Asciidoctor.debug {
|
38
|
+
msg = []
|
39
|
+
msg << "Views going in are like so:"
|
40
|
+
msg << @views.map {|k, v| "#{k}: #{v}"}
|
41
|
+
msg << '=' * 60
|
42
|
+
msg * "\n"
|
43
|
+
}
|
44
|
+
|
24
45
|
# Grab the files in the top level of the directory (we're not traversing)
|
25
46
|
files = Dir.glob(File.join(template_dir, '*')).select{|f| File.stat(f).file?}
|
26
47
|
files.inject(@views) do |view_hash, view|
|
27
48
|
name = File.basename(view).split('.').first
|
28
|
-
view_hash.merge!(name => Tilt.new(view, nil, :trim => '<>'))
|
49
|
+
view_hash.merge!(name => Tilt.new(view, nil, :trim => '<>', :attr_wrapper => '"'))
|
29
50
|
end
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
51
|
+
|
52
|
+
Asciidoctor.debug {
|
53
|
+
msg = []
|
54
|
+
msg << "Views going in are like so:"
|
55
|
+
msg << @views.map {|k, v| "#{k}: #{v}"}
|
56
|
+
msg << '=' * 60
|
57
|
+
msg * "\n"
|
58
|
+
}
|
35
59
|
end
|
36
60
|
|
37
61
|
@render_stack = []
|
@@ -44,11 +68,13 @@ class Asciidoctor::Renderer
|
|
44
68
|
# locals - the optional Hash of locals to be passed to Tilt (default {}) (also ignored, really)
|
45
69
|
def render(view, object, locals = {})
|
46
70
|
@render_stack.push([view, object])
|
47
|
-
|
71
|
+
|
72
|
+
if !@views.has_key? view
|
48
73
|
raise "Couldn't find a view in @views for #{view}"
|
49
74
|
else
|
50
|
-
Asciidoctor.debug "View for #{view} is #{@views[view]}, object is #{object}"
|
75
|
+
Asciidoctor.debug { "View for #{view} is #{@views[view]}, object is #{object}" }
|
51
76
|
end
|
77
|
+
|
52
78
|
ret = @views[view].render(object, locals)
|
53
79
|
|
54
80
|
if @debug
|
@@ -57,7 +83,7 @@ class Asciidoctor::Renderer
|
|
57
83
|
STDERR.puts "Rendering:"
|
58
84
|
@render_stack.each do |stack_view, stack_obj|
|
59
85
|
obj_info = case stack_obj
|
60
|
-
when Asciidoctor::Section; "SECTION #{stack_obj.
|
86
|
+
when Asciidoctor::Section; "SECTION #{stack_obj.title}"
|
61
87
|
when Asciidoctor::Block;
|
62
88
|
if stack_obj.context == :dlist
|
63
89
|
dt_list = stack_obj.buffer.map{|dt,dd| dt.content.strip}.join(', ')
|
@@ -79,4 +105,74 @@ class Asciidoctor::Renderer
|
|
79
105
|
@render_stack.pop
|
80
106
|
ret
|
81
107
|
end
|
108
|
+
|
109
|
+
def views
|
110
|
+
readonly_views = @views.dup
|
111
|
+
readonly_views.freeze
|
112
|
+
readonly_views
|
113
|
+
end
|
114
|
+
|
115
|
+
# Internal: Load the eRuby implementation
|
116
|
+
#
|
117
|
+
# name - the String name of the eRuby implementation (default: 'erb')
|
118
|
+
#
|
119
|
+
# returns the eRuby implementation class
|
120
|
+
def load_eruby(name)
|
121
|
+
if name.nil? || !['erb', 'erubis'].include?(name)
|
122
|
+
name = 'erb'
|
123
|
+
end
|
124
|
+
|
125
|
+
Asciidoctor.require_library name
|
126
|
+
|
127
|
+
if name == 'erb'
|
128
|
+
::ERB
|
129
|
+
elsif name == 'erubis'
|
130
|
+
::Erubis::FastEruby
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Internal: Extracts the view name and backend from a qualified Ruby class
|
135
|
+
#
|
136
|
+
# The purpose of this method is to determine the view name and backend to
|
137
|
+
# which a built-in template class maps. We can make certain assumption since
|
138
|
+
# we have control over these class names. The Asciidoctor:: prefix and
|
139
|
+
# Template suffix are stripped as the first step in the conversion.
|
140
|
+
#
|
141
|
+
# qualified_class - The Class or String qualified class name from which to extract the view name and backend
|
142
|
+
#
|
143
|
+
# Examples
|
144
|
+
#
|
145
|
+
# Renderer.extract_view_mapping(Asciidoctor::HTML5::DocumentTemplate)
|
146
|
+
# # => ['document', 'html5']
|
147
|
+
#
|
148
|
+
# Renderer.extract_view_mapping(Asciidoctor::DocBook45::BlockSidebarTemplate)
|
149
|
+
# # => ['block_sidebar', 'docbook45']
|
150
|
+
#
|
151
|
+
# Returns A two-element String Array mapped as [view_name, backend], where backend may be nil
|
152
|
+
def self.extract_view_mapping(qualified_class)
|
153
|
+
view_name, backend = qualified_class.to_s.
|
154
|
+
gsub(/^Asciidoctor::/, '').
|
155
|
+
gsub(/Template$/, '').
|
156
|
+
split('::').reverse
|
157
|
+
view_name = camelcase_to_underscore(view_name)
|
158
|
+
backend = backend.downcase unless backend.nil?
|
159
|
+
[view_name, backend]
|
160
|
+
end
|
161
|
+
|
162
|
+
# Internal: Convert a CamelCase word to an underscore-delimited word
|
163
|
+
#
|
164
|
+
# Examples
|
165
|
+
#
|
166
|
+
# Renderer.camelcase_to_underscore('BlockSidebar')
|
167
|
+
# # => 'block_sidebar'
|
168
|
+
#
|
169
|
+
# Renderer.camelcase_to_underscore('BlockUlist')
|
170
|
+
# # => 'block_ulist'
|
171
|
+
#
|
172
|
+
# Returns the String converted from CamelCase to underscore-delimited
|
173
|
+
def self.camelcase_to_underscore(str)
|
174
|
+
str.gsub(/([[:upper:]]+)([[:upper:]][[:alpha:]])/, '\1_\2').
|
175
|
+
gsub(/([[:lower:]])([[:upper:]])/, '\1_\2').downcase
|
176
|
+
end
|
177
|
+
|
82
178
|
end
|
data/lib/asciidoctor/section.rb
CHANGED
@@ -1,113 +1,83 @@
|
|
1
|
-
# Public: Methods for managing sections of
|
1
|
+
# Public: Methods for managing sections of AsciiDoc content in a document.
|
2
2
|
# The section responds as an Array of content blocks by delegating
|
3
3
|
# block-related methods to its @blocks Array.
|
4
4
|
#
|
5
5
|
# Examples
|
6
6
|
#
|
7
7
|
# section = Asciidoctor::Section.new
|
8
|
-
# section.
|
9
|
-
# section.
|
8
|
+
# section.title = 'Section 1'
|
9
|
+
# section.id = 'sect1'
|
10
10
|
#
|
11
11
|
# section.size
|
12
12
|
# => 0
|
13
13
|
#
|
14
|
-
# section.
|
15
|
-
# => "
|
14
|
+
# section.id
|
15
|
+
# => "sect1"
|
16
16
|
#
|
17
17
|
# section << new_block
|
18
18
|
# section.size
|
19
19
|
# => 1
|
20
|
-
class Asciidoctor::Section
|
21
|
-
# Public: Get/Set the Integer section level.
|
22
|
-
attr_accessor :level
|
20
|
+
class Asciidoctor::Section < Asciidoctor::AbstractBlock
|
23
21
|
|
24
|
-
# Public: Set the
|
25
|
-
|
26
|
-
|
27
|
-
# Public: Get/Set the String section caption.
|
28
|
-
attr_accessor :caption
|
29
|
-
|
30
|
-
# Public: Get/Set the String section anchor name.
|
31
|
-
attr_accessor :anchor
|
32
|
-
alias :id :anchor
|
33
|
-
|
34
|
-
# Public: Get the Hash of attributes for this block
|
35
|
-
attr_accessor :attributes
|
36
|
-
|
37
|
-
# Public: Get the Array of section blocks.
|
38
|
-
attr_reader :blocks
|
22
|
+
# Public: Get/Set the Integer index of this section within the parent block
|
23
|
+
attr_accessor :index
|
39
24
|
|
40
25
|
# Public: Initialize an Asciidoctor::Section object.
|
41
26
|
#
|
42
27
|
# parent - The parent Asciidoc Object.
|
43
|
-
def initialize(parent)
|
44
|
-
|
45
|
-
|
46
|
-
|
28
|
+
def initialize(parent = nil, level = nil)
|
29
|
+
super(parent, :section)
|
30
|
+
if level.nil? && !parent.nil?
|
31
|
+
@level = parent.level + 1
|
32
|
+
end
|
33
|
+
@index = 0
|
47
34
|
end
|
48
35
|
|
49
|
-
# Public:
|
50
|
-
|
51
|
-
|
36
|
+
# Public: The name of this section, an alias of the section title
|
37
|
+
alias :name :title
|
38
|
+
|
39
|
+
# Public: Generate a String id for this section.
|
52
40
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# => "git-web--browse(1) Manual Page"
|
41
|
+
# The generated id is prefixed with value of the 'idprefix' attribute, which
|
42
|
+
# is an underscore by default.
|
56
43
|
#
|
57
|
-
#
|
58
|
-
def name
|
59
|
-
@name &&
|
60
|
-
@name.gsub(/(^|[^\\])\{(\w[\w\-]+\w)\}/) { $1 + Asciidoctor::INTRINSICS[$2] }.
|
61
|
-
gsub( /`([^`]+)`/, '<tt>\1</tt>' )
|
62
|
-
end
|
63
|
-
|
64
|
-
# Public: Get the String section id prefixed with value of idprefix attribute, otherwise an underscore
|
44
|
+
# Section id synthesis can be disabled by undefining the 'sectids' attribute.
|
65
45
|
#
|
66
|
-
#
|
46
|
+
# If the generated id is already in use in the document, a count is appended
|
47
|
+
# until a unique id is found.
|
67
48
|
#
|
68
49
|
# Examples
|
69
50
|
#
|
70
51
|
# section = Section.new(parent)
|
71
|
-
# section.
|
72
|
-
# section.
|
52
|
+
# section.title = "Foo"
|
53
|
+
# section.generate_id
|
73
54
|
# => "_foo"
|
74
|
-
|
75
|
-
|
76
|
-
|
55
|
+
#
|
56
|
+
# another_section = Section.new(parent)
|
57
|
+
# another_section.title = "Foo"
|
58
|
+
# another_section.generate_id
|
59
|
+
# => "_foo_1"
|
60
|
+
def generate_id
|
61
|
+
if @document.attr?('sectids')
|
62
|
+
base_id = @document.attr('idprefix', '_') + title.downcase.gsub(/&#[0-9]+;/, '_').
|
63
|
+
gsub(/\W+/, '_').tr_s('_', '_').gsub(/^_?(.*?)_?$/, '\1')
|
64
|
+
gen_id = base_id
|
65
|
+
cnt = 2
|
66
|
+
while @document.references[:ids].has_key? gen_id
|
67
|
+
gen_id = "#{base_id}_#{cnt}"
|
68
|
+
cnt += 1
|
69
|
+
end
|
70
|
+
@document.references[:ids][gen_id] = title
|
71
|
+
gen_id
|
77
72
|
else
|
78
73
|
nil
|
79
74
|
end
|
80
75
|
end
|
81
76
|
|
82
|
-
# Public: Get the Asciidoctor::Document instance to which this Block belongs
|
83
|
-
def document
|
84
|
-
@parent.is_a?(Asciidoctor::Document) ? @parent : @parent.document
|
85
|
-
end
|
86
|
-
|
87
|
-
def attr(name, default = nil)
|
88
|
-
default.nil? ? @attributes.fetch(name.to_s, self.document.attr(name)) :
|
89
|
-
@attributes.fetch(name.to_s, self.document.attr(name, default))
|
90
|
-
end
|
91
|
-
|
92
|
-
def attr?(name)
|
93
|
-
@attributes.has_key?(name.to_s) || self.document.attr?(name)
|
94
|
-
end
|
95
|
-
|
96
|
-
def update_attributes(attributes)
|
97
|
-
@attributes.update(attributes)
|
98
|
-
end
|
99
|
-
|
100
|
-
# Public: Get the Asciidoctor::Renderer instance being used for the ancestor
|
101
|
-
# Asciidoctor::Document instance.
|
102
|
-
def renderer
|
103
|
-
Asciidoctor.debug "Section#renderer: Looking for my renderer up in #{@parent}"
|
104
|
-
@parent.renderer
|
105
|
-
end
|
106
|
-
|
107
77
|
# Public: Get the rendered String content for this Section and all its child
|
108
78
|
# Blocks.
|
109
79
|
def render
|
110
|
-
Asciidoctor.debug "Now rendering section for #{self}"
|
80
|
+
Asciidoctor.debug { "Now rendering section for #{self}" }
|
111
81
|
renderer.render('section', self)
|
112
82
|
end
|
113
83
|
|
@@ -122,129 +92,70 @@ class Asciidoctor::Section
|
|
122
92
|
# section.content
|
123
93
|
# "<div class=\"paragraph\"><p>foo</p></div>\n<div class=\"paragraph\"><p>bar</p></div>\n<div class=\"paragraph\"><p>baz</p></div>"
|
124
94
|
def content
|
125
|
-
@blocks.map
|
126
|
-
Asciidoctor.debug "Begin rendering block #{block.is_a?(Asciidoctor::Section) ? block.name : 'n/a'} #{block} (context: #{block.is_a?(Asciidoctor::Block) ? block.context : 'n/a' })"
|
127
|
-
poo = block.render
|
128
|
-
Asciidoctor.debug "===> Done rendering block #{block.is_a?(Asciidoctor::Section) ? block.name : 'n/a'} #{block} (context: #{block.is_a?(Asciidoctor::Block) ? block.context : 'n/a' })"
|
129
|
-
poo
|
130
|
-
end.join
|
131
|
-
end
|
132
|
-
|
133
|
-
# Public: The title of this section, an alias of the section name
|
134
|
-
def title
|
135
|
-
@name
|
136
|
-
end
|
137
|
-
|
138
|
-
# Public: Get the Integer number of blocks in the section.
|
139
|
-
#
|
140
|
-
# Examples
|
141
|
-
#
|
142
|
-
# section = Section.new
|
143
|
-
#
|
144
|
-
# section.size
|
145
|
-
# => 0
|
146
|
-
#
|
147
|
-
# section << 'foo'
|
148
|
-
# section << 'bar'
|
149
|
-
# section.size
|
150
|
-
# => 2
|
151
|
-
def size
|
152
|
-
@blocks.size
|
95
|
+
@blocks.map {|b| b.render }.join
|
153
96
|
end
|
154
97
|
|
155
|
-
# Public: Get the
|
156
|
-
#
|
157
|
-
# i - The Integer array index number.
|
158
|
-
#
|
159
|
-
# section = Section.new
|
98
|
+
# Public: Get the section number for the current Section
|
160
99
|
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
def [](i)
|
166
|
-
@blocks[i]
|
167
|
-
end
|
168
|
-
|
169
|
-
# Public: Delete the element at i in the array of section blocks,
|
170
|
-
# returning that element or nil if i is out of range.
|
100
|
+
# The section number is a unique, dot separated String
|
101
|
+
# where each entry represents one level of nesting and
|
102
|
+
# the value of each entry is the 1-based index of
|
103
|
+
# the Section amongst its sibling Sections
|
171
104
|
#
|
172
|
-
#
|
105
|
+
# delimiter - the delimiter to separate the number for each level
|
106
|
+
# append - the String to append at the end of the section number
|
107
|
+
# or Boolean to indicate the delimiter should not be
|
108
|
+
# appended to the final level
|
109
|
+
# (default: nil)
|
173
110
|
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
# section << 'foo'
|
177
|
-
# section << 'bar'
|
178
|
-
# section.delete_at(1)
|
179
|
-
# => "bar"
|
180
|
-
#
|
181
|
-
# section.blocks
|
182
|
-
# => ["foo"]
|
183
|
-
def delete_at(i)
|
184
|
-
@blocks.delete_at(i)
|
185
|
-
end
|
186
|
-
|
187
|
-
# Public: Append a content block to this section's list of blocks.
|
188
|
-
#
|
189
|
-
# block - The new section block.
|
190
|
-
#
|
191
|
-
# section = Section.new
|
192
|
-
#
|
193
|
-
# section << 'foo'
|
194
|
-
# section << 'bar'
|
195
|
-
# section.blocks
|
196
|
-
# => ["foo", "bar"]
|
197
|
-
def <<(block)
|
198
|
-
@blocks << block
|
199
|
-
end
|
200
|
-
|
201
|
-
# Public: Clear this Section's list of blocks.
|
202
|
-
#
|
203
|
-
# section = Section.new
|
204
|
-
#
|
205
|
-
# section << 'foo'
|
206
|
-
# section << 'bar'
|
207
|
-
# section.blocks
|
208
|
-
# => ["foo", "bar"]
|
209
|
-
# section.clear_blocks
|
210
|
-
# section.blocks
|
211
|
-
# => []
|
212
|
-
def clear_blocks
|
213
|
-
@blocks = []
|
214
|
-
end
|
215
|
-
|
216
|
-
# Public: Insert a content block at the specified index in this section's
|
217
|
-
# list of blocks.
|
218
|
-
#
|
219
|
-
# i - The Integer array index number.
|
220
|
-
# val = The content block to insert.
|
221
|
-
#
|
222
|
-
# section = Section.new
|
111
|
+
# Examples
|
223
112
|
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
227
|
-
#
|
228
|
-
#
|
229
|
-
|
230
|
-
|
113
|
+
# sect1 = Section.new(document)
|
114
|
+
# sect1.level = 1
|
115
|
+
# sect1_1 = Section.new(sect1)
|
116
|
+
# sect1_1.level = 2
|
117
|
+
# sect1_2 = Section.new(sect1)
|
118
|
+
# sect1_2.level = 2
|
119
|
+
# sect1 << sect1_1
|
120
|
+
# sect1 << sect1_2
|
121
|
+
# sect1_1_1 = Section.new(sect1_1)
|
122
|
+
# sect1_1_1.level = 3
|
123
|
+
# sect1_1 << sect1_1_1
|
124
|
+
#
|
125
|
+
# sect1.sectnum
|
126
|
+
# # => 1.
|
127
|
+
#
|
128
|
+
# sect1_1.sectnum
|
129
|
+
# # => 1.1.
|
130
|
+
#
|
131
|
+
# sect1_2.sectnum
|
132
|
+
# # => 1.2.
|
133
|
+
#
|
134
|
+
# sect1_1_1.sectnum
|
135
|
+
# # => 1.1.1.
|
136
|
+
#
|
137
|
+
# sect1_1_1.sectnum(',', false)
|
138
|
+
# # => 1,1,1
|
139
|
+
#
|
140
|
+
# Returns the section number as a String
|
141
|
+
def sectnum(delimiter = '.', append = nil)
|
142
|
+
append ||= (append == false ? '' : delimiter)
|
143
|
+
if !@level.nil? && @level > 1 && @parent.is_a?(::Asciidoctor::Section)
|
144
|
+
"#{@parent.sectnum(delimiter)}#{@index + 1}#{append}"
|
145
|
+
else
|
146
|
+
"#{@index + 1}#{append}"
|
147
|
+
end
|
231
148
|
end
|
232
149
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
# section << 'bar'
|
244
|
-
# section << 'baz'
|
245
|
-
# section.index{|el| el =~ /^ba/}
|
246
|
-
# => 1
|
247
|
-
def index(&block)
|
248
|
-
@blocks.index(&block)
|
150
|
+
def to_s
|
151
|
+
if @title
|
152
|
+
if @level && @index
|
153
|
+
%[#{super.to_s} - #{sectnum} #@title [blocks:#{@blocks.size}]]
|
154
|
+
else
|
155
|
+
%[#{super.to_s} - #@title [blocks:#{@blocks.size}]]
|
156
|
+
end
|
157
|
+
else
|
158
|
+
super.to_s
|
159
|
+
end
|
249
160
|
end
|
250
161
|
end
|