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 / .svn / pristine / d8 / d8ff1c547a8ab5f2037b019f178ac4f2175d8b5d.svn-base @ 1297:0a574315af3e

History | View | Annotate | Download (5.91 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
    
12
    extend PluginHost
13
    plugin_path File.dirname(__FILE__), 'encoders'
14
    
15
    # = Encoder
16
    #
17
    # The Encoder base class. Together with Scanner and
18
    # Tokens, it forms the highlighting triad.
19
    #
20
    # Encoder instances take a Tokens object and do something with it.
21
    #
22
    # The most common Encoder is surely the HTML encoder
23
    # (CodeRay::Encoders::HTML). It highlights the code in a colorful
24
    # html page.
25
    # If you want the highlighted code in a div or a span instead,
26
    # use its subclasses Div and Span.
27
    class Encoder
28
      extend Plugin
29
      plugin_host Encoders
30
      
31
      class << self
32
        
33
        # If FILE_EXTENSION isn't defined, this method returns the
34
        # downcase class name instead.
35
        def const_missing sym
36
          if sym == :FILE_EXTENSION
37
            (defined?(@plugin_id) && @plugin_id || name[/\w+$/].downcase).to_s
38
          else
39
            super
40
          end
41
        end
42
        
43
        # The default file extension for output file of this encoder class.
44
        def file_extension
45
          self::FILE_EXTENSION
46
        end
47
        
48
      end
49
      
50
      # Subclasses are to store their default options in this constant.
51
      DEFAULT_OPTIONS = { }
52
      
53
      # The options you gave the Encoder at creating.
54
      attr_accessor :options, :scanner
55
      
56
      # Creates a new Encoder.
57
      # +options+ is saved and used for all encode operations, as long
58
      # as you don't overwrite it there by passing additional options.
59
      #
60
      # Encoder objects provide three encode methods:
61
      # - encode simply takes a +code+ string and a +lang+
62
      # - encode_tokens expects a +tokens+ object instead
63
      #
64
      # Each method has an optional +options+ parameter. These are
65
      # added to the options you passed at creation.
66
      def initialize options = {}
67
        @options = self.class::DEFAULT_OPTIONS.merge options
68
        @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = false
69
      end
70
      
71
      # Encode a Tokens object.
72
      def encode_tokens tokens, options = {}
73
        options = @options.merge options
74
        @scanner = tokens.scanner if tokens.respond_to? :scanner
75
        setup options
76
        compile tokens, options
77
        finish options
78
      end
79
      
80
      # Encode the given +code+ using the Scanner for +lang+.
81
      def encode code, lang, options = {}
82
        options = @options.merge options
83
        @scanner = Scanners[lang].new code, CodeRay.get_scanner_options(options).update(:tokens => self)
84
        setup options
85
        @scanner.tokenize
86
        finish options
87
      end
88
      
89
      # You can use highlight instead of encode, if that seems
90
      # more clear to you.
91
      alias highlight encode
92
      
93
      # The default file extension for this encoder.
94
      def file_extension
95
        self.class.file_extension
96
      end
97
      
98
      def << token
99
        unless @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN
100
          warn 'Using old Tokens#<< interface.'
101
          @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = true
102
        end
103
        self.token(*token)
104
      end
105
      
106
      # Called with +content+ and +kind+ of the currently scanned token.
107
      # For simple scanners, it's enougth to implement this method.
108
      #
109
      # By default, it calls text_token, begin_group, end_group, begin_line,
110
      # or end_line, depending on the +content+.
111
      def token content, kind
112
        case content
113
        when String
114
          text_token content, kind
115
        when :begin_group
116
          begin_group kind
117
        when :end_group
118
          end_group kind
119
        when :begin_line
120
          begin_line kind
121
        when :end_line
122
          end_line kind
123
        else
124
          raise ArgumentError, 'Unknown token content type: %p, kind = %p' % [content, kind]
125
        end
126
      end
127
      
128
      # Called for each text token ([text, kind]), where text is a String.
129
      def text_token text, kind
130
        @out << text
131
      end
132
      
133
      # Starts a token group with the given +kind+.
134
      def begin_group kind
135
      end
136
      
137
      # Ends a token group with the given +kind+.
138
      def end_group kind
139
      end
140
      
141
      # Starts a new line token group with the given +kind+.
142
      def begin_line kind
143
      end
144
      
145
      # Ends a new line token group with the given +kind+.
146
      def end_line kind
147
      end
148
      
149
    protected
150
      
151
      # Called with merged options before encoding starts.
152
      # Sets @out to an empty string.
153
      #
154
      # See the HTML Encoder for an example of option caching.
155
      def setup options
156
        @out = get_output(options)
157
      end
158
      
159
      def get_output options
160
        options[:out] || ''
161
      end
162
      
163
      # Append data.to_s to the output. Returns the argument.
164
      def output data
165
        @out << data.to_s
166
        data
167
      end
168
      
169
      # Called with merged options after encoding starts.
170
      # The return value is the result of encoding, typically @out.
171
      def finish options
172
        @out
173
      end
174
      
175
      # Do the encoding.
176
      #
177
      # The already created +tokens+ object must be used; it must be a
178
      # Tokens object.
179
      def compile tokens, options = {}
180
        content = nil
181
        for item in tokens
182
          if item.is_a? Array
183
            raise ArgumentError, 'Two-element array tokens are no longer supported.'
184
          end
185
          if content
186
            token content, item
187
            content = nil
188
          else
189
            content = item
190
          end
191
        end
192
        raise 'odd number list for Tokens' if content
193
      end
194
      
195
      alias tokens compile
196
      public :tokens
197
      
198
    end
199
    
200
  end
201
end