wikitext 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ // Copyright 2008 Wincent Colaiuta
2
+ // This program is free software: you can redistribute it and/or modify
3
+ // it under the terms of the GNU General Public License as published by
4
+ // the Free Software Foundation, either version 3 of the License, or
5
+ // (at your option) any later version.
6
+ //
7
+ // This program is distributed in the hope that it will be useful,
8
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ // GNU General Public License for more details.
11
+ //
12
+ // You should have received a copy of the GNU General Public License
13
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+
15
+ #include "ary.h"
16
+
17
+ void ary_free(ary_t *ary)
18
+ {
19
+ free(ary->entries);
20
+ free(ary);
21
+ }
data/ext/ary.h CHANGED
@@ -26,6 +26,10 @@ typedef struct
26
26
 
27
27
  #define NO_ITEM(item) (item == INT_MAX)
28
28
 
29
+ // Mark the ary struct designated by ptr as a participant in Ruby's mark-and-sweep garbage collection scheme.
30
+ // A variable named name is placed on the C stack to prevent the structure from being prematurely collected.
31
+ #define GC_WRAP_ARY(ptr, name) volatile VALUE name = Data_Wrap_Struct(rb_cObject, 0, ary_free, ptr)
32
+
29
33
  inline ary_t *ary_new(void)
30
34
  {
31
35
  ary_t *ary = ALLOC_N(ary_t, 1);
@@ -35,11 +39,8 @@ inline ary_t *ary_new(void)
35
39
  return ary;
36
40
  }
37
41
 
38
- inline void ary_free(ary_t *ary)
39
- {
40
- free(ary->entries);
41
- free(ary);
42
- }
42
+ // this method not inlined so its address can be passed to the Data_Wrap_Struct function.
43
+ void ary_free(ary_t *ary);
43
44
 
44
45
  inline int ary_entry(ary_t *ary, int idx)
45
46
  {
data/ext/depend CHANGED
@@ -16,7 +16,9 @@
16
16
 
17
17
  CFLAGS += -std=gnu99
18
18
 
19
- parser.o : ary.h parser.c parser.h token.h str.h wikitext.h wikitext_ragel.h
19
+ ary.o : ary.c ary.h
20
+ parser.o : ary.c ary.h parser.c parser.h token.h str.c str.h wikitext.h wikitext_ragel.h
21
+ str.o : str.c str.h
20
22
  token.o : token.c token.h wikitext.h
21
23
  wikitext.o : parser.h token.h wikitext.c wikitext.h wikitext_ragel.h
22
24
  wikitext_ragel.o : token.h wikitext.h wikitext_ragel.h wikitext_ragel.c
@@ -207,9 +207,7 @@ inline void _Wikitext_indent(parser_t *parser)
207
207
  if (space_count > 0)
208
208
  {
209
209
  char *old_end, *new_end;
210
- if (!parser->tabulation)
211
- parser->tabulation = str_new_size(space_count);
212
- else if (parser->tabulation->len < space_count)
210
+ if (parser->tabulation->len < space_count)
213
211
  str_grow(parser->tabulation, space_count); // reallocates if necessary
214
212
  old_end = parser->tabulation->ptr + parser->tabulation->len;
215
213
  new_end = parser->tabulation->ptr + space_count;
@@ -930,17 +928,22 @@ VALUE Wikitext_parser_parse(int argc, VALUE *argv, VALUE self)
930
928
  parser->external_link_class = link_class;
931
929
  parser->img_prefix = rb_iv_get(self, "@img_prefix");
932
930
  parser->scope = ary_new();
931
+ GC_WRAP_ARY(parser->scope, scope_gc);
933
932
  parser->line = ary_new();
933
+ GC_WRAP_ARY(parser->line, line_gc);
934
934
  parser->line_buffer = ary_new();
935
+ GC_WRAP_ARY(parser->line_buffer, line_buffer_gc);
935
936
  parser->pending_crlf = Qfalse;
936
937
  parser->autolink = rb_iv_get(self, "@autolink");
937
938
  parser->treat_slash_as_special = rb_iv_get(self, "@treat_slash_as_special");
938
939
  parser->space_to_underscore = rb_iv_get(self, "@space_to_underscore");
939
940
  parser->special_link = Qfalse;
940
941
  parser->line_ending = str_new_from_string(line_ending);
942
+ GC_WRAP_STR(parser->line_ending, line_ending_gc);
941
943
  parser->base_indent = base_indent;
942
944
  parser->current_indent = 0;
943
- parser->tabulation = NULL;
945
+ parser->tabulation = str_new();
946
+ GC_WRAP_STR(parser->tabulation, tabulation_gc);
944
947
 
945
948
  token_t _token;
946
949
  _token.type = NO_TOKEN;
@@ -2266,12 +2269,5 @@ VALUE Wikitext_parser_parse(int argc, VALUE *argv, VALUE self)
2266
2269
  token = NULL;
2267
2270
  } while (1);
2268
2271
  return_output:
2269
- // BUG: these will leak if we exit this function by raising an exception; need to investigate using Data_Wrap_Struct
2270
- ary_free(parser->scope);
2271
- ary_free(parser->line);
2272
- ary_free(parser->line_buffer);
2273
- str_free(parser->line_ending);
2274
- if (parser->tabulation)
2275
- str_free(parser->tabulation);
2276
2272
  return parser->output;
2277
2273
  }
