erbook 6.1.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. data/bin/erbook +29 -25
  2. data/doc/HelloWorld.spec +3 -1
  3. data/doc/api/classes/ERBook.html +86 -0
  4. data/doc/api/classes/ERBook/Document.html +399 -0
  5. data/doc/api/classes/ERBook/Document/Node.html +110 -0
  6. data/doc/api/classes/ERBook/Template.html +309 -0
  7. data/doc/api/classes/ERBook/Template/Sandbox.html +134 -0
  8. data/doc/api/classes/RDoc.html +69 -0
  9. data/doc/api/classes/RDoc/AnyMethod.html +249 -0
  10. data/doc/api/classes/RDoc/DummyMarkup.html +60 -0
  11. data/doc/api/classes/RDoc/DummyMixin.html +54 -0
  12. data/doc/api/classes/RDoc/DummyOptions.html +60 -0
  13. data/doc/api/classes/RDoc/TopLevel.html +344 -0
  14. data/doc/api/classes/String.html +212 -0
  15. data/doc/api/created.rid +1 -0
  16. data/doc/api/css/main.css +263 -0
  17. data/doc/api/css/panel.css +383 -0
  18. data/doc/api/css/reset.css +53 -0
  19. data/doc/api/files/ANN_eml.html +276 -0
  20. data/doc/api/files/ANN_html.html +407 -0
  21. data/doc/api/files/ANN_txt.html +271 -0
  22. data/doc/api/files/LICENSE.html +76 -0
  23. data/doc/api/files/lib/erbook/document_rb.html +74 -0
  24. data/doc/api/files/lib/erbook/rdoc_rb.html +77 -0
  25. data/doc/api/files/lib/erbook/template_rb.html +66 -0
  26. data/doc/api/files/lib/erbook/to_xhtml_rb.html +89 -0
  27. data/doc/api/files/lib/erbook_rb.html +70 -0
  28. data/doc/api/i/arrows.png +0 -0
  29. data/doc/api/i/results_bg.png +0 -0
  30. data/doc/api/i/tree_bg.png +0 -0
  31. data/doc/api/index.html +14 -18
  32. data/doc/api/js/jquery-1.3.2.min.js +19 -0
  33. data/doc/api/js/jquery-effect.js +593 -0
  34. data/doc/api/js/main.js +22 -0
  35. data/doc/api/js/searchdoc.js +605 -0
  36. data/doc/api/panel/index.html +63 -0
  37. data/doc/api/panel/search_index.js +1 -0
  38. data/doc/api/panel/tree.js +1 -0
  39. data/doc/formats.erb +63 -115
  40. data/doc/history.erb +125 -92
  41. data/doc/index.erb +12 -7
  42. data/doc/index.xhtml +1020 -1347
  43. data/doc/intro.erb +42 -40
  44. data/doc/setup.erb +18 -18
  45. data/doc/theory.erb +24 -31
  46. data/doc/usage.erb +14 -24
  47. data/fmt/xhtml.icons/index.yaml +16 -14
  48. data/fmt/xhtml.icons/rakefile +33 -0
  49. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/16x16/places/start-here.png +0 -0
  50. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/32x32/actions/go-down.png +0 -0
  51. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/32x32/actions/go-up.png +0 -0
  52. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/32x32/places/start-here.png +0 -0
  53. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/32x32/status/software-update-available.png +0 -0
  54. data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/apps/accessories-text-editor.png +0 -0
  55. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/48x48/apps/internet-group-chat.png +0 -0
  56. data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/emblems/emblem-important.png +0 -0
  57. data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/status/dialog-error.png +0 -0
  58. data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/status/dialog-information.png +0 -0
  59. data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/status/dialog-warning.png +0 -0
  60. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/COPYING +1 -0
  61. data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/README +0 -0
  62. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/bookmark-new.svg +672 -0
  63. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/go-down.svg +200 -0
  64. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/go-home.svg +445 -0
  65. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/go-up.svg +196 -0
  66. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/view-refresh.svg +393 -0
  67. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/apps/accessories-text-editor.svg +554 -0
  68. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/apps/internet-group-chat.svg +312 -0
  69. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/emblems/emblem-favorite.svg +242 -0
  70. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/emblems/emblem-important.svg +164 -0
  71. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/mimetypes/application-certificate.svg +443 -0
  72. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/places/start-here.svg +492 -0
  73. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/status/dialog-error.svg +330 -0
  74. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/status/dialog-information.svg +1159 -0
  75. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/status/dialog-warning.svg +373 -0
  76. data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/status/software-update-available.svg +209 -0
  77. data/fmt/xhtml.scripts/jquery-1.3.2.min.js +19 -0
  78. data/fmt/xhtml.scripts/jquery.localscroll-1.2.7-min.js +9 -0
  79. data/fmt/xhtml.scripts/jquery.scrollTo-1.4.1-min.js +11 -0
  80. data/fmt/xhtml.yaml +470 -454
  81. data/lang/de.yaml +5 -5
  82. data/lang/el.yaml +4 -4
  83. data/lang/es.yaml +5 -5
  84. data/lang/fr.yaml +5 -5
  85. data/lang/it.yaml +5 -5
  86. data/lang/ja.yaml +4 -4
  87. data/lang/ko.yaml +4 -4
  88. data/lang/nl.yaml +4 -4
  89. data/lang/phrases.yaml +4 -4
  90. data/lang/pt.yaml +5 -5
  91. data/lang/ru.yaml +5 -5
  92. data/lang/zh.yaml +5 -5
  93. data/lang/zt.yaml +5 -5
  94. data/lib/erbook.rb +12 -5
  95. data/lib/erbook/document.rb +127 -107
  96. data/lib/erbook/rdoc.rb +18 -11
  97. data/lib/erbook/template.rb +86 -176
  98. data/lib/erbook/to_xhtml.rb +98 -25
  99. data/{Rakefile → rakefile} +1 -0
  100. metadata +106 -53
  101. data/doc/api/ERBook.html +0 -35
  102. data/doc/api/ERBook/Document.html +0 -669
  103. data/doc/api/ERBook/Document/Node.html +0 -102
  104. data/doc/api/ERBook/Template.html +0 -670
  105. data/doc/api/RDoc.html +0 -23
  106. data/doc/api/RDoc/AnyMethod.html +0 -302
  107. data/doc/api/RDoc/DummyMarkup.html +0 -73
  108. data/doc/api/RDoc/DummyMixin.html +0 -23
  109. data/doc/api/RDoc/DummyOptions.html +0 -140
  110. data/doc/api/RDoc/TopLevel.html +0 -465
  111. data/doc/api/String.html +0 -372
  112. data/doc/api/all-methods.html +0 -253
  113. data/doc/api/all-namespaces.html +0 -42
  114. data/doc/api/app.js +0 -18
  115. data/doc/api/jquery.js +0 -11
  116. data/doc/api/readme.html +0 -38
  117. data/doc/api/style.css +0 -68
  118. data/doc/api/syntax_highlight.css +0 -21
  119. data/fmt/xhtml.icons/tango-icon-theme-0.8.1/48x48/README +0 -2
  120. data/fmt/xhtml.icons/tango-icon-theme-0.8.1/48x48/apps/internet-group-chat.png +0 -0
  121. data/fmt/xhtml.icons/tango-icon-theme-0.8.1/COPYING +0 -67
