wikitext 0.4 → 0.5

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.
@@ -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
  - - ">="