@@ -0,0 +1,22 @@
1
+ // Copyright 2008 Wincent Colaiuta
2
+ // This program is free software: you can redistribute it and/or modify
3
+ // it under the terms of the GNU General Public License as published by
4
+ // the Free Software Foundation, either version 3 of the License, or
5
+ // (at your option) any later version.
6
+ //
7
+ // This program is distributed in the hope that it will be useful,
8
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ // GNU General Public License for more details.
11
+ //
12
+ // You should have received a copy of the GNU General Public License
13
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+
15
+ #include "str.h"
16
+
17
+ void str_free(str_t *str)
18
+ {
19
+ if (str->ptr)
20
+ free(str->ptr);
21
+ free(str);
22
+ }
data/ext/str.h CHANGED
@@ -21,6 +21,10 @@ typedef struct
21
21
  long capacity;
22
22
  } str_t;
23
23
 
24
+ // Mark the str struct designated by ptr as a participant in Ruby's mark-and-sweep garbage collection scheme.
25
+ // A variable named name is placed on the C stack to prevent the structure from being prematurely collected.
26
+ #define GC_WRAP_STR(ptr, name) volatile VALUE name = Data_Wrap_Struct(rb_cObject, 0, str_free, ptr)
27
+
24
28
  // create a new, empty string struct
25
29
  inline str_t *str_new(void)
26
30
  {
@@ -127,9 +131,5 @@ inline void str_clear(str_t *str)
127
131
  str->len = 0;
128
132
  }
129
133
 
130
- inline void str_free(str_t *str)
131
- {
132
- if (str->ptr)
133
- free(str->ptr);
134
- free(str);
135
- }
134
+ // this method not inlined so its address can be passed to the Data_Wrap_Struct function.
135
+ void str_free(str_t *str);
@@ -0,0 +1,14 @@
1
+ require 'wikitext/string'
2
+
3
+ module Wikitext
4
+ class TemplateHandler
5
+ def initialize view
6
+ end
7
+
8
+ def render text, locals = {}
9
+ text.w
10
+ end
11
+ end
12
+ end
13
+
14
+ ActionView::Base.register_template_handler :wikitext, Wikitext::TemplateHandler
@@ -0,0 +1,21 @@
1
+ require 'wikitext'
2
+
3
+ class String
4
+
5
+ def to_wikitext
6
+ @@shared_wikitext_parser ||= Wikitext::Parser.new(:space_to_underscore => true)
7
+ @@shared_wikitext_parser.parse wikitext_preprocess
8
+ end
9
+
10
+ # Convenience shortcut
11
+ alias :w :to_wikitext
12
+
13
+ private
14
+
15
+ # for now do this in pure Ruby
16
+ # if speed later becomes a concern can whip up a Ragel C extension to do it
17
+ def wikitext_preprocess
18
+ gsub /\b(bug|issue|request) #(\d+)/i, '[[issues/\2|\1 #\2]]'
19
+ end
20
+
21
+ end
@@ -265,4 +265,13 @@ describe Wikitext::Parser, 'with large slab of input text' do
265
265
 
266
266
  @parser.parse(input).should == expected
267
267
  end
268
+
269
+ # Without something like this it is possible to complete the entire spec suite without
270
+ # triggering garbage collection at all, or at least enough to expose memory-related bugs.
271
+ # So add one long-running spec to hopefully catch any GC and memory-related bugs.
272
+ it 'should work correctly during long runs (when Garbage Collection runs)' do
273
+ input = "a <strong>simple</strong> ''test'' of the [[wikitext parser]]"
274
+ expected = %Q{<p>a <strong>simple</strong> <em>test</em> of the <a href="/wiki/wikitext%20parser">wikitext parser</a></p>\n}
275
+ 100_000.times { @parser.parse(input).should == expected }
276
+ end
268
277
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wikitext
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.4"
4
+ version: "0.5"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wincent Colaiuta
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-19 00:00:00 +01:00
12
+ date: 2008-02-23 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -53,7 +53,9 @@ files:
53
53
  - spec/ul_spec.rb
54
54
  - spec/wikitext_spec.rb
55
55
  - ext/extconf.rb
56
+ - ext/ary.c
56
57
  - ext/parser.c
58
+ - ext/str.c
57
59
  - ext/token.c
58
60
  - ext/wikitext.c
59
61
  - ext/wikitext_ragel.c
@@ -64,6 +66,8 @@ files:
64
66
  - ext/wikitext.h
65
67
  - ext/wikitext_ragel.h
66
68
  - ext/depend
69
+ - lib/wikitext/rails.rb
70
+ - lib/wikitext/string.rb
67
71
  has_rdoc: true
68
72
  homepage: http://wikitext.rubyforge.org/
69
73
  post_install_message:
@@ -71,6 +75,7 @@ rdoc_options: []
71
75
 
72
76
  require_paths:
73
77
  - ext
78
+ - lib
74
79
  required_ruby_version: !ruby/object:Gem::Requirement
75
80
  requirements:
76
81
  - - ">="