rygments 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,14 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  doc/
6
+ tmp/
7
+
8
+ lib/rygments/*.pyc
9
+ lib/*.so
10
+ lib/*.bundle
11
+ lib/*.o
12
+
13
+ ext/Makefile
14
+ ext/*.so
15
+ ext/*.bundle
16
+ ext/*.o
@@ -0,0 +1,11 @@
1
+ # Release history for Rygments
2
+
3
+ ## 0.2.0
4
+
5
+ * Exceptions from Pygments are now passed on to Ruby
6
+ * Added strictly defined error handling
7
+ * Added RSpec tests
8
+
9
+ ## 0.1.0
10
+
11
+ * Initial release
data/README.markdown CHANGED
@@ -6,10 +6,10 @@ highlighter.
6
6
  Rygments differs from other implementations in that it embeds a full
7
7
  Python interpreter for the Pygments Python files as a Ruby C extension.
8
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
9
+ invoking Pygments from a native Python application, and without the overhead of forking
10
10
  a new process. This difference in performance really pays off when
11
11
  you are highlighting lots of smaller code fragments, e.g. for blog
12
- posts.
12
+ posts or documentation generators such as Rocco.
13
13
 
14
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
15
 
@@ -73,7 +73,14 @@ website.
73
73
 
74
74
  # Compatibility
75
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.
76
+ Rygments has been tested and is known to work on Ruby Enterprise Edition 1.8.7-2011.01 and Ruby 1.9.2.
77
+
78
+ It has been tested on the following platforms:
79
+
80
+ * OSX Snow Leopard (10.6.6)
81
+ * Ubuntu Linux (8.04 and 10.10)
82
+
83
+ If you used it with success on a different Ruby implementation or platform then please let me know so I can extend this list.
77
84
 
78
85
  # License
79
86
 
data/Rakefile CHANGED
@@ -1,2 +1,16 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/extensiontask'
5
+ Rake::ExtensionTask.new do |ext|
6
+ ext.name = 'wrapper'
7
+ ext.ext_dir = 'ext'
8
+ end
9
+
10
+ require 'rspec/core/rake_task'
11
+ RSpec::Core::RakeTask.new(:spec) do |t|
12
+ t.rspec_opts = ['--options', 'spec/spec.opts']
13
+ end
14
+
15
+ task :spec => :compile
16
+ task :default => :spec
data/ext/wrapper.c CHANGED
@@ -25,6 +25,34 @@ struct wrapper_struct {
25
25
  static VALUE rygments_class = Qnil;
26
26
  static VALUE wrapper_class = Qnil;
27
27
 
28
+ /* This function collects a Python exception and raises it as a Ruby exception */
29
+ static void reraise() {
30
+ PyObject *ptype, *pvalue, *ptraceback, *pystr = NULL;
31
+ VALUE rstr;
32
+
33
+ if (PyErr_Occurred()) {
34
+ /* Fetch and normalize information about the exception */
35
+ PyErr_Fetch(&ptype, &pvalue, &ptraceback);
36
+ PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
37
+
38
+ /* Convert the Python exception string to a Ruby string */
39
+ if (pvalue != NULL && (pystr = PyObject_Str(pvalue)) != NULL && PyString_Check(pystr)) {
40
+ rstr = rb_str_new2(PyString_AsString(pystr));
41
+ } else {
42
+ rstr = rb_str_new2("An unknown Python exception was thrown");
43
+ }
44
+ Py_XDECREF(pystr);
45
+
46
+ /* Release the references given by PyErr_Fetch */
47
+ Py_DECREF(ptype);
48
+ Py_XDECREF(pvalue);
49
+ Py_XDECREF(ptraceback);
50
+
51
+ /* Raise a Ruby exception */
52
+ rb_raise(rb_eRuntimeError, "%s", RSTRING_PTR(rstr));
53
+ }
54
+ }
55
+
28
56
  /* This function places a string at a certain index in the given tuple */