data/lib/erbook/rdoc.rb CHANGED
@@ -1,17 +1,23 @@
1
- # Workaround for: `rdoc --fmt xml` does not dump information about methods.
2
-
1
+ # Workaround for `rdoc --fmt xml` not dumping information about methods.
2
+ #--
3
+ # Copyright 2008 Suraj N. Kurapati
4
+ # See the LICENSE file for details.
5
+ #++
6
+
7
+ require 'rubygems'
8
+ gem 'rdoc', '>= 2.4.3', '< 2.5'
3
9
  require 'rdoc/rdoc'
4
10
 
5
11
  module RDoc
6
12
  class TopLevel
7
13
  # Returns an array of all classes recorded thus far.
8
14
  def self.all_classes
9
- @@all_classes.values
15
+ @all_classes.values
10
16
  end
11
17
 
12
18
  # Returns an array of all modules recorded thus far.
13
19
  def self.all_modules
14
- @@all_modules.values
20
+ @all_modules.values
15
21
  end
16
22
 
17
23
  # Returns an array of RDoc::AnyMethod objects
@@ -25,10 +31,10 @@ module RDoc
25
31
  def self.refresh_all_classes_and_modules
26
32
  visit = lambda do |node|
27
33
  if node.is_a? NormalClass or node.is_a? SingleClass
