To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / vendor / gems / coderay-0.9.7 / lib / coderay / encoder.rb @ 442:753f1380d6bc

History | View | Annotate | Download (6.41 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
    extend PluginHost
12
    plugin_path File.dirname(__FILE__), 'encoders'
13

    
14
    # = Encoder
15
    #
16
    # The Encoder base class. Together with Scanner and
17
    # Tokens, it forms the highlighting triad.
18
    #
19
    # Encoder instances take a Tokens object and do something with it.
20
    #
21
    # The most common Encoder is surely the HTML encoder
22
    # (CodeRay::Encoders::HTML). It highlights the code in a colorful
23
    # html page.
24
    # If you want the highlighted code in a div or a span instead,
25
    # use its subclasses Div and Span.
26
    class Encoder
27
      extend Plugin
28
      plugin_host Encoders
29

    
30
      attr_reader :token_stream
31

    
32
      class << self
33

    
34
        # Returns if the Encoder can be used in streaming mode.
35
        def streamable?
36
          is_a? Streamable
37
        end
38

    
39
        # If FILE_EXTENSION isn't defined, this method returns the
40
        # downcase class name instead.
41
        def const_missing sym
42
          if sym == :FILE_EXTENSION
43
            plugin_id
44
          else
45
            super
46
          end
47
        end
48

    
49
      end
50

    
51
      # Subclasses are to store their default options in this constant.
52
      DEFAULT_OPTIONS = { :stream => false }
53

    
54
      # The options you gave the Encoder at creating.
55
      attr_accessor :options
56

    
57
      # Creates a new Encoder.
58
      # +options+ is saved and used for all encode operations, as long
59
      # as you don't overwrite it there by passing additional options.
60
      #
61
      # Encoder objects provide three encode methods:
62
      # - encode simply takes a +code+ string and a +lang+
63
      # - encode_tokens expects a +tokens+ object instead
64
      # - encode_stream is like encode, but uses streaming mode.
65
      #
66
      # Each method has an optional +options+ parameter. These are
67
      # added to the options you passed at creation.
68
      def initialize options = {}
69
        @options = self.class::DEFAULT_OPTIONS.merge options
70
        raise "I am only the basic Encoder class. I can't encode "\
71
          "anything. :( Use my subclasses." if self.class == Encoder
72
      end
73

    
74
      # Encode a Tokens object.
75
      def encode_tokens tokens, options = {}
76
        options = @options.merge options
77
        setup options
78
        compile tokens, options
79
        finish options
80
      end
81

    
82
      # Encode the given +code+ after tokenizing it using the Scanner
83
      # for +lang+.
84
      def encode code, lang, options = {}
85
        options = @options.merge options
86
        scanner_options = CodeRay.get_scanner_options(options)
87
        tokens = CodeRay.scan code, lang, scanner_options
88
        encode_tokens tokens, options
89
      end
90

    
91
      # You can use highlight instead of encode, if that seems
92
      # more clear to you.
93
      alias highlight encode
94

    
95
      # Encode the given +code+ using the Scanner for +lang+ in
96
      # streaming mode.
97
      def encode_stream code, lang, options = {}
98
        raise NotStreamableError, self unless kind_of? Streamable
99
        options = @options.merge options
100
        setup options
101
        scanner_options = CodeRay.get_scanner_options options
102
        @token_stream =
103
          CodeRay.scan_stream code, lang, scanner_options, &self
104
        finish options
105
      end
106

    
107
      # Behave like a proc. The token method is converted to a proc.
108
      def to_proc
109
        method(:token).to_proc
110
      end
111

    
112
      # Return the default file extension for outputs of this encoder.
113
      def file_extension
114
        self.class::FILE_EXTENSION
115
      end
116

    
117
    protected
118

    
119
      # Called with merged options before encoding starts.
120
      # Sets @out to an empty string.
121
      #
122
      # See the HTML Encoder for an example of option caching.
123
      def setup options
124
        @out = ''
125
      end
126

    
127
      # Called with +content+ and +kind+ of the currently scanned token.
128
      # For simple scanners, it's enougth to implement this method.
129
      #
130
      # By default, it calls text_token or block_token, depending on
131
      # whether +content+ is a String.
132
      def token content, kind
133
        encoded_token =
134
          if content.is_a? ::String
135
            text_token content, kind
136
          elsif content.is_a? ::Symbol
137
            block_token content, kind
138
          else
139
            raise 'Unknown token content type: %p' % [content]
140
          end
141
        append_encoded_token_to_output encoded_token
142
      end
143
      
144
      def append_encoded_token_to_output encoded_token
145
        @out << encoded_token if encoded_token && defined?(@out) && @out
146
      end
147
      
148
      # Called for each text token ([text, kind]), where text is a String.
149
      def text_token text, kind
150
      end
151
      
152
      # Called for each block (non-text) token ([action, kind]),
153
      # where +action+ is a Symbol.
154
      # 
155
      # Calls open_token, close_token, begin_line, and end_line according to
156
      # the value of +action+.
157
      def block_token action, kind
158
        case action
159
        when :open
160
          open_token kind
161
        when :close
162
          close_token kind
163
        when :begin_line
164
          begin_line kind
165
        when :end_line
166
          end_line kind
167
        else
168
          raise 'unknown block action: %p' % action
169
        end
170
      end
171
      
172
      # Called for each block token at the start of the block ([:open, kind]).
173
      def open_token kind
174
      end
175
      
176
      # Called for each block token end of the block ([:close, kind]).
177
      def close_token kind
178
      end
179
      
180
      # Called for each line token block at the start of the line ([:begin_line, kind]).
181
      def begin_line kind
182
      end
183
      
184
      # Called for each line token block at the end of the line ([:end_line, kind]).
185
      def end_line kind
186
      end
187

    
188
      # Called with merged options after encoding starts.
189
      # The return value is the result of encoding, typically @out.
190
      def finish options
191
        @out
192
      end
193

    
194
      # Do the encoding.
195
      #
196
      # The already created +tokens+ object must be used; it can be a
197
      # TokenStream or a Tokens object.
198
      if RUBY_VERSION >= '1.9'
199
        def compile tokens, options
200
          for text, kind in tokens
201
            token text, kind
202
          end
203
        end
204
      else
205
        def compile tokens, options
206
          tokens.each(&self)
207
        end
208
      end
209

    
210
    end
211

    
212
  end
213
end