coderay 0.4.3.48
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 +340 -0
- data/README +103 -0
- data/demo/demo_count.rb +10 -0
- data/demo/demo_css.rb +4 -0
- data/demo/demo_div.rb +19 -0
- data/demo/demo_dump.rb +15 -0
- data/demo/demo_encoder.rb +39 -0
- data/demo/demo_global_vars.rb +13 -0
- data/demo/demo_global_vars2.rb +28 -0
- data/demo/demo_html.rb +394 -0
- data/demo/demo_html2.rb +11 -0
- data/demo/demo_load_encoder.rb +17 -0
- data/demo/demo_more.rb +204 -0
- data/demo/demo_scanner.rb +36 -0
- data/demo/demo_server.rb +92 -0
- data/demo/demo_simple.rb +10 -0
- data/demo/demo_stream.rb +25 -0
- data/demo/demo_stream2.rb +8 -0
- data/demo/demo_tokens.rb +3 -0
- data/lib/coderay.rb +284 -0
- data/lib/coderay/encoder.rb +151 -0
- data/lib/coderay/encoders/count.rb +21 -0
- data/lib/coderay/encoders/div.rb +16 -0
- data/lib/coderay/encoders/helpers/html_css.rb +155 -0
- data/lib/coderay/encoders/helpers/html_helper.rb +68 -0
- data/lib/coderay/encoders/helpers/html_output.rb +237 -0
- data/lib/coderay/encoders/html.rb +169 -0
- data/lib/coderay/encoders/null.rb +20 -0
- data/lib/coderay/encoders/span.rb +16 -0
- data/lib/coderay/encoders/statistic.rb +74 -0
- data/lib/coderay/encoders/text.rb +33 -0
- data/lib/coderay/encoders/tokens.rb +44 -0
- data/lib/coderay/encoders/yaml.rb +19 -0
- data/lib/coderay/helpers/filetype.rb +145 -0
- data/lib/coderay/helpers/gzip_simple.rb +123 -0
- data/lib/coderay/helpers/plugin.rb +286 -0
- data/lib/coderay/helpers/scanner_helper.rb +63 -0
- data/lib/coderay/scanner.rb +197 -0
- data/lib/coderay/scanners/c.rb +147 -0
- data/lib/coderay/scanners/delphi.rb +123 -0
- data/lib/coderay/scanners/helpers/ruby_helper.rb +212 -0
- data/lib/coderay/scanners/plaintext.rb +13 -0
- data/lib/coderay/scanners/ruby.rb +337 -0
- data/lib/coderay/tokens.rb +324 -0
- metadata +89 -0
data/demo/demo_html2.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'coderay'
|
2
|
+
|
3
|
+
# scan this file
|
4
|
+
tokens = CodeRay.scan(File.read($0) * 1, :ruby)
|
5
|
+
|
6
|
+
# output it with two styles of line numbers
|
7
|
+
out = tokens.div(:line_numbers => :table)
|
8
|
+
out << '<hr />'
|
9
|
+
out << tokens.div(:line_numbers => :inline, :line_number_start => 8)
|
10
|
+
|
11
|
+
puts out.page
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'coderay'
|
2
|
+
|
3
|
+
begin
|
4
|
+
CodeRay::Encoders::YAML
|
5
|
+
rescue
|
6
|
+
puts 'CodeRay::Encoders::YAML is not defined; you must load it first.'
|
7
|
+
end
|
8
|
+
|
9
|
+
yaml_encoder = CodeRay::Encoders[:yaml]
|
10
|
+
print 'Now it is loaded: '
|
11
|
+
p yaml_encoder
|
12
|
+
puts 'See?'
|
13
|
+
|
14
|
+
tokens_encoder = require_plugin 'CodeRay::Encoders/tokens'
|
15
|
+
print 'Require is also possible: '
|
16
|
+
p tokens_encoder
|
17
|
+
puts 'See?'
|
data/demo/demo_more.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'coderay'
|
2
|
+
|
3
|
+
c, ruby = DATA.read.split(/^---$/)
|
4
|
+
DATA.rewind
|
5
|
+
me = DATA.read[/.*^__END__$/m]
|
6
|
+
$input = c + ruby + me
|
7
|
+
|
8
|
+
require 'benchmark'
|
9
|
+
time = Benchmark.realtime do
|
10
|
+
|
11
|
+
# here CodeRay comes to play
|
12
|
+
hl = CodeRay.encoder(:html, :tab_width => 2, :line_numbers => :table, :wrap => :div)
|
13
|
+
c = hl.highlight c, :c
|
14
|
+
ruby = hl.highlight ruby, :ruby
|
15
|
+
me = hl.highlight me, :ruby
|
16
|
+
|
17
|
+
body = %w[C Ruby Genereated\ by].zip([c, ruby, me]).map do |title, code|
|
18
|
+
"<h1>#{title}</h1>\n#{code}"
|
19
|
+
end.join
|
20
|
+
body = hl.class::Output.new(body, :div).page!
|
21
|
+
|
22
|
+
# CodeRay also provides a simple page generator
|
23
|
+
$output = body #hl.class.wrap_in_page body
|
24
|
+
end
|
25
|
+
|
26
|
+
File.open('test.html', 'w') do |f|
|
27
|
+
f.write $output
|
28
|
+
end
|
29
|
+
puts 'Input: %dB, Output: %dB' % [$input.size, $output.size]
|
30
|
+
puts 'Created "test.html" in %0.3f seconds (%d KB/s). Take a look with your browser.' % [time, $input.size / 1024.0 / time]
|
31
|
+
|
32
|
+
__END__
|
33
|
+
/**********************************************************************
|
34
|
+
|
35
|
+
version.c -
|
36
|
+
|
37
|
+
$Author: nobu $
|
38
|
+
$Date: 2004/03/25 12:01:40 $
|
39
|
+
created at: Thu Sep 30 20:08:01 JST 1993
|
40
|
+
|
41
|
+
Copyright (C) 1993-2003 Yukihiro Matsumoto
|
42
|
+
|
43
|
+
**********************************************************************/
|
44
|
+
|
45
|
+
#include "ruby.h"
|
46
|
+
#include "version.h"
|
47
|
+
#include <stdio.h>
|
48
|
+
|
49
|
+
const char ruby_version[] = RUBY_VERSION;
|
50
|
+
const char ruby_release_date[] = RUBY_RELEASE_DATE;
|
51
|
+
const char ruby_platform[] = RUBY_PLATFORM;
|
52
|
+
|
53
|
+
void
|
54
|
+
Init_version()
|
55
|
+
{
|
56
|
+
VALUE v = rb_obj_freeze(rb_str_new2(ruby_version));
|
57
|
+
VALUE d = rb_obj_freeze(rb_str_new2(ruby_release_date));
|
58
|
+
VALUE p = rb_obj_freeze(rb_str_new2(ruby_platform));
|
59
|
+
|
60
|
+
rb_define_global_const("RUBY_VERSION", v);
|
61
|
+
rb_define_global_const("RUBY_RELEASE_DATE", d);
|
62
|
+
rb_define_global_const("RUBY_PLATFORM", p);
|
63
|
+
}
|
64
|
+
|
65
|
+
void
|
66
|
+
ruby_show_version()
|
67
|
+
{
|
68
|
+
printf("ruby %s (%s) [%s]\n", RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PLATFORM);
|
69
|
+
}
|
70
|
+
|
71
|
+
void
|
72
|
+
ruby_show_copyright()
|
73
|
+
{
|
74
|
+
printf("ruby - Copyright (C) 1993-%d Yukihiro Matsumoto\n", RUBY_RELEASE_YEAR);
|
75
|
+
exit(0);
|
76
|
+
}
|
77
|
+
---
|
78
|
+
#
|
79
|
+
# = ostruct.rb: OpenStruct implementation
|
80
|
+
#
|
81
|
+
# Author:: Yukihiro Matsumoto
|
82
|
+
# Documentation:: Gavin Sinclair
|
83
|
+
#
|
84
|
+
# OpenStruct allows the creation of data objects with arbitrary attributes.
|
85
|
+
# See OpenStruct for an example.
|
86
|
+
#
|
87
|
+
|
88
|
+
#
|
89
|
+
# OpenStruct allows you to create data objects and set arbitrary attributes.
|
90
|
+
# For example:
|
91
|
+
#
|
92
|
+
# require 'ostruct'
|
93
|
+
#
|
94
|
+
# record = OpenStruct.new
|
95
|
+
# record.name = "John Smith"
|
96
|
+
# record.age = 70
|
97
|
+
# record.pension = 300
|
98
|
+
#
|
99
|
+
# puts record.name # -> "John Smith"
|
100
|
+
# puts record.address # -> nil
|
101
|
+
#
|
102
|
+
# It is like a hash with a different way to access the data. In fact, it is
|
103
|
+
# implemented with a hash, and you can initialize it with one.
|
104
|
+
#
|
105
|
+
# hash = { "country" => "Australia", :population => 20_000_000 }
|
106
|
+
# data = OpenStruct.new(hash)
|
107
|
+
#
|
108
|
+
# p data # -> <OpenStruct country="Australia" population=20000000>
|
109
|
+
#
|
110
|
+
class OpenStruct
|
111
|
+
#
|
112
|
+
# Create a new OpenStruct object. The optional +hash+, if given, will
|
113
|
+
# generate attributes and values. For example.
|
114
|
+
#
|
115
|
+
# require 'ostruct'
|
116
|
+
# hash = { "country" => "Australia", :population => 20_000_000 }
|
117
|
+
# data = OpenStruct.new(hash)
|
118
|
+
#
|
119
|
+
# p data # -> <OpenStruct country="Australia" population=20000000>
|
120
|
+
#
|
121
|
+
# By default, the resulting OpenStruct object will have no attributes.
|
122
|
+
#
|
123
|
+
def initialize(hash=nil)
|
124
|
+
@table = {}
|
125
|
+
if hash
|
126
|
+
for k,v in hash
|
127
|
+
@table[k.to_sym] = v
|
128
|
+
new_ostruct_member(k)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Duplicate an OpenStruct object members.
|
134
|
+
def initialize_copy(orig)
|
135
|
+
super
|
136
|
+
@table = @table.dup
|
137
|
+
end
|
138
|
+
|
139
|
+
def marshal_dump
|
140
|
+
@table
|
141
|
+
end
|
142
|
+
def marshal_load(x)
|
143
|
+
@table = x
|
144
|
+
@table.each_key{|key| new_ostruct_member(key)}
|
145
|
+
end
|
146
|
+
|
147
|
+
def new_ostruct_member(name)
|
148
|
+
unless self.respond_to?(name)
|
149
|
+
self.instance_eval %{
|
150
|
+
def #{name}; @table[:#{name}]; end
|
151
|
+
def #{name}=(x); @table[:#{name}] = x; end
|
152
|
+
}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def method_missing(mid, *args) # :nodoc:
|
157
|
+
mname = mid.id2name
|
158
|
+
len = args.length
|
159
|
+
if mname =~ /=$/
|
160
|
+
if len != 1
|
161
|
+
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
|
162
|
+
end
|
163
|
+
if self.frozen?
|
164
|
+
raise TypeError, "can't modify frozen #{self.class}", caller(1)
|
165
|
+
end
|
166
|
+
mname.chop!
|
167
|
+
@table[mname.intern] = args[0]
|
168
|
+
self.new_ostruct_member(mname)
|
169
|
+
elsif len == 0
|
170
|
+
@table[mid]
|
171
|
+
else
|
172
|
+
raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Remove the named field from the object.
|
178
|
+
#
|
179
|
+
def delete_field(name)
|
180
|
+
@table.delete name.to_sym
|
181
|
+
end
|
182
|
+
|
183
|
+
#
|
184
|
+
# Returns a string containing a detailed summary of the keys and values.
|
185
|
+
#
|
186
|
+
def inspect
|
187
|
+
str = "<#{self.class}"
|
188
|
+
for k,v in @table
|
189
|
+
str << " #{k}=#{v.inspect}"
|
190
|
+
end
|
191
|
+
str << ">"
|
192
|
+
end
|
193
|
+
|
194
|
+
attr_reader :table # :nodoc:
|
195
|
+
protected :table
|
196
|
+
|
197
|
+
#
|
198
|
+
# Compare this object and +other+ for equality.
|
199
|
+
#
|
200
|
+
def ==(other)
|
201
|
+
return false unless(other.kind_of?(OpenStruct))
|
202
|
+
return @table == other.table
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'coderay'
|
2
|
+
|
3
|
+
c_code = "if (*p == '{') nest++;"
|
4
|
+
puts 'C Code: ' + c_code
|
5
|
+
puts
|
6
|
+
|
7
|
+
c_scanner = CodeRay::Scanners[:c].new c_code
|
8
|
+
|
9
|
+
puts '> print only operators:'
|
10
|
+
for text, kind in c_scanner
|
11
|
+
print text if kind == :operator
|
12
|
+
end
|
13
|
+
puts
|
14
|
+
puts '-' * 30
|
15
|
+
puts
|
16
|
+
|
17
|
+
ruby_code = %q!ruby_code(:can, BE, %r[q[ui]te #{ /comple/x },] => $-s, &?\xee)!
|
18
|
+
puts 'Ruby Code: ' + ruby_code
|
19
|
+
puts
|
20
|
+
|
21
|
+
ruby_scanner = CodeRay::Scanners[:ruby].new ruby_code
|
22
|
+
|
23
|
+
puts '> has a string?'
|
24
|
+
puts ruby_scanner.
|
25
|
+
any? { |text, kind| kind == :string }
|
26
|
+
puts
|
27
|
+
|
28
|
+
puts '> number of regexps?'
|
29
|
+
puts ruby_scanner.
|
30
|
+
select { |token| token == [:open, :regexp] }.size
|
31
|
+
puts
|
32
|
+
|
33
|
+
puts '> has a string?'
|
34
|
+
puts ruby_scanner.
|
35
|
+
reject { |text, kind| not text.is_a? String }.
|
36
|
+
map { |text, kind| %("#{text}" (#{kind})) }.join(', ')
|
data/demo/demo_server.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# CodeRay dynamic highlighter
|
2
|
+
#
|
3
|
+
# Usage: start this and your browser.
|
4
|
+
#
|
5
|
+
# Go to http://localhost:49374/?<path to the file>
|
6
|
+
# (mnemonic: 49374 = Four-Nine-Three-Seven-Four = For No Token Shall Fall)
|
7
|
+
# and you should get the highlighted version.
|
8
|
+
|
9
|
+
require 'webrick'
|
10
|
+
require 'pathname'
|
11
|
+
|
12
|
+
class << File
|
13
|
+
alias dir? directory?
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'erb'
|
17
|
+
include ERB::Util
|
18
|
+
def url_decode s
|
19
|
+
s.to_s.gsub(/%([0-9a-f]{2})/i) { [$1.hex].pack 'C' }
|
20
|
+
end
|
21
|
+
|
22
|
+
class String
|
23
|
+
def to_link name = File.basename(self)
|
24
|
+
"<a href=\"?path=#{url_encode self}\">#{name}</a>"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'coderay'
|
29
|
+
class CodeRayServlet < WEBrick::HTTPServlet::AbstractServlet
|
30
|
+
|
31
|
+
STYLE = 'style="font-family: sans-serif; color: navy;"'
|
32
|
+
BANNER = '<p><img src="http://rd.cYcnus.de/coderay/coderay-banner" style="border: 0" alt="HIghlighted by CodeRay"/></p>'
|
33
|
+
|
34
|
+
def do_GET req, res
|
35
|
+
q = req.query_string || ''
|
36
|
+
args = Hash[*q.scan(/(.*?)=(.*?)(?:&|$)/).flatten].each_value { |v| v.replace url_decode(v) }
|
37
|
+
path = args.fetch 'path', '.'
|
38
|
+
|
39
|
+
backlinks = '<p>current path: %s<br />' % html_escape(path) +
|
40
|
+
(Pathname.new(path) + '..').cleanpath.to_s.to_link('up') + ' - ' +
|
41
|
+
'.'.to_link('current') + '</p>'
|
42
|
+
|
43
|
+
res.body =
|
44
|
+
if File.dir? path
|
45
|
+
path = Pathname.new(path).cleanpath.to_s
|
46
|
+
dirs, files = Dir[File.join(path, '*')].sort.partition { |p| File.dir? p }
|
47
|
+
|
48
|
+
page = "<html><head></head><body #{STYLE}>"
|
49
|
+
page << backlinks
|
50
|
+
|
51
|
+
page << '<dl>'
|
52
|
+
page << "<dt>Directories</dt>\n" + dirs.map do |p|
|
53
|
+
"<dd>#{p.to_link}</dd>\n"
|
54
|
+
end.join << "\n"
|
55
|
+
page << "<dt>Files</dt>\n" + files.map do |p|
|
56
|
+
"<dd>#{p.to_link}</dd>\n"
|
57
|
+
end.join << "\n"
|
58
|
+
page << "</dl>\n"
|
59
|
+
page << "#{BANNER}</body></html>"
|
60
|
+
|
61
|
+
elsif File.exist? path
|
62
|
+
div = CodeRay.scan_file(path).html :tab_width => 8, :wrap => :div
|
63
|
+
div.replace <<-DIV
|
64
|
+
<div #{STYLE}>
|
65
|
+
#{backlinks}
|
66
|
+
#{div}
|
67
|
+
</div>
|
68
|
+
#{BANNER}
|
69
|
+
DIV
|
70
|
+
div.page
|
71
|
+
end
|
72
|
+
|
73
|
+
res['Content-Type'] = 'text/html'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# this is taken by "qip_msgd" - I don't know that.
|
78
|
+
module CodeRay
|
79
|
+
PORT = 0xC0DE / 20
|
80
|
+
end
|
81
|
+
|
82
|
+
server = WEBrick::HTTPServer.new :Port => CodeRay::PORT
|
83
|
+
|
84
|
+
server.mount '/', CodeRayServlet
|
85
|
+
|
86
|
+
server.mount_proc '/version' do |req, res|
|
87
|
+
res.body = 'CodeRay::Version = ' + CodeRay::Version
|
88
|
+
res['Content-Type'] = "text/plain"
|
89
|
+
end
|
90
|
+
|
91
|
+
trap("INT") { server.shutdown }
|
92
|
+
server.start
|
data/demo/demo_simple.rb
ADDED
data/demo/demo_stream.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'coderay'
|
2
|
+
|
3
|
+
code = File.read($0) * 500
|
4
|
+
puts "Size of code: %d KB" % [code.size / 1024]
|
5
|
+
|
6
|
+
puts "Use your system's memory tracker to see how much RAM this takes."
|
7
|
+
print 'Press some key to continue...'; gets
|
8
|
+
|
9
|
+
require 'benchmark'
|
10
|
+
e = CodeRay.encoder(:div)
|
11
|
+
for do_stream in [true, false]
|
12
|
+
puts "Scanning and encoding in %s mode, please wait..." %
|
13
|
+
[do_stream ? 'streaming' : 'normal']
|
14
|
+
output = ''
|
15
|
+
time = Benchmark.realtime do
|
16
|
+
if do_stream
|
17
|
+
output = e.encode_stream(code, :ruby)
|
18
|
+
else
|
19
|
+
output = e.encode_tokens(t = CodeRay.scan(code, :ruby))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
puts 'Finished after %4.2f seconds.' % time
|
23
|
+
puts "Size of output: %d KB" % [output.size / 1024]
|
24
|
+
print 'Press some key to continue...'; gets
|
25
|
+
end
|
data/demo/demo_tokens.rb
ADDED
data/lib/coderay.rb
ADDED
@@ -0,0 +1,284 @@
|
|
1
|
+
# = CodeRay Library
|
2
|
+
#
|
3
|
+
# $Id: coderay.rb 44 2005-10-01 00:59:05Z murphy $
|
4
|
+
#
|
5
|
+
# CodeRay is a Ruby library for syntax highlighting.
|
6
|
+
#
|
7
|
+
# I try to make CodeRay easy to use and intuitive, but at the same time fully featured, complete,
|
8
|
+
# fast and efficient.
|
9
|
+
#
|
10
|
+
# See README.
|
11
|
+
#
|
12
|
+
# It consists mainly of
|
13
|
+
# * the main engine: CodeRay (Scanners::Scanner, Tokens/TokenStream, Encoders::Encoder), PluginHost
|
14
|
+
# * the scanners in CodeRay::Scanners
|
15
|
+
# * the encoders in CodeRay::Encoders
|
16
|
+
#
|
17
|
+
# Here's a fancy graphic to light up this gray docu:
|
18
|
+
#
|
19
|
+
# http://rd.cYcnus.de/coderay/scheme.png
|
20
|
+
#
|
21
|
+
# == Documentation
|
22
|
+
#
|
23
|
+
# See CodeRay, Encoders, Scanners, Tokens.
|
24
|
+
#
|
25
|
+
# == Usage
|
26
|
+
#
|
27
|
+
# Remember you need RubyGems to use CodeRay. Run Ruby with -rubygems option
|
28
|
+
# if required.
|
29
|
+
#
|
30
|
+
# === Highlight Ruby code in a string as html
|
31
|
+
#
|
32
|
+
# require 'coderay'
|
33
|
+
# print CodeRay.scan('puts "Hello, world!"', :ruby).html
|
34
|
+
#
|
35
|
+
# # prints something like this:
|
36
|
+
# puts <span class="s">"Hello, world!"</span>
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# === Highlight C code from a file in a html div
|
40
|
+
#
|
41
|
+
# require 'coderay'
|
42
|
+
# print CodeRay.scan(File.read('ruby.h'), :c).div
|
43
|
+
# print CodeRay.scan_file('ruby.h').html.div
|
44
|
+
#
|
45
|
+
# You can include this div in your page. The used CSS styles can be printed with
|
46
|
+
#
|
47
|
+
# % ruby -rcoderay -e "print CodeRay::Encoders[:html]::CSS"
|
48
|
+
#
|
49
|
+
# === Highlight without typing too much
|
50
|
+
#
|
51
|
+
# If you are one of the hasty (or lazy, or extremely curious) people, just run this file:
|
52
|
+
#
|
53
|
+
# % ruby -rubygems coderay.rb
|
54
|
+
#
|
55
|
+
# If the output was to fast for you, try
|
56
|
+
#
|
57
|
+
# % ruby -rubygems coderay.rb > example.html
|
58
|
+
#
|
59
|
+
# and look at the file it created.
|
60
|
+
#
|
61
|
+
# = CodeRay Module
|
62
|
+
#
|
63
|
+
# The CodeRay module provides convenience methods for the engine.
|
64
|
+
#
|
65
|
+
# * The +lang+ and +format+ arguments select Scanner and Encoder to use. These are
|
66
|
+
# simply lower-case symbols, like <tt>:python</tt> or <tt>:html</tt>.
|
67
|
+
# * All methods take an optional hash as last parameter, +options+, that is send to
|
68
|
+
# the Encoder / Scanner.
|
69
|
+
# * Input and language are always sorted in this order: +code+, +lang+.
|
70
|
+
# (This is in alphabetical order, if you need a mnemonic ;)
|
71
|
+
#
|
72
|
+
# You should be able to highlight everything you want just using this methods;
|
73
|
+
# so there is no need to dive into CodeRay's deep class hierarchy.
|
74
|
+
#
|
75
|
+
# The exmaples in the demo/ directory demonstrate common cases using this interface.
|
76
|
+
#
|
77
|
+
# = Basic Access Ways
|
78
|
+
#
|
79
|
+
# Read this to get a general view what CodeRay provides.
|
80
|
+
#
|
81
|
+
# == Scanning
|
82
|
+
#
|
83
|
+
# Scanning means analysing an input string, splitting it up into Tokens.
|
84
|
+
# Each Token knows about what type it is: string, comment, class name, etc.
|
85
|
+
#
|
86
|
+
# Each +lang+ (language) has its own Scanner; for example, <tt>:ruby</tt> code is
|
87
|
+
# handled by CodeRay::Scanners::RubyScanner.
|
88
|
+
#
|
89
|
+
# CodeRay.scan:: Scan a string in a given language into Tokens.
|
90
|
+
# This is the most common method to use.
|
91
|
+
# CodeRay.scan_file:: Scan a file and guess the language using FileType.
|
92
|
+
#
|
93
|
+
# The Tokens object you get from these methods can encode itself; see Tokens.
|
94
|
+
#
|
95
|
+
# == Encoding
|
96
|
+
#
|
97
|
+
# Encoding means compiling Tokens into an output. This can be colored HTML or
|
98
|
+
# LaTeX, a textual statistic or just the number of non-whitespace tokens.
|
99
|
+
#
|
100
|
+
# Each Encoder provides output in a specific +format+, so you select Encoders via
|
101
|
+
# formats like <tt>:html</tt> or <tt>:statistic</tt>.
|
102
|
+
#
|
103
|
+
# CodeRay.encode:: Scan and encode a string in a given language.
|
104
|
+
# CodeRay.encode_tokens:: Encode the given tokens.
|
105
|
+
# CodeRay.encode_file:: Scan a file, guess the language using FileType and encode it.
|
106
|
+
#
|
107
|
+
# == Streaming
|
108
|
+
#
|
109
|
+
# Streaming saves RAM by running Scanner and Encoder in some sort of
|
110
|
+
# pipe mode; see TokenStream.
|
111
|
+
#
|
112
|
+
# CodeRay.scan_stream:: Scan in stream mode.
|
113
|
+
#
|
114
|
+
# == All-in-One Encoding
|
115
|
+
#
|
116
|
+
# CodeRay.encode:: Highlight a string with a given input and output format.
|
117
|
+
#
|
118
|
+
# == Instanciating
|
119
|
+
#
|
120
|
+
# You can use an Encoder instance to highlight multiple inputs. This way, the setup
|
121
|
+
# for this Encoder must only be done once.
|
122
|
+
#
|
123
|
+
# CodeRay.encoder:: Create an Encoder instance with format and options.
|
124
|
+
#
|
125
|
+
# There is no CodeRay.scanner method because Scanners are bound to an input string
|
126
|
+
# on creation; you can't re-use them with another string.
|
127
|
+
#
|
128
|
+
# The scanning methods provide more flexibility; we recommend to use these.
|
129
|
+
module CodeRay
|
130
|
+
|
131
|
+
Version = '0.4.4'
|
132
|
+
|
133
|
+
require 'coderay/tokens'
|
134
|
+
require 'coderay/scanner'
|
135
|
+
require 'coderay/encoder'
|
136
|
+
|
137
|
+
|
138
|
+
class << self
|
139
|
+
|
140
|
+
# Scans the given +code+ (a String) with the Scanner for +lang+.
|
141
|
+
#
|
142
|
+
# This is a simple way to use CodeRay. Example:
|
143
|
+
# require 'coderay'
|
144
|
+
# page = CodeRay.scan("puts 'Hello, world!'", :ruby).html
|
145
|
+
#
|
146
|
+
# See also demo/demo_simple.
|
147
|
+
def scan code, lang, options = {}, &block
|
148
|
+
scanner = Scanners[lang].new code, options, &block
|
149
|
+
scanner.tokenize
|
150
|
+
end
|
151
|
+
|
152
|
+
# Scans +filename+ (a path to a code file) with the Scanner for +lang+.
|
153
|
+
#
|
154
|
+
# If +lang+ is :auto or omitted, the CodeRay::FileType module is used to
|
155
|
+
# determine it. If it cannot find out what type it is, it uses
|
156
|
+
# CodeRay::Scanners::Plaintext.
|
157
|
+
#
|
158
|
+
# Calls CodeRay.scan.
|
159
|
+
#
|
160
|
+
# Example:
|
161
|
+
# require 'coderay'
|
162
|
+
# page = CodeRay.scan_file('some_c_code.c').html
|
163
|
+
def scan_file filename, lang = :auto, options = {}, &block
|
164
|
+
file = IO.read filename
|
165
|
+
if lang == :auto
|
166
|
+
require 'coderay/helpers/filetype'
|
167
|
+
lang = FileType.fetch filename, :plaintext, true
|
168
|
+
end
|
169
|
+
scan file, lang, options = {}, &block
|
170
|
+
end
|
171
|
+
|
172
|
+
# Scan the +code+ (a string) with the scanner for +lang+.
|
173
|
+
#
|
174
|
+
# Calls scan.
|
175
|
+
#
|
176
|
+
# See CodeRay.scan.
|
177
|
+
def scan_stream code, lang, options = {}, &block
|
178
|
+
options[:stream] = true
|
179
|
+
scan code, lang, options, &block
|
180
|
+
end
|
181
|
+
|
182
|
+
# Encode a string in Streaming mode.
|
183
|
+
#
|
184
|
+
# This starts scanning +code+ with the the Scanner for +lang+
|
185
|
+
# while encodes the output with the Encoder for +format+.
|
186
|
+
# +options+ will be passed to the Encoder.
|
187
|
+
#
|
188
|
+
# See CodeRay::Encoder.encode_stream
|
189
|
+
def encode_stream code, lang, format, options = {}
|
190
|
+
encoder(format, options).encode_stream code, lang, options
|
191
|
+
end
|
192
|
+
|
193
|
+
# Encode a string.
|
194
|
+
#
|
195
|
+
# This scans +code+ with the the Scanner for +lang+ and then
|
196
|
+
# encodes it with the Encoder for +format+.
|
197
|
+
# +options+ will be passed to the Encoder.
|
198
|
+
#
|
199
|
+
# See CodeRay::Encoder.encode
|
200
|
+
def encode code, lang, format, options = {}
|
201
|
+
encoder(format, options).encode code, lang, options
|
202
|
+
end
|
203
|
+
|
204
|
+
# Encode pre-scanned Tokens.
|
205
|
+
# Use this together with CodeRay.scan:
|
206
|
+
#
|
207
|
+
# require 'coderay'
|
208
|
+
#
|
209
|
+
# # Highlight a short Ruby code example in a HTML span
|
210
|
+
# tokens = CodeRay.scan '1 + 2', :ruby
|
211
|
+
# puts CodeRay.encode_tokens(tokens, :span)
|
212
|
+
#
|
213
|
+
def encode_tokens tokens, format, options = {}
|
214
|
+
encoder(format, options).encode_tokens tokens, options
|
215
|
+
end
|
216
|
+
|
217
|
+
# Encodes +filename+ (a path to a code file) with the Scanner for +lang+.
|
218
|
+
#
|
219
|
+
# See CodeRay.scan_file.
|
220
|
+
# Notice that the second argument is the output +format+, not the input language.
|
221
|
+
#
|
222
|
+
# Example:
|
223
|
+
# require 'coderay'
|
224
|
+
# page = CodeRay.encode_file 'some_c_code.c', :html
|
225
|
+
def encode_file filename, format, options = {}
|
226
|
+
tokens = scan_file filename, auto, get_scanner_options(options)
|
227
|
+
encode_tokens tokens, format, options
|
228
|
+
end
|
229
|
+
|
230
|
+
# Finds the Encoder class for +format+ and creates an instance, passing
|
231
|
+
# +options+ to it.
|
232
|
+
#
|
233
|
+
# Example:
|
234
|
+
# require 'coderay'
|
235
|
+
#
|
236
|
+
# stats = CodeRay.encoder(:statistic)
|
237
|
+
# stats.encode("puts 17 + 4\n", :ruby)
|
238
|
+
#
|
239
|
+
# puts '%d out of %d tokens have the kind :integer.' % [
|
240
|
+
# stats.type_stats[:integer].count,
|
241
|
+
# stats.real_token_count
|
242
|
+
# ]
|
243
|
+
# #-> 2 out of 4 tokens have the kind :integer.
|
244
|
+
def encoder format, options = {}
|
245
|
+
Encoders[format].new options
|
246
|
+
end
|
247
|
+
|
248
|
+
# Extract the options for the scanner from the +options+ hash.
|
249
|
+
#
|
250
|
+
# Returns an empty Hash if <tt>:scanner_options</tt> is not set.
|
251
|
+
#
|
252
|
+
# This is used if a method like CodeRay.encode has to provide options
|
253
|
+
# for Encoder _and_ scanner.
|
254
|
+
def get_scanner_options options
|
255
|
+
options.fetch :scanner_options, {}
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
# This Exception is raised when you try to stream with something that is not
|
261
|
+
# capable of streaming.
|
262
|
+
class NotStreamableError < Exception
|
263
|
+
def initialize obj
|
264
|
+
@obj = obj
|
265
|
+
end
|
266
|
+
|
267
|
+
def to_s
|
268
|
+
'%s is not Streamable!' % @obj.class
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# A dummy module that is included by subclasses of CodeRay::Scanner an CodeRay::Encoder
|
273
|
+
# to show that they are able to handle streams.
|
274
|
+
module Streamable
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
# Run a test script.
|
280
|
+
if $0 == __FILE__
|
281
|
+
$stderr.print 'Press key to print demo.'; gets
|
282
|
+
code = File.read($0)[/module CodeRay.*/m]
|
283
|
+
print CodeRay.scan(code, :ruby).html
|
284
|
+
end
|