erbook 5.0.0 → 6.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/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)
|