Chris@210: # = CodeRay Library Chris@210: # Chris@210: # CodeRay is a Ruby library for syntax highlighting. Chris@210: # Chris@210: # I try to make CodeRay easy to use and intuitive, but at the same time fully featured, complete, Chris@210: # fast and efficient. Chris@210: # Chris@210: # See README. Chris@210: # Chris@210: # It consists mainly of Chris@210: # * the main engine: CodeRay (Scanners::Scanner, Tokens/TokenStream, Encoders::Encoder), PluginHost Chris@210: # * the scanners in CodeRay::Scanners Chris@210: # * the encoders in CodeRay::Encoders Chris@210: # Chris@210: # Here's a fancy graphic to light up this gray docu: Chris@210: # Chris@210: # http://cycnus.de/raindark/coderay/scheme.png Chris@210: # Chris@210: # == Documentation Chris@210: # Chris@210: # See CodeRay, Encoders, Scanners, Tokens. Chris@210: # Chris@210: # == Usage Chris@210: # Chris@210: # Remember you need RubyGems to use CodeRay, unless you have it in your load path. Run Ruby with Chris@210: # -rubygems option if required. Chris@210: # Chris@210: # === Highlight Ruby code in a string as html Chris@210: # Chris@210: # require 'coderay' Chris@210: # print CodeRay.scan('puts "Hello, world!"', :ruby).html Chris@210: # Chris@210: # # prints something like this: Chris@210: # puts "Hello, world!" Chris@210: # Chris@210: # Chris@210: # === Highlight C code from a file in a html div Chris@210: # Chris@210: # require 'coderay' Chris@210: # print CodeRay.scan(File.read('ruby.h'), :c).div Chris@210: # print CodeRay.scan_file('ruby.h').html.div Chris@210: # Chris@210: # You can include this div in your page. The used CSS styles can be printed with Chris@210: # Chris@210: # % coderay_stylesheet Chris@210: # Chris@210: # === Highlight without typing too much Chris@210: # Chris@210: # If you are one of the hasty (or lazy, or extremely curious) people, just run this file: Chris@210: # Chris@210: # % ruby -rubygems /path/to/coderay/coderay.rb > example.html Chris@210: # Chris@210: # and look at the file it created in your browser. Chris@210: # Chris@210: # = CodeRay Module Chris@210: # Chris@210: # The CodeRay module provides convenience methods for the engine. Chris@210: # Chris@210: # * The +lang+ and +format+ arguments select Scanner and Encoder to use. These are Chris@210: # simply lower-case symbols, like :python or :html. Chris@210: # * All methods take an optional hash as last parameter, +options+, that is send to Chris@210: # the Encoder / Scanner. Chris@210: # * Input and language are always sorted in this order: +code+, +lang+. Chris@210: # (This is in alphabetical order, if you need a mnemonic ;) Chris@210: # Chris@210: # You should be able to highlight everything you want just using these methods; Chris@210: # so there is no need to dive into CodeRay's deep class hierarchy. Chris@210: # Chris@210: # The examples in the demo directory demonstrate common cases using this interface. Chris@210: # Chris@210: # = Basic Access Ways Chris@210: # Chris@210: # Read this to get a general view what CodeRay provides. Chris@210: # Chris@210: # == Scanning Chris@210: # Chris@210: # Scanning means analysing an input string, splitting it up into Tokens. Chris@210: # Each Token knows about what type it is: string, comment, class name, etc. Chris@210: # Chris@210: # Each +lang+ (language) has its own Scanner; for example, :ruby code is Chris@210: # handled by CodeRay::Scanners::Ruby. Chris@210: # Chris@210: # CodeRay.scan:: Scan a string in a given language into Tokens. Chris@210: # This is the most common method to use. Chris@210: # CodeRay.scan_file:: Scan a file and guess the language using FileType. Chris@210: # Chris@210: # The Tokens object you get from these methods can encode itself; see Tokens. Chris@210: # Chris@210: # == Encoding Chris@210: # Chris@210: # Encoding means compiling Tokens into an output. This can be colored HTML or Chris@210: # LaTeX, a textual statistic or just the number of non-whitespace tokens. Chris@210: # Chris@210: # Each Encoder provides output in a specific +format+, so you select Encoders via Chris@210: # formats like :html or :statistic. Chris@210: # Chris@210: # CodeRay.encode:: Scan and encode a string in a given language. Chris@210: # CodeRay.encode_tokens:: Encode the given tokens. Chris@210: # CodeRay.encode_file:: Scan a file, guess the language using FileType and encode it. Chris@210: # Chris@210: # == Streaming Chris@210: # Chris@210: # Streaming saves RAM by running Scanner and Encoder in some sort of Chris@210: # pipe mode; see TokenStream. Chris@210: # Chris@210: # CodeRay.scan_stream:: Scan in stream mode. Chris@210: # Chris@210: # == All-in-One Encoding Chris@210: # Chris@210: # CodeRay.encode:: Highlight a string with a given input and output format. Chris@210: # Chris@210: # == Instanciating Chris@210: # Chris@210: # You can use an Encoder instance to highlight multiple inputs. This way, the setup Chris@210: # for this Encoder must only be done once. Chris@210: # Chris@210: # CodeRay.encoder:: Create an Encoder instance with format and options. Chris@210: # CodeRay.scanner:: Create an Scanner instance for lang, with '' as default code. Chris@210: # Chris@210: # To make use of CodeRay.scanner, use CodeRay::Scanner::code=. Chris@210: # Chris@210: # The scanning methods provide more flexibility; we recommend to use these. Chris@210: # Chris@210: # == Reusing Scanners and Encoders Chris@210: # Chris@210: # If you want to re-use scanners and encoders (because that is faster), see Chris@210: # CodeRay::Duo for the most convenient (and recommended) interface. Chris@210: module CodeRay Chris@210: Chris@210: $CODERAY_DEBUG ||= false Chris@210: Chris@210: # Version: Major.Minor.Teeny[.Revision] Chris@210: # Major: 0 for pre-stable, 1 for stable Chris@210: # Minor: feature milestone Chris@210: # Teeny: development state, 0 for pre-release Chris@210: # Revision: Subversion Revision number (generated on rake gem:make) Chris@210: VERSION = '0.9.7' Chris@210: Chris@210: require 'coderay/tokens' Chris@210: require 'coderay/token_classes' Chris@210: require 'coderay/scanner' Chris@210: require 'coderay/encoder' Chris@210: require 'coderay/duo' Chris@210: require 'coderay/style' Chris@210: Chris@210: Chris@210: class << self Chris@210: Chris@210: # Scans the given +code+ (a String) with the Scanner for +lang+. Chris@210: # Chris@210: # This is a simple way to use CodeRay. Example: Chris@210: # require 'coderay' Chris@210: # page = CodeRay.scan("puts 'Hello, world!'", :ruby).html Chris@210: # Chris@210: # See also demo/demo_simple. Chris@210: def scan code, lang, options = {}, &block Chris@210: scanner = Scanners[lang].new code, options, &block Chris@210: scanner.tokenize Chris@210: end Chris@210: Chris@210: # Scans +filename+ (a path to a code file) with the Scanner for +lang+. Chris@210: # Chris@210: # If +lang+ is :auto or omitted, the CodeRay::FileType module is used to Chris@210: # determine it. If it cannot find out what type it is, it uses Chris@210: # CodeRay::Scanners::Plaintext. Chris@210: # Chris@210: # Calls CodeRay.scan. Chris@210: # Chris@210: # Example: Chris@210: # require 'coderay' Chris@210: # page = CodeRay.scan_file('some_c_code.c').html Chris@210: def scan_file filename, lang = :auto, options = {}, &block Chris@210: file = IO.read filename Chris@210: if lang == :auto Chris@210: require 'coderay/helpers/file_type' Chris@210: lang = FileType.fetch filename, :plaintext, true Chris@210: end Chris@210: scan file, lang, options = {}, &block Chris@210: end Chris@210: Chris@210: # Scan the +code+ (a string) with the scanner for +lang+. Chris@210: # Chris@210: # Calls scan. Chris@210: # Chris@210: # See CodeRay.scan. Chris@210: def scan_stream code, lang, options = {}, &block Chris@210: options[:stream] = true Chris@210: scan code, lang, options, &block Chris@210: end Chris@210: Chris@210: # Encode a string in Streaming mode. Chris@210: # Chris@210: # This starts scanning +code+ with the the Scanner for +lang+ Chris@210: # while encodes the output with the Encoder for +format+. Chris@210: # +options+ will be passed to the Encoder. Chris@210: # Chris@210: # See CodeRay::Encoder.encode_stream Chris@210: def encode_stream code, lang, format, options = {} Chris@210: encoder(format, options).encode_stream code, lang, options Chris@210: end Chris@210: Chris@210: # Encode a string. Chris@210: # Chris@210: # This scans +code+ with the the Scanner for +lang+ and then Chris@210: # encodes it with the Encoder for +format+. Chris@210: # +options+ will be passed to the Encoder. Chris@210: # Chris@210: # See CodeRay::Encoder.encode Chris@210: def encode code, lang, format, options = {} Chris@210: encoder(format, options).encode code, lang, options Chris@210: end Chris@210: Chris@210: # Highlight a string into a HTML
. Chris@210: # Chris@210: # CSS styles use classes, so you have to include a stylesheet Chris@210: # in your output. Chris@210: # Chris@210: # See encode. Chris@210: def highlight code, lang, options = { :css => :class }, format = :div Chris@210: encode code, lang, format, options Chris@210: end Chris@210: Chris@210: # Encode pre-scanned Tokens. Chris@210: # Use this together with CodeRay.scan: Chris@210: # Chris@210: # require 'coderay' Chris@210: # Chris@210: # # Highlight a short Ruby code example in a HTML span Chris@210: # tokens = CodeRay.scan '1 + 2', :ruby Chris@210: # puts CodeRay.encode_tokens(tokens, :span) Chris@210: # Chris@210: def encode_tokens tokens, format, options = {} Chris@210: encoder(format, options).encode_tokens tokens, options Chris@210: end Chris@210: Chris@210: # Encodes +filename+ (a path to a code file) with the Scanner for +lang+. Chris@210: # Chris@210: # See CodeRay.scan_file. Chris@210: # Notice that the second argument is the output +format+, not the input language. Chris@210: # Chris@210: # Example: Chris@210: # require 'coderay' Chris@210: # page = CodeRay.encode_file 'some_c_code.c', :html Chris@210: def encode_file filename, format, options = {} Chris@210: tokens = scan_file filename, :auto, get_scanner_options(options) Chris@210: encode_tokens tokens, format, options Chris@210: end Chris@210: Chris@210: # Highlight a file into a HTML
. Chris@210: # Chris@210: # CSS styles use classes, so you have to include a stylesheet Chris@210: # in your output. Chris@210: # Chris@210: # See encode. Chris@210: def highlight_file filename, options = { :css => :class }, format = :div Chris@210: encode_file filename, format, options Chris@210: end Chris@210: Chris@210: # Finds the Encoder class for +format+ and creates an instance, passing Chris@210: # +options+ to it. Chris@210: # Chris@210: # Example: Chris@210: # require 'coderay' Chris@210: # Chris@210: # stats = CodeRay.encoder(:statistic) Chris@210: # stats.encode("puts 17 + 4\n", :ruby) Chris@210: # Chris@210: # puts '%d out of %d tokens have the kind :integer.' % [ Chris@210: # stats.type_stats[:integer].count, Chris@210: # stats.real_token_count Chris@210: # ] Chris@210: # #-> 2 out of 4 tokens have the kind :integer. Chris@210: def encoder format, options = {} Chris@210: Encoders[format].new options Chris@210: end Chris@210: Chris@210: # Finds the Scanner class for +lang+ and creates an instance, passing Chris@210: # +options+ to it. Chris@210: # Chris@210: # See Scanner.new. Chris@210: def scanner lang, options = {} Chris@210: Scanners[lang].new '', options Chris@210: end Chris@210: Chris@210: # Extract the options for the scanner from the +options+ hash. Chris@210: # Chris@210: # Returns an empty Hash if :scanner_options is not set. Chris@210: # Chris@210: # This is used if a method like CodeRay.encode has to provide options Chris@210: # for Encoder _and_ scanner. Chris@210: def get_scanner_options options Chris@210: options.fetch :scanner_options, {} Chris@210: end Chris@210: Chris@210: end Chris@210: Chris@210: # This Exception is raised when you try to stream with something that is not Chris@210: # capable of streaming. Chris@210: class NotStreamableError < Exception Chris@210: def initialize obj Chris@210: @obj = obj Chris@210: end Chris@210: Chris@210: def to_s Chris@210: '%s is not Streamable!' % @obj.class Chris@210: end Chris@210: end Chris@210: Chris@210: # A dummy module that is included by subclasses of CodeRay::Scanner an CodeRay::Encoder Chris@210: # to show that they are able to handle streams. Chris@210: module Streamable Chris@210: end Chris@210: Chris@210: end Chris@210: Chris@210: # Run a test script. Chris@210: if $0 == __FILE__ Chris@210: $stderr.print 'Press key to print demo.'; gets Chris@210: # Just use this file as an example of Ruby code. Chris@210: code = File.read(__FILE__)[/module CodeRay.*/m] Chris@210: print CodeRay.scan(code, :ruby).html Chris@210: end