rygments 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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