summaryrefslogtreecommitdiff
path: root/lib/coderay/duo.rb
blob: d8b064d58edc4d642db450859ff7d048c3ca87d6 (plain)
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
($:.unshift '..'; require 'coderay') unless defined? CodeRay
module CodeRay
  
  # = Duo
  #
  # A Duo is a convenient way to use CodeRay. You just create a Duo,
  # giving it a lang (language of the input code) and a format (desired
  # output format), and call Duo#highlight with the code.
  # 
  # Duo makes it easy to re-use both scanner and encoder for a repetitive
  # task. It also provides a very easy interface syntax:
  # 
  #   require 'coderay'
  #   CodeRay::Duo[:python, :div].highlight 'import this'
  # 
  # Until you want to do uncommon things with CodeRay, I recommend to use
  # this method, since it takes care of everything.
  class Duo

    attr_accessor :lang, :format, :options
    
    # Create a new Duo, holding a lang and a format to highlight code.
    # 
    # simple:
    #   CodeRay::Duo[:ruby, :page].highlight 'bla 42'
    # 
    # with options:
    #   CodeRay::Duo[:ruby, :html, :hint => :debug].highlight '????::??'
    # 
    # alternative syntax without options:
    #   CodeRay::Duo[:ruby => :statistic].encode 'class << self; end'
    # 
    # alternative syntax with options:
    #   CodeRay::Duo[{ :ruby => :statistic }, :do => :something].encode 'abc'
    # 
    # The options are forwarded to scanner and encoder
    # (see CodeRay.get_scanner_options).
    def initialize lang = nil, format = nil, options = {}
      if format == nil and lang.is_a? Hash and lang.size == 1
        @lang = lang.keys.first
        @format = lang[@lang]
      else
        @lang = lang
        @format = format
      end
      @options = options
    end
    
    class << self
      # To allow calls like Duo[:ruby, :html].highlight.
      alias [] new
    end
    
    # The scanner of the duo. Only created once.
    def scanner
      @scanner ||= CodeRay.scanner @lang, CodeRay.get_scanner_options(@options)
    end
    
    # The encoder of the duo. Only created once.
    def encoder
      @encoder ||= CodeRay.encoder @format, @options
    end
    
    # Tokenize and highlight the code using +scanner+ and +encoder+.
    def encode code, options = {}
      options = @options.merge options
      encoder.encode(code, @lang, options)
    end
    alias highlight encode
    
    # Allows to use Duo like a proc object:
    # 
    #  CodeRay::Duo[:python => :yaml].call(code)
    # 
    # or, in Ruby 1.9 and later:
    # 
    #  CodeRay::Duo[:python => :yaml].(code)
    alias call encode
    
  end
  
end

if $0 == __FILE__
  $VERBOSE = true
  $: << File.join(File.dirname(__FILE__), '..')
  eval DATA.read, nil, $0, __LINE__ + 4
end

__END__
require 'test/unit'

class DuoTest < Test::Unit::TestCase
  
  def test_two_arguments
    duo = CodeRay::Duo[:ruby, :html]
    assert_kind_of CodeRay::Scanners[:ruby], duo.scanner
    assert_kind_of CodeRay::Encoders[:html], duo.encoder
  end
  
  def test_two_hash
    duo = CodeRay::Duo[:ruby => :html]
    assert_kind_of CodeRay::Scanners[:ruby], duo.scanner
    assert_kind_of CodeRay::Encoders[:html], duo.encoder
  end
  
  def test_call
    duo = CodeRay::Duo[:python => :yaml]
    assert_equal <<-'YAML', duo.call('def test: "pass"')
--- 
- - def
  - :keyword
- - " "
  - :space
- - test
  - :method
- - ":"
  - :operator
- - " "
  - :space
- - :begin_group
  - :string
- - "\""
  - :delimiter
- - pass
  - :content
- - "\""
  - :delimiter
- - :end_group
  - :string
    YAML
  end
  
end