bee_java 0.0.1

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/beedoc ADDED
@@ -0,0 +1,801 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright 2006-2010 Michel Casabianca <michel.casabianca@gmail.com>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # Script to generate documentation from various sources.
18
+
19
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
20
+ require 'rubygems'
21
+ require 'bee'
22
+ require 'erb'
23
+ require 'fileutils'
24
+ require 'yaml'
25
+ require 'rexml/document'
26
+ require 'rdoc/markup/simple_markup'
27
+ require 'rdoc/markup/simple_markup/to_html'
28
+ require 'singleton'
29
+ require 'syntax/convertors/html'
30
+
31
+ module Bee
32
+
33
+ # Module for Bee documentation generation.
34
+ module Doc
35
+
36
+ # Console help.
37
+ HELP = 'beedoc [-h] [-o dir] menu
38
+ -h Print help about usage and exit.
39
+ -o Output directory for documentation.
40
+ menu Menu file to process.'
41
+ # Exit value on error parsing command line
42
+ EXIT_PARSING_CMDLINE = 1
43
+ # Exit value on doc error
44
+ EXIT_DOC_ERROR = 2
45
+ # Exit value on unknown error
46
+ EXIT_UNKNOWN_ERROR = 3
47
+
48
+ #########################################################################
49
+ # CLASS DOCERROR #
50
+ #########################################################################
51
+
52
+ class DocError < RuntimeError; end
53
+
54
+ module DocErrorMixin
55
+
56
+ # Convenient method to raise a DocError.
57
+ # - message: error message.
58
+ def error(message)
59
+ raise DocError.new(message)
60
+ end
61
+
62
+ end
63
+
64
+ #########################################################################
65
+ # PARSE COMMAND LINE #
66
+ #########################################################################
67
+
68
+ # Parse command line and return arguments.
69
+ def self.parse_command_line
70
+ help = false
71
+ output = nil
72
+ require 'getoptlong'
73
+ begin
74
+ opts = GetoptLong.new(['--help', '-h', GetoptLong::NO_ARGUMENT ],
75
+ ['--output', '-o', GetoptLong::REQUIRED_ARGUMENT])
76
+ opts.each do |opt, arg|
77
+ case opt
78
+ when '--help'
79
+ help = true
80
+ when '--output'
81
+ output = arg
82
+ end
83
+ end
84
+ help = true if ARGV.length > 1
85
+ menu = ARGV[0]
86
+ return [help, output, menu]
87
+ end
88
+ end
89
+
90
+ # Run BeeDoc from command line.
91
+ def self.start_command_line
92
+ STDOUT.sync = true
93
+ begin
94
+ help, output, menu = parse_command_line
95
+ rescue
96
+ puts "ERROR: parsing command line (type 'beedoc -h' for help): #{$!}"
97
+ exit(EXIT_PARSING_CMDLINE)
98
+ end
99
+ begin
100
+ if help
101
+ puts COPYRIGHT
102
+ puts HELP
103
+ else
104
+ raise DocError.new("No menu file") if not menu
105
+ Bee::Doc::Menu.new(menu).generate(output)
106
+ puts "OK"
107
+ end
108
+ rescue DocError
109
+ puts "ERROR: #{$!}"
110
+ exit(EXIT_DOC_ERROR)
111
+ rescue Exception => e
112
+ puts "ERROR: #{$!}"
113
+ puts e.backtrace.join("\n")
114
+ exit(EXIT_UNKNOWN_ERROR)
115
+ end
116
+ end
117
+
118
+ #########################################################################
119
+ # CLASS MENU #
120
+ #########################################################################
121
+
122
+ class Menu
123
+
124
+ include DocErrorMixin
125
+
126
+ # Title for documentation.
127
+ attr_reader :title
128
+ # Generation date.
129
+ attr_reader :date
130
+ # List of menu entries.
131
+ attr_reader :entries
132
+ # Base directory.
133
+ attr_reader :base
134
+ # Contents for page being generated.
135
+ attr_reader :contents
136
+ # Processor for PI.
137
+ attr_reader :processor
138
+
139
+ # Constructor.
140
+ # - file: menu file to load.
141
+ def initialize(file)
142
+ begin
143
+ @base = File.dirname(file)
144
+ @processor = Processor.new(self)
145
+ source = File.read(file)
146
+ menu = YAML::load(source)
147
+ @entries = []
148
+ error "Menu must be a list" unless menu.kind_of?(Array)
149
+ error "Menu description must be first entry" unless
150
+ menu[0].kind_of?(Hash) and menu[0]['menu']
151
+ @title = menu[0]['menu']
152
+ @date = Time.now
153
+ for entry in menu[1..-1]
154
+ @entries << Entry.new(entry, self)
155
+ end
156
+ rescue
157
+ error "Error loading menu file: #{$!}"
158
+ end
159
+ end
160
+
161
+ # Generate documentation.
162
+ # - output: output directory.
163
+ def generate(output)
164
+ error "Destination directory '#{output}' already exists" if
165
+ File.exists?(output)
166
+ FileUtils.makedirs(output)
167
+ for entry in @entries
168
+ entry.generate(output, @date)
169
+ end
170
+ # write stylesheet
171
+ File.open(File.join(output, 'stylesheet.css'), 'w') do |file|
172
+ file.write(Entry::DEFAULT_STYLESHEET)
173
+ end
174
+ end
175
+
176
+ # Get absolute path for file relative to menu file.
177
+ # - file: file relative to menu file.
178
+ def abs_file(file)
179
+ return File.join(@base, file)
180
+ end
181
+
182
+ end
183
+
184
+ #########################################################################
185
+ # CLASS ENTRY #
186
+ #########################################################################
187
+
188
+ # A menu entry.
189
+ class Entry
190
+
191
+ include DocErrorMixin
192
+
193
+ # Parent menu.
194
+ attr_reader :menu
195
+ # Title.
196
+ attr_reader :title
197
+ # Document type (text, html, dir or link).
198
+ attr_reader :type
199
+ # File.
200
+ attr_reader :file
201
+ # Source directory.
202
+ attr_reader :dir
203
+ # Destination file.
204
+ attr_reader :dest
205
+ # Generation date.
206
+ attr_reader :date
207
+
208
+ # Entry types.
209
+ TYPES = ['yaml', 'rdoc', 'html', 'text', 'dir', 'link', 'section']
210
+ # Default TOC level (header level parsed to generate TOC).
211
+ DEFAULT_TOC_LEVEL = 2
212
+ # Default TOC depth.
213
+ DEFAULT_TOC_DEPTH = 1
214
+
215
+ # Constructor.
216
+ # - entry: menu entry as a Hash.
217
+ # - menu: the root menu for the entry.
218
+ def initialize(entry, menu)
219
+ # check keys in entry
220
+ error "Unknown entry type '#{entry['type']}'" unless
221
+ TYPES.member?(entry['type'])
222
+ error "A menu entry must be a Hash" unless entry.kind_of?(Hash)
223
+ error "'title' key is mandatory in menu entries" unless entry['title']
224
+ error "One of 'file' or 'dir' keys must be in a menu entry" unless
225
+ (entry['file'] or entry['dir']) or entry['type'] == 'link' or
226
+ entry['type'] == 'section'
227
+ error "'file' and 'dir' keys can't be in a menu entry at the " +
228
+ "same time" if entry['file'] and entry['dir']
229
+ # save keys into fields
230
+ @menu = menu
231
+ @title = entry['title']
232
+ @type = entry['type']
233
+ @file = entry['file']
234
+ @dir = entry['dir']
235
+ @dest = entry['dest']
236
+ @template = entry['template']
237
+ @erb = entry['erb']
238
+ @toc = entry['toc']
239
+ @level = entry['level'] || DEFAULT_TOC_LEVEL
240
+ @depth = entry['depth'] || DEFAULT_TOC_DEPTH
241
+ @process = entry['process']
242
+ end
243
+
244
+ # Generate a menu entry.
245
+ # - output: destination directory.
246
+ # - date: generation date.
247
+ def generate(output, date)
248
+ @date = date
249
+ case @type
250
+ when 'yaml'
251
+ # entry is a yaml file: process using an ERB
252
+ puts "Generating '#{@dest}' from yaml..."
253
+ template = load_template(output)
254
+ erb = ERB.new(File.read(@menu.abs_file(@erb)), nil, '%')
255
+ @data = YAML::load(File.read(@menu.abs_file(file)))
256
+ @contents = erb.result(get_binding)
257
+ @contents = process_instructions(@contents) if @process
258
+ @table = generate_toc(@contents, @level, @depth) if @toc
259
+ result = template.result(get_binding)
260
+ File.open(File.join(output, @dest), 'w') do |file|
261
+ file.write(result)
262
+ end
263
+ when 'rdoc'
264
+ # entry is a rdoc file: process rdoc
265
+ puts "Generating '#{@dest}' from rdoc..."
266
+ template = load_template(output)
267
+ markup = SM::SimpleMarkup.new
268
+ tohtml = SM::ToHtml.new
269
+ rdoc = File.read(@menu.abs_file(@file))
270
+ @contents = markup.convert(rdoc, tohtml)
271
+ @contents = process_instructions(@contents) if @process
272
+ @table = generate_toc(@contents, @level, @depth) if @toc
273
+ result = template.result(get_binding)
274
+ File.open(File.join(output, @dest), 'w') do |file|
275
+ file.write(result)
276
+ end
277
+ when 'text'
278
+ # entry is a text file: process it to remove HTML entities
279
+ puts "Generating '#{@dest}' from text..."
280
+ template = load_template(output)
281
+ @contents = File.read(@menu.abs_file(@file))
282
+ @contents = Entry.escape_special_characters(@contents)
283
+ @contents = process_instructions(@contents) if @process
284
+ result = template.result(get_binding)
285
+ File.open(File.join(output, @dest), 'w') do |file|
286
+ file.write(result)
287
+ end
288
+ when 'html'
289
+ # entry is an HTML file: put it verbatim
290
+ puts "Generating '#{@dest}' from html..."
291
+ template = load_template(output)
292
+ @contents = File.read(@menu.abs_file(@file))
293
+ @contents = process_instructions(@contents) if @process
294
+ @table = generate_toc(@contents, @level, @depth) if @toc
295
+ result = template.result(get_binding)
296
+ File.open(File.join(output, @dest), 'w') do |file|
297
+ file.write(result)
298
+ end
299
+ when 'dir'
300
+ # entry is a directory: copy it to destination directory
301
+ puts "Copying directory '#{@dir}'..."
302
+ FileUtils.cp_r(File.join(@menu.base, @dir),
303
+ File.join(output, @dest))
304
+ when 'link'
305
+ # entry is a link: nothing to do
306
+ when 'section'
307
+ # entry is a section: nothing to do
308
+ else
309
+ error "Unknown entry type '#{@type}'"
310
+ end
311
+ end
312
+
313
+ private
314
+
315
+ # Load template and write default stylesheet if necessary.
316
+ # - output: output directory.
317
+ def load_template(output)
318
+ if @template
319
+ template = ERB.new(File.read(@menu.abs_file(@template)))
320
+ else
321
+ template = ERB.new(DEFAULT_TEMPLATE)
322
+ File.open(File.join(output, 'stylesheet.css'), 'w') do |file|
323
+ file.write(DEFAULT_STYLESHEET)
324
+ end
325
+ end
326
+ return template
327
+ end
328
+
329
+ # Generate table of contents as an Array.
330
+ # - contents: HTML page contents.
331
+ # - level: header level to scan.
332
+ # - depth: toc depth.
333
+ # Return: TOC as an Array with reference to link the page.
334
+ def generate_toc(contents, level, depth)
335
+ level = DEFAULT_TOC_LEVEL if not level
336
+ levels = (level..(level+depth-1)).to_a.join
337
+ toc = []
338
+ contents.gsub!(/<[h|H][#{levels}]>.*?<\/[h|H][#{levels}]>/) do |tag|
339
+ name = tag.match(/<[h|H][#{levels}]>(.*?)<\/[h|H][#{levels}]>/)[1]
340
+ d = tag.match(/<[h|H]([#{levels}])>.*?<\/[h|H][#{levels}]>/)[1].to_i -
341
+ level
342
+ toc << { :title => name, :depth => d }
343
+ "<a name=\"#{name}\">#{tag}</a>"
344
+ end
345
+ return toc
346
+ end
347
+
348
+ # Get a binding for ERB generation.
349
+ def get_binding
350
+ return binding
351
+ end
352
+
353
+ # Escape HTML special characters (such as & " ' < and >).
354
+ # - string: string to process.
355
+ # Return: processed string.
356
+ def self.escape_special_characters(string)
357
+ return string.gsub(/&/, '&amp;').gsub(/"/, '&quot;').
358
+ gsub(/'/, '&apos;').gsub(/</, '&lt;').gsub(/>/, '&gt;')
359
+ end
360
+
361
+ # Process page contents using processing instructions.
362
+ # - contents: contents to process.
363
+ def process_instructions(contents)
364
+ return contents.gsub(/<\?.*?\?>/m) do |instruction|
365
+ call_processor(instruction)
366
+ end
367
+ end
368
+
369
+ # Process a given processing instruction.
370
+ # - instruction: processing instruction to process.
371
+ def call_processor(instruction)
372
+ begin
373
+ xml = "<#{instruction[2..-3].strip}/>"
374
+ document = REXML::Document.new(xml)
375
+ root = document.root
376
+ command = root.name
377
+ args = {}
378
+ for name in root.attributes.keys
379
+ value = root.attributes[name]
380
+ args[name] = value
381
+ end
382
+ error "Instruction '#{command}' not found" if
383
+ not @menu.processor.respond_to?(command)
384
+ return @menu.processor.send(command, args)
385
+ rescue
386
+ error "Error parsing instruction '#{instruction}': #{$!}"
387
+ end
388
+ end
389
+
390
+ # Default ERB template to generate HTML.
391
+ DEFAULT_TEMPLATE = '<html>
392
+ <head>
393
+ <meta http-equiv=Content-Type content="text/html; charset=utf-8">
394
+ <title><%= @menu.title %></title>
395
+ <link rel="stylesheet" type="text/css" href="stylesheet.css">
396
+ <link rel="stylesheet" type="text/css" href="ruby.css">
397
+ <link rel="stylesheet" type="text/css" href="yaml.css">
398
+ <link rel="stylesheet" type="text/css" href="xml.css">
399
+ </head>
400
+ <body marginwidth="10" marginheight=10" bgcolor="#213449">
401
+ <table class="page" width="850" height="100%" align="center">
402
+ <tr class="title">
403
+ <td class="title" colspan="2" height="100">
404
+ <table class="title" width="100%">
405
+ <tr class="title">
406
+ <td class="title" align="left" width="75%">
407
+ <img src="bee-icon.png">
408
+ </td>
409
+ <td class="title" align="center" width="25%">
410
+ <img src="bee-logo.gif">
411
+ </td>
412
+ </tr>
413
+ </table>
414
+ </td>
415
+ </tr>
416
+ <tr>
417
+ <td class="ruller" colspan="2"
418
+ align="left" valign="middle"
419
+ height="10">
420
+ Last update: <%= @date.strftime("%Y-%m-%d") %>
421
+ </td>
422
+ </tr>
423
+ <tr>
424
+ <td class="menu"
425
+ align="left" valign="top"
426
+ width="130">
427
+ <%
428
+ for entry in @menu.entries
429
+ link = entry.dest
430
+ link += \'/index.html\' if entry.dir
431
+ if entry.type != "section"
432
+ %>
433
+ <a class="menu" href="<%= link %>"><%= entry.title %></a><br>
434
+ <%
435
+ else
436
+ %>
437
+ <h2 class="menu"><%= entry.title %></h2>
438
+ <%
439
+ end
440
+ if entry.title == @title
441
+ if @table
442
+ %>
443
+ <table class="space"><tr class="space"><td class="space"></td></tr></table>
444
+ <table class="toc" width="100%">
445
+ <tr class="toc">
446
+ <td class="toc">
447
+ <% for section in @table %>
448
+ <% indent = "&#x00A0;&#x00A0;"*section[:depth] %>
449
+ <%= indent %><a class="toc" href="#<%= section[:title] %>"><font size="-<%= section[:depth]+1 %>"><%= section[:title] %></font></a><br/>
450
+ <% end %>
451
+ </td>
452
+ </tr>
453
+ </table>
454
+ <table class="space"><tr class="space"><td class="space"></td></tr></table>
455
+ <%
456
+ end
457
+ end
458
+ end
459
+ %>
460
+ </td>
461
+ <td class="page"
462
+ align="left" valign="top">
463
+ <h1><%= @title %></h1>
464
+ <% if @type == "text" %>
465
+ <pre class="page"><%= @contents %></pre>
466
+ <% else %>
467
+ <%= @contents %>
468
+ <% end %>
469
+ <br>
470
+ </td>
471
+ </tr>
472
+ </table>
473
+ <table class="footer" width="800" align="center">
474
+ <tr class="footer">
475
+ <td class="footer">
476
+ (C) Michel Casabianca & Contributors - 2006-2010 - Pictures courtesy of
477
+ <a class="footer" href="http://pdphoto.org/">PD Photo.org</a>
478
+ </td>
479
+ </tr>
480
+ </table>
481
+ </body>
482
+ </html>'
483
+
484
+ public
485
+
486
+ # Default style sheet.
487
+ DEFAULT_STYLESHEET = '
488
+ /* Title style */
489
+ table.title {
490
+ border: solid Opx #FFFFFF;
491
+ border-collapse: collapse;
492
+ }
493
+ tr.title {
494
+ border: solid Opx #FFFFFF;
495
+ }
496
+ td.title {
497
+ border: solid 0px #000000;
498
+ padding: 0px;
499
+ background-color: #F8DE5A;
500
+ }
501
+
502
+ /* Ruller style */
503
+ td.ruller {
504
+ border: solid 0px #000000;
505
+ text-align: right;
506
+ padding: 3px;
507
+ background-color: #000000;
508
+ color: #FFFFFF;
509
+ font-family: Verdana, Helvetica, Arial, sans-serif;
510
+ font-size: 8pt;
511
+ }
512
+
513
+ /* Menu style */
514
+ td.menu {
515
+ border: solid 0px #000000;
516
+ padding: 10px;
517
+ background-color: #FF9000;
518
+ font-family: Verdana, Helvetica, Arial, sans-serif;
519
+ font-size: 12pt;
520
+ }
521
+ h2.menu {
522
+ font-family: Verdana, Helvetica, Arial, sans-serif;
523
+ color: #000000;
524
+ border-bottom: 1px dotted #FFFFFF;
525
+ font-size: 12pt;
526
+ }
527
+ a.menu:link {
528
+ text-decoration: none;
529
+ color: #000000;
530
+ }
531
+ a.menu:visited {
532
+ text-decoration: none;
533
+ color: #000000;
534
+ }
535
+ a.menu:active {
536
+ text-decoration: none;
537
+ color: #000000;
538
+ }
539
+ a.menu:hover {
540
+ text-decoration: underline;
541
+ color: #000000;
542
+ background-color: #FF9000;
543
+ }
544
+
545
+ /* TOC style */
546
+ table.toc {
547
+ border: solid 1px #A0A0A0;
548
+ }
549
+ td.toc {
550
+ border: solid 0px #000000;
551
+ padding: 5px;
552
+ background-color: #F0F0A0;
553
+ font-family: Verdana, Helvetica, Arial, sans-serif;
554
+ font-size: 10pt;
555
+ }
556
+ a.toc:link {
557
+ text-decoration: none;
558
+ color: #000000;
559
+ }
560
+ a.toc:visited {
561
+ text-decoration: none;
562
+ color: #000000;
563
+ }
564
+ a.toc:active {
565
+ text-decoration: none;
566
+ color: #000000;
567
+ }
568
+ a.toc:hover {
569
+ text-decoration: underline;
570
+ color: #000000;
571
+ }
572
+
573
+ /* Page style */
574
+ pre.page {
575
+ font-family: Courier, Verdana, Helvetica, Arial, sans-serif;
576
+ font-size: 10pt;
577
+ background-color: #FFFFFF;
578
+ border-width: 0px;
579
+ border-color: #FFFFFF;
580
+ border-style: solid;
581
+ }
582
+ table.page {
583
+ border: solid 2px #000000;
584
+ }
585
+ td.page {
586
+ padding: 10px;
587
+ border: solid 0px #000000;
588
+ font-family: Verdana, Helvetica, Arial, sans-serif;
589
+ font-size: 10pt;
590
+ background-color: #FFFFFF;
591
+ }
592
+
593
+ /* Footer style */
594
+ table.footer {
595
+ border: solid 0px #000000;
596
+ }
597
+ td.footer {
598
+ padding: 5px;
599
+ border: solid 0px #000000;
600
+ font-family: Verdana, Helvetica, Arial, sans-serif;
601
+ font-size: 8pt;
602
+ color: #A0A0A0;
603
+ text-align: center;
604
+ }
605
+ a.footer:link {
606
+ text-decoration: none;
607
+ color: #FF9000;
608
+ }
609
+ a.footer:visited {
610
+ text-decoration: none;
611
+ color: #A0A0A0;
612
+ }
613
+ a.footer:active {
614
+ text-decoration: none;
615
+ color: #FF9000;
616
+ }
617
+ a.footer:hover {
618
+ text-decoration: underline;
619
+ color: #FF9000;
620
+ }
621
+
622
+ /* Style that defines table elements for spacing */
623
+ table.space {
624
+ border: solid 0px #000000;
625
+ }
626
+ tr.space {
627
+ border: solid 0px #000000;
628
+ }
629
+ td.space {
630
+ border: solid 0px #000000;
631
+ padding: 2px;
632
+ }
633
+
634
+ /* pre element for term output */
635
+ pre.term {
636
+ clear: both;
637
+ overflow: auto;
638
+ color: #FFFFFF;
639
+ background-color: #555555;
640
+ padding: 0;
641
+ padding: 1.0em;
642
+ border-width: 1px;
643
+ border-color: #C0C0C0;
644
+ border-style: solid;
645
+ }
646
+
647
+ /* Contents style (default element form) */
648
+ h1 {
649
+ font-family: Verdana, Helvetica, Arial, sans-serif;
650
+ color: #FF9000;
651
+ text-align: center;
652
+ font-size: 30pt;
653
+ }
654
+ h2,h3,h4,h5 {
655
+ font-family: Verdana, Helvetica, Arial, sans-serif;
656
+ color: #FF9000;
657
+ border-bottom: 2px dotted #000000;
658
+ }
659
+ p {
660
+ font-family: Verdana, Helvetica, Arial, sans-serif;
661
+ font-size: 10pt;
662
+ }
663
+ table {
664
+ font-family: Verdana, Helvetica, Arial, sans-serif;
665
+ font-size: 10pt;
666
+ border: solid 0px #000000;
667
+ border-collapse: collapse;
668
+ }
669
+ th {
670
+ padding: 5px;
671
+ background-color: #FF9000;
672
+ border: solid 1px #000000;
673
+ text-align: left;
674
+ }
675
+ td {
676
+ padding: 5px;
677
+ border: solid 1px #000000;
678
+ text-align: left;
679
+ }
680
+ li {
681
+ font-family: Verdana, Helvetica, Arial, sans-serif;
682
+ font-size: 10pt;
683
+ list-style: square;
684
+ }
685
+ a:link {
686
+ text-decoration: none;
687
+ color: #FF9000;
688
+ }
689
+ a:visited {
690
+ text-decoration: none;
691
+ color: #000000;
692
+ }
693
+ a:active {
694
+ text-decoration: none;
695
+ color: #000000;
696
+ }
697
+ a:hover {
698
+ text-decoration: underline;
699
+ color: #FF9000;
700
+ }
701
+ pre {
702
+ clear: both;
703
+ overflow: auto;
704
+ background-color: #EFEFEF;
705
+ padding: 0;
706
+ padding: 1.0em;
707
+ border-width: 1px;
708
+ border-color: #C0C0C0;
709
+ border-style: solid;
710
+ }
711
+ '
712
+
713
+ end
714
+
715
+ # Class for PI processing.
716
+ class Processor
717
+
718
+ include DocErrorMixin
719
+
720
+ def initialize(menu)
721
+ @menu = menu
722
+ end
723
+
724
+ def include(args)
725
+ file = args['file']
726
+ error "Missing argument 'file' for 'include' instruction" if not file
727
+ abs_file = @menu.abs_file(file)
728
+ error "File to include not found '#{abs_file}'" if
729
+ not File.exists?(abs_file)
730
+ return Bee::Doc::syntax_colorization(abs_file)
731
+ end
732
+
733
+ def bee(args)
734
+ build = args['build']
735
+ options = args['options']
736
+ if build
737
+ abs_file = @menu.abs_file(build)
738
+ error "Build file not found '#{abs_file}'" if
739
+ not File.exists?(abs_file)
740
+ value = `bee #{options} -f #{abs_file}`
741
+ else
742
+ value = `bee #{options}`
743
+ end
744
+ escaped = Entry.escape_special_characters(value)
745
+ return "<pre class='term'>#{escaped}</pre>"
746
+ end
747
+
748
+ def run(args)
749
+ command = args['command']
750
+ raise "Missing argument 'command' for 'run' instruction" if not command
751
+ directory = args['directory']||'.'
752
+ print = args['print']||command
753
+ error = (args['error']=='true' or
754
+ args['error']=='yes' or
755
+ args['error']=='1')||false
756
+ current_dir = Dir.pwd
757
+ begin
758
+ Dir.chdir(@menu.base)
759
+ Dir.chdir(directory)
760
+ output = `#{command} 2>&1`
761
+ if $? != 0 and not error
762
+ raise "Error running command '#{command}': exit value #{$?}"
763
+ end
764
+ if $? == 0 and error
765
+ raise "Error running command '#{command}': error expected"
766
+ end
767
+ escaped = Entry.escape_special_characters(output)
768
+ return "<pre class='term'>$ #{print}\n#{escaped}</pre>"
769
+ ensure
770
+ Dir.chdir(current_dir)
771
+ end
772
+ end
773
+
774
+ end
775
+
776
+ TYPES = {
777
+ '.rb' => 'ruby',
778
+ '.yml' => 'yaml',
779
+ '.yaml' => 'yaml',
780
+ '.xml' => 'xml'
781
+ }
782
+
783
+ def self.syntax_colorization(file)
784
+ type = TYPES[File.extname(file)]
785
+ if type
786
+ convertor = Syntax::Convertors::HTML.for_syntax(type)
787
+ body = convertor.convert(File.read(file), false)
788
+ return "<pre class='#{type}'>#{body}</pre>"
789
+ else
790
+ return "<pre>#{Entry.escape_special_characters(File.read(file))}</pre>"
791
+ end
792
+ end
793
+
794
+ end
795
+
796
+ end
797
+
798
+ # Start command line
799
+ if $0 == __FILE__
800
+ Bee::Doc.start_command_line
801
+ end