28
- @@all_classes[node.full_name] = node
34
+ @all_classes[node.full_name] = node
29
35
 
30
36
  elsif node.is_a? NormalModule
31
- @@all_modules[node.full_name] = node
37
+ @all_modules[node.full_name] = node
32
38
  end
33
39
 
34
40
  (node.classes + node.modules).each {|n| visit[n] }
@@ -48,14 +54,15 @@ module RDoc
48
54
  # RDoc will ignore the given code string! :-(
49
55
  #
50
56
  def self.parse aCodeString, aFileName = __FILE__
51
- top = ParserFactory.parser_for(
52
- TopLevel.new(aFileName), aFileName,
53
- aCodeString, DummyOptions.new, Stats.new
54
- ).scan
57
+ tl = TopLevel.new(aFileName)
58
+ op = DummyOptions.new
59
+ st = Stats.new(0)
60
+
61
+ result = Parser.for(tl, aFileName, aCodeString, op, st).scan
55
62
 
56
63
  refresh_all_classes_and_modules
57
64
 
58
- top
65
+ result
59
66
  end
60
67
 
61
68
  # Returns a RDoc::TopLevel object containing information
@@ -1,210 +1,120 @@
1
- require 'erb'
2
- require 'pathname'
1
+ #--
2
+ # Copyright 2008 Suraj N. Kurapati
3
+ # See the LICENSE file for details.
4
+ #++
5
+
6
+ require 'ember'
3
7
 
4
8
  module ERBook
5
9
  ##
6
- # An eRuby template which allows access to the underlying result
10
+ # eRuby template that provides access to the underlying result
7
11
  # buffer (which contains the result of template evaluation thus
8
12
  # far) and provides sandboxing for isolated template rendering.
9
13
  #
10
- # In addition to the standard <% eRuby %> directives, this template supports:
11
- #
12
- # * Lines that begin with '%' are treated as normal eRuby directives.
13
- #
14
- # * Include directives (<%#include YOUR_PATH #%>) are replaced by the result
15
- # of reading and evaluating the YOUR_PATH file in the current context.
16
- #
17
- # * Unless YOUR_PATH is an absolute path, it is treated as being
18
- # relative to the file which contains the include directive.
19
- #
20
- # * Errors originating from included files are given a proper
21
- # stack trace which shows the chain of inclusion plus any
22
- # further trace steps originating from the included file itself.
23
- #
24
- # * eRuby directives delimiting Ruby blocks (<% ... do %>
25
- # ... <% end %>) can be heirarchically unindented by the
26
- # crown margin of the opening (<% ... do %>) delimiter.
27
- #
28
- class Template < ERB
29
- # The result of template evaluation thus far.
30
- attr_reader :buffer
14
+ class Template < Ember::Template
15
+ attr_reader :sandbox
31
16
 
32
17
  ##
33
- # @param [String] source
18
+ # ==== Parameters
19
+ #
20
+ # [source]
34
21
  # Replacement for the ambiguous '(erb)' identifier in stack traces;
35
22
  # so that the user can better determine the source of an error.
36
23
  #
37
- # @param [String] input
24
+ # [input]
38
25
  # A string containing eRuby directives.
39
26
  #
40
- # @param [boolean] unindent
27
+ # [unindent]
41
28
  # If true, then all content blocks will be unindented hierarchically,
42
- # by the leading space of their 'do' and 'end' delimiters.
43
29
  #
44
- # @param safe_level
30
+ # [safe_level]
45
31
  # See safe_level in ERB::new().
