Module: Pygments::Popen

Extended by:
Popen
Includes:
POSIX::Spawn
Included in:
Pygments, Popen
Defined in:
lib/pygments/popen.rb

Instance Method Summary collapse

Instance Method Details

#alive?Boolean

Check for a @pid variable, and then hit `kill -0` with the pid to check if the pid is still in the process table. If this function gives us an ENOENT or ESRCH, we can also safely return false (no process to worry about). Defensively, if EPERM is raised, in a odd/rare dying process situation (e.g., mentos is checking on the pid of a dead process and the pid has already been re-used) we'll want to raise that as a more informative Mentos exception.

Returns true if the child is alive.

Returns:

  • (Boolean)


75
76
77
78
79
80
81
82
# File 'lib/pygments/popen.rb', line 75

def alive?
  return true if @pid && Process.kill(0, @pid)
  false
rescue Errno::ENOENT, Errno::ESRCH
  false
rescue Errno::EPERM
  raise MentosError, "EPERM checking if child process is alive."
end

#css(klass = '', opts = {}) ⇒ Object

Public: Return css for highlighted code



144
145
146
147
148
149
150
# File 'lib/pygments/popen.rb', line 144

def css(klass='', opts={})
  if klass.is_a?(Hash)
    opts = klass
    klass = ''
  end
  mentos(:css, ['html', klass], opts)
end

#filtersObject

Public: Return an array of all available filters



134
135
136
# File 'lib/pygments/popen.rb', line 134

def filters
  mentos(:get_all_filters)
end

#formattersObject

Public: Get an array of available Pygments formatters

Returns an array of formatters.



87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/pygments/popen.rb', line 87

def formatters
  mentos(:get_all_formatters).inject(Hash.new) do | hash, (name, desc, aliases) |
    # Remove the long-winded and repetitive 'Formatter' suffix
    name.sub!(/Formatter$/, '')
    hash[name] = {
      :name => name,
      :description => desc,
      :aliases => aliases
    }
    hash
  end
end

#highlight(code, opts = {}) ⇒ Object

Public: Highlight code.

Takes a first-position argument of the code to be highlighted, and a second-position hash of various arguments specifiying highlighting properties.



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/pygments/popen.rb', line 174

def highlight(code, opts={})
  # If the caller didn't give us any code, we have nothing to do,
  # so return right away.
  return code if code.nil? || code.empty?

  # Callers pass along options in the hash
  opts[:options] ||= {}

  # Default to utf-8 for the output encoding, if not given.
  opts[:options][:outencoding] ||= 'utf-8'

  # Get back the string from mentos and force encoding if we can
  str = mentos(:highlight, nil, opts, code)
  str.force_encoding(opts[:options][:outencoding]) if str.respond_to?(:force_encoding)
  str
end

#lexer_name_for(*args) ⇒ Object

Public: Return the name of a lexer.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/pygments/popen.rb', line 153

def lexer_name_for(*args)
  # Pop off the last arg if it's a hash, which becomes our opts
  if args.last.is_a?(Hash)
    opts = args.pop
  else
    opts = {}
  end

  if args.last.is_a?(String)
    code = args.pop
  else
    code = nil
  end

  mentos(:lexer_name_for, args, opts, code)
end

#lexersObject

Public: Get all lexers from a serialized array. This avoids needing to spawn mentos when it's not really needed (e.g,. one-off jobs, loading the Rails env, etc).

Should be preferred to #lexers!

Returns an array of lexers



107
108
109
110
111
112
113
114
115
# File 'lib/pygments/popen.rb', line 107

def lexers
  begin
    lexer_file = File.expand_path('../../../lexers', __FILE__)
    raw = File.open(lexer_file, "r").read
    Marshal.load(raw)
  rescue Errno::ENOENT
    raise MentosError, "Error loading lexer file. Was it created and vendored?"
  end
end

#lexers!Object

Public: Get back all available lexers from mentos itself

Returns an array of lexers



120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/pygments/popen.rb', line 120

def lexers!
  mentos(:get_all_lexers).inject(Hash.new) do |hash, lxr|
    name = lxr[0]
    hash[name] = {
      :name => name,
      :aliases => lxr[1],
      :filenames => lxr[2],
      :mimetypes => lxr[3]
    }
    hash
  end
end

#start(pygments_path = File.expand_path('../../../vendor/pygments-main/', __FILE__)) ⇒ Object

Get things started by opening a pipe to mentos (the freshmaker), a Python process that talks to the Pygments library. We'll talk back and forth across this pipe.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/pygments/popen.rb', line 22

def start(pygments_path = File.expand_path('../../../vendor/pygments-main/', __FILE__))
  begin
    @log = Logger.new(ENV['MENTOS_LOG'] ||= '/dev/null')
    @log.level = Logger::INFO
    @log.datetime_format = "%Y-%m-%d %H:%M "
  rescue
    @log = Logger.new('/dev/null')
  end

  ENV['PYGMENTS_PATH'] = pygments_path

  # Make sure we kill off the child when we're done
  at_exit { stop "Exiting" }

  # A pipe to the mentos python process. #popen4 gives us
  # the pid and three IO objects to write and read.
  @pid, @in, @out, @err = popen4(File.expand_path('../mentos.py', __FILE__))
  @log.info "[#{Time.now.iso8601}] Starting pid #{@pid.to_s} with fd #{@out.to_i.to_s}."
end

#stop(reason) ⇒ Object

Stop the child process by issuing a kill -9.

We then call waitpid() with the pid, which waits for that particular child and reaps it.

kill() can set errno to ESRCH if, for some reason, the file is gone; regardless the final outcome of this method will be to set our @pid variable to nil.

Technically, kill() can also fail with EPERM or EINVAL (wherein the signal isn't sent); but we have permissions, and we're not doing anything invalid here.



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/pygments/popen.rb', line 54

def stop(reason)
  if @pid
    begin
      Process.kill('KILL', @pid)
      Process.waitpid(@pid)
    rescue Errno::ESRCH, Errno::ECHILD
    end
  end
  @log.info "[#{Time.now.iso8601}] Killing pid: #{@pid.to_s}. Reason: #{reason}"
  @pid = nil
end

#stylesObject

Public: Return an array of all available styles



139
140
141
# File 'lib/pygments/popen.rb', line 139

def styles
  mentos(:get_all_styles)
end