coderay 0.4.3.48
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,151 @@
|
|
1
|
+
module CodeRay
|
2
|
+
|
3
|
+
# This module holds the Encoder class and its subclasses.
|
4
|
+
# For example, the HTML encoder is named CodeRay::Encoders::HTML
|
5
|
+
# can be found in coderay/encoders/html.
|
6
|
+
#
|
7
|
+
# Encoders also provides methods and constants for the register
|
8
|
+
# mechanism and the [] method that returns the Encoder class
|
9
|
+
# belonging to the given format.
|
10
|
+
module Encoders
|
11
|
+
extend PluginHost
|
12
|
+
plugin_path 'coderay/encoders'
|
13
|
+
|
14
|
+
# = Encoder
|
15
|
+
#
|
16
|
+
# The Encoder base class. Together with Scanner and
|
17
|
+
# Tokens, it forms the highlighting triad.
|
18
|
+
#
|
19
|
+
# Encoder instances take a Tokens object and do something with it.
|
20
|
+
#
|
21
|
+
# The most common Encoder is surely the HTML encoder
|
22
|
+
# (CodeRay::Encoders::HTML). It highlights the code in a colorful
|
23
|
+
# html page.
|
24
|
+
# If you want the highlighted code in a div or a span instead,
|
25
|
+
# use its subclasses Div and Span.
|
26
|
+
class Encoder
|
27
|
+
extend Plugin
|
28
|
+
plugin_host Encoders
|
29
|
+
|
30
|
+
attr_reader :token_stream
|
31
|
+
|
32
|
+
class << self
|
33
|
+
|
34
|
+
# Returns if the Encoder can be used in streaming mode.
|
35
|
+
def streamable?
|
36
|
+
is_a? Streamable
|
37
|
+
end
|
38
|
+
|
39
|
+
# If FILE_EXTENSION isn't defined, this method returns the
|
40
|
+
# downcase class name instead.
|
41
|
+
def const_missing sym
|
42
|
+
if sym == :FILE_EXTENSION
|
43
|
+
sym.to_s.downcase
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
# Subclasses are to store their default options in this constant.
|
52
|
+
DEFAULT_OPTIONS = { :stream => false }
|
53
|
+
|
54
|
+
# The options you gave the Encoder at creating.
|
55
|
+
attr_accessor :options
|
56
|
+
|
57
|
+
# Creates a new Encoder.
|
58
|
+
# +options+ is saved and used for all encode operations, as long
|
59
|
+
# as you don't overwrite it there by passing additional options.
|
60
|
+
#
|
61
|
+
# Encoder objects provide three encode methods:
|
62
|
+
# - encode simply takes a +code+ string and a +lang+
|
63
|
+
# - encode_tokens expects a +tokens+ object instead
|
64
|
+
# - encode_stream is like encode, but uses streaming mode.
|
65
|
+
#
|
66
|
+
# Each method has an optional +options+ parameter. These are
|
67
|
+
# added to the options you passed at creation.
|
68
|
+
def initialize options = {}
|
69
|
+
@options = self.class::DEFAULT_OPTIONS.merge options
|
70
|
+
raise "I am only the basic Encoder class. I can't encode "\
|
71
|
+
"anything. :( Use my subclasses." if self.class == Encoder
|
72
|
+
end
|
73
|
+
|
74
|
+
# Encode a Tokens object.
|
75
|
+
def encode_tokens tokens, options = {}
|
76
|
+
options = @options.merge options
|
77
|
+
setup options
|
78
|
+
compile tokens, options
|
79
|
+
finish options
|
80
|
+
end
|
81
|
+
|
82
|
+
# Encode the given +code+ after tokenizing it using the Scanner
|
83
|
+
# for +lang+.
|
84
|
+
def encode code, lang, options = {}
|
85
|
+
options = @options.merge options
|
86
|
+
scanner_options = CodeRay.get_scanner_options(options)
|
87
|
+
tokens = CodeRay.scan code, lang, scanner_options
|
88
|
+
encode_tokens tokens, options
|
89
|
+
end
|
90
|
+
|
91
|
+
# You can use highlight instead of encode, if that seems
|
92
|
+
# more clear to you.
|
93
|
+
alias highlight encode
|
94
|
+
|
95
|
+
# Encode the given +code+ using the Scanner for +lang+ in
|
96
|
+
# streaming mode.
|
97
|
+
def encode_stream code, lang, options = {}
|
98
|
+
raise NotStreamableError, self unless kind_of? Streamable
|
99
|
+
options = @options.merge options
|
100
|
+
setup options
|
101
|
+
scanner_options = CodeRay.get_scanner_options options
|
102
|
+
@token_stream =
|
103
|
+
CodeRay.scan_stream code, lang, scanner_options, &self
|
104
|
+
finish options
|
105
|
+
end
|
106
|
+
|
107
|
+
# Behave like a proc. The token method is converted to a proc.
|
108
|
+
def to_proc
|
109
|
+
method(:token).to_proc
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
|
114
|
+
# Called with merged options before encoding starts.
|
115
|
+
# Sets @out to an empty string.
|
116
|
+
#
|
117
|
+
# See the HTML Encoder for an example of option caching.
|
118
|
+
def setup options
|
119
|
+
@out = ''
|
120
|
+
end
|
121
|
+
|
122
|
+
# Called with +text+ and +kind+ of the currently scanned token.
|
123
|
+
# For simple scanners, it's enougth to implement this method.
|
124
|
+
#
|
125
|
+
# Raises a NotImplementedError exception if it is not overwritten
|
126
|
+
# in subclass.
|
127
|
+
def token text, kind
|
128
|
+
raise NotImplementedError,
|
129
|
+
"#{self.class}#token not implemented."
|
130
|
+
end
|
131
|
+
|
132
|
+
# Called with merged options after encoding starts.
|
133
|
+
# The return value is the result of encoding, typically @out.
|
134
|
+
def finish options
|
135
|
+
@out
|
136
|
+
end
|
137
|
+
|
138
|
+
# Do the encoding.
|
139
|
+
#
|
140
|
+
# The already created +tokens+ object must be used; it can be a
|
141
|
+
# TokenStream or a Tokens object.
|
142
|
+
def compile tokens, options
|
143
|
+
tokens.each(&self)
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# vim:sw=2:ts=2:noet:tw=78
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module CodeRay module Encoders
|
2
|
+
|
3
|
+
require 'coderay/encoders/html'
|
4
|
+
class Div < HTML
|
5
|
+
|
6
|
+
FILE_EXTENSION = 'div.html'
|
7
|
+
|
8
|
+
register_for :div
|
9
|
+
|
10
|
+
DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge({
|
11
|
+
:css => :style,
|
12
|
+
:wrap => :div,
|
13
|
+
})
|
14
|
+
end
|
15
|
+
|
16
|
+
end end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module CodeRay module Encoders
|
2
|
+
|
3
|
+
class HTML
|
4
|
+
class CSS
|
5
|
+
|
6
|
+
def initialize stylesheet = TOKENS
|
7
|
+
@classes = Hash.new
|
8
|
+
parse stylesheet
|
9
|
+
end
|
10
|
+
|
11
|
+
def [] *styles
|
12
|
+
cl = @classes[styles.first]
|
13
|
+
return '' unless cl
|
14
|
+
style = false
|
15
|
+
1.upto(cl.size + 1) do |offset|
|
16
|
+
break if style = cl[styles[offset .. -1]]
|
17
|
+
end
|
18
|
+
return style
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
CSS_CLASS_PATTERN = /
|
24
|
+
( (?: # $1 = classes
|
25
|
+
\s* \. [-\w]+
|
26
|
+
)+ )
|
27
|
+
\s* \{
|
28
|
+
( [^\}]* ) # $2 = style
|
29
|
+
\} \s*
|
30
|
+
|
|
31
|
+
( . ) # $3 = error
|
32
|
+
/mx
|
33
|
+
def parse stylesheet
|
34
|
+
stylesheet.scan CSS_CLASS_PATTERN do |classes, style, error|
|
35
|
+
raise "CSS parse error: '#{error.inspect}' not recognized" if error
|
36
|
+
styles = classes.scan(/[-\w]+/)
|
37
|
+
cl = styles.pop
|
38
|
+
@classes[cl] ||= Hash.new
|
39
|
+
@classes[cl][styles] = style.strip
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
MAIN = <<-'MAIN'
|
44
|
+
.CodeRay {
|
45
|
+
background-color: #f8f8f8;
|
46
|
+
border: 1px solid silver;
|
47
|
+
font-family: 'Courier New', 'Terminal', monospace;
|
48
|
+
color: black;
|
49
|
+
width: 100%;
|
50
|
+
padding: 2px;
|
51
|
+
}
|
52
|
+
.CodeRay pre { margin: 0px; }
|
53
|
+
|
54
|
+
div.CodeRay { }
|
55
|
+
|
56
|
+
span.CodeRay { white-space: pre; border: 0; }
|
57
|
+
|
58
|
+
table.CodeRay { border-collapse: collapse; }
|
59
|
+
table.CodeRay td { padding: 2px 4px; vertical-align: top; }
|
60
|
+
|
61
|
+
.CodeRay .line_numbers, .CodeRay .no {
|
62
|
+
background-color: #def;
|
63
|
+
color: gray;
|
64
|
+
text-align: right;
|
65
|
+
}
|
66
|
+
.CodeRay .line_numbers tt { font-weight: bold; }
|
67
|
+
.CodeRay .no { padding: 0px 4px; }
|
68
|
+
.CodeRay .code { width: 100%; }
|
69
|
+
|
70
|
+
.CodeRay .code {
|
71
|
+
}
|
72
|
+
.CodeRay .code pre { overflow: auto; }
|
73
|
+
MAIN
|
74
|
+
|
75
|
+
TOKENS = <<-'TOKENS'
|
76
|
+
.af { color:#00C; }
|
77
|
+
.an { color:#007; }
|
78
|
+
.av { color:#700; }
|
79
|
+
.aw { color:#C00; }
|
80
|
+
.bi { color:#509; font-weight:bold; }
|
81
|
+
.c { color:#888; }
|
82
|
+
|
83
|
+
.ch { color:#04D; }
|
84
|
+
.ch .k { color:#04D; }
|
85
|
+
.ch .dl { color:#039; }
|
86
|
+
|
87
|
+
.cl { color:#B06; font-weight:bold; }
|
88
|
+
.co { color:#036; font-weight:bold; }
|
89
|
+
.cr { color:#0A0; }
|
90
|
+
.cv { color:#369; }
|
91
|
+
.df { color:#099; font-weight:bold; }
|
92
|
+
.di { color:#088; font-weight:bold; }
|
93
|
+
.dl { color:black; }
|
94
|
+
.do { color:#970; }
|
95
|
+
.ds { color:#D42; font-weight:bold; }
|
96
|
+
.e { color:#666; font-weight:bold; }
|
97
|
+
.er { color:#F00; background-color:#FAA; }
|
98
|
+
.ex { color:#F00; font-weight:bold; }
|
99
|
+
.fl { color:#60E; font-weight:bold; }
|
100
|
+
.fu { color:#06B; font-weight:bold; }
|
101
|
+
.gv { color:#d70; font-weight:bold; }
|
102
|
+
.hx { color:#058; font-weight:bold; }
|
103
|
+
.i { color:#00D; font-weight:bold; }
|
104
|
+
.ic { color:#B44; font-weight:bold; }
|
105
|
+
.in { color:#B2B; font-weight:bold; }
|
106
|
+
.iv { color:#33B; }
|
107
|
+
.la { color:#970; font-weight:bold; }
|
108
|
+
.lv { color:#963; }
|
109
|
+
.oc { color:#40E; font-weight:bold; }
|
110
|
+
.on { color:#000; font-weight:bold; }
|
111
|
+
.pc { color:#038; font-weight:bold; }
|
112
|
+
.pd { color:#369; font-weight:bold; }
|
113
|
+
.pp { color:#579; }
|
114
|
+
.pt { color:#339; font-weight:bold; }
|
115
|
+
.r { color:#080; font-weight:bold; }
|
116
|
+
|
117
|
+
.rx { background-color:#fff0ff; }
|
118
|
+
.rx .k { color:#808; }
|
119
|
+
.rx .dl { color:#404; }
|
120
|
+
.rx .mod { color:#C2C; }
|
121
|
+
.rx .fu { color:#404; font-weight: bold; }
|
122
|
+
|
123
|
+
.s { background-color:#fff0f0; }
|
124
|
+
.s .s { background-color:#ffe0e0; }
|
125
|
+
.s .s .s { background-color:#ffd0d0; }
|
126
|
+
.s .k { color:#D20; }
|
127
|
+
.s .dl { color:#710; }
|
128
|
+
|
129
|
+
.sh { background-color:#f0fff0; }
|
130
|
+
.sh .k { color:#2B2; }
|
131
|
+
.sh .dl { color:#161; }
|
132
|
+
|
133
|
+
.sy { color:#A60; }
|
134
|
+
.sy .k { color:#A60; }
|
135
|
+
.sy .dl { color:#630; }
|
136
|
+
|
137
|
+
.ta { color:#070; }
|
138
|
+
.tf { color:#070; font-weight:bold; }
|
139
|
+
.ts { color:#D70; font-weight:bold; }
|
140
|
+
.ty { color:#339; font-weight:bold; }
|
141
|
+
.v { color:#036; }
|
142
|
+
.xt { color:#444; }
|
143
|
+
TOKENS
|
144
|
+
|
145
|
+
DEFAULT_STYLESHEET = MAIN + TOKENS.gsub(/^(?!$)/, '.CodeRay ')
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end end
|
151
|
+
|
152
|
+
if $0 == __FILE__
|
153
|
+
require 'pp'
|
154
|
+
pp CodeRay::Encoders::HTML::CSS.new
|
155
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module CodeRay module Encoders
|
2
|
+
|
3
|
+
class HTML
|
4
|
+
|
5
|
+
ClassOfKind = {
|
6
|
+
:attribute_name => 'an',
|
7
|
+
:attribute_name_fat => 'af',
|
8
|
+
:attribute_value => 'av',
|
9
|
+
:attribute_value_fat => 'aw',
|
10
|
+
:bin => 'bi',
|
11
|
+
:char => 'ch',
|
12
|
+
:class => 'cl',
|
13
|
+
:class_variable => 'cv',
|
14
|
+
:color => 'cr',
|
15
|
+
:comment => 'c',
|
16
|
+
:constant => 'co',
|
17
|
+
:content => 'k',
|
18
|
+
:definition => 'df',
|
19
|
+
:delimiter => 'dl',
|
20
|
+
:directive => 'di',
|
21
|
+
:doc => 'do',
|
22
|
+
:doc_string => 'ds',
|
23
|
+
:error => 'er',
|
24
|
+
:escape => 'e',
|
25
|
+
:exception => 'ex',
|
26
|
+
:float => 'fl',
|
27
|
+
:function => 'fu',
|
28
|
+
:global_variable => 'gv',
|
29
|
+
:hex => 'hx',
|
30
|
+
:include => 'ic',
|
31
|
+
:instance_variable => 'iv',
|
32
|
+
:integer => 'i',
|
33
|
+
:interpreted => 'in',
|
34
|
+
:label => 'la',
|
35
|
+
:local_variable => 'lv',
|
36
|
+
:modifier => 'mod',
|
37
|
+
:oct => 'oc',
|
38
|
+
:operator_name => 'on',
|
39
|
+
:pre_constant => 'pc',
|
40
|
+
:pre_type => 'pt',
|
41
|
+
:predefined => 'pd',
|
42
|
+
:preprocessor => 'pp',
|
43
|
+
:regexp => 'rx',
|
44
|
+
:reserved => 'r',
|
45
|
+
:shell => 'sh',
|
46
|
+
:string => 's',
|
47
|
+
:symbol => 'sy',
|
48
|
+
:tag => 'ta',
|
49
|
+
:tag_fat => 'tf',
|
50
|
+
:tag_special => 'ts',
|
51
|
+
:type => 'ty',
|
52
|
+
:variable => 'v',
|
53
|
+
:xml_text => 'xt',
|
54
|
+
|
55
|
+
:ident => :NO_HIGHLIGHT, # 'id'
|
56
|
+
:operator => :NO_HIGHLIGHT, # 'op'
|
57
|
+
:space => :NO_HIGHLIGHT, # 'sp'
|
58
|
+
:plain => :NO_HIGHLIGHT,
|
59
|
+
}
|
60
|
+
ClassOfKind[:procedure] = ClassOfKind[:method] = ClassOfKind[:function]
|
61
|
+
ClassOfKind[:open] = ClassOfKind[:close] = ClassOfKind[:delimiter]
|
62
|
+
ClassOfKind[:nesting_delimiter] = ClassOfKind[:delimiter]
|
63
|
+
ClassOfKind[:escape] = ClassOfKind[:delimiter]
|
64
|
+
ClassOfKind.default = ClassOfKind[:error] or raise 'no class found for :error!'
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
module CodeRay
|
2
|
+
module Encoders
|
3
|
+
|
4
|
+
class HTML
|
5
|
+
|
6
|
+
# This module is included in the output String from thew HTML Encoder.
|
7
|
+
#
|
8
|
+
# It provides methods like wrap, div, page etc.
|
9
|
+
#
|
10
|
+
# Remember to use #clone instead of #dup to keep the modules the object was
|
11
|
+
# extended with.
|
12
|
+
#
|
13
|
+
# TODO: more doc.
|
14
|
+
module Output
|
15
|
+
|
16
|
+
class << self
|
17
|
+
|
18
|
+
# This makes Output look like a class.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
#
|
22
|
+
# a = Output.new '<span class="co">Code</span>'
|
23
|
+
# a.wrap! :page
|
24
|
+
def new string, element = nil
|
25
|
+
output = string.clone.extend self
|
26
|
+
output.wrapped_in = element
|
27
|
+
output
|
28
|
+
end
|
29
|
+
|
30
|
+
# Raises an exception if an object that doesn't respond to to_str is extended by Output,
|
31
|
+
# to prevent users from misuse. Use Module#remove_method to disable.
|
32
|
+
def extended o
|
33
|
+
warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str
|
34
|
+
end
|
35
|
+
|
36
|
+
def page_template_for_css css = :default
|
37
|
+
css = CSS::DEFAULT_STYLESHEET if css == :default
|
38
|
+
PAGE.apply 'CSS', css
|
39
|
+
end
|
40
|
+
|
41
|
+
# Define a new wrapper. This is meta programming.
|
42
|
+
def wrapper *wrappers
|
43
|
+
wrappers.each do |wrapper|
|
44
|
+
define_method wrapper do |*args|
|
45
|
+
wrap wrapper, *args
|
46
|
+
end
|
47
|
+
define_method "#{wrapper}!".to_sym do |*args|
|
48
|
+
wrap! wrapper, *args
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
wrapper :div, :span, :page
|
55
|
+
|
56
|
+
def wrapped_in
|
57
|
+
@wrapped_in ||= nil
|
58
|
+
end
|
59
|
+
attr_writer :wrapped_in
|
60
|
+
|
61
|
+
def wrapped_in? element
|
62
|
+
wrapped_in == element
|
63
|
+
end
|
64
|
+
|
65
|
+
def wrap_in template
|
66
|
+
clone.wrap_in! template
|
67
|
+
end
|
68
|
+
|
69
|
+
def wrap_in! template
|
70
|
+
Template.wrap! self, template, 'CONTENT'
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
def wrap! element, *args
|
75
|
+
return self if not element or element == wrapped_in
|
76
|
+
case element
|
77
|
+
when :div
|
78
|
+
raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil
|
79
|
+
wrap_in! DIV
|
80
|
+
when :span
|
81
|
+
raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil
|
82
|
+
wrap_in! SPAN
|
83
|
+
when :page
|
84
|
+
wrap! :div if wrapped_in? nil
|
85
|
+
raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div
|
86
|
+
wrap_in! Output.page_template_for_css
|
87
|
+
when nil
|
88
|
+
return self
|
89
|
+
else
|
90
|
+
raise "Unknown value %p for :wrap" % element
|
91
|
+
end
|
92
|
+
@wrapped_in = element
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
def wrap *args
|
97
|
+
clone.wrap!(*args)
|
98
|
+
end
|
99
|
+
|
100
|
+
def numerize! mode = :table, options = {}
|
101
|
+
return self unless mode
|
102
|
+
|
103
|
+
start = options.fetch :line_number_start, DEFAULT_OPTIONS[:line_number_start]
|
104
|
+
unless start.is_a? Integer
|
105
|
+
raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start
|
106
|
+
end
|
107
|
+
|
108
|
+
unless NUMERIZABLE_WRAPPINGS.include? options[:wrap]
|
109
|
+
raise ArgumentError, "Can't numerize, :wrap must be in %p, but is %p" % [NUMERIZABLE_WRAPPINGS, options[:wrap]]
|
110
|
+
end
|
111
|
+
|
112
|
+
bold_every = options.fetch :bold_every, DEFAULT_OPTIONS[:bold_every]
|
113
|
+
bolding =
|
114
|
+
if bold_every == :no_bolding or bold_every == 0
|
115
|
+
proc { |line| line.to_s }
|
116
|
+
elsif bold_every.is_a? Integer
|
117
|
+
proc do |line|
|
118
|
+
if line % bold_every == 0
|
119
|
+
"<strong>#{line}</strong>" # every bold_every-th number in bold
|
120
|
+
else
|
121
|
+
line.to_s
|
122
|
+
end
|
123
|
+
end
|
124
|
+
else
|
125
|
+
raise ArgumentError, "Invalid value %p for :bolding; :no_bolding or Integer expected." % bolding
|
126
|
+
end
|
127
|
+
|
128
|
+
line_count = count("\n")
|
129
|
+
line_count += 1 if self[-1] != ?\n
|
130
|
+
|
131
|
+
case mode
|
132
|
+
when :inline
|
133
|
+
max_width = (start + line_count).to_s.size
|
134
|
+
line = start
|
135
|
+
gsub!(/^/) do
|
136
|
+
line_number = bolding.call line
|
137
|
+
line += 1
|
138
|
+
"<span class=\"no\">#{ line_number.rjust(max_width) }</span> "
|
139
|
+
end
|
140
|
+
wrap! :div
|
141
|
+
|
142
|
+
when :table
|
143
|
+
# This is really ugly.
|
144
|
+
# Because even monospace fonts seem to have different heights when bold,
|
145
|
+
# I make the newline bold, both in the code and the line numbers.
|
146
|
+
# FIXME Still not working perfect for Mr. Internet Exploder
|
147
|
+
line_numbers = (start ... start + line_count).to_a.map(&bolding).join("\n")
|
148
|
+
line_numbers << "\n" # also for Mr. MS Internet Exploder :-/
|
149
|
+
line_numbers.gsub!(/\n/) { "<tt>\n</tt>" }
|
150
|
+
|
151
|
+
line_numbers_tpl = DIV_TABLE.apply('LINE_NUMBERS', line_numbers)
|
152
|
+
gsub!(/\n/) { "<tt>\n</tt>" }
|
153
|
+
wrap_in! line_numbers_tpl
|
154
|
+
@wrapped_in = :div
|
155
|
+
|
156
|
+
else
|
157
|
+
raise ArgumentError, "Unknown value %p for mode: :inline or :table expected" % mode
|
158
|
+
end
|
159
|
+
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
163
|
+
def numerize *args
|
164
|
+
clone.numerize!(*args)
|
165
|
+
end
|
166
|
+
|
167
|
+
class Template < String
|
168
|
+
|
169
|
+
def self.wrap! str, template, target
|
170
|
+
target = Regexp.new(Regexp.escape("<%#{target}%>"))
|
171
|
+
if template =~ target
|
172
|
+
str[0,0] = $`
|
173
|
+
str << $'
|
174
|
+
else
|
175
|
+
raise "Template target <%%%p%%> not found" % target
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def apply target, replacement
|
180
|
+
target = Regexp.new(Regexp.escape("<%#{target}%>"))
|
181
|
+
if self =~ target
|
182
|
+
Template.new($` + replacement + $')
|
183
|
+
else
|
184
|
+
raise "Template target <%%%p%%> not found" % target
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
module Simple
|
189
|
+
def ` str #`
|
190
|
+
Template.new str
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
extend Template::Simple
|
196
|
+
|
197
|
+
#-- don't include the templates in docu
|
198
|
+
|
199
|
+
SPAN = `<span class="CodeRay"><%CONTENT%></span>`
|
200
|
+
|
201
|
+
DIV = <<-`DIV`
|
202
|
+
<div class="CodeRay">
|
203
|
+
<div class="code"><pre><%CONTENT%></pre></div>
|
204
|
+
</div>
|
205
|
+
DIV
|
206
|
+
|
207
|
+
DIV_TABLE = <<-`DIV_TABLE`
|
208
|
+
<table class="CodeRay"> <tr>
|
209
|
+
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre><%LINE_NUMBERS%></pre></td>
|
210
|
+
<td class="code"><pre title="double click to expand" ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><%CONTENT%></pre></td>
|
211
|
+
</tr> </table>
|
212
|
+
DIV_TABLE
|
213
|
+
|
214
|
+
PAGE = <<-`PAGE`
|
215
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
216
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
217
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="de">
|
218
|
+
<head>
|
219
|
+
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
220
|
+
<title>CodeRay HTML Encoder Example</title>
|
221
|
+
<style type="text/css">
|
222
|
+
<%CSS%>
|
223
|
+
</style>
|
224
|
+
</head>
|
225
|
+
<body style="background-color: white;">
|
226
|
+
|
227
|
+
<%CONTENT%>
|
228
|
+
</body>
|
229
|
+
</html>
|
230
|
+
PAGE
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
end
|