To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / .svn / pristine / d8 / d8ff1c547a8ab5f2037b019f178ac4f2175d8b5d.svn-base @ 1297:0a574315af3e
History | View | Annotate | Download (5.91 KB)
| 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 |
|
| 12 |
extend PluginHost |
| 13 |
plugin_path File.dirname(__FILE__), 'encoders' |
| 14 |
|
| 15 |
# = Encoder |
| 16 |
# |
| 17 |
# The Encoder base class. Together with Scanner and |
| 18 |
# Tokens, it forms the highlighting triad. |
| 19 |
# |
| 20 |
# Encoder instances take a Tokens object and do something with it. |
| 21 |
# |
| 22 |
# The most common Encoder is surely the HTML encoder |
| 23 |
# (CodeRay::Encoders::HTML). It highlights the code in a colorful |
| 24 |
# html page. |
| 25 |
# If you want the highlighted code in a div or a span instead, |
| 26 |
# use its subclasses Div and Span. |
| 27 |
class Encoder |
| 28 |
extend Plugin |
| 29 |
plugin_host Encoders |
| 30 |
|
| 31 |
class << self |
| 32 |
|
| 33 |
# If FILE_EXTENSION isn't defined, this method returns the |
| 34 |
# downcase class name instead. |
| 35 |
def const_missing sym |
| 36 |
if sym == :FILE_EXTENSION |
| 37 |
(defined?(@plugin_id) && @plugin_id || name[/\w+$/].downcase).to_s |
| 38 |
else |
| 39 |
super |
| 40 |
end |
| 41 |
end |
| 42 |
|
| 43 |
# The default file extension for output file of this encoder class. |
| 44 |
def file_extension |
| 45 |
self::FILE_EXTENSION |
| 46 |
end |
| 47 |
|
| 48 |
end |
| 49 |
|
| 50 |
# Subclasses are to store their default options in this constant. |
| 51 |
DEFAULT_OPTIONS = { }
|
| 52 |
|
| 53 |
# The options you gave the Encoder at creating. |
| 54 |
attr_accessor :options, :scanner |
| 55 |
|
| 56 |
# Creates a new Encoder. |
| 57 |
# +options+ is saved and used for all encode operations, as long |
| 58 |
# as you don't overwrite it there by passing additional options. |
| 59 |
# |
| 60 |
# Encoder objects provide three encode methods: |
| 61 |
# - encode simply takes a +code+ string and a +lang+ |
| 62 |
# - encode_tokens expects a +tokens+ object instead |
| 63 |
# |
| 64 |
# Each method has an optional +options+ parameter. These are |
| 65 |
# added to the options you passed at creation. |
| 66 |
def initialize options = {}
|
| 67 |
@options = self.class::DEFAULT_OPTIONS.merge options |
| 68 |
@@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = false |
| 69 |
end |
| 70 |
|
| 71 |
# Encode a Tokens object. |
| 72 |
def encode_tokens tokens, options = {}
|
| 73 |
options = @options.merge options |
| 74 |
@scanner = tokens.scanner if tokens.respond_to? :scanner |
| 75 |
setup options |
| 76 |
compile tokens, options |
| 77 |
finish options |
| 78 |
end |
| 79 |
|
| 80 |
# Encode the given +code+ using the Scanner for +lang+. |
| 81 |
def encode code, lang, options = {}
|
| 82 |
options = @options.merge options |
| 83 |
@scanner = Scanners[lang].new code, CodeRay.get_scanner_options(options).update(:tokens => self) |
| 84 |
setup options |
| 85 |
@scanner.tokenize |
| 86 |
finish options |
| 87 |
end |
| 88 |
|
| 89 |
# You can use highlight instead of encode, if that seems |
| 90 |
# more clear to you. |
| 91 |
alias highlight encode |
| 92 |
|
| 93 |
# The default file extension for this encoder. |
| 94 |
def file_extension |
| 95 |
self.class.file_extension |
| 96 |
end |
| 97 |
|
| 98 |
def << token |
| 99 |
unless @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN |
| 100 |
warn 'Using old Tokens#<< interface.' |
| 101 |
@@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = true |
| 102 |
end |
| 103 |
self.token(*token) |
| 104 |
end |
| 105 |
|
| 106 |
# Called with +content+ and +kind+ of the currently scanned token. |
| 107 |
# For simple scanners, it's enougth to implement this method. |
| 108 |
# |
| 109 |
# By default, it calls text_token, begin_group, end_group, begin_line, |
| 110 |
# or end_line, depending on the +content+. |
| 111 |
def token content, kind |
| 112 |
case content |
| 113 |
when String |
| 114 |
text_token content, kind |
| 115 |
when :begin_group |
| 116 |
begin_group kind |
| 117 |
when :end_group |
| 118 |
end_group kind |
| 119 |
when :begin_line |
| 120 |
begin_line kind |
| 121 |
when :end_line |
| 122 |
end_line kind |
| 123 |
else |
| 124 |
raise ArgumentError, 'Unknown token content type: %p, kind = %p' % [content, kind] |
| 125 |
end |
| 126 |
end |
| 127 |
|
| 128 |
# Called for each text token ([text, kind]), where text is a String. |
| 129 |
def text_token text, kind |
| 130 |
@out << text |
| 131 |
end |
| 132 |
|
| 133 |
# Starts a token group with the given +kind+. |
| 134 |
def begin_group kind |
| 135 |
end |
| 136 |
|
| 137 |
# Ends a token group with the given +kind+. |
| 138 |
def end_group kind |
| 139 |
end |
| 140 |
|
| 141 |
# Starts a new line token group with the given +kind+. |
| 142 |
def begin_line kind |
| 143 |
end |
| 144 |
|
| 145 |
# Ends a new line token group with the given +kind+. |
| 146 |
def end_line kind |
| 147 |
end |
| 148 |
|
| 149 |
protected |
| 150 |
|
| 151 |
# Called with merged options before encoding starts. |
| 152 |
# Sets @out to an empty string. |
| 153 |
# |
| 154 |
# See the HTML Encoder for an example of option caching. |
| 155 |
def setup options |
| 156 |
@out = get_output(options) |
| 157 |
end |
| 158 |
|
| 159 |
def get_output options |
| 160 |
options[:out] || '' |
| 161 |
end |
| 162 |
|
| 163 |
# Append data.to_s to the output. Returns the argument. |
| 164 |
def output data |
| 165 |
@out << data.to_s |
| 166 |
data |
| 167 |
end |
| 168 |
|
| 169 |
# Called with merged options after encoding starts. |
| 170 |
# The return value is the result of encoding, typically @out. |
| 171 |
def finish options |
| 172 |
@out |
| 173 |
end |
| 174 |
|
| 175 |
# Do the encoding. |
| 176 |
# |
| 177 |
# The already created +tokens+ object must be used; it must be a |
| 178 |
# Tokens object. |
| 179 |
def compile tokens, options = {}
|
| 180 |
content = nil |
| 181 |
for item in tokens |
| 182 |
if item.is_a? Array |
| 183 |
raise ArgumentError, 'Two-element array tokens are no longer supported.' |
| 184 |
end |
| 185 |
if content |
| 186 |
token content, item |
| 187 |
content = nil |
| 188 |
else |
| 189 |
content = item |
| 190 |
end |
| 191 |
end |
| 192 |
raise 'odd number list for Tokens' if content |
| 193 |
end |
| 194 |
|
| 195 |
alias tokens compile |
| 196 |
public :tokens |
| 197 |
|
| 198 |
end |
| 199 |
|
| 200 |
end |
| 201 |
end |