aoeu

Ruby code posted by aoeu
created at 21 Mar 11:13

Edit | Back
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# encoding: utf-8

module Nanoc3::Filters
  class ColorizeSyntax < Nanoc3::Filter

    # The default colorizer to use for a language if the colorizer for that
    # language is not overridden.
    DEFAULT_COLORIZER = :coderay

    # Syntax-highlights code blocks in the given content. Code blocks should
    # be enclosed in `pre` elements that contain a `code` element. The code
    # element should have a class starting with `language-` and followed by
    # the programming language, as specified by HTML5.
    #
    # Options for individual colorizers will be taken from the {#run}
    # options’ value for the given colorizer. For example, if the filter is
    # invoked with a `:coderay => coderay_options_hash` option, the
    # `coderay_options_hash` hash will be passed to the CodeRay colorizer.
    #
    # Currently, only the `:coderay` and `:pygmentize` colorizers are
    # implemented. Additional colorizer implementations are welcome!
    #
    # @example Content that will be highlighted
    #
    #     <pre><code class="language-ruby">
    #     def foo
    #       "asdf"
    #     end
    #     </code></pre>
    #
    # @example Invoking the filter with custom parameters
    #
    #     filter :colorize_syntax,
    #            :colorizers => { :ruby => :coderay },
    #            :coderay    => { :line_numbers => :list }
    #
    # @param [String] content The content to filter
    #
    # @option params [Hash] :colorizers (DEFAULT_COLORIZER) A hash containing
    #   a mapping of programming languages (symbols, not strings) onto
    #   colorizers (symbols).
    #
    # @return [String] The filtered content
    def run(content, params={})
      require 'nokogiri'

      # Take colorizers from parameters
      @colorizers = Hash.new(DEFAULT_COLORIZER)
      (params[:colorizers] || {}).each_pair do |language, colorizer|
        @colorizers[language] = colorizer
      end

      # Colorize
      doc = Nokogiri::HTML.fragment(content)
      doc.css('pre > code[class*="language-"]').each do |element|
        # Get language
        match = element['class'].match(/(^| )language-([^ ]+)/)
        next if match.nil?
        language = match[2]

        # Highlight
        highlighted_code = highlight(element.inner_text, language, params)
        element.inner_html = highlighted_code
      end

      doc.to_html(:encoding => 'UTF-8')
    end

  private

    KNOWN_COLORIZERS = [ :coderay, :dummy, :pygmentize ]

    def highlight(code, language, params={})
      colorizer = @colorizers[language.to_sym]
      if KNOWN_COLORIZERS.include?(colorizer)
        send(colorizer, code, language, params[colorizer] || {})
      else
        raise RuntimeError, "I don’t know how to highlight code using the “#{colorizer}” colorizer"
      end
    end

    def coderay(code, language, params={})
      require 'coderay'

      ::CodeRay.scan(code, language).html(params)
    end

    def dummy(code, language, params={})
      code
    end

    def pygmentize(code, language, params={})
      IO.popen("pygmentize -l #{language} -f html", "r+") do |io|
        io.write(code)
        io.close_write
        highlighted_code = io.read

        doc = Nokogiri::HTML.fragment(highlighted_code)
        return doc.xpath('./div[@class="highlight"]/pre').inner_html
      end
    end

  end
end
3.35 KB in 4 ms with coderay