summaryrefslogtreecommitdiff
path: root/lib/coderay/encoders/encoder.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/coderay/encoders/encoder.rb')
-rw-r--r--lib/coderay/encoders/encoder.rb190
1 files changed, 190 insertions, 0 deletions
diff --git a/lib/coderay/encoders/encoder.rb b/lib/coderay/encoders/encoder.rb
new file mode 100644
index 0000000..fa5695d
--- /dev/null
+++ b/lib/coderay/encoders/encoder.rb
@@ -0,0 +1,190 @@
+module CodeRay
+ module Encoders
+
+ # = 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
+ extend Plugin
+ plugin_host Encoders
+
+ class << self
+
+ # If FILE_EXTENSION isn't defined, this method returns the
+ # downcase class name instead.
+ def const_missing sym
+ if sym == :FILE_EXTENSION
+ (defined?(@plugin_id) && @plugin_id || name[/\w+$/].downcase).to_s
+ else
+ super
+ end
+ end
+
+ # The default file extension for output file of this encoder class.
+ def file_extension
+ self::FILE_EXTENSION
+ end
+
+ end
+
+ # Subclasses are to store their default options in this constant.
+ DEFAULT_OPTIONS = { }
+
+ # The options you gave the Encoder at creating.
+ attr_accessor :options, :scanner
+
+ # 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
+ #
+ # 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
+ @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = false
+ end
+
+ # Encode a Tokens object.
+ def encode_tokens tokens, options = {}
+ options = @options.merge options
+ @scanner = tokens.scanner if tokens.respond_to? :scanner
+ setup options
+ compile tokens, options
+ finish options
+ end
+
+ # Encode the given +code+ using the Scanner for +lang+.
+ def encode code, lang, options = {}
+ options = @options.merge options
+ @scanner = Scanners[lang].new code, CodeRay.get_scanner_options(options).update(:tokens => self)
+ setup options
+ @scanner.tokenize
+ finish options
+ end
+
+ # You can use highlight instead of encode, if that seems
+ # more clear to you.
+ alias highlight encode
+
+ # The default file extension for this encoder.
+ def file_extension
+ self.class.file_extension
+ end
+
+ def << token
+ unless @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN
+ warn 'Using old Tokens#<< interface.'
+ @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = true
+ end
+ self.token(*token)
+ end
+
+ # Called with +content+ and +kind+ of the currently scanned token.
+ # For simple scanners, it's enougth to implement this method.
+ #
+ # By default, it calls text_token, begin_group, end_group, begin_line,
+ # or end_line, depending on the +content+.
+ def token content, kind
+ case content
+ when String
+ text_token content, kind
+ when :begin_group
+ begin_group kind
+ when :end_group
+ end_group kind
+ when :begin_line
+ begin_line kind
+ when :end_line
+ end_line kind
+ else
+ raise ArgumentError, 'Unknown token content type: %p, kind = %p' % [content, kind]
+ end
+ end
+
+ # Called for each text token ([text, kind]), where text is a String.
+ def text_token text, kind
+ @out << text
+ end
+
+ # Starts a token group with the given +kind+.
+ def begin_group kind
+ end
+
+ # Ends a token group with the given +kind+.
+ def end_group kind
+ end
+
+ # Starts a new line token group with the given +kind+.
+ def begin_line kind
+ end
+
+ # Ends a new line token group with the given +kind+.
+ def end_line kind
+ 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 = get_output(options)
+ end
+
+ def get_output options
+ options[:out] || ''
+ end
+
+ # Append data.to_s to the output. Returns the argument.
+ def output data
+ @out << data.to_s
+ data
+ 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 must be a
+ # Tokens object.
+ def compile tokens, options = {}
+ content = nil
+ for item in tokens
+ if item.is_a? Array
+ raise ArgumentError, 'Two-element array tokens are no longer supported.'
+ end
+ if content
+ token content, item
+ content = nil
+ else
+ content = item
+ end
+ end
+ raise 'odd number list for Tokens' if content
+ end
+
+ alias tokens compile
+ public :tokens
+
+ end
+
+ end
+end