diff options
-rw-r--r-- | lib/coderay/encoder.rb | 426 | ||||
-rw-r--r-- | lib/coderay/scanner.rb | 84 |
2 files changed, 263 insertions, 247 deletions
diff --git a/lib/coderay/encoder.rb b/lib/coderay/encoder.rb index 4340b29..c5295be 100644 --- a/lib/coderay/encoder.rb +++ b/lib/coderay/encoder.rb @@ -1,216 +1,218 @@ module CodeRay
- # This module holds the Encoder class and its subclasses.
- # For example, the HTML encoder is named CodeRay::Encoders::HTML
- # can be found in coderay/encoders/html.
- #
- # Encoders also provides methods and constants for the register mechanism
- # and the [] method that returns the Encoder class belonging to the
- # given format.
- module Encoders
-
- # Raised if Encoders::[] fails because:
- # * a file could not be found
- # * the requested Encoder is not registered
- EncoderNotFound = Class.new Exception
-
- def Encoders.create_encoders_hash
- Hash.new do |h, lang|
- path = Encoders.path_to lang
- lang = lang.to_sym
- begin
- require path
- rescue LoadError
- raise EncoderNotFound, "#{path} not found."
- else
- # Encoder should have registered by now
- unless h[lang]
- raise EncoderNotFound, "No Encoder for #{lang} found in #{path}."
- end
- end
- h[lang]
- end
- end
-
- # Loaded Encoders are saved here.
- ENCODERS = create_encoders_hash
-
- class << self
-
- # Every Encoder class must register itself for one or more +formats+
- # by calling register_for, which calls this method.
- #
- # See CodeRay::Encoder.register_for.
- def register encoder_class, *formats
- for format in formats
- ENCODERS[format.to_sym] = encoder_class
- end
- end
-
- # Returns the Encoder for +lang+.
- #
- # Example:
- # require 'coderay'
- # yaml_encoder = CodeRay::Encoders[:yaml]
- def [] lang
- ENCODERS[lang]
- end
-
- # Alias for +[]+.
- alias load []
-
- # Returns the path to the encoder for format.
- def path_to plugin
- File.join 'coderay', 'encoders', "#{plugin}.rb"
- end
-
- end
-
-
- # = Encoder
- #
- # The Encoder base class. Together with Scanner and
- # Tokens, it forms the highlighting triad.
- #
- # Encoder instances take a Tokens object and do something with it.
- #
- # The most common Encoder is surely the HTML encoder
- # (CodeRay::Encoders::HTML). It highlights the code in a colorful
- # html page.
- # If you want the highlighted code in a div or a span instead,
- # use its subclasses Div and Span.
- class Encoder
-
- attr_reader :token_stream
-
- class << self
-
- # Register this class for the given langs.
- #
- # Example:
- # class MyEncoder < CodeRay::Encoders:Encoder
- # register_for :myenc
- # ...
- # end
- #
- # See Encoder.register.
- def register_for *args
- Encoders.register self, *args
- end
-
- # Returns if the Encoder can be used in streaming mode.
- def streamable?
- is_a? Streamable
- end
-
- # If FILE_EXTENSION isn't defined, this method returns the downcase
- # class name instead.
- def const_missing sym
- if sym == :FILE_EXTENSION
- sym.to_s.downcase
- else
- super
- end
- end
-
- end
-
- # Subclasses are to store their default options in this constant.
- DEFAULT_OPTIONS = { :stream => false }
-
- # The options you gave the Encoder at creating.
- attr_accessor :options
-
- # Creates a new Encoder.
- # +options+ is saved and used for all encode operations, as long as you
- # don't overwrite it there by passing additional options.
- #
- # Encoder objects provide three encode methods:
- # - encode simply takes a +code+ string and a +lang+
- # - encode_tokens expects a +tokens+ object instead
- # - encode_stream is like encode, but uses streaming mode.
- #
- # Each method has an optional +options+ parameter. These are added to
- # the options you passed at creation.
- def initialize options = {}
- @options = self.class::DEFAULT_OPTIONS.merge options
- raise "I am only the basic Encoder class. I can't encode anything. :(\n" +
- "Use my subclasses." if self.class == Encoder
- end
-
- # Encode a Tokens object.
- def encode_tokens tokens, options = {}
- options = @options.merge options
- setup options
- compile tokens, options
- finish options
- end
-
- # Encode the given +code+ after tokenizing it using the Scanner for
- # +lang+.
- def encode code, lang, options = {}
- options = @options.merge options
- scanner_options = get_scanner_options(options)
- tokens = CodeRay.scan code, lang, scanner_options
- encode_tokens tokens, options
- end
-
- # You can use highlight instead of encode, if that seems
- # more clear to you.
- alias highlight encode
-
- # Encode the given +code+ using the Scanner for +lang+ in streaming
- # mode.
- def encode_stream code, lang, options = {}
- raise NotStreamableError, self unless kind_of? Streamable
- options = @options.merge options
- setup options
- scanner_options = CodeRay.get_scanner_options options
- @token_stream = CodeRay.scan_stream code, lang, scanner_options, &self
- finish options
- end
-
- # Behave like a proc. The token method is converted to a proc.
- def to_proc
- method(:token).to_proc
- end
-
- protected
-
- # Called with merged options before encoding starts.
- # Sets @out to an empty string.
- #
- # See the HTML Encoder for an example of option caching.
- def setup options
- @out = ''
- end
-
- # Called with +text+ and +kind+ of the currently scanned token.
- # For simple scanners, it's enougth to implement this method.
- #
- # Raises a NotImplementedError exception if it is not overwritten in
- # subclass.
- def token text, kind
- raise NotImplementedError, "#{self.class}#token not implemented."
- end
-
- # Called with merged options after encoding starts.
- # The return value is the result of encoding, typically @out.
- def finish options
- @out
- end
-
- # Do the encoding.
- #
- # The already created +tokens+ object must be used; it can be a
- # TokenStream or a Tokens object.
- def compile tokens, options
- tokens.each(&self)
- end
-
- end
-
- end
+ # This module holds the Encoder class and its subclasses.
+ # For example, the HTML encoder is named CodeRay::Encoders::HTML
+ # can be found in coderay/encoders/html.
+ #
+ # Encoders also provides methods and constants for the register
+ # mechanism and the [] method that returns the Encoder class
+ # belonging to the given format.
+ module Encoders
+
+ # Raised if Encoders::[] fails because:
+ # * a file could not be found
+ # * the requested Encoder is not registered
+ EncoderNotFound = Class.new Exception
+
+ def Encoders.create_encoders_hash
+ Hash.new do |h, lang|
+ path = Encoders.path_to lang
+ lang = lang.to_sym
+ begin
+ require path
+ rescue LoadError
+ raise EncoderNotFound, "#{path} not found."
+ else
+ # Encoder should have registered by now
+ unless h[lang]
+ raise EncoderNotFound,
+ "No Encoder for #{lang} found in #{path}."
+ end
+ end
+ h[lang]
+ end
+ end
+
+ # Loaded Encoders are saved here.
+ ENCODERS = create_encoders_hash
+
+ class << self
+
+ # Every Encoder class must register itself for one or more
+ # +formats+ by calling register_for, which calls this method.
+ #
+ # See CodeRay::Encoder.register_for.
+ def register encoder_class, *formats
+ for format in formats
+ ENCODERS[format.to_sym] = encoder_class
+ end
+ end
+
+ # Returns the Encoder for +lang+.
+ #
+ # Example:
+ # require 'coderay'
+ # yaml_encoder = CodeRay::Encoders[:yaml]
+ def [] lang
+ ENCODERS[lang]
+ end
+
+ # Alias for +[]+.
+ alias load []
+
+ # Returns the path to the encoder for format.
+ def path_to plugin
+ File.join 'coderay', 'encoders', "#{plugin}.rb"
+ end
+
+ end
+
+
+ # = Encoder
+ #
+ # The Encoder base class. Together with Scanner and
+ # Tokens, it forms the highlighting triad.
+ #
+ # Encoder instances take a Tokens object and do something with it.
+ #
+ # The most common Encoder is surely the HTML encoder
+ # (CodeRay::Encoders::HTML). It highlights the code in a colorful
+ # html page.
+ # If you want the highlighted code in a div or a span instead,
+ # use its subclasses Div and Span.
+ class Encoder
+
+ attr_reader :token_stream
+
+ class << self
+
+ # Register this class for the given langs.
+ #
+ # Example:
+ # class MyEncoder < CodeRay::Encoders:Encoder
+ # register_for :myenc
+ # ...
+ # end
+ #
+ # See Encoder.register.
+ def register_for *args
+ Encoders.register self, *args
+ end
+
+ # Returns if the Encoder can be used in streaming mode.
+ def streamable?
+ is_a? Streamable
+ end
+
+ # If FILE_EXTENSION isn't defined, this method returns the
+ # downcase class name instead.
+ def const_missing sym
+ if sym == :FILE_EXTENSION
+ sym.to_s.downcase
+ else
+ super
+ end
+ end
+
+ end
+
+ # Subclasses are to store their default options in this constant.
+ DEFAULT_OPTIONS = { :stream => false }
+
+ # The options you gave the Encoder at creating.
+ attr_accessor :options
+
+ # Creates a new Encoder.
+ # +options+ is saved and used for all encode operations, as long
+ # as you don't overwrite it there by passing additional options.
+ #
+ # Encoder objects provide three encode methods:
+ # - encode simply takes a +code+ string and a +lang+
+ # - encode_tokens expects a +tokens+ object instead
+ # - encode_stream is like encode, but uses streaming mode.
+ #
+ # Each method has an optional +options+ parameter. These are added
+ # to the options you passed at creation.
+ def initialize options = {}
+ @options = self.class::DEFAULT_OPTIONS.merge options
+ raise "I am only the basic Encoder class. I can't encode anything. :(\n"\
+ "Use my subclasses." if self.class == Encoder
+ end
+
+ # Encode a Tokens object.
+ def encode_tokens tokens, options = {}
+ options = @options.merge options
+ setup options
+ compile tokens, options
+ finish options
+ end
+
+ # Encode the given +code+ after tokenizing it using the Scanner for
+ # +lang+.
+ def encode code, lang, options = {}
+ options = @options.merge options
+ scanner_options = CodeRay.get_scanner_options(options)
+ tokens = CodeRay.scan code, lang, scanner_options
+ encode_tokens tokens, options
+ end
+
+ # You can use highlight instead of encode, if that seems
+ # more clear to you.
+ alias highlight encode
+
+ # Encode the given +code+ using the Scanner for +lang+ in streaming
+ # mode.
+ def encode_stream code, lang, options = {}
+ raise NotStreamableError, self unless kind_of? Streamable
+ options = @options.merge options
+ setup options
+ scanner_options = CodeRay.get_scanner_options options
+ @token_stream =
+ CodeRay.scan_stream code, lang, scanner_options, &self
+ finish options
+ end
+
+ # Behave like a proc. The token method is converted to a proc.
+ def to_proc
+ method(:token).to_proc
+ end
+
+ protected
+
+ # Called with merged options before encoding starts.
+ # Sets @out to an empty string.
+ #
+ # See the HTML Encoder for an example of option caching.
+ def setup options
+ @out = ''
+ end
+
+ # Called with +text+ and +kind+ of the currently scanned token.
+ # For simple scanners, it's enougth to implement this method.
+ #
+ # Raises a NotImplementedError exception if it is not overwritten
+ # in subclass.
+ def token text, kind
+ raise NotImplementedError, "#{self.class}#token not implemented."
+ end
+
+ # Called with merged options after encoding starts.
+ # The return value is the result of encoding, typically @out.
+ def finish options
+ @out
+ end
+
+ # Do the encoding.
+ #
+ # The already created +tokens+ object must be used; it can be a
+ # TokenStream or a Tokens object.
+ def compile tokens, options
+ tokens.each(&self)
+ end
+
+ end
+
+ end
end
-# vim:sw=2:ts=2:et:tw=78
+# vim:sw=2:ts=2:noet:tw=78
diff --git a/lib/coderay/scanner.rb b/lib/coderay/scanner.rb index a74a736..58a92f7 100644 --- a/lib/coderay/scanner.rb +++ b/lib/coderay/scanner.rb @@ -4,9 +4,9 @@ module CodeRay # For example, the Ruby scanner is named CodeRay::Scanners::Ruby
# can be found in coderay/scanners/ruby.
#
- # Scanner also provides methods and constants for the register mechanism
- # and the [] method that returns the Scanner class belonging to the
- # given lang.
+ # Scanner also provides methods and constants for the register
+ # mechanism and the [] method that returns the Scanner class
+ # belonging to the given lang.
module Scanners
# Raised if Scanners[] fails because:
@@ -28,7 +28,10 @@ module CodeRay # register_for :ruby
def register scanner_class, *langs
for lang in langs
- raise ArgumentError, 'lang must be a Symbol, but it was a %s' % lang.class unless lang.is_a? Symbol
+ unless lang.is_a? Symbol
+ raise ArgumentError,
+ "lang must be a Symbol, but it was a #{lang.class}"
+ end
SCANNERS[lang] = scanner_class
end
end
@@ -43,8 +46,8 @@ module CodeRay # * a String containing only alphanumeric characters (\w+)
# * a Symbol
#
- # Strings are converted to lowercase symbols (so +'C'+ and +'c'+ load the
- # same scanner, namely the one registered for +:c+.)
+ # Strings are converted to lowercase symbols (so +'C'+ and +'c'+
+ # load the same scanner, namely the one registered for +:c+.)
#
# If the scanner isn't registered yet, it is searched.
# CodeRay expects that the scanner class is defined in
@@ -55,9 +58,10 @@ module CodeRay #
# If the file isn't found, a ScannerNotFound exception is raised
#
- # The scanner should register itself using +register+. If the scanner is
- # still not found (because has not registered or registered under another lang),
- # a ScannerNotFound exception is raised.
+ # The scanner should register itself using +register+. If the
+ # scanner is still not found (because has not registered or
+ # registered under another
+ # lang), a ScannerNotFound exception is raised.
def [] lang
lang = normalize lang
@@ -123,7 +127,8 @@ Known scanners: #{SCANNERS} elsif lang.nil?
:plaintext
else
- raise ArgumentError, "String or Symbol expected, but #{lang.class} given."
+ raise ArgumentError,
+ "String or Symbol expected, but #{lang.class} given."
end
end
@@ -151,7 +156,8 @@ Known scanners: #{SCANNERS} # # prints: (*==)++;
#
# OK, this is a very simple example :)
- # You can also use +map+, +any?+, +find+ and even +sort_by+, if you want.
+ # You can also use +map+, +any?+, +find+ and even +sort_by+,
+ # if you want.
class Scanner < StringScanner
# Raised if a Scanner fails while scanning
@@ -177,23 +183,26 @@ Known scanners: #{SCANNERS} def streamable?
is_a? Streamable
end
-
+
end
=begin
- ## Excluded for speed reasons - protected seems to make methods slow.
+ ## Excluded for speed reasons; protected seems to make methods slow.
# Save the StringScanner methods from being called.
# This would not be useful for highlighting.
- strscan_public_methods = StringScanner.instance_methods - StringScanner.ancestors[1].instance_methods
- protected(*strscan_public_methods)
+strscan_public_methods =
+ StringScanner.instance_methods - StringScanner.ancestors[1].instance_methods
+protected(*strscan_public_methods)
=end
+
# Creates a new Scanner.
#
- # * +code+ is the input String and is handled by the superclass StringScanner.
+ # * +code+ is the input String and is handled by the superclass
+ # StringScanner.
# * +options+ is a Hash with Symbols as keys.
- # It is merged with the default options of the class (you can overwrite
- # default options here.)
+ # It is merged with the default options of the class (you can
+ # overwrite default options here.)
# * +block+ is the callback for streamed highlighting.
#
# If you set :stream to +true+ in the options, the Scanner uses a
@@ -205,15 +214,18 @@ Known scanners: #{SCANNERS} raise "I am only the basic Scanner class. I can't scan anything. :(\n" +
"Use my subclasses." if self.class == Scanner
- # I love this hack. It seems to silence all dos/unix/mac newline problems.
+ # I love this hack. It seems to silence
+ # all dos/unix/mac newline problems.
super code.gsub(/\r\n?/, "\n")
if @options[:stream]
- warn "warning in CodeRay::Scanner.new: :stream is set, but no block was given" unless block_given?
+ warn "warning in CodeRay::Scanner.new: :stream is set, "\
+ "but no block was given" unless block_given?
raise NotStreamableError, self unless kind_of? Streamable
@tokens = TokenStream.new(&block)
else
- warn "warning in CodeRay::Scanner.new: Block given, but :stream is #{@options[:stream]}" if block_given?
+ warn "warning in CodeRay::Scanner.new: Block given, "\
+ "but :stream is #{@options[:stream]}" if block_given?
@tokens = Tokens.new
end
end
@@ -238,7 +250,8 @@ Known scanners: #{SCANNERS} # Traverses the tokens.
def each &block
- raise ArgumentError, 'Cannot traverse TokenStream.' if @options[:stream]
+ raise ArgumentError,
+ 'Cannot traverse TokenStream.' if @options[:stream]
tokens.each(&block)
end
include Enumerable
@@ -250,13 +263,14 @@ Known scanners: #{SCANNERS} def line
string[0..pos].count("\n") + 1
end
-
- protected
- # This is the central method, and often the only one a subclass implements.
+ protected
+
+ # This is the central method, and commonly the only one a subclass
+ # implements.
#
- # Subclasses must implement this method; it must return +tokens+ and must only
- # use Tokens#<< for storing scanned tokens.
+ # Subclasses must implement this method; it must return +tokens+
+ # and must only use Tokens#<< for storing scanned tokens!
def scan_tokens tokens, options
raise NotImplementedError, "#{self.class}#scan_tokens not implemented."
end
@@ -282,13 +296,13 @@ surrounding code: ***ERROR***
EOE
- File.basename(caller[0]),
- msg,
- tokens.last(10).map { |t| t.inspect }.join("\n"),
- line, pos,
- matched, bol?, eos?,
- string[pos-ambit,ambit],
- string[pos,ambit],
+ File.basename(caller[0]),
+ msg,
+ tokens.last(10).map { |t| t.inspect }.join("\n"),
+ line, pos,
+ matched, bol?, eos?,
+ string[pos-ambit,ambit],
+ string[pos,ambit],
]
end
@@ -297,4 +311,4 @@ surrounding code: end
end
-# vim:sw=2:ts=2:et:tw=78
+# vim:sw=2:ts=2:noet:tw=78
|