rygments 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rygments.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,86 @@
1
+ # Rygments
2
+
3
+ Rygments is a Ruby wrapper for the awesome Python based Pygments syntax
4
+ highlighter.
5
+
6
+ Rygments differs from other implementations in that it embeds a full
7
+ Python interpreter for the Pygments Python files as a Ruby C extension.
8
+ This enables Rygments to reach a level of performance that is equal to
9
+ invoking Pygments from a native Python application, and without the overhead forking
10
+ a new process. This difference in performance really pays off when
11
+ you are highlighting lots of smaller code fragments, e.g. for blog
12
+ posts.
13
+
14
+ Compared to Albino (another popular Pygments Ruby wrapper) Rygments is over 30% faster when using it to highlight all files from the Ruby 1.9.2 source code.
15
+
16
+ # Installation
17
+
18
+ ## Pygments
19
+
20
+ First, you need to make sure Pygments and the Python development headers are installed. How this can be done
21
+ depends on your platform.
22
+
23
+ ### Debian and Ubuntu Linux
24
+
25
+ sudo apt-get install python-dev python-pygments
26
+
27
+ ### OSX (Homebrew)
28
+
29
+ brew install pip && pip install pygments
30
+
31
+ The Python development headers are supplied with XCode.
32
+
33
+ ### OSX (Distutils)
34
+
35
+ sudo easy_install Pygments
36
+
37
+ The Python development headers are supplied with XCode.
38
+
39
+ ## Rygments
40
+
41
+ After installing Pygments you can install the Rygments gem via Rubygems:
42
+
43
+ gem install rygments
44
+
45
+ and you're good to go!
46
+
47
+ # Usage
48
+
49
+ Usage is easy. First you have to require the Rygments gem:
50
+
51
+ require "rygments"
52
+
53
+ Rygments then gives you two class methods that enable you to highlight code from wherever you want.
54
+
55
+ To highlight source code from a string use:
56
+
57
+ Rygments.highlight_string(source_code, lexer, formatter)
58
+
59
+ and to highlight source code from a file use:
60
+
61
+ Rygments.highlight_file(filename, lexer, formatter)
62
+
63
+ Both methods return a string containing the highlighted code.
64
+
65
+ The _lexer_ is a lowercase string specifying the programming language you want
66
+ to highlight for, e.g. `ruby` or `sass`.
67
+
68
+ The _formatter_ is a lowercase string specifying the kind of output you want,
69
+ e.g. `html` or `latex`.
70
+
71
+ A full list of lexers and formatters is available on the Pygments
72
+ website.
73
+
74
+ # Compatibility
75
+
76
+ Rygments has been tested on OSX Snow Leopard (10.6.6) and Ubuntu Linux 10.10. If you used it with success on a different platform then please let me know so I can extend this list.
77
+
78
+ # License
79
+
80
+ Copyright (c) 2011 Emil Loer <http://emilloer.com>
81
+
82
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
83
+
84
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
85
+
86
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,8 @@
1
+ require "rubygems"
2
+ require "rygments"
3
+
4
+ # Highlight a string with some HTML in it
5
+ puts Rygments.highlight_string("<div id=\"foo\">bar</div>", "html")
6
+
7
+ # Highlight this file
8
+ puts Rygments.highlight_file(__FILE__)
data/ext/extconf.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "mkmf"
2
+
3
+ extension_name = "wrapper"
4
+
5
+ dir_config(extension_name)
6
+
7
+ $CFLAGS << " #{`python-config --cflags`.chomp} -Wno-strict-prototypes"
8
+ $LDFLAGS << " #{`python-config --ldflags`.chomp}"
9
+
10
+ # python-config adds arch options for ppc and x64 on Darwin. Ruby 1.9
11
+ # does not like this, so we'll have to remove them.
12
+ if RUBY_VERSION.start_with? "1.9" and RUBY_PLATFORM =~ /darwin/
13
+ $CFLAGS.gsub! /\s+-arch\s+\w+/, " "
14
+ end
15
+
16
+ create_makefile(extension_name)
data/ext/wrapper.c ADDED
@@ -0,0 +1,239 @@
1
+ /* vim:set expandtab: */
2
+
3
+ #include <ruby.h>
4
+
5
+ /* Python.h redefines macros on Darwin, we don't want any warnings so we
6
+ * undefine them here first. */
7
+ #ifdef _DARWIN_C_SOURCE
8
+ #undef _XOPEN_SOURCE
9
+ #undef SIZEOF_TIME_T
10
+ #undef SIZEOF_LONG
11
+ #undef WORDS_BIGENDIAN
12
+ #endif
13
+
14
+ #include <Python.h>
15
+
16
+ #define log(x) (printf(">> %s\n",(x)));
17
+
18
+ /* Structure containing the state of the embedded interpreter */
19
+ struct wrapper_struct {
20
+ PyObject *module;
21
+ PyObject *rygmentize;
22
+ };
23
+
24
+ /* References to our created classes and modules */
25
+ static VALUE rygments_class = Qnil;
26
+ static VALUE wrapper_class = Qnil;
27
+
28
+ /* This function places a string at a certain index in the given tuple */
29
+ static int put_in_tuple(PyObject *tuple, int index, const char *string) {
30
+ /* Don't accept NULL pointers */
31
+ if (string == NULL) {
32
+ return 1;
33
+ }
34
+
35
+ /* Duplicate the string */
36
+ PyObject *pystr = PyString_FromString(string);
37
+ if (pystr == NULL) {
38
+ return 1;
39
+ }
40
+
41
+ /* Inject it in the tuple */
42
+ return PyTuple_SetItem(tuple, index, pystr);
43
+ }
44
+
45
+ /* Initializes the python interpreter and loads the rygments Python
46
+ * code */
47
+ static int initialize(struct wrapper_struct *s) {
48
+ PyObject *module_name;
49
+
50
+ /* Initialize Python */
51
+ Py_InitializeEx(0);
52
+
53
+ /* Load the rygments module */
54
+ module_name = PyString_FromString("rygments");
55
+ s->module = PyImport_Import(module_name);
56
+ Py_DECREF(module_name);
57
+
58
+ /* Check if module was loaded successfully */
59
+ if (s->module == NULL) {
60
+ PyErr_Print();
61
+ fprintf(stderr, "Failed to load the rygments python module\n");
62
+ return 1;
63
+ }
64
+
65
+ /* Get a reference to the rygmentize function */
66
+ s->rygmentize = PyObject_GetAttrString(s->module, "rygmentize");
67
+
68
+ /* Check if we have a function reference */
69
+ if (!s->rygmentize || !PyCallable_Check(s->rygmentize)) {
70
+ Py_XDECREF(s->rygmentize);
71
+ Py_DECREF(s->module);
72
+
73
+ if (PyErr_Occurred()) {
74
+ PyErr_Print();
75
+ }
76
+
77
+ fprintf(stderr, "Cannot find the rygmentize function in the python module\n");
78
+ return 1;
79
+ }
80
+
81
+ return 0;
82
+ }
83
+
84
+ /*
85
+ * call-seq:
86
+ * wrapper.highlight_string(string, lexer, formatter) -> string
87
+ *
88
+ * This method performs syntax highlighting on a string. Do not call this
89
+ * function directly. Instead, use the Rygments.highlight functions.
90
+ *
91
+ * The return value is always a string. An exception is raised whenever
92
+ * an error occurs.
93
+ */
94
+ static VALUE wrapper_highlight_string(VALUE self, VALUE code, VALUE lexer, VALUE formatter) {
95
+ struct wrapper_struct *s;
96
+ PyObject *pArgs, *pValue;
97
+ int res;
98
+
99
+ /* Get the wrapper structure */
100
+ Data_Get_Struct(self, struct wrapper_struct, s);
101
+
102
+ /* Collect arguments in a tuple */
103
+ pArgs = PyTuple_New(3);
104
+ res = 0;
105
+ res += put_in_tuple(pArgs, 0, RSTRING_PTR(code));
106
+ res += put_in_tuple(pArgs, 1, RSTRING_PTR(lexer));
107
+ res += put_in_tuple(pArgs, 2, RSTRING_PTR(formatter));
108
+
109
+ /* Check if we have bad arguments */
110
+ if (res) {
111
+ Py_DECREF(pArgs);
112
+ fprintf(stderr,"Bad arguments\n");
113
+ return Qnil;
114
+ }
115
+
116
+ /* Call the function */
117
+ pValue = PyObject_CallObject(s->rygmentize, pArgs);
118
+ Py_DECREF(pArgs);
119
+
120
+ /* Check if we have a valid result */
121
+ if (pValue == NULL) {
122
+ fprintf(stderr,"Call failed\n");
123
+ return Qnil;
124
+ }
125
+
126
+ /* Convert the pygmentized result to a Ruby string */
127
+ VALUE result = rb_str_new2(PyString_AsString(pValue));
128
+ Py_DECREF(pValue);
129
+
130
+ return result;
131
+ }
132
+
133
+ /*
134
+ * call-seq:
135
+ * wrapper.highlight_file(filename, lexer, formatter) -> string
136
+ *
137
+ * This method performs syntax highlighting on a file. Do not call this
138
+ * function directly. Instead, use the Rygments.highlight functions.
139
+ *
140
+ * The return value is always a string. An exception is raised whenever
141
+ * an error occurs.
142
+ */
143
+ static VALUE wrapper_highlight_file(VALUE self, VALUE filename, VALUE lexer, VALUE formatter) {
144
+ FILE *f;
145
+
146
+ /* Open the file */
147
+ if ((f=fopen(RSTRING_PTR(filename),"r"))==NULL) {
148
+ printf("error: could not open file\n");
149
+ return Qnil;
150
+ }
151
+
152
+ /* Determine the file size */
153
+ fseek(f,0,SEEK_END);
154
+ long fsize=ftell(f);
155
+ rewind(f);
156
+
157
+ /* Read the contents of the file into a buffer */
158
+ char *buf=ALLOC_N(char, fsize);
159
+ if ((fread(buf,1,fsize,f))!=(size_t)fsize) {
160
+ printf("error: could not read from file \"\"\n");
161
+ fclose(f);
162
+ return Qnil;
163
+ }
164
+ fclose(f);
165
+
166
+ /* Convert the buffer to a Ruby string */
167
+ VALUE code = rb_str_new(buf, fsize);
168
+ free(buf);
169
+
170
+ /* Call the string highlighting method */
171
+ return wrapper_highlight_string(self, code, lexer, formatter);
172
+ }
173
+
174
+ /* Free the wrapper structure and deinitialize the Python interpreter */
175
+ static void wrapper_free(void *p) {
176
+ struct wrapper_struct *s = (struct wrapper_struct *)p;
177
+
178
+ /* Decrese refcounts of the Python helper */
179
+ Py_DECREF(s->rygmentize);
180
+ Py_DECREF(s->module);
181
+
182
+ /* If we came here through an error we should print int */
183
+ if (PyErr_Occurred()) {
184
+ PyErr_Print();
185
+ }
186
+
187
+ /* Free the Python interpreter */
188
+ Py_Finalize();
189
+
190
+ /* Release our structure pointer */
191
+ free(p);
192
+ }
193
+
194
+ /*
195
+ * call-seq:
196
+ * Wrapper.new(helper_path) -> Wrapper instance
197
+ *
198
+ * Creates a new instance of the Python wrapper. Do not use this
199
+ * function directly. Instead, use the Rygments.highlight functions
200
+ * which will take care of handling the wrapper.
201
+ *
202
+ * Note: The Wrapper should be treated as a singleton. It is not designed
203
+ * to handle multiple instances. Furthermore, on Darwin initializing,
204
+ * finalizing and again initializing the Python interpreter results in
205
+ * segmentation faults.
206
+ */
207
+ static VALUE wrapper_new(VALUE klass, VALUE path) {
208
+ /* Patch the Python search path to include the rygments module path */
209
+ setenv("PYTHONPATH", RSTRING_PTR(path), 1);
210
+
211
+ /* Initialize the Python interpreter and load the helper module */
212
+ struct wrapper_struct *ptr = ALLOC(struct wrapper_struct);
213
+ initialize(ptr);
214
+
215
+ /* Wrap the state structure */
216
+ VALUE tdata = Data_Wrap_Struct(klass, 0, wrapper_free, ptr);
217
+ return tdata;
218
+ }
219
+
220
+ /*
221
+ * This Ruby C extension defines a Rygments::Wrapper class.
222
+ *
223
+ * The Rygments::Wrapper class is a wrapper around the Python interpreter.
224
+ * This means that Pygments can be invoked multiple times without having
225
+ * to fork or reload anything, thus reducing the overhead to a minimum.
226
+ *
227
+ * As a Rygments user you do not have to deal with the wrapper system
228
+ * directly. Instead, you should use the static functions that are exposed
229
+ * in the Rygments module.
230
+ */
231
+ void Init_wrapper(void) {
232
+ rygments_class = rb_define_module("Rygments");
233
+ wrapper_class = rb_define_class_under(rygments_class, "Wrapper", rb_cObject);
234
+
235
+ rb_define_singleton_method(wrapper_class, "new", wrapper_new, 1);
236
+
237
+ rb_define_method(wrapper_class, "highlight_string", wrapper_highlight_string, 3);
238
+ rb_define_method(wrapper_class, "highlight_file", wrapper_highlight_file, 3);
239
+ }
@@ -0,0 +1,8 @@
1
+ from pygments import highlight
2
+ from pygments.lexers import get_lexer_by_name
3
+ from pygments.formatters import get_formatter_by_name
4
+
5
+ def rygmentize(code, lexer, formatter):
6
+ lexer = get_lexer_by_name(lexer)
7
+ formatter = get_formatter_by_name(formatter)
8
+ return highlight(code, lexer, formatter)
@@ -0,0 +1,3 @@
1
+ module Rygments
2
+ VERSION = "0.1.0"
3
+ end
data/lib/rygments.rb ADDED
@@ -0,0 +1,65 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "ext", "wrapper"))
2
+
3
+ # = Introduction
4
+ #
5
+ # Rygments is a Ruby wrapper for the awesome Python based Pygments syntax
6
+ # highlighter.
7
+ #
8
+ # Rygments differs from other implementations in that it embeds a full
9
+ # Python interpreter for the Pygments Python files as a Ruby C extension.
10
+ # This enables Rygments to reach a level of performance that is equal to
11
+ # invoking Pygments from a native Python application without forking
12
+ # a new process. This difference in performance really pays off when
13
+ # you are highlighting lots of smaller code fragments, e.g. for a blog
14
+ # post.
15
+ #
16
+ # = Usage
17
+ #
18
+ # Usage is easy. Rygments comes with two class methods that enable you
19
+ # to highlight code from wherever you want.
20
+ #
21
+ # To highlight source code from a string use:
22
+ #
23
+ # Rygments.highlight_string(source_code, lexer, formatter)
24
+ #
25
+ # and to highlight source code from a file use:
26
+ #
27
+ # Rygments.highlight_file(filename, lexer, formatter)
28
+ #
29
+ # Both functions return a string containing the highlighted code.
30
+ #
31
+ # The _lexer_ is a string specifying the programming language you want
32
+ # to highlight for, e.g. +ruby+ or +sass+.
33
+ #
34
+ # The _formatter_ is a string specifying the kind of output you want,
35
+ # e.g. +html+ or +latex+.
36
+ #
37
+ # A full list of lexers and formatters is available on the Pygments
38
+ # website.
39
+ #
40
+ # Author:: Emil Loer (http://emilloer.com)
41
+ # License:: Licensed under the terms of the MIT license
42
+ module Rygments
43
+ # Perform syntax highlighting on a string.
44
+ # Returns the highlighted string.
45
+ def self.highlight_string(code, lexer = "ruby", formatter = "html")
46
+ wrapper.highlight_string code, lexer, formatter
47
+ end
48
+
49
+ # Reads a file and performs syntax highlighting on the file's contents.
50
+ # Returns the highlighted string.
51
+ def self.highlight_file(filename, lexer = "ruby", formatter = "html")
52
+ wrapper.highlight_file filename, lexer, formatter
53
+ end
54
+
55
+ private
56
+
57
+ # The full filename of the Python helper script
58
+ HELPER_PATH = File.expand_path(File.join(File.dirname(__FILE__), "rygments"))
59
+
60
+ # This function maintains a single instance of the Python wrapper
61
+ # extension.
62
+ def self.wrapper
63
+ @wrapper ||= Rygments::Wrapper.new(HELPER_PATH)
64
+ end
65
+ end
data/rygments.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rygments/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rygments"
7
+ s.version = Rygments::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Emil Loer"]
10
+ s.email = ["emil@koffietijd.net"]
11
+ s.homepage = "https://github.com/thedjinn/rygments"
12
+ s.summary = %q{Rygments is a Ruby wrapper for Pygments}
13
+ s.description = %q{Rygments is a Ruby wrapper for the Pygments syntax highlighter. It uses an embedded Python interpreter to get high processing throughput.}
14
+
15
+ s.rubyforge_project = "rygments"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.has_rdoc = true
23
+ s.extensions = ["ext/extconf.rb"]
24
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rygments
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Emil Loer
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-27 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Rygments is a Ruby wrapper for the Pygments syntax highlighter. It uses an embedded Python interpreter to get high processing throughput.
23
+ email:
24
+ - emil@koffietijd.net
25
+ executables: []
26
+
27
+ extensions:
28
+ - ext/extconf.rb
29
+ extra_rdoc_files: []
30
+
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - README.markdown
35
+ - Rakefile
36
+ - example/example.rb
37
+ - ext/extconf.rb
38
+ - ext/wrapper.c
39
+ - lib/rygments.rb
40
+ - lib/rygments/rygments.py
41
+ - lib/rygments/version.rb
42
+ - rygments.gemspec
43
+ has_rdoc: true
44
+ homepage: https://github.com/thedjinn/rygments
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project: rygments
73
+ rubygems_version: 1.5.2
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Rygments is a Ruby wrapper for Pygments
77
+ test_files: []
78
+