| |   |
| 1 | # = CodeRay Library |
| 2 | # |
| 3 | # $Id: coderay.rb 70 2006-07-11 13:42:07Z 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 these methods; |
| 73 | # so there is no need to dive into CodeRay's deep class hierarchy. |
| 74 | # |
| 75 | # The examples 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::Ruby. |
| 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: Major.Minor.Teeny[.Revision] |
| 132 | # Major: 0 for pre-release |
| 133 | # Minor: odd for beta, even for stable |
| 134 | # Teeny: development state |
| 135 | # Revision: Subversion Revision number (generated on rake) |
| 136 | Version = '0.7.2' |
| 137 | |
| 138 | require 'coderay/tokens' |
| 139 | require 'coderay/scanner' |
| 140 | require 'coderay/encoder' |
| 141 | require 'coderay/duo' |
| 142 | require 'coderay/style' |
| 143 | |
| 144 | |
| 145 | class << self |
| 146 | |
| 147 | # Scans the given +code+ (a String) with the Scanner for +lang+. |
| 148 | # |
| 149 | # This is a simple way to use CodeRay. Example: |
| 150 | # require 'coderay' |
| 151 | # page = CodeRay.scan("puts 'Hello, world!'", :ruby).html |
| 152 | # |
| 153 | # See also demo/demo_simple. |
| 154 | def scan code, lang, options = {}, &block |
| 155 | scanner = Scanners[lang].new code, options, &block |
| 156 | scanner.tokenize |
| 157 | end |
| 158 | |
| 159 | # Scans +filename+ (a path to a code file) with the Scanner for +lang+. |
| 160 | # |
| 161 | # If +lang+ is :auto or omitted, the CodeRay::FileType module is used to |
| 162 | # determine it. If it cannot find out what type it is, it uses |
| 163 | # CodeRay::Scanners::Plaintext. |
| 164 | # |
| 165 | # Calls CodeRay.scan. |
| 166 | # |
| 167 | # Example: |
| 168 | # require 'coderay' |
| 169 | # page = CodeRay.scan_file('some_c_code.c').html |
| 170 | def scan_file filename, lang = :auto, options = {}, &block |
| 171 | file = IO.read filename |
| 172 | if lang == :auto |
| 173 | require 'coderay/helpers/filetype' |
| 174 | lang = FileType.fetch filename, :plaintext, true |
| 175 | end |
| 176 | scan file, lang, options = {}, &block |
| 177 | end |
| 178 | |
| 179 | # Scan the +code+ (a string) with the scanner for +lang+. |
| 180 | # |
| 181 | # Calls scan. |
| 182 | # |
| 183 | # See CodeRay.scan. |
| 184 | def scan_stream code, lang, options = {}, &block |
| 185 | options[:stream] = true |
| 186 | scan code, lang, options, &block |
| 187 | end |
| 188 | |
| 189 | # Encode a string in Streaming mode. |
| 190 | # |
| 191 | # This starts scanning +code+ with the the Scanner for +lang+ |
| 192 | # while encodes the output with the Encoder for +format+. |
| 193 | # +options+ will be passed to the Encoder. |
| 194 | # |
| 195 | # See CodeRay::Encoder.encode_stream |
| 196 | def encode_stream code, lang, format, options = {} |
| 197 | encoder(format, options).encode_stream code, lang, options |
| 198 | end |
| 199 | |
| 200 | # Encode a string. |
| 201 | # |
| 202 | # This scans +code+ with the the Scanner for +lang+ and then |
| 203 | # encodes it with the Encoder for +format+. |
| 204 | # +options+ will be passed to the Encoder. |
| 205 | # |
| 206 | # See CodeRay::Encoder.encode |
| 207 | def encode code, lang, format, options = {} |
| 208 | encoder(format, options).encode code, lang, options |
| 209 | end |
| 210 | |
| 211 | # Highlight a string into a HTML <div>. |
| 212 | # |
| 213 | # CSS styles use classes, so you have to include a stylesheet |
| 214 | # in your output. |
| 215 | # |
| 216 | # See encode. |
| 217 | def highlight code, lang, options = { :css => :class }, format = :div |
| 218 | encode code, lang, format, options |
| 219 | end |
| 220 | |
| 221 | # Encode pre-scanned Tokens. |
| 222 | # Use this together with CodeRay.scan: |
| 223 | # |
| 224 | # require 'coderay' |
| 225 | # |
| 226 | # # Highlight a short Ruby code example in a HTML span |
| 227 | # tokens = CodeRay.scan '1 + 2', :ruby |
| 228 | # puts CodeRay.encode_tokens(tokens, :span) |
| 229 | # |
| 230 | def encode_tokens tokens, format, options = {} |
| 231 | encoder(format, options).encode_tokens tokens, options |
| 232 | end |
| 233 | |
| 234 | # Encodes +filename+ (a path to a code file) with the Scanner for +lang+. |
| 235 | # |
| 236 | # See CodeRay.scan_file. |
| 237 | # Notice that the second argument is the output +format+, not the input language. |
| 238 | # |
| 239 | # Example: |
| 240 | # require 'coderay' |
| 241 | # page = CodeRay.encode_file 'some_c_code.c', :html |
| 242 | def encode_file filename, format, options = {} |
| 243 | tokens = scan_file filename, :auto, get_scanner_options(options) |
| 244 | encode_tokens tokens, format, options |
| 245 | end |
| 246 | |
| 247 | # Highlight a file into a HTML <div>. |
| 248 | # |
| 249 | # CSS styles use classes, so you have to include a stylesheet |
| 250 | # in your output. |
| 251 | # |
| 252 | # See encode. |
| 253 | def highlight_file filename, options = { :css => :class }, format = :div |
| 254 | encode_file filename, format, options |
| 255 | end |
| 256 | |
| 257 | # Finds the Encoder class for +format+ and creates an instance, passing |
| 258 | # +options+ to it. |
| 259 | # |
| 260 | # Example: |
| 261 | # require 'coderay' |
| 262 | # |
| 263 | # stats = CodeRay.encoder(:statistic) |
| 264 | # stats.encode("puts 17 + 4\n", :ruby) |
| 265 | # |
| 266 | # puts '%d out of %d tokens have the kind :integer.' % [ |
| 267 | # stats.type_stats[:integer].count, |
| 268 | # stats.real_token_count |
| 269 | # ] |
| 270 | # #-> 2 out of 4 tokens have the kind :integer. |
| 271 | def encoder format, options = {} |
| 272 | Encoders[format].new options |
| 273 | end |
| 274 | |
| 275 | # Finds the Scanner class for +lang+ and creates an instance, passing |
| 276 | # +options+ to it. |
| 277 | # |
| 278 | # See Scanner.new. |
| 279 | def scanner lang, options = {} |
| 280 | Scanners[lang].new '', options |
| 281 | end |
| 282 | |
| 283 | # Extract the options for the scanner from the +options+ hash. |
| 284 | # |
| 285 | # Returns an empty Hash if <tt>:scanner_options</tt> is not set. |
| 286 | # |
| 287 | # This is used if a method like CodeRay.encode has to provide options |
| 288 | # for Encoder _and_ scanner. |
| 289 | def get_scanner_options options |
| 290 | options.fetch :scanner_options, {} |
| 291 | end |
| 292 | |
| 293 | end |
| 294 | |
| 295 | # This Exception is raised when you try to stream with something that is not |
| 296 | # capable of streaming. |
| 297 | class NotStreamableError < Exception |
| 298 | def initialize obj |
| 299 | @obj = obj |
| 300 | end |
| 301 | |
| 302 | def to_s |
| 303 | '%s is not Streamable!' % @obj.class |
| 304 | end |
| 305 | end |
| 306 | |
| 307 | # A dummy module that is included by subclasses of CodeRay::Scanner an CodeRay::Encoder |
| 308 | # to show that they are able to handle streams. |
| 309 | module Streamable |
| 310 | end |
| 311 | |
| 312 | end |
| 313 | |
| 314 | # Run a test script. |
| 315 | if $0 == __FILE__ |
| 316 | $stderr.print 'Press key to print demo.'; gets |
| 317 | code = File.read($0)[/module CodeRay.*/m] |
| 318 | print CodeRay.scan(code, :ruby).html |
| 319 | end |
| toggle raw diff |
--- /dev/null
+++ b/vendor/coderay.rb
@@ -0,0 +1,319 @@
+# = CodeRay Library
+#
+# $Id: coderay.rb 70 2006-07-11 13:42:07Z murphy $
+#
+# CodeRay is a Ruby library for syntax highlighting.
+#
+# I try to make CodeRay easy to use and intuitive, but at the same time fully featured, complete,
+# fast and efficient.
+#
+# See README.
+#
+# It consists mainly of
+# * the main engine: CodeRay (Scanners::Scanner, Tokens/TokenStream, Encoders::Encoder), PluginHost
+# * the scanners in CodeRay::Scanners
+# * the encoders in CodeRay::Encoders
+#
+# Here's a fancy graphic to light up this gray docu:
+#
+# http://rd.cYcnus.de/coderay/scheme.png
+#
+# == Documentation
+#
+# See CodeRay, Encoders, Scanners, Tokens.
+#
+# == Usage
+#
+# Remember you need RubyGems to use CodeRay. Run Ruby with -rubygems option
+# if required.
+#
+# === Highlight Ruby code in a string as html
+#
+# require 'coderay'
+# print CodeRay.scan('puts "Hello, world!"', :ruby).html
+#
+# # prints something like this:
+# puts <span class="s">"Hello, world!"</span>
+#
+#
+# === Highlight C code from a file in a html div
+#
+# require 'coderay'
+# print CodeRay.scan(File.read('ruby.h'), :c).div
+# print CodeRay.scan_file('ruby.h').html.div
+#
+# You can include this div in your page. The used CSS styles can be printed with
+#
+# % ruby -rcoderay -e "print CodeRay::Encoders[:html]::CSS"
+#
+# === Highlight without typing too much
+#
+# If you are one of the hasty (or lazy, or extremely curious) people, just run this file:
+#
+# % ruby -rubygems coderay.rb
+#
+# If the output was to fast for you, try
+#
+# % ruby -rubygems coderay.rb > example.html
+#
+# and look at the file it created.
+#
+# = CodeRay Module
+#
+# The CodeRay module provides convenience methods for the engine.
+#
+# * The +lang+ and +format+ arguments select Scanner and Encoder to use. These are
+# simply lower-case symbols, like <tt>:python</tt> or <tt>:html</tt>.
+# * All methods take an optional hash as last parameter, +options+, that is send to
+# the Encoder / Scanner.
+# * Input and language are always sorted in this order: +code+, +lang+.
+# (This is in alphabetical order, if you need a mnemonic ;)
+#
+# You should be able to highlight everything you want just using these methods;
+# so there is no need to dive into CodeRay's deep class hierarchy.
+#
+# The examples in the demo directory demonstrate common cases using this interface.
+#
+# = Basic Access Ways
+#
+# Read this to get a general view what CodeRay provides.
+#
+# == Scanning
+#
+# Scanning means analysing an input string, splitting it up into Tokens.
+# Each Token knows about what type it is: string, comment, class name, etc.
+#
+# Each +lang+ (language) has its own Scanner; for example, <tt>:ruby</tt> code is
+# handled by CodeRay::Scanners::Ruby.
+#
+# CodeRay.scan:: Scan a string in a given language into Tokens.
+# This is the most common method to use.
+# CodeRay.scan_file:: Scan a file and guess the language using FileType.
+#
+# The Tokens object you get from these methods can encode itself; see Tokens.
+#
+# == Encoding
+#
+# Encoding means compiling Tokens into an output. This can be colored HTML or
+# LaTeX, a textual statistic or just the number of non-whitespace tokens.
+#
+# Each Encoder provides output in a specific +format+, so you select Encoders via
+# formats like <tt>:html</tt> or <tt>:statistic</tt>.
+#
+# CodeRay.encode:: Scan and encode a string in a given language.
+# CodeRay.encode_tokens:: Encode the given tokens.
+# CodeRay.encode_file:: Scan a file, guess the language using FileType and encode it.
+#
+# == Streaming
+#
+# Streaming saves RAM by running Scanner and Encoder in some sort of
+# pipe mode; see TokenStream.
+#
+# CodeRay.scan_stream:: Scan in stream mode.
+#
+# == All-in-One Encoding
+#
+# CodeRay.encode:: Highlight a string with a given input and output format.
+#
+# == Instanciating
+#
+# You can use an Encoder instance to highlight multiple inputs. This way, the setup
+# for this Encoder must only be done once.
+#
+# CodeRay.encoder:: Create an Encoder instance with format and options.
+#
+# There is no CodeRay.scanner method because Scanners are bound to an input string
+# on creation; you can't re-use them with another string.
+#
+# The scanning methods provide more flexibility; we recommend to use these.
+module CodeRay
+
+ # Version: Major.Minor.Teeny[.Revision]
+ # Major: 0 for pre-release
+ # Minor: odd for beta, even for stable
+ # Teeny: development state
+ # Revision: Subversion Revision number (generated on rake)
+ Version = '0.7.2'
+
+ require 'coderay/tokens'
+ require 'coderay/scanner'
+ require 'coderay/encoder'
+ require 'coderay/duo'
+ require 'coderay/style'
+
+
+ class << self
+
+ # Scans the given +code+ (a String) with the Scanner for +lang+.
+ #
+ # This is a simple way to use CodeRay. Example:
+ # require 'coderay'
+ # page = CodeRay.scan("puts 'Hello, world!'", :ruby).html
+ #
+ # See also demo/demo_simple.
+ def scan code, lang, options = {}, &block
+ scanner = Scanners[lang].new code, options, &block
+ scanner.tokenize
+ end
+
+ # Scans +filename+ (a path to a code file) with the Scanner for +lang+.
+ #
+ # If +lang+ is :auto or omitted, the CodeRay::FileType module is used to
+ # determine it. If it cannot find out what type it is, it uses
+ # CodeRay::Scanners::Plaintext.
+ #
+ # Calls CodeRay.scan.
+ #
+ # Example:
+ # require 'coderay'
+ # page = CodeRay.scan_file('some_c_code.c').html
+ def scan_file filename, lang = :auto, options = {}, &block
+ file = IO.read filename
+ if lang == :auto
+ require 'coderay/helpers/filetype'
+ lang = FileType.fetch filename, :plaintext, true
+ end
+ scan file, lang, options = {}, &block
+ end
+
+ # Scan the +code+ (a string) with the scanner for +lang+.
+ #
+ # Calls scan.
+ #
+ # See CodeRay.scan.
+ def scan_stream code, lang, options = {}, &block
+ options[:stream] = true
+ scan code, lang, options, &block
+ end
+
+ # Encode a string in Streaming mode.
+ #
+ # This starts scanning +code+ with the the Scanner for +lang+
+ # while encodes the output with the Encoder for +format+.
+ # +options+ will be passed to the Encoder.
+ #
+ # See CodeRay::Encoder.encode_stream
+ def encode_stream code, lang, format, options = {}
+ encoder(format, options).encode_stream code, lang, options
+ end
+
+ # Encode a string.
+ #
+ # This scans +code+ with the the Scanner for +lang+ and then
+ # encodes it with the Encoder for +format+.
+ # +options+ will be passed to the Encoder.
+ #
+ # See CodeRay::Encoder.encode
+ def encode code, lang, format, options = {}
+ encoder(format, options).encode code, lang, options
+ end
+
+ # Highlight a string into a HTML <div>.
+ #
+ # CSS styles use classes, so you have to include a stylesheet
+ # in your output.
+ #
+ # See encode.
+ def highlight code, lang, options = { :css => :class }, format = :div
+ encode code, lang, format, options
+ end
+
+ # Encode pre-scanned Tokens.
+ # Use this together with CodeRay.scan:
+ #
+ # require 'coderay'
+ #
+ # # Highlight a short Ruby code example in a HTML span
+ # tokens = CodeRay.scan '1 + 2', :ruby
+ # puts CodeRay.encode_tokens(tokens, :span)
+ #
+ def encode_tokens tokens, format, options = {}
+ encoder(format, options).encode_tokens tokens, options
+ end
+
+ # Encodes +filename+ (a path to a code file) with the Scanner for +lang+.
+ #
+ # See CodeRay.scan_file.
+ # Notice that the second argument is the output +format+, not the input language.
+ #
+ # Example:
+ # require 'coderay'
+ # page = CodeRay.encode_file 'some_c_code.c', :html
+ def encode_file filename, format, options = {}
+ tokens = scan_file filename, :auto, get_scanner_options(options)
+ encode_tokens tokens, format, options
+ end
+
+ # Highlight a file into a HTML <div>.
+ #
+ # CSS styles use classes, so you have to include a stylesheet
+ # in your output.
+ #
+ # See encode.
+ def highlight_file filename, options = { :css => :class }, format = :div
+ encode_file filename, format, options
+ end
+
+ # Finds the Encoder class for +format+ and creates an instance, passing
+ # +options+ to it.
+ #
+ # Example:
+ # require 'coderay'
+ #
+ # stats = CodeRay.encoder(:statistic)
+ # stats.encode("puts 17 + 4\n", :ruby)
+ #
+ # puts '%d out of %d tokens have the kind :integer.' % [
+ # stats.type_stats[:integer].count,
+ # stats.real_token_count
+ # ]
+ # #-> 2 out of 4 tokens have the kind :integer.
+ def encoder format, options = {}
+ Encoders[format].new options
+ end
+
+ # Finds the Scanner class for +lang+ and creates an instance, passing
+ # +options+ to it.
+ #
+ # See Scanner.new.
+ def scanner lang, options = {}
+ Scanners[lang].new '', options
+ end
+
+ # Extract the options for the scanner from the +options+ hash.
+ #
+ # Returns an empty Hash if <tt>:scanner_options</tt> is not set.
+ #
+ # This is used if a method like CodeRay.encode has to provide options
+ # for Encoder _and_ scanner.
+ def get_scanner_options options
+ options.fetch :scanner_options, {}
+ end
+
+ end
+
+ # This Exception is raised when you try to stream with something that is not
+ # capable of streaming.
+ class NotStreamableError < Exception
+ def initialize obj
+ @obj = obj
+ end
+
+ def to_s
+ '%s is not Streamable!' % @obj.class
+ end
+ end
+
+ # A dummy module that is included by subclasses of CodeRay::Scanner an CodeRay::Encoder
+ # to show that they are able to handle streams.
+ module Streamable
+ end
+
+end
+
+# Run a test script.
+if $0 == __FILE__
+ $stderr.print 'Press key to print demo.'; gets
+ code = File.read($0)[/module CodeRay.*/m]
+ print CodeRay.scan(code, :ruby).html
+end |