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.
- data/bin/erbook +29 -25
- data/doc/HelloWorld.spec +3 -1
- data/doc/api/classes/ERBook.html +86 -0
- data/doc/api/classes/ERBook/Document.html +399 -0
- data/doc/api/classes/ERBook/Document/Node.html +110 -0
- data/doc/api/classes/ERBook/Template.html +309 -0
- data/doc/api/classes/ERBook/Template/Sandbox.html +134 -0
- data/doc/api/classes/RDoc.html +69 -0
- data/doc/api/classes/RDoc/AnyMethod.html +249 -0
- data/doc/api/classes/RDoc/DummyMarkup.html +60 -0
- data/doc/api/classes/RDoc/DummyMixin.html +54 -0
- data/doc/api/classes/RDoc/DummyOptions.html +60 -0
- data/doc/api/classes/RDoc/TopLevel.html +344 -0
- data/doc/api/classes/String.html +212 -0
- data/doc/api/created.rid +1 -0
- data/doc/api/css/main.css +263 -0
- data/doc/api/css/panel.css +383 -0
- data/doc/api/css/reset.css +53 -0
- data/doc/api/files/ANN_eml.html +276 -0
- data/doc/api/files/ANN_html.html +407 -0
- data/doc/api/files/ANN_txt.html +271 -0
- data/doc/api/files/LICENSE.html +76 -0
- data/doc/api/files/lib/erbook/document_rb.html +74 -0
- data/doc/api/files/lib/erbook/rdoc_rb.html +77 -0
- data/doc/api/files/lib/erbook/template_rb.html +66 -0
- data/doc/api/files/lib/erbook/to_xhtml_rb.html +89 -0
- data/doc/api/files/lib/erbook_rb.html +70 -0
- data/doc/api/i/arrows.png +0 -0
- data/doc/api/i/results_bg.png +0 -0
- data/doc/api/i/tree_bg.png +0 -0
- data/doc/api/index.html +14 -18
- data/doc/api/js/jquery-1.3.2.min.js +19 -0
- data/doc/api/js/jquery-effect.js +593 -0
- data/doc/api/js/main.js +22 -0
- data/doc/api/js/searchdoc.js +605 -0
- data/doc/api/panel/index.html +63 -0
- data/doc/api/panel/search_index.js +1 -0
- data/doc/api/panel/tree.js +1 -0
- data/doc/formats.erb +63 -115
- data/doc/history.erb +125 -92
- data/doc/index.erb +12 -7
- data/doc/index.xhtml +1020 -1347
- data/doc/intro.erb +42 -40
- data/doc/setup.erb +18 -18
- data/doc/theory.erb +24 -31
- data/doc/usage.erb +14 -24
- data/fmt/xhtml.icons/index.yaml +16 -14
- data/fmt/xhtml.icons/rakefile +33 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/16x16/places/start-here.png +0 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/32x32/actions/go-down.png +0 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/32x32/actions/go-up.png +0 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/32x32/places/start-here.png +0 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/32x32/status/software-update-available.png +0 -0
- data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/apps/accessories-text-editor.png +0 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/48x48/apps/internet-group-chat.png +0 -0
- data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/emblems/emblem-important.png +0 -0
- data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/status/dialog-error.png +0 -0
- data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/status/dialog-information.png +0 -0
- data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/48x48/status/dialog-warning.png +0 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/COPYING +1 -0
- data/fmt/xhtml.icons/{tango-icon-theme-0.8.1 → tango-icon-theme-0.8.90}/README +0 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/bookmark-new.svg +672 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/go-down.svg +200 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/go-home.svg +445 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/go-up.svg +196 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/actions/view-refresh.svg +393 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/apps/accessories-text-editor.svg +554 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/apps/internet-group-chat.svg +312 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/emblems/emblem-favorite.svg +242 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/emblems/emblem-important.svg +164 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/mimetypes/application-certificate.svg +443 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/places/start-here.svg +492 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/status/dialog-error.svg +330 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/status/dialog-information.svg +1159 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/status/dialog-warning.svg +373 -0
- data/fmt/xhtml.icons/tango-icon-theme-0.8.90/scalable/status/software-update-available.svg +209 -0
- data/fmt/xhtml.scripts/jquery-1.3.2.min.js +19 -0
- data/fmt/xhtml.scripts/jquery.localscroll-1.2.7-min.js +9 -0
- data/fmt/xhtml.scripts/jquery.scrollTo-1.4.1-min.js +11 -0
- data/fmt/xhtml.yaml +470 -454
- data/lang/de.yaml +5 -5
- data/lang/el.yaml +4 -4
- data/lang/es.yaml +5 -5
- data/lang/fr.yaml +5 -5
- data/lang/it.yaml +5 -5
- data/lang/ja.yaml +4 -4
- data/lang/ko.yaml +4 -4
- data/lang/nl.yaml +4 -4
- data/lang/phrases.yaml +4 -4
- data/lang/pt.yaml +5 -5
- data/lang/ru.yaml +5 -5
- data/lang/zh.yaml +5 -5
- data/lang/zt.yaml +5 -5
- data/lib/erbook.rb +12 -5
- data/lib/erbook/document.rb +127 -107
- data/lib/erbook/rdoc.rb +18 -11
- data/lib/erbook/template.rb +86 -176
- data/lib/erbook/to_xhtml.rb +98 -25
- data/{Rakefile → rakefile} +1 -0
- metadata +106 -53
- data/doc/api/ERBook.html +0 -35
- data/doc/api/ERBook/Document.html +0 -669
- data/doc/api/ERBook/Document/Node.html +0 -102
- data/doc/api/ERBook/Template.html +0 -670
- data/doc/api/RDoc.html +0 -23
- data/doc/api/RDoc/AnyMethod.html +0 -302
- data/doc/api/RDoc/DummyMarkup.html +0 -73
- data/doc/api/RDoc/DummyMixin.html +0 -23
- data/doc/api/RDoc/DummyOptions.html +0 -140
- data/doc/api/RDoc/TopLevel.html +0 -465
- data/doc/api/String.html +0 -372
- data/doc/api/all-methods.html +0 -253
- data/doc/api/all-namespaces.html +0 -42
- data/doc/api/app.js +0 -18
- data/doc/api/jquery.js +0 -11
- data/doc/api/readme.html +0 -38
- data/doc/api/style.css +0 -68
- data/doc/api/syntax_highlight.css +0 -21
- data/fmt/xhtml.icons/tango-icon-theme-0.8.1/48x48/README +0 -2
- data/fmt/xhtml.icons/tango-icon-theme-0.8.1/48x48/apps/internet-group-chat.png +0 -0
- 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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
34
|
+
@all_classes[node.full_name] = node
|
|
29
35
|
|
|
30
36
|
elsif node.is_a? NormalModule
|
|
31
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
65
|
+
result
|
|
59
66
|
end
|
|
60
67
|
|
|
61
68
|
# Returns a RDoc::TopLevel object containing information
|
data/lib/erbook/template.rb
CHANGED
|
@@ -1,210 +1,120 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
24
|
+
# [input]
|
|
38
25
|
# A string containing eRuby directives.
|
|
39
26
|
#
|
|
40
|
-
#
|
|
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
|
-
#
|
|
30
|
+
# [safe_level]
|
|
45
31
|
# See safe_level in ERB::new().
|
|
46
32
|
#
|
|
47
|
-
def initialize source, input, unindent =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
186
|
-
end
|
|
82
|
+
render
|
|
187
83
|
|
|
188
|
-
|
|
84
|
+
ensure
|
|
85
|
+
@sandbox = old_sandbox
|
|
86
|
+
end
|
|
189
87
|
end
|
|
190
88
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
#
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
data/lib/erbook/to_xhtml.rb
CHANGED
|
@@ -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.
|
|
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 ( ), in source code.
|
|
25
|
-
PROTECTED_TAGS =
|
|
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 =
|
|
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
|
|
41
|
-
#
|
|
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
|
|
69
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
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
|
-
|
|
87
|
-
|
|
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
|
-
%{
|
|
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
|
|
100
|
-
#
|
|
101
|
-
#
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|