29
57
  static int put_in_tuple(PyObject *tuple, int index, const char *string) {
30
58
  /* Don't accept NULL pointers */
@@ -57,9 +85,7 @@ static int initialize(struct wrapper_struct *s) {
57
85
 
58
86
  /* Check if module was loaded successfully */
59
87
  if (s->module == NULL) {
60
- PyErr_Print();
61
- fprintf(stderr, "Failed to load the rygments python module\n");
62
- return 1;
88
+ reraise();
63
89
  }
64
90
 
65
91
  /* Get a reference to the rygmentize function */
@@ -71,11 +97,12 @@ static int initialize(struct wrapper_struct *s) {
71
97
  Py_DECREF(s->module);
72
98
 
73
99
  if (PyErr_Occurred()) {
74
- PyErr_Print();
100
+ reraise();
75
101
  }
76
102
 
77
- fprintf(stderr, "Cannot find the rygmentize function in the python module\n");
78
- return 1;
103
+ Py_Finalize();
104
+
105
+ rb_raise(rb_eRuntimeError, "Cannot find the rygmentize function in the Python module");
79
106
  }
80
107
 
81
108
  return 0;
@@ -96,6 +123,11 @@ static VALUE wrapper_highlight_string(VALUE self, VALUE code, VALUE lexer, VALUE
96
123
  PyObject *pArgs, *pValue;
97
124
  int res;
98
125
 
126
+ /* Make sure we have three strings as input */
127
+ Check_Type(code, T_STRING);
128
+ Check_Type(lexer, T_STRING);
129
+ Check_Type(formatter, T_STRING);
130
+
99
131
  /* Get the wrapper structure */
100
132
  Data_Get_Struct(self, struct wrapper_struct, s);
101
133
 
@@ -109,8 +141,7 @@ static VALUE wrapper_highlight_string(VALUE self, VALUE code, VALUE lexer, VALUE
109
141
  /* Check if we have bad arguments */
110
142
  if (res) {
111
143
  Py_DECREF(pArgs);
112
- fprintf(stderr,"Bad arguments\n");
113
- return Qnil;
144
+ rb_raise(rb_eRuntimeError, "bad input given");
114
145
  }
115
146
 
116
147
  /* Call the function */
@@ -119,8 +150,9 @@ static VALUE wrapper_highlight_string(VALUE self, VALUE code, VALUE lexer, VALUE
119
150
 
120
151
  /* Check if we have a valid result */
121
152
  if (pValue == NULL) {
122
- fprintf(stderr,"Call failed\n");
123
- return Qnil;
153
+ reraise();
154
+
155
+ rb_raise(rb_eRuntimeError, "Call failed");
124
156
  }
125
157
 
126
158
  /* Convert the pygmentized result to a Ruby string */
@@ -143,23 +175,33 @@ static VALUE wrapper_highlight_string(VALUE self, VALUE code, VALUE lexer, VALUE
143
175
  static VALUE wrapper_highlight_file(VALUE self, VALUE filename, VALUE lexer, VALUE formatter) {
144
176
  FILE *f;
145
177
 
178
+ /* Make sure the filename is a string */
179
+ Check_Type(filename, T_STRING);
180
+
146
181
  /* Open the file */
147
182
  if ((f=fopen(RSTRING_PTR(filename),"r"))==NULL) {
148
- printf("error: could not open file\n");
149
- return Qnil;
183
+ rb_sys_fail("could not open file");
150
184
  }
151
185
 
152
186
  /* Determine the file size */
153
- fseek(f,0,SEEK_END);
187
+ if (fseek(f,0,SEEK_END) == -1) {
188
+ rb_sys_fail("could not seek to end of file");
189
+ }
154
190
  long fsize=ftell(f);
191
+ if (fsize == -1) {
192
+ rb_sys_fail("could not determine file length");
193
+ }
155
194
  rewind(f);
156
195
 
157
196
  /* Read the contents of the file into a buffer */
158
197
  char *buf=ALLOC_N(char, fsize);
159
198
  if ((fread(buf,1,fsize,f))!=(size_t)fsize) {
160
- printf("error: could not read from file \"\"\n");
199
+ /* Close file handle with cached errno value */
200
+ int err = errno;
161
201
  fclose(f);
162
- return Qnil;
202
+ errno = err;
203
+
204
+ rb_sys_fail("could not read from file");
163
205
  }
164
206
  fclose(f);
165
207
 
@@ -174,7 +216,7 @@ static VALUE wrapper_highlight_file(VALUE self, VALUE filename, VALUE lexer, VAL
174
216
  /* Free the wrapper structure and deinitialize the Python interpreter */
175
217
  static void wrapper_free(void *p) {
176
218
  struct wrapper_struct *s = (struct wrapper_struct *)p;
177
-
219
+
178
220
  /* Decrese refcounts of the Python helper */
179
221
  Py_DECREF(s->rygmentize);
180
222
  Py_DECREF(s->module);
@@ -183,7 +225,7 @@ static void wrapper_free(void *p) {
183
225
  if (PyErr_Occurred()) {
184
226
  PyErr_Print();
185
227
  }
186
-
228
+
187
229
  /* Free the Python interpreter */
188
230
  Py_Finalize();
189
231
 
data/lib/rygments.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "ext", "wrapper"))
1
+ require "wrapper"
2
2
 
3
3
  # = Introduction
4
4
  #
@@ -40,6 +40,9 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "ext", "wrapper
40
40
  # Author:: Emil Loer (http://emilloer.com)
41
41
  # License:: Licensed under the terms of the MIT license
42
42
  module Rygments
43
+ # The full filename of the Python helper script
44
+ HELPER_PATH = File.expand_path(File.join(File.dirname(__FILE__), "rygments"))
45
+
43
46
  # Perform syntax highlighting on a string.
44
47
  # Returns the highlighted string.
45
48
  def self.highlight_string(code, lexer = "ruby", formatter = "html")
@@ -52,11 +55,6 @@ module Rygments
52
55
  wrapper.highlight_file filename, lexer, formatter
53
56
  end
54
57
 
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
58
  # This function maintains a single instance of the Python wrapper
61
59
  # extension.
62
60
  def self.wrapper
@@ -1,3 +1,3 @@
1
1
  module Rygments
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/rygments.gemspec CHANGED
@@ -19,6 +19,9 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
+ s.add_development_dependency("rspec", ["~> 2.0"])
23
+ s.add_development_dependency("rake-compiler", ["~> 0.7"])
24
+
22
25
  s.has_rdoc = true
23
26
  s.extensions = ["ext/extconf.rb"]
24
27
  end
@@ -0,0 +1,125 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Rygments::Wrapper do
4
+ subject do
5
+ # We don't want to recreate wrappers because reinitializing Python
6
+ # fails on OSX
7
+ Rygments.wrapper
8
+ end
9
+
10
+ describe "#highlight_string" do
11
+ it "should return a string" do
12
+ subject.highlight_string("puts 'Hello World!'", "ruby", "html").should be_a(String)
13
+ end
14
+
15
+ it "should raise an exception when given an invalid formatter" do
16
+ expect {
17
+ subject.highlight_string("puts 'Hello World!", "ruby", "awesome_nonexistant_formatter")
18
+ }.to raise_error
19
+ end
20
+
21
+ it "should raise an exception when given an invalid lexer" do
22
+ expect {
23
+ subject.highlight_string("puts 'Hello World!", "awesome_nonexistant_lexer", "html")
24
+ }.to raise_error
25
+ end
26
+ end
27
+
28
+ describe "#highlight_file" do
29
+ it "should return a string" do
30
+ subject.highlight_file(__FILE__, "ruby", "html").should be_a(String)
31
+ end
32
+
33
+ it "should raise an exception when given a nonexisting filename" do
34
+ expect {
35
+ subject.highlight_file("this_file_does_not_exist", "ruby", "html")
36
+ }.to raise_error
37
+ end
38
+
39
+ it "should raise an exception when given an invalid formatter" do
40
+ expect {
41
+ subject.highlight_file(__FILE__, "ruby", "awesome_nonexistant_formatter")
42
+ }.to raise_error
43
+ end
44
+
45
+ it "should raise an exception when given an invalid lexer" do
46
+ expect {
47
+ subject.highlight_file(__FILE__, "awesome_nonexistant_lexer", "html")
48
+ }.to raise_error
49
+ end
50
+ end
51
+ end
52
+
53
+ describe Rygments do
54
+ describe "#highlight_string" do
55
+ it "should return a string" do
56
+ Rygments.highlight_string("puts 'Hello World!'", "ruby", "html").should be_a(String)
57
+ end
58
+
59
+ it "should raise an exception when given an invalid formatter" do
60
+ expect {
61
+ Rygments.highlight_string("puts 'Hello World!", "ruby", "awesome_nonexistant_formatter")
62
+ }.to raise_error
63
+ end
64
+
65
+ it "should raise an exception when given an invalid lexer" do
66
+ expect {
67
+ Rygments.highlight_string("puts 'Hello World!", "awesome_nonexistant_lexer", "html")
68
+ }.to raise_error
69
+ end
70
+
71
+ it "should raise an exception when the first argument is not a string" do
72
+ expect {
73
+ Rygments.highlight_string(:no_string, "ruby", "html")
74
+ }.to raise_error
75
+ end
76
+
77
+ it "should raise an exception when the second argument is not a string" do
78
+ expect {
79
+ Rygments.highlight_string("puts 'Hello World!", :no_string, "html")
80
+ }.to raise_error
81
+ end
82
+
83
+ it "should raise an exception when the third argument is not a string" do
84
+ expect {
85
+ Rygments.highlight_string("puts 'Hello World!", "ruby", :no_string)
86
+ }.to raise_error
87
+ end
88
+ end
89
+
90
+ describe "#highlight_file" do
91
+ it "should return a string" do
92
+ Rygments.highlight_file(__FILE__, "ruby", "html").should be_a(String)
93
+ end
94
+
95
+ it "should raise an exception when given an invalid formatter" do
96
+ expect {
97
+ Rygments.highlight_file(__FILE__, "ruby", "awesome_nonexistant_formatter")
98
+ }.to raise_error
99
+ end
100
+
101
+ it "should raise an exception when given an invalid lexer" do
102
+ expect {
103
+ Rygments.highlight_file(__FILE__, "awesome_nonexistant_lexer", "html")
104
+ }.to raise_error
105
+ end
106
+
107
+ it "should raise an exception when the first argument is not a string" do
108
+ expect {
109
+ Rygments.highlight_file(:no_string, "ruby", "html")
110
+ }.to raise_error
111
+ end
112
+
113
+ it "should raise an exception when the second argument is not a string" do
114
+ expect {
115
+ Rygments.highlight_file(__FILE__, :no_string, "html")
116
+ }.to raise_error
117
+ end
118
+
119
+ it "should raise an exception when the third argument is not a string" do
120
+ expect {
121
+ Rygments.highlight_file(__FILE__, "ruby", :no_string)
122
+ }.to raise_error
123
+ end
124
+ end
125
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format documentation
@@ -0,0 +1,6 @@
1
+ SPEC_DIR = File.dirname(__FILE__)
2
+ lib_path = File.expand_path(File.join(SPEC_DIR, "..", "lib"))
3
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
4
+
5
+ require "rygments"
6
+ require "wrapper"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rygments
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Emil Loer
@@ -15,10 +15,39 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-27 00:00:00 +01:00
18
+ date: 2011-03-02 00:00:00 +01:00
19
19
  default_executable:
20
- dependencies: []
21
-
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 2
32
+ - 0
33
+ version: "2.0"
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake-compiler
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 5
45
+ segments:
46
+ - 0
47
+ - 7
48
+ version: "0.7"
49
+ type: :development
50
+ version_requirements: *id002
22
51
  description: Rygments is a Ruby wrapper for the Pygments syntax highlighter. It uses an embedded Python interpreter to get high processing throughput.
23
52
  email:
24
53
  - emil@koffietijd.net
@@ -30,6 +59,7 @@ extra_rdoc_files: []
30
59
 
31
60
  files:
32
61
  - .gitignore
62
+ - CHANGELOG.markdown
33
63
  - Gemfile
34
64
  - README.markdown
35
65
  - Rakefile
@@ -40,6 +70,9 @@ files:
40
70
  - lib/rygments/rygments.py
41
71
  - lib/rygments/version.rb
42
72
  - rygments.gemspec
73
+ - spec/rygments_spec.rb
74
+ - spec/spec.opts
75
+ - spec/spec_helper.rb
43
76
  has_rdoc: true
44
77
  homepage: https://github.com/thedjinn/rygments
45
78
  licenses: []
@@ -74,5 +107,7 @@ rubygems_version: 1.5.2
74
107
  signing_key:
75
108
  specification_version: 3
76
109
  summary: Rygments is a Ruby wrapper for Pygments
77
- test_files: []
78
-
110
+ test_files:
111
+ - spec/rygments_spec.rb
112
+ - spec/spec.opts
113
+ - spec/spec_helper.rb