erbook 5.0.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/Rakefile +6 -79
- data/bin/erbook +25 -319
- data/doc/HelloWorld.spec +23 -21
- data/doc/README +4 -3
- data/doc/api/ERBook.html +35 -0
- data/doc/api/ERBook/Document.html +673 -0
- data/doc/api/ERBook/Document/Node.html +102 -0
- data/doc/api/ERBook/Template.html +670 -0
- data/doc/api/RDoc.html +23 -0
- data/doc/api/RDoc/AnyMethod.html +302 -0
- data/doc/api/RDoc/DummyMarkup.html +73 -0
- data/doc/api/RDoc/DummyMixin.html +23 -0
- data/doc/api/RDoc/DummyOptions.html +140 -0
- data/doc/api/RDoc/TopLevel.html +465 -0
- data/doc/api/String.html +372 -0
- data/doc/api/all-methods.html +253 -0
- data/doc/api/all-namespaces.html +42 -0
- data/doc/api/app.js +18 -0
- data/doc/api/index.html +16 -22
- data/doc/api/jquery.js +11 -0
- data/doc/api/readme.html +35 -0
- data/doc/api/style.css +68 -0
- data/doc/api/syntax_highlight.css +21 -0
- data/doc/erbook.png +0 -0
- data/doc/erbook.svg +150 -88
- data/doc/formats.erb +387 -0
- data/doc/history.erb +62 -0
- data/doc/index.erb +8 -0
- data/doc/index.xhtml +846 -654
- data/doc/intro.erb +97 -0
- data/doc/setup.erb +62 -0
- data/doc/theory.erb +187 -0
- data/doc/usage.erb +39 -0
- data/fmt/xhtml.yaml +497 -372
- data/lib/erbook.rb +18 -10
- data/lib/erbook/document.rb +233 -0
- data/lib/erbook/template.rb +210 -0
- data/lib/erbook/to_xhtml.rb +25 -17
- metadata +39 -45
- data/README +0 -14
- data/doc/api/classes/ERBook.html +0 -164
- data/doc/api/classes/RDoc.html +0 -112
- data/doc/api/classes/RDoc/AnyMethod.html +0 -195
- data/doc/api/classes/RDoc/AnyMethod.src/M000003.html +0 -18
- data/doc/api/classes/RDoc/AnyMethod.src/M000004.html +0 -23
- data/doc/api/classes/RDoc/AnyMethod.src/M000005.html +0 -18
- data/doc/api/classes/RDoc/AnyMethod.src/M000006.html +0 -22
- data/doc/api/classes/RDoc/TopLevel.html +0 -250
- data/doc/api/classes/RDoc/TopLevel.src/M000007.html +0 -18
- data/doc/api/classes/RDoc/TopLevel.src/M000008.html +0 -18
- data/doc/api/classes/RDoc/TopLevel.src/M000009.html +0 -18
- data/doc/api/classes/RDoc/TopLevel.src/M000010.html +0 -29
- data/doc/api/classes/RDoc/TopLevel.src/M000011.html +0 -25
- data/doc/api/classes/RDoc/TopLevel.src/M000012.html +0 -18
- data/doc/api/classes/String.html +0 -196
- data/doc/api/classes/String.src/M000001.html +0 -18
- data/doc/api/classes/String.src/M000002.html +0 -31
- data/doc/api/created.rid +0 -1
- data/doc/api/files/lib/erbook/rdoc_rb.html +0 -116
- data/doc/api/files/lib/erbook/to_xhtml_rb.html +0 -125
- data/doc/api/files/lib/erbook_rb.html +0 -107
- data/doc/api/fr_class_index.html +0 -31
- data/doc/api/fr_file_index.html +0 -29
- data/doc/api/fr_method_index.html +0 -38
- data/doc/api/rdoc-style.css +0 -208
- data/doc/feed-icon-28x28.png +0 -0
- data/doc/manual.erb +0 -812
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Copyright 2006 Suraj N. Kurapati <sunaku@gmail.com>
|
2
2
|
|
3
|
-
Permission to use, copy, modify, and distribute this software for any
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
4
4
|
purpose with or without fee is hereby granted, provided that the above
|
5
5
|
copyright notice and this permission notice appear in all copies.
|
6
6
|
|
data/Rakefile
CHANGED
@@ -1,80 +1,7 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems'
|
2
|
+
require 'inochi'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# user manual
|
8
|
-
src = 'doc/manual.erb'
|
9
|
-
dst = 'doc/index.xhtml'
|
10
|
-
|
11
|
-
task :manual => dst
|
12
|
-
task :doc => :manual
|
13
|
-
|
14
|
-
file dst => src do
|
15
|
-
sh "ruby bin/erbook -u xhtml #{src} > #{dst}"
|
16
|
-
end
|
17
|
-
|
18
|
-
CLOBBER.include dst
|
19
|
-
|
20
|
-
# API reference
|
21
|
-
require 'rake/rdoctask'
|
22
|
-
|
23
|
-
Rake::RDocTask.new 'doc/api' do |t|
|
24
|
-
t.rdoc_dir = t.name
|
25
|
-
t.rdoc_files.exclude('pkg').include('**/*.rb')
|
26
|
-
end
|
27
|
-
|
28
|
-
task :doc => 'doc/api'
|
29
|
-
|
30
|
-
# packaging
|
31
|
-
require 'rake/gempackagetask'
|
32
|
-
require 'lib/erbook' # project info
|
33
|
-
|
34
|
-
spec = Gem::Specification.new do |s|
|
35
|
-
s.rubyforge_project = 'sunaku'
|
36
|
-
s.author, s.email = File.read('LICENSE').
|
37
|
-
scan(/Copyright \d+ (.*) <(.*?)>/).first
|
38
|
-
|
39
|
-
s.name = ERBook::PROJECT
|
40
|
-
s.version = ERBook::VERSION
|
41
|
-
s.summary = ERBook::SUMMARY
|
42
|
-
s.description = s.summary
|
43
|
-
s.homepage = ERBook::WEBSITE
|
44
|
-
s.files = FileList['**/*']
|
45
|
-
s.executables = s.name
|
46
|
-
s.has_rdoc = true
|
47
|
-
|
48
|
-
# gems needed by the main program executable
|
49
|
-
s.add_dependency 'trollop', '~> 1.10'
|
50
|
-
|
51
|
-
# gems needed by the default 'xhtml' format
|
52
|
-
s.add_dependency 'maruku', '~> 0.5'
|
53
|
-
s.add_dependency 'coderay', '>= 0.7'
|
54
|
-
end
|
55
|
-
|
56
|
-
Rake::GemPackageTask.new(spec) do |pkg|
|
57
|
-
pkg.need_tar = true
|
58
|
-
pkg.need_zip = true
|
59
|
-
end
|
60
|
-
|
61
|
-
desc 'Build release packages.'
|
62
|
-
task :pack => [:clobber, :doc] do
|
63
|
-
sh $0, 'package'
|
64
|
-
end
|
65
|
-
|
66
|
-
# releasing
|
67
|
-
desc 'Upload to project website.'
|
68
|
-
task :website => :doc do
|
69
|
-
sh "rsync -av doc/ ~/www/lib/#{spec.name}"
|
70
|
-
sh "rsync -av doc/api/ ~/www/lib/#{spec.name}/api/ --delete"
|
71
|
-
end
|
72
|
-
|
73
|
-
desc 'Publish release packages.'
|
74
|
-
task :publish => :pack do
|
75
|
-
sh 'rubyforge', 'login'
|
76
|
-
|
77
|
-
Dir['pkg/*.[a-z]*'].each do |pkg|
|
78
|
-
sh 'rubyforge', 'add_release', '--release_date', ERBook::RELEASE, spec.rubyforge_project, spec.name, spec.version.to_s, pkg
|
79
|
-
end
|
80
|
-
end
|
4
|
+
Inochi.rake :ERBook,
|
5
|
+
:rubyforge_project => 'sunaku',
|
6
|
+
:upload_target => File.expand_path('~/www/lib/erbook/'),
|
7
|
+
:upload_delete => true
|
data/bin/erbook
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/ruby -w
|
2
2
|
#
|
3
|
-
# erbook is an extensible document processor based on eRuby.
|
4
|
-
#
|
5
3
|
# * The standard input stream will be read if an input file is not specified.
|
6
4
|
#
|
7
5
|
# * The final output document will be written to the standard output stream.
|
@@ -15,329 +13,37 @@
|
|
15
13
|
# erbook [Option...] FormatFile [InputFile]
|
16
14
|
#
|
17
15
|
|
18
|
-
|
19
|
-
require '
|
20
|
-
|
21
|
-
module ERBook
|
22
|
-
# Prints the given message and raises the given error.
|
23
|
-
def ERBook.error aMessage, aError = $!
|
24
|
-
STDERR.printf "%s:\n\n", aMessage
|
25
|
-
raise aError
|
26
|
-
end
|
27
|
-
|
28
|
-
require 'digest/sha1'
|
29
|
-
# Returns a digest of this string that's not altered by String#to_html.
|
30
|
-
def ERBook.digest aInput
|
31
|
-
# XXX: surround all digits with alphabets so
|
32
|
-
# Maruku doesn't change them into HTML
|
33
|
-
Digest::SHA1.hexdigest(aInput.to_s).gsub(/\d/, 'z\&z')
|
34
|
-
end
|
35
|
-
|
36
|
-
require 'erb'
|
37
|
-
class Template < ERB
|
38
|
-
# The result of template evaluation thus far.
|
39
|
-
attr_reader :buffer
|
40
|
-
|
41
|
-
# aSource:: String that replaces the ambiguous '(erb)'
|
42
|
-
# identifier in stack traces, so that the user
|
43
|
-
# can better determine the source of an error.
|
44
|
-
#
|
45
|
-
# aInput:: String containing eRuby directives. This
|
46
|
-
# string will be modified by this method!
|
47
|
-
#
|
48
|
-
# aSafeLevel:: See safe_level in ERB::new().
|
49
|
-
#
|
50
|
-
def initialize aSource, aInput, aUnindent = false, aSafeLevel = nil
|
51
|
-
# convert "% at beginning of line" usage into <% normal %> usage
|
52
|
-
aInput.gsub! %r{^([ \t]*)(%[=# \t].*)$}, '\1<\2 %>'
|
53
|
-
aInput.gsub! %r{^([ \t]*)%%}, '\1%'
|
54
|
-
|
55
|
-
# silence the code-only <% ... %> directive, just like PHP does
|
56
|
-
aInput.gsub! %r{^[ \t]*(<%[^%=]((?!<%).)*?[^%]%>)[ \t]*\r?\n}m, '\1'
|
16
|
+
require 'rubygems'
|
17
|
+
require 'inochi'
|
57
18
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
result = []
|
63
|
-
|
64
|
-
buffer = aInput
|
65
|
-
tags.each do |tag|
|
66
|
-
chunk, buffer = buffer.split(tag, 2)
|
67
|
-
chunk << tag
|
68
|
-
|
69
|
-
# perform unindentation
|
70
|
-
result << chunk.gsub(/^#{margins.last}/, '')
|
71
|
-
|
72
|
-
# prepare for next unindentation
|
73
|
-
case tag
|
74
|
-
when /<%[^%=].*?\bdo\b.*?%>/m
|
75
|
-
margins.push buffer[/^[ \t]*(?=\S)/]
|
76
|
-
|
77
|
-
when /<%\s*end\s*%>/m
|
78
|
-
margins.pop
|
79
|
-
end
|
80
|
-
end
|
81
|
-
result << buffer
|
82
|
-
|
83
|
-
aInput = result.join
|
84
|
-
end
|
85
|
-
|
86
|
-
# use @buffer to store the result of the ERB template
|
87
|
-
super aInput, aSafeLevel, nil, :@buffer
|
88
|
-
|
89
|
-
self.filename = aSource
|
90
|
-
end
|
19
|
+
# command line
|
20
|
+
options = Inochi.main :ERBook do
|
21
|
+
# show list of available formats
|
22
|
+
text 'FormatName:'
|
91
23
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
instance_variable_set var, val
|
98
|
-
end
|
99
|
-
|
100
|
-
binding
|
101
|
-
end
|
102
|
-
|
103
|
-
result(context)
|
24
|
+
require 'yaml'
|
25
|
+
ERBook::FORMAT_FILES.each do |file|
|
26
|
+
name = File.basename(file, '.yaml')
|
27
|
+
desc = YAML.load_file(file)['desc'] rescue nil
|
28
|
+
banner '%16s: %s' % [name, desc]
|
104
29
|
end
|
105
30
|
|
106
|
-
|
107
|
-
|
108
|
-
# Returns the content that the given block wants to append to
|
109
|
-
# the buffer. If the given block does not want to append to the
|
110
|
-
# buffer, then returns the result of invoking the given block.
|
111
|
-
def content_from_block *aBlockArgs
|
112
|
-
raise ArgumentError, 'block must be given' unless block_given?
|
113
|
-
|
114
|
-
head = @buffer.length
|
115
|
-
body = yield(*aBlockArgs) # this will do: @buffer << content
|
116
|
-
tail = @buffer.length
|
117
|
-
|
118
|
-
if tail > head
|
119
|
-
@buffer.slice! head..tail
|
120
|
-
else
|
121
|
-
body
|
122
|
-
end.to_s
|
123
|
-
end
|
124
|
-
end
|
31
|
+
text ''
|
125
32
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
undef id if respond_to? :id
|
130
|
-
undef type if respond_to? :type
|
33
|
+
# show list of command-line options
|
34
|
+
text 'Option:'
|
35
|
+
opt :unindent, 'Unindent node content hierarchically'
|
131
36
|
end
|
132
37
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
# parse command-line options
|
138
|
-
begin require 'rubygems' rescue LoadError end
|
139
|
-
require 'trollop'
|
140
|
-
|
141
|
-
opts = Trollop::options do
|
142
|
-
# show program description located at the top of this file
|
143
|
-
banner File.read(__FILE__)[/\A.*?^$\n/m].
|
144
|
-
gsub(/^# ?/, '').sub(/\A.*?\n/, '')
|
145
|
-
banner ''
|
146
|
-
|
147
|
-
# show list of available formats
|
148
|
-
banner 'FormatName:'
|
149
|
-
ERBook::FORMAT_FILES.each do |file|
|
150
|
-
name = File.basename(file, '.yaml')
|
151
|
-
desc = YAML.load_file(file)['desc'] rescue nil
|
152
|
-
banner '%16s: %s' % [name, desc]
|
153
|
-
end
|
154
|
-
banner ''
|
155
|
-
|
156
|
-
# show list of command-line options
|
157
|
-
banner 'Option:'
|
158
|
-
opt :unindent, 'Unindent node content hierarchically'
|
159
|
-
|
160
|
-
# show program version information
|
161
|
-
version [
|
162
|
-
"project: #{ERBook::PROJECT}",
|
163
|
-
"version: #{ERBook::VERSION}",
|
164
|
-
"release: #{ERBook::RELEASE}",
|
165
|
-
"website: #{ERBook::WEBSITE}",
|
166
|
-
"install: #{ERBook::INSTALL_DIR}",
|
167
|
-
].join("\n")
|
168
|
-
end
|
169
|
-
|
170
|
-
# load format specification file
|
171
|
-
spec_file = ARGV.shift or
|
172
|
-
raise ArgumentError, "Format was not specified. Run `#{$0} -h` for help."
|
38
|
+
# program body
|
39
|
+
format = ARGV.shift or
|
40
|
+
raise ArgumentError, "Format was not specified. Run `#{$0} -h` for help."
|
173
41
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
spec_data[:file] = File.expand_path(spec_file)
|
180
|
-
spec_data[:name] = File.basename(spec_file).sub(/\..*?$/, '')
|
181
|
-
|
182
|
-
if spec_data.key? 'code'
|
183
|
-
eval spec_data['code'].to_s, TOPLEVEL_BINDING, "#{spec_file}:code"
|
184
|
-
end
|
185
|
-
|
186
|
-
rescue Exception
|
187
|
-
error "Error when loading the format specification file (#{spec_file.inspect})"
|
188
|
-
end
|
189
|
-
|
190
|
-
# load input document
|
191
|
-
if input_file = ARGV.shift
|
192
|
-
input = File.read input_file
|
193
|
-
else
|
194
|
-
input_file, input = 'STDIN', STDIN.read
|
195
|
-
end
|
196
|
-
|
197
|
-
begin
|
198
|
-
# expand all "include" directives in the input
|
199
|
-
begin end while input.gsub! %r{<%#\s*include\s+(.+?)\s*#%>} do
|
200
|
-
file, line = $1, $`.count("\n").next
|
201
|
-
|
202
|
-
# provide more accurate stack trace for
|
203
|
-
# errors originating from included files.
|
204
|
-
#
|
205
|
-
# NOTE: eRuby does NOT seem to provide line numbers for trace
|
206
|
-
# entries that are deeper than the input document itself
|
207
|
-
#
|
208
|
-
"<%
|
209
|
-
begin
|
210
|
-
%>#{File.read file}<%
|
211
|
-
rescue Exception => err
|
212
|
-
bak = err.backtrace
|
213
|
-
|
214
|
-
# set the input document's originating line number to
|
215
|
-
# where this file was included in the input document
|
216
|
-
top = bak.find {|t| t =~ /#{/#{input_file}/}:\\d+$/ }
|
217
|
-
top.sub! %r/\\d+$/, '#{line}'
|
218
|
-
|
219
|
-
# add a stack trace entry mentioning this included file
|
220
|
-
ins = bak.index top
|
221
|
-
bak.insert ins, #{file.inspect}
|
222
|
-
|
223
|
-
raise err
|
224
|
-
end
|
225
|
-
%>"
|
226
|
-
end
|
227
|
-
|
228
|
-
# create sandbox for input evaluation
|
229
|
-
template = Template.new(input_file, input, opts[:unindent])
|
230
|
-
|
231
|
-
template_vars = {
|
232
|
-
:@spec => spec_data,
|
233
|
-
:@roots => roots = [], # root nodes of all trees
|
234
|
-
:@nodes => nodes = [], # all nodes in the forest
|
235
|
-
:@types => types = Hash.new {|h,k| h[k] = []}, # nodes by type
|
236
|
-
}.each_pair {|k,v| template.instance_variable_set(k, v) }
|
237
|
-
|
238
|
-
node_defs = spec_data['nodes'].each_pair do |type, defn|
|
239
|
-
template.instance_eval %{
|
240
|
-
#
|
241
|
-
# XXX: using a string because define_method()
|
242
|
-
# does not accept a block until Ruby 1.9
|
243
|
-
#
|
244
|
-
def #{type} *aArgs, &aBlock
|
245
|
-
node = Node.new(
|
246
|
-
:type => #{type.inspect},
|
247
|
-
:args => aArgs,
|
248
|
-
:trace => caller,
|
249
|
-
:children => []
|
250
|
-
)
|
251
|
-
@nodes << node
|
252
|
-
@types[node.type] << node
|
253
|
-
|
254
|
-
# calculate occurrence number for this node
|
255
|
-
if #{defn['number']}
|
256
|
-
@count ||= Hash.new {|h,k| h[k] = []}
|
257
|
-
node.number = (@count[node.type] << node).length
|
258
|
-
end
|
259
|
-
|
260
|
-
@stack ||= []
|
261
|
-
|
262
|
-
# assign node family
|
263
|
-
if parent = @stack.last
|
264
|
-
parent.children << node
|
265
|
-
node.parent = parent
|
266
|
-
node.depth = parent.depth.next
|
267
|
-
|
268
|
-
# calculate latex-style index number for this node
|
269
|
-
if #{defn['index']}
|
270
|
-
branches = parent.children.select {|n| n.index}
|
271
|
-
node.index = [parent.index, branches.length.next].join('.')
|
272
|
-
end
|
273
|
-
else
|
274
|
-
@roots << node
|
275
|
-
node.parent = nil
|
276
|
-
node.depth = 0
|
277
|
-
|
278
|
-
# calculate latex-style index number for this node
|
279
|
-
if #{defn['index']}
|
280
|
-
branches = @roots.select {|n| n.index}
|
281
|
-
node.index = branches.length.next.to_s
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
# assign node content
|
286
|
-
if block_given?
|
287
|
-
@stack.push node
|
288
|
-
content = content_from_block(node, &aBlock)
|
289
|
-
@stack.pop
|
290
|
-
|
291
|
-
digest = ERBook.digest(content)
|
292
|
-
self.buffer << digest
|
293
|
-
else
|
294
|
-
content = nil
|
295
|
-
digest = ERBook.digest(node.object_id)
|
296
|
-
end
|
297
|
-
|
298
|
-
node.content = content
|
299
|
-
node.digest = digest
|
300
|
-
|
301
|
-
digest
|
302
|
-
end
|
303
|
-
}, __FILE__, Kernel.caller.first[/\d+/].to_i.next
|
304
|
-
end
|
305
|
-
|
306
|
-
# build the document tree
|
307
|
-
document = template.instance_eval { result(binding) }
|
308
|
-
|
309
|
-
# replace nodes with output
|
310
|
-
expander = lambda do |n, buf|
|
311
|
-
# calculate node output
|
312
|
-
source = "#{spec_file}:nodes:#{n.type}:output"
|
313
|
-
n.output = Template.new(
|
314
|
-
source, node_defs[n.type]['output'].to_s.chomp).
|
315
|
-
render_with(template_vars.merge(:@node => n))
|
316
|
-
|
317
|
-
# replace node with output
|
318
|
-
if node_defs[n.type]['silent']
|
319
|
-
buf[n.digest] = ''
|
320
|
-
buf = n.output
|
321
|
-
else
|
322
|
-
buf[n.digest] = n.output
|
323
|
-
end
|
324
|
-
|
325
|
-
# repeat for all child nodes
|
326
|
-
n.children.each {|c| expander[c, buf] }
|
327
|
-
end
|
328
|
-
|
329
|
-
roots.each {|n| expander[n, document] }
|
330
|
-
|
331
|
-
rescue Exception => e
|
332
|
-
# omit erbook internals from the stack trace
|
333
|
-
e.backtrace.reject! {|t| t =~ /^#{$0}:\d+/ } unless $DEBUG
|
334
|
-
|
335
|
-
puts input # so the user can debug the line numbers in the stack trace
|
336
|
-
error "Error when processing the input document (#{input_file})"
|
337
|
-
end
|
338
|
-
|
339
|
-
# emit output document
|
340
|
-
puts Template.new("#{spec_file}:output", spec_data['output'].to_s).
|
341
|
-
render_with(template_vars.merge(:@content => document))
|
42
|
+
if input_file = ARGV.shift
|
43
|
+
input_text = File.read(input_file)
|
44
|
+
else
|
45
|
+
input_file = 'STDIN'
|
46
|
+
input_text = STDIN.read
|
342
47
|
end
|
343
|
-
|
48
|
+
|
49
|
+
puts ERBook::Document.new(format, input_text, input_file, options)
|