46
32
  #
47
- def initialize source, input, unindent = false, safe_level = nil
48
- # expand all "include" directives in the input
49
- expander = lambda do |src_file, src_text, path_stack, stack_trace|
50
- src_path = File.expand_path(src_file)
51
- src_line = 1 # line number of the current include directive in src_file
52
-
53
- chunks = src_text.split(/<%#\s*include\s+(.+?)\s*#%>/)
54
-
55
- path_stack.push src_path
56
- chunks.each_with_index do |chunk, i|
57
- # even number: chunk is not an include directive
58
- if i & 1 == 0
59
- src_line += chunk.count("\n")
60
-
61
- # odd number: chunk is the target of the include directive
62
- else
63
- # resolve correct path of target file
64
- dst_file = chunk
65
-
66
- unless Pathname.new(dst_file).absolute?
67
- # target is relative to the file in
68
- # which the include directive exists
69
- dst_file = File.join(File.dirname(src_file), dst_file)
70
- end
71
-
72
- dst_path = File.expand_path(dst_file)
73
-
74
- # include the target file
75
- if path_stack.include? dst_file
76
- raise "Cannot include #{dst_file.inspect} at #{src_file.inspect}:#{src_line} because that would cause an infinite loop in the inclusion stack: #{path_stack.inspect}."
77
- else
78
- stack_trace.push "#{src_path}:#{src_line}"
79
- dst_text = eval('File.read dst_file', binding, src_file, src_line)
80
-
81
- # recursively expand any include directives within
82
- # the expansion of the current include directive
83
- dst_text = expander[dst_file, dst_text, path_stack, stack_trace]
84
-
85
- # provide more accurate stack trace for
86
- # errors originating from included files
87
- line_var = "__erbook_var_#{dst_file.object_id.abs}__"
88
- dst_text = %{<%
89
- #{line_var} = __LINE__ + 2 # content is 2 newlines below
90
- begin
91
- %>#{dst_text}<%
92
- rescue Exception => err
93
- bak = err.backtrace
94
-
95
- top = []
96
- found_top = false
97
- prev_line = nil
98
-
99
- bak.each do |step|
100
- if step =~ /^#{/#{source}/}:(\\d+)(.*)/
101
- line, desc = $1, $2
102
- line = line.to_i - #{line_var} + 1
103
-
104
- if line > 0 and line != prev_line
105
- top << "#{dst_path}:\#{line}\#{desc}"
106
- found_top = true
107
- prev_line = line
108
- end
109
- elsif !found_top
110
- top << step
111
- end
112
- end
113
-
114
- if found_top
115
- bak.replace top
116
- bak.concat #{stack_trace.reverse.inspect}
117
- end
118
-
119
- raise err
120
- end
121
- %>}
122
-
123
- stack_trace.pop
124
- end
125
-
126
- chunks[i] = dst_text
127
- end
128
- end
129
- path_stack.pop
130
-
131
- chunks.join
132
- end
133
-
134
- input = expander[source, input, [], []]
135
-
136
- # convert "% at beginning of line" usage into <% normal %> usage
137
- input.gsub! %r{^([ \t]*)(%[=# \t].*)$}, '\1<\2 %>'
138
- input.gsub! %r{^([ \t]*)%%}, '\1%'
139
-
140
- # unindent node content hierarchically
141
- if unindent
142
- tags = input.scan(/<%(?:.(?!<%))*?%>/m)
143
- margins = []
144
- result = []
145
-
146
- buffer = input
147
- tags.each do |tag|
148
- chunk, buffer = buffer.split(tag, 2)
149
- chunk << tag
150
-
151
- # perform unindentation
152
- result << chunk.gsub(/^#{margins.last}/, '')
153
-
154
- # prepare for next unindentation
155
- case tag
156
- when /<%[^%=].*?\bdo\b.*?%>/m
157
- margins.push buffer[/^[ \t]*(?=\S)/]
158
-
159
- when /<%\s*end\s*%>/m
160
- margins.pop
161
- end
162
- end
163
- result << buffer
164
-
165
- input = result.join
33
+ def initialize source, input, unindent = true, safe_level = nil
34
+ super input,
35
+ :result_variable => :@buffer,
36
+ :source_file => source,
37
+ :unindent => unindent,
38
+ :shorthand => true,
39
+ :infer_end => true
40
+
41
+ @sandbox = Sandbox.new
42
+
43
+ if $DEBUG
44
+ IO.popen('cat -n', 'w+') do |io|
45
+ io.write self.program
46
+ io.close_write
47
+ STDERR.puts io.read
166
48
  end
49
+ end
50
+ end
167
51
 
168
- # silence the code-only <% ... %> directive, just like PHP does
169
- input.gsub! %r{^[ \t]*(<%[^%=]((?!<%).)*?[^%]%>)[ \t]*\r?\n}m, '\1'
170
-
171
- # use @buffer to store the result of the ERB template
172
- super input, safe_level, nil, :@buffer
52
+ ##
53
+ # Returns the output of evaluating this template inside the given context.
54
+ #
55
+ # If no context is given, then the sandbox of this template is used.
56
+ #
57
+ def render
58
+ super @sandbox.instance_eval('binding')
59
+ end
173
60
 
174
- self.filename = source
61
+ ##
62
+ # Returns the result of template evaluation thus far.
63
+ #
64
+ def buffer
65
+ @sandbox.instance_variable_get(:@buffer)
175
66
  end
176
67
 
177
- # Renders this template within a fresh object that is populated with
68
+ ##
69
+ # Renders this template within a fresh sandbox that is populated with
178
70
  # the given instance variables, whose names must be prefixed with '@'.
71
+ #
179
72
  def render_with inst_vars = {}
180
- context = Object.new.instance_eval do
73
+ old_sandbox = @sandbox
74
+
75
+ begin
76
+ @sandbox = Sandbox.new
77
+
181
78
  inst_vars.each_pair do |var, val|
182
- instance_variable_set var, val
79
+ @sandbox.instance_variable_set var, val
183
80
  end
184
81
 
185
- binding
186
- end
82
+ render
187
83
 
188
- result context
84
+ ensure
85
+ @sandbox = old_sandbox
86
+ end
189
87
  end
190
88
 
191
- protected
192
-
193
- # Returns the content that the given block wants to append to
194
- # the buffer. If the given block does not want to append to the
195
- # buffer, then returns the result of invoking the given block.
196
- def content_from_block *block_args
197
- raise ArgumentError, 'block must be given' unless block_given?
198
-
199
- head = @buffer.length
200
- body = yield(*block_args) # this appends 'content' to '@buffer'
201
- tail = @buffer.length
89
+ ##
90
+ # Environment for template evaluation.
91
+ #
92
+ class Sandbox
93
+ ##
94
+ # Returns an array of things that the given
95
+ # block wants to append to the buffer. If
96
+ # the given block does not want to append
97
+ # to the buffer, then returns the result of
98
+ # invoking the given block inside an array.
99
+ #
100
+ def __block_content__ *block_args
101
+ raise ArgumentError, 'block must be given' unless block_given?
102
+
103
+ original = @buffer
104
+
105
+ begin
106
+ block_content = @buffer = []
107
+ return_value = yield(*block_args) # this appends content to @buffer
108
+ ensure
109
+ @buffer = original
110
+ end
202
111
 
203
- if tail > head
204
- @buffer.slice! head..tail
205
- else
206
- body
207
- end.to_s
112
+ if block_content.empty?
113
+ [return_value]
114
+ else
115
+ block_content
116
+ end
117
+ end
208
118
  end
209
119
  end
210
120
  end
@@ -4,13 +4,18 @@
4
4
  # This particular implementation features the Markdown
5
5
  # formatting system via Maruku, syntax coloring via CodeRay,
6
6
  # and smart source code sizing (block versus inline display).
7
+ #--
8
+ # Copyright 2006 Suraj N. Kurapati
9
+ # See the LICENSE file for details.
10
+ #++
7
11
 
8
12
  require 'cgi'
13
+ require 'digest/sha1'
9
14
 
10
15
  begin
11
16
  require 'rubygems'
12
17
  gem 'maruku', '~> 0.5'
13
- gem 'coderay', '>= 0.7'
18
+ gem 'coderay', '>= 0.8'
14
19
  rescue LoadError
15
20
  end
16
21
 
@@ -22,23 +27,33 @@ class String
22
27
  # they are being processed by Textile. By doing this, we
23
28
  # avoid unwanted Textile transformations, such as quotation
24
29
  # marks becoming curly (&#8192;), in source code.
25
- PROTECTED_TAGS = %w[tt code pre]
30
+ PROTECTED_TAGS = {
31
+ :pre => :block, # tag => is it a block or inline element?
32
+ :code => :inline,
33
+ :tt => :inline
34
+ }
26
35
 
27
36
  # The content of these XHTML tags will be preserved
28
37
  # *verbatim* throughout the text-to-XHTML conversion process.
29
- VERBATIM_TAGS = %w[noformat]
38
+ VERBATIM_TAGS = {
39
+ :noformat => :block # tag => is it a block or inline element?
40
+ }
30
41
 
42
+ ##
31
43
  # Transforms this string into an *inline* XHTML string (one that
32
44
  # does not contain any block-level XHTML elements at the root).
45
+ #
33
46
  def to_inline_xhtml
34
47
  to_xhtml true
35
48
  end
36
49
 
50
+ ##
37
51
  # Transforms this string into XHTML while ensuring that the
38
52
  # result contains one or more block-level elements at the root.
39
53
  #
40
- # inline:: If true, the resulting XHTML will *not*
41
- # contain a block-level element at the root.
54
+ # [inline]
55
+ # If true, the resulting XHTML will *not*
56
+ # contain a block-level element at the root.
42
57
  #
43
58
  def to_xhtml inline = false
44
59
  with_protected_tags(self, VERBATIM_TAGS, true) do |text|
@@ -63,51 +78,85 @@ class String
63
78
  end
64
79
  end
65
80
 
81
+ ##
66
82
  # Returns the result of running this string through Maruku.
67
83
  #
68
- # inline:: If true, the resulting XHTML will *not*
69
- # be wrapped in a XHTML paragraph element.
84
+ # [inline]
85
+ # If true, the resulting XHTML will *not*
86
+ # be wrapped in a XHTML paragraph element.
70
87
  #
71
88
  def thru_maruku inline = false #:nodoc:
72
- html = Maruku.new(self).to_html
89
+ #
90
+ # XXX: add a newline at the beginning of the text to
91
+ # prevent Maruku from interpreting the first line
92
+ # of text as a parameter definition, which is the
93
+ # case if that first line matches /\S{2}: /
94
+ #
95
+ # see this bug report for details:
96
+ # http://rubyforge.org/tracker/?func=detail&atid=10735&aid=25697&group_id=2795
97
+ #
98
+ html = Maruku.new("\n#{self}").to_html
73
99
  html.sub! %r{\A<p>(.*)</p>\Z}, '\1' if inline
74
100
  html
75
101
  end
76
102
 
77
- # Adds syntax coloring to <code> elements in the given text. If the
78
- # <code> tag has an attribute lang="...", then that is considered the
79
- # programming language for which appropriate syntax coloring should be
80
- # applied. Otherwise, the programming language is assumed to be ruby.
103
+ ##
104
+ # Adds syntax coloring to <code> elements in this string.
105
+ #
106
+ # Each <code> element is annotated with a class="line"
107
+ # or a class="para" attribute, according to whether it
108
+ # spans a single line or multiple lines of code.
109
+ #
110
+ # In the latter case, the <code> element is replaced with a <pre> element
111
+ # so that its multi-line body appears correctly in text-mode web browsers.
112
+ #
113
+ # If a <code> element has a lang="..." attribute,
114
+ # then that attribute's value is considered to be
115
+ # the programming language for which appropriate
116
+ # syntax coloring should be applied. Otherwise,
117
+ # the programming language is assumed to be ruby.
118
+ #
81
119
  def thru_coderay #:nodoc:
82
120
  gsub %r{<(code)(.*?)>(.*?)</\1>}m do
83
- atts, code = $2, CGI.unescapeHTML($3).sub(/\A\r?\n/, '')
121
+ elem, atts, code = $1, $2, CGI.unescapeHTML($3).sub(/\A\r?\n/, '')
84
122
  lang = atts[/\blang=('|")(.*?)\1/i, 2] || :ruby
85
123
 
86
- html = CodeRay.scan(code, lang).html(:css => :style)
87
- tag = if code =~ /\n/ then :pre else :code end
124
+ body = CodeRay.scan(code, lang).html(:css => :style)
125
+
126
+ if code =~ /\n/
127
+ span = :para
128
+ head = "<ins><pre"
129
+ tail = "</pre></ins>"
130
+
131
+ else
132
+ span = :line
133
+ head = "<#{elem}"
134
+ tail = "</#{elem}>"
135
+ end
88
136
 
89
- %{<#{tag} class="code"#{atts}>#{html}</#{tag}>}
137
+ %{#{head} class="#{span}"#{atts}>#{body}#{tail}}
90
138
  end
91
139
  end
92
140
 
93
141
  private
94
142
 
143
+ ##
95
144
  # Protects the given tags in the given input, passes
96
145
  # that protected input to the given block, restores the
97
146
  # given tags in the result of the block and returns it.
98
147
  #
99
- # verbatim:: If true, the content of the elments having the
100
- # given tags will not be temporarily altered so
101
- # that process nested elements can be processed.
148
+ # [verbatim]
149
+ # If true, the content of the elments having the given tags will not be
150
+ # temporarily altered so that process nested elements can be processed.
102
151
  #
103
- def with_protected_tags input, tags, verbatim #:nodoc: :yields: input
152
+ def with_protected_tags input, tag_defs, verbatim #:yields: input
104
153
  raise ArgumentError unless block_given?
105
154
 
106
155
  input = input.dup
107
156
  escapes = {}
108
157
 
109
158
  # protect the given tags by escaping them
110
- tags.each do |tag|
159
+ tag_defs.each_key do |tag|
111
160
  input.gsub! %r{(<#{tag}.*?>)(.*?)(</#{tag}>)}m do
112
161
  head, body, tail = $1, $2, $3
113
162
 
@@ -123,7 +172,7 @@ class String
123
172
  head << CGI.escapeHTML(CGI.unescapeHTML(body)) << tail
124
173
  end
125
174
 
126
- escaped = ERBook::Document.digest(original)
175
+ escaped = calc_digest(original)
127
176
  escapes[escaped] = original
128
177
 
129
178
  escaped
@@ -136,12 +185,36 @@ class String
136
185
  # restore the protected tags by unescaping them
137
186
  until escapes.empty?
138
187
  escapes.each_pair do |esc, orig|
139
- if output.gsub! esc, orig
140
- escapes.delete esc
141
- end
188
+ tag = orig[/<\/(.+?)>\s*\z/, 1].to_sym
189
+ raise ArgumentError, tag unless tag_defs.key? tag
190
+
191
+ restore_ok =
192
+ case tag_defs[tag]
193
+ when :inline
194
+ # process inline elements normally
195
+ output.gsub! esc, orig
196
+
197
+ when :block
198
+ # pull block-level elements out of paragraph tag added by Maruku
199
+ output.gsub!(/(<p>\s*)?#{Regexp.quote esc}/){ orig + $1.to_s }
200
+ end
201
+
202
+ escapes.delete esc if restore_ok
142
203
  end
143
204
  end
144
205
 
145
206
  output
146
207
  end
208
+
209
+ ##
210
+ # Returns a digest of the given string that
211
+ # will not be altered by String#to_xhtml.
212
+ #
213
+ def calc_digest input
214
+ Digest::SHA1.hexdigest(input.to_s).
215
+
216
+ # XXX: surround all digits with alphabets so
217
+ # Maruku doesn't change them into HTML
218
+ gsub(/\d/, 'z\&z')
219
+ end
147
220
  end