walrus 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (208) hide show
  1. data/bin/walrus +44 -0
  2. data/ext/jindex/extconf.rb +11 -0
  3. data/ext/jindex/jindex.c +79 -0
  4. data/ext/mkdtemp/extconf.rb +11 -0
  5. data/ext/mkdtemp/mkdtemp.c +41 -0
  6. data/lib/walrus/additions/module.rb +36 -0
  7. data/lib/walrus/additions/string.rb +37 -0
  8. data/lib/walrus/additions/test/unit/error_collector.rb +62 -0
  9. data/lib/walrus/compile_error.rb +28 -0
  10. data/lib/walrus/compiler.rb +124 -0
  11. data/lib/walrus/contrib/spec/walruscloth_spec.rb +32 -0
  12. data/lib/walrus/contrib/walruscloth.rb +82 -0
  13. data/lib/walrus/diff.rb +89 -0
  14. data/lib/walrus/document.rb +98 -0
  15. data/lib/walrus/grammar/additions/proc.rb +20 -0
  16. data/lib/walrus/grammar/additions/regexp.rb +21 -0
  17. data/lib/walrus/grammar/additions/string.rb +52 -0
  18. data/lib/walrus/grammar/additions/symbol.rb +42 -0
  19. data/lib/walrus/grammar/and_predicate.rb +40 -0
  20. data/lib/walrus/grammar/array_result.rb +19 -0
  21. data/lib/walrus/grammar/continuation_wrapper_exception.rb +28 -0
  22. data/lib/walrus/grammar/left_recursion_exception.rb +27 -0
  23. data/lib/walrus/grammar/location_tracking.rb +105 -0
  24. data/lib/walrus/grammar/match_data_wrapper.rb +65 -0
  25. data/lib/walrus/grammar/memoizing.rb +41 -0
  26. data/lib/walrus/grammar/memoizing_cache.rb +94 -0
  27. data/lib/walrus/grammar/node.rb +60 -0
  28. data/lib/walrus/grammar/not_predicate.rb +40 -0
  29. data/lib/walrus/grammar/parse_error.rb +39 -0
  30. data/lib/walrus/grammar/parser_state.rb +181 -0
  31. data/lib/walrus/grammar/parslet.rb +28 -0
  32. data/lib/walrus/grammar/parslet_choice.rb +120 -0
  33. data/lib/walrus/grammar/parslet_combination.rb +26 -0
  34. data/lib/walrus/grammar/parslet_combining.rb +154 -0
  35. data/lib/walrus/grammar/parslet_merge.rb +88 -0
  36. data/lib/walrus/grammar/parslet_omission.rb +57 -0
  37. data/lib/walrus/grammar/parslet_repetition.rb +97 -0
  38. data/lib/walrus/grammar/parslet_repetition_default.rb +58 -0
  39. data/lib/walrus/grammar/parslet_sequence.rb +202 -0
  40. data/lib/walrus/grammar/predicate.rb +57 -0
  41. data/lib/walrus/grammar/proc_parslet.rb +52 -0
  42. data/lib/walrus/grammar/regexp_parslet.rb +73 -0
  43. data/lib/walrus/grammar/skipped_substring_exception.rb +36 -0
  44. data/lib/walrus/grammar/string_enumerator.rb +45 -0
  45. data/lib/walrus/grammar/string_parslet.rb +75 -0
  46. data/lib/walrus/grammar/string_result.rb +24 -0
  47. data/lib/walrus/grammar/symbol_parslet.rb +63 -0
  48. data/lib/walrus/grammar.rb +170 -0
  49. data/lib/walrus/no_parameter_marker.rb +19 -0
  50. data/lib/walrus/parser.rb +420 -0
  51. data/lib/walrus/runner.rb +356 -0
  52. data/lib/walrus/template.rb +75 -0
  53. data/lib/walrus/walrus_grammar/assignment_expression.rb +24 -0
  54. data/lib/walrus/walrus_grammar/block_directive.rb +28 -0
  55. data/lib/walrus/walrus_grammar/comment.rb +24 -0
  56. data/lib/walrus/walrus_grammar/def_directive.rb +64 -0
  57. data/lib/walrus/walrus_grammar/echo_directive.rb +44 -0
  58. data/lib/walrus/walrus_grammar/escape_sequence.rb +24 -0
  59. data/lib/walrus/walrus_grammar/import_directive.rb +44 -0
  60. data/lib/walrus/walrus_grammar/include_directive.rb +27 -0
  61. data/lib/walrus/walrus_grammar/instance_variable.rb +24 -0
  62. data/lib/walrus/walrus_grammar/literal.rb +24 -0
  63. data/lib/walrus/walrus_grammar/message_expression.rb +25 -0
  64. data/lib/walrus/walrus_grammar/multiline_comment.rb +54 -0
  65. data/lib/walrus/walrus_grammar/placeholder.rb +40 -0
  66. data/lib/walrus/walrus_grammar/raw_directive.rb +42 -0
  67. data/lib/walrus/walrus_grammar/raw_text.rb +45 -0
  68. data/lib/walrus/walrus_grammar/ruby_directive.rb +29 -0
  69. data/lib/walrus/walrus_grammar/ruby_expression.rb +31 -0
  70. data/lib/walrus/walrus_grammar/set_directive.rb +24 -0
  71. data/lib/walrus/walrus_grammar/silent_directive.rb +44 -0
  72. data/lib/walrus/walrus_grammar/slurp_directive.rb +25 -0
  73. data/lib/walrus/walrus_grammar/super_directive.rb +27 -0
  74. data/lib/walrus.rb +64 -0
  75. data/spec/acceptance/acceptance_spec.rb +97 -0
  76. data/spec/acceptance/block/basic_block.expected +1 -0
  77. data/spec/acceptance/block/basic_block.tmpl +3 -0
  78. data/spec/acceptance/block/nested_blocks.expected +5 -0
  79. data/spec/acceptance/block/nested_blocks.tmpl +11 -0
  80. data/spec/acceptance/comments/comments_and_text.expected +3 -0
  81. data/spec/acceptance/comments/comments_and_text.tmpl +6 -0
  82. data/spec/acceptance/comments/single_comment.expected +0 -0
  83. data/spec/acceptance/comments/single_comment.tmpl +1 -0
  84. data/spec/acceptance/def/alternative_def_calling_conventions.expected +3 -0
  85. data/spec/acceptance/def/alternative_def_calling_conventions.tmpl +18 -0
  86. data/spec/acceptance/def/basic_def_block_no_output.expected +0 -0
  87. data/spec/acceptance/def/basic_def_block_no_output.tmpl +17 -0
  88. data/spec/acceptance/def/defs_can_be_called_multiple_times.expected +3 -0
  89. data/spec/acceptance/def/defs_can_be_called_multiple_times.tmpl +6 -0
  90. data/spec/acceptance/def/defs_can_be_dynamic.expected +4 -0
  91. data/spec/acceptance/def/defs_can_be_dynamic.tmpl +12 -0
  92. data/spec/acceptance/echo/echo_directive_with_numeric_literal.expected +1 -0
  93. data/spec/acceptance/echo/echo_directive_with_numeric_literal.tmpl +1 -0
  94. data/spec/acceptance/echo/echo_expression_list.expected +1 -0
  95. data/spec/acceptance/echo/echo_expression_list.tmpl +1 -0
  96. data/spec/acceptance/echo/echo_short_notation.expected +1 -0
  97. data/spec/acceptance/echo/echo_short_notation.tmpl +1 -0
  98. data/spec/acceptance/echo/echo_simple_expression.expected +1 -0
  99. data/spec/acceptance/echo/echo_simple_expression.tmpl +1 -0
  100. data/spec/acceptance/echo/echo_single_quoted_string_literal.expected +1 -0
  101. data/spec/acceptance/echo/echo_single_quoted_string_literal.tmpl +1 -0
  102. data/spec/acceptance/echo/multiple_echo_statements.expected +1 -0
  103. data/spec/acceptance/echo/multiple_echo_statements.tmpl +2 -0
  104. data/spec/acceptance/includes/basic_included_file.txt +1 -0
  105. data/spec/acceptance/includes/basic_includer.complex +3 -0
  106. data/spec/acceptance/includes/basic_includer.expected +3 -0
  107. data/spec/acceptance/includes/basic_includer.rb +38 -0
  108. data/spec/acceptance/includes/complicated_included_file.txt +3 -0
  109. data/spec/acceptance/includes/complicated_includer.complex +3 -0
  110. data/spec/acceptance/includes/complicated_includer.expected +3 -0
  111. data/spec/acceptance/includes/complicated_includer.rb +41 -0
  112. data/spec/acceptance/includes/nested_include_1.txt +3 -0
  113. data/spec/acceptance/includes/nested_include_2.txt +1 -0
  114. data/spec/acceptance/includes/nested_includer.complex +3 -0
  115. data/spec/acceptance/includes/nested_includer.expected +4 -0
  116. data/spec/acceptance/includes/nested_includer.rb +41 -0
  117. data/spec/acceptance/inheritance/basic_child.complex +10 -0
  118. data/spec/acceptance/inheritance/basic_child.expected +9 -0
  119. data/spec/acceptance/inheritance/basic_child.rb +54 -0
  120. data/spec/acceptance/inheritance/basic_parent.complex +5 -0
  121. data/spec/acceptance/inheritance/basic_parent.expected +3 -0
  122. data/spec/acceptance/inheritance/basic_parent.rb +41 -0
  123. data/spec/acceptance/inheritance/importing_child.complex +8 -0
  124. data/spec/acceptance/inheritance/importing_child.expected +7 -0
  125. data/spec/acceptance/inheritance/importing_child.rb +46 -0
  126. data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.complex +8 -0
  127. data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.expected +7 -0
  128. data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.rb +44 -0
  129. data/spec/acceptance/multiline_comments/multiline_comment_with_directives_inside.expected +0 -0
  130. data/spec/acceptance/multiline_comments/multiline_comment_with_directives_inside.tmpl +15 -0
  131. data/spec/acceptance/multiline_comments/simple_multiline_comment.expected +2 -0
  132. data/spec/acceptance/multiline_comments/simple_multiline_comment.tmpl +4 -0
  133. data/spec/acceptance/raw/complicated_raw_example.expected +57 -0
  134. data/spec/acceptance/raw/complicated_raw_example.tmpl +79 -0
  135. data/spec/acceptance/raw-text/UTF_8.expected +12 -0
  136. data/spec/acceptance/raw-text/UTF_8.tmpl +12 -0
  137. data/spec/acceptance/raw-text/empty_file.expected +0 -0
  138. data/spec/acceptance/raw-text/empty_file.tmpl +0 -0
  139. data/spec/acceptance/raw-text/multi_line.expected +4 -0
  140. data/spec/acceptance/raw-text/multi_line.tmpl +4 -0
  141. data/spec/acceptance/raw-text/single_line.expected +1 -0
  142. data/spec/acceptance/raw-text/single_line.tmpl +1 -0
  143. data/spec/acceptance/raw-text/single_line_whitespace.expected +1 -0
  144. data/spec/acceptance/raw-text/single_line_whitespace.tmpl +1 -0
  145. data/spec/acceptance/ruby/ruby_directive_is_just_like_silent.expected +1 -0
  146. data/spec/acceptance/ruby/ruby_directive_is_just_like_silent.tmpl +4 -0
  147. data/spec/acceptance/ruby/ruby_directive_using_here_doc.expected +1 -0
  148. data/spec/acceptance/ruby/ruby_directive_using_here_doc.tmpl +4 -0
  149. data/spec/acceptance/ruby/ruby_directive_using_here_doc_alt_syntax.expected +1 -0
  150. data/spec/acceptance/ruby/ruby_directive_using_here_doc_alt_syntax.tmpl +4 -0
  151. data/spec/acceptance/ruby/ruby_directive_with_accumulate.expected +1 -0
  152. data/spec/acceptance/ruby/ruby_directive_with_accumulate.tmpl +4 -0
  153. data/spec/acceptance/ruby/ruby_directive_with_accumulate_and_block.expected +1 -0
  154. data/spec/acceptance/ruby/ruby_directive_with_accumulate_and_block.tmpl +6 -0
  155. data/spec/acceptance/set/unused_set.expected +0 -0
  156. data/spec/acceptance/set/unused_set.tmpl +1 -0
  157. data/spec/acceptance/set/used_set.expected +1 -0
  158. data/spec/acceptance/set/used_set.tmpl +2 -0
  159. data/spec/acceptance/silent/silent_and_echo_combined.expected +1 -0
  160. data/spec/acceptance/silent/silent_and_echo_combined.tmpl +2 -0
  161. data/spec/acceptance/silent/silent_short_notation.expected +1 -0
  162. data/spec/acceptance/silent/silent_short_notation.tmpl +1 -0
  163. data/spec/acceptance/silent/simple_silent_directive.expected +0 -0
  164. data/spec/acceptance/silent/simple_silent_directive.tmpl +1 -0
  165. data/spec/acceptance/slurp/basic_slurp_demo.expected +1 -0
  166. data/spec/acceptance/slurp/basic_slurp_demo.tmpl +4 -0
  167. data/spec/acceptance/super/super_with_no_effect.expected +4 -0
  168. data/spec/acceptance/super/super_with_no_effect.tmpl +5 -0
  169. data/spec/additions/module_spec.rb +126 -0
  170. data/spec/additions/string_spec.rb +99 -0
  171. data/spec/compiler_spec.rb +55 -0
  172. data/spec/grammar/additions/proc_spec.rb +25 -0
  173. data/spec/grammar/additions/regexp_spec.rb +37 -0
  174. data/spec/grammar/additions/string_spec.rb +106 -0
  175. data/spec/grammar/and_predicate_spec.rb +29 -0
  176. data/spec/grammar/continuation_wrapper_exception_spec.rb +23 -0
  177. data/spec/grammar/match_data_wrapper_spec.rb +41 -0
  178. data/spec/grammar/memoizing_cache_spec.rb +112 -0
  179. data/spec/grammar/node_spec.rb +126 -0
  180. data/spec/grammar/not_predicate_spec.rb +29 -0
  181. data/spec/grammar/parser_state_spec.rb +172 -0
  182. data/spec/grammar/parslet_choice_spec.rb +49 -0
  183. data/spec/grammar/parslet_combining_spec.rb +287 -0
  184. data/spec/grammar/parslet_merge_spec.rb +33 -0
  185. data/spec/grammar/parslet_omission_spec.rb +58 -0
  186. data/spec/grammar/parslet_repetition_spec.rb +77 -0
  187. data/spec/grammar/parslet_sequence_spec.rb +49 -0
  188. data/spec/grammar/parslet_spec.rb +23 -0
  189. data/spec/grammar/predicate_spec.rb +53 -0
  190. data/spec/grammar/proc_parslet_spec.rb +52 -0
  191. data/spec/grammar/regexp_parslet_spec.rb +347 -0
  192. data/spec/grammar/string_enumerator_spec.rb +94 -0
  193. data/spec/grammar/string_parslet_spec.rb +143 -0
  194. data/spec/grammar/symbol_parslet_spec.rb +30 -0
  195. data/spec/grammar_spec.rb +545 -0
  196. data/spec/parser_spec.rb +1418 -0
  197. data/spec/spec_helper.rb +34 -0
  198. data/spec/walrus_grammar/comment_spec.rb +39 -0
  199. data/spec/walrus_grammar/echo_directive_spec.rb +63 -0
  200. data/spec/walrus_grammar/escape_sequence_spec.rb +85 -0
  201. data/spec/walrus_grammar/literal_spec.rb +41 -0
  202. data/spec/walrus_grammar/message_expression_spec.rb +37 -0
  203. data/spec/walrus_grammar/multiline_comment_spec.rb +58 -0
  204. data/spec/walrus_grammar/placeholder_spec.rb +48 -0
  205. data/spec/walrus_grammar/raw_directive_spec.rb +81 -0
  206. data/spec/walrus_grammar/raw_text_spec.rb +65 -0
  207. data/spec/walrus_grammar/silent_directive_spec.rb +34 -0
  208. metadata +291 -0
data/bin/walrus ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright 2007 Wincent Colaiuta
3
+ # This program is distributed in the hope that it will be useful, but WITHOUT
4
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6
+ # in the accompanying file, "LICENSE.txt", for more details.
7
+ #
8
+ # $Id: diff.rb 89 2007-02-26 15:35:56Z wincent $
9
+
10
+ module Walrus
11
+
12
+ EXIT_LOAD_ERROR = 1
13
+ EXIT_ARGUMENT_ERROR = 2
14
+ EXIT_OTHER_ERROR = 3
15
+
16
+ begin
17
+ require 'walrus/runner'
18
+ rescue LoadError => e
19
+ $stderr.puts <<-HERE
20
+ Error: load error (#{e.to_s})
21
+
22
+ If you are trying to run Walrus but have not yet installed it, it may be that
23
+ Ruby cannot find the Walrus files. You can help Ruby to find the Walrus "lib"
24
+ and "ext" directories by adding them to the RUBYLIB environment variable. For
25
+ example, you could do the following if you are using the Bash shell,
26
+ substituting absolute paths for "lib" and "ext":
27
+
28
+ export RUBYLIB="${RUBYLIB}:lib:ext"
29
+
30
+ HERE
31
+ exit EXIT_LOAD_ERROR
32
+ end
33
+
34
+ begin
35
+ Runner.new.run
36
+ rescue Runner::ArgumentError => e
37
+ $stderr.puts "Error: #{e.to_s}", "For usage information type: #{$0} --help"
38
+ exit EXIT_ARGUMENT_ERROR
39
+ rescue Runner::Error => e
40
+ $stderr.puts "Error: #{e.to_s}"
41
+ exit EXIT_OTHER_ERROR
42
+ end
43
+
44
+ end # module Walrus
@@ -0,0 +1,11 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'mkmf'
10
+ create_makefile('jindex')
11
+
@@ -0,0 +1,79 @@
1
+ /*
2
+ Copyright 2007 Wincent Colaiuta
3
+ This program is distributed in the hope that it will be useful, but WITHOUT
4
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6
+ in the accompanying file, "LICENSE.txt", for more details.
7
+
8
+ $Id$
9
+ */
10
+
11
+ #include <ruby.h>
12
+
13
+ /*
14
+
15
+ Common code used by almost identical "jindex" and "jrindex" methods. A C extension is necessary here because with direct access to the rb_backref_get and rb_backref_set API there is no way to propagate $~ back to the caller after invoking the "index" and "rindex" methods. The code is basically equivalent to the following Ruby code:
16
+
17
+ def index arg1, optional_arg
18
+ index = super # plus code here for deciding whether or not to pass optional argument
19
+ match = ($~ ? $~.clone : nil)
20
+ index unpack('C*')[0...index].pack('C*').jlength # jlength clobbers $~ as a side effect, should consider rewriting it
21
+ $~ = match # in pure Ruby setting $~ here has only a local effect (not seen by caller)
22
+ index
23
+ end
24
+
25
+ */
26
+ static VALUE walrus_str_index_common(ID func, int argc, VALUE *argv, VALUE str)
27
+ {
28
+ VALUE jindex = Qnil; /* default return value */
29
+ VALUE index = rb_funcall2(str, func, argc, argv); /* call String#index or String#rindex*/
30
+ VALUE match = rb_backref_get(); /* save $~ */
31
+ if (!NIL_P(index))
32
+ {
33
+ VALUE packing_format = rb_str_new2("C*");
34
+ VALUE unpacked = rb_funcall(str, rb_intern("unpack"), 1, packing_format); /* unpack('C*') */
35
+ VALUE range = rb_funcall(rb_cRange, rb_intern("new"), 3, INT2FIX(0), index, Qtrue);
36
+ VALUE slice = rb_funcall(unpacked, rb_intern("slice"), 1, range); /* [0...idx] */
37
+ VALUE packed = rb_funcall(slice, rb_intern("pack"), 1, packing_format); /* pack('C*') */
38
+ jindex = rb_funcall(packed, rb_intern("jlength"), 0); /* jlength */
39
+ }
40
+ rb_backref_set(match); /* restore $~ */
41
+ return jindex;
42
+ }
43
+
44
+ /*
45
+
46
+ call-seq:
47
+ str.jindex(substring [, offset]) -> Fixnum or nil
48
+ str.jindex(fixnum [, offset]) -> Fixnum or nil
49
+ str.jindex(regexp [, offset]) -> Fixnum or nil
50
+
51
+ Multibyte-friendly equivalent of the String#index method. If $KCODE is appropriately set will return an accurate index based on character count rather than byte counts.
52
+
53
+ */
54
+ static VALUE walrus_str_jindex_m(int argc, VALUE *argv, VALUE str)
55
+ {
56
+ return walrus_str_index_common(rb_intern("index"), argc, argv, str);
57
+ }
58
+
59
+ /*
60
+
61
+ call-seq:
62
+ str.jrindex(substring [, offset]) -> Fixnum or nil
63
+ str.jrindex(fixnum [, offset]) -> Fixnum or nil
64
+ str.jrindex(regexp [, offset]) -> Fixnum or nil
65
+
66
+ Multibyte-friendly equivalent of the String#rindex method. If $KCODE is appropriately set will return an accurate index based on character count rather than byte counts.
67
+
68
+ */
69
+ static VALUE walrus_str_jrindex_m(int argc, VALUE *argv, VALUE str)
70
+ {
71
+ return walrus_str_index_common(rb_intern("rindex"), argc, argv, str);
72
+ }
73
+
74
+ void Init_jindex()
75
+ {
76
+ rb_define_method(rb_cString, "jindex", walrus_str_jindex_m, -1);
77
+ rb_define_method(rb_cString, "jrindex", walrus_str_jrindex_m, -1);
78
+ }
79
+
@@ -0,0 +1,11 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'mkmf'
10
+ create_makefile('mkdtemp')
11
+
@@ -0,0 +1,41 @@
1
+ /*
2
+ Copyright 2007 Wincent Colaiuta
3
+ This program is distributed in the hope that it will be useful, but WITHOUT
4
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6
+ in the accompanying file, "LICENSE.txt", for more details.
7
+
8
+ $Id$
9
+ */
10
+
11
+ #include <ruby.h>
12
+ #include <errno.h>
13
+
14
+ /*
15
+
16
+ call-seq:
17
+ Dir.mkdtemp([string]) -> String or nil
18
+
19
+ This method securely creates temporary directories. It is a wrapper for the mkdtemp() function in the standard C library. It takes an optional String parameter as a template describing the desired form of the directory name; if no template is supplied then "/tmp/temp.XXXXXX" is used as a default.
20
+
21
+ */
22
+ static VALUE walrus_dir_mkdtemp_m(int argc, VALUE *argv, VALUE self)
23
+ {
24
+ VALUE template;
25
+ if (rb_scan_args(argc, argv, "01", &template) == 0) /* check for 0 mandatory arguments, 1 optional argument */
26
+ template = Qnil; /* default to nil if no argument passed */
27
+ if (NIL_P(template))
28
+ template = rb_str_new2("/tmp/temp.XXXXXX"); /* fallback to this template if passed nil */
29
+ SafeStringValue(template); /* raises if template is tainted and SAFE level > 0 */
30
+ VALUE safe = StringValue(template); /* duck typing support */
31
+ char *path = mkdtemp(RSTRING(safe)->ptr);
32
+ if (path == NULL)
33
+ rb_raise(rb_eSystemCallError, "mkdtemp failed (error: %d)", errno);
34
+ return rb_str_new2(path);
35
+ }
36
+
37
+ void Init_mkdtemp()
38
+ {
39
+ rb_define_module_function(rb_cDir, "mkdtemp", walrus_dir_mkdtemp_m, -1);
40
+ }
41
+
@@ -0,0 +1,36 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ class Module
12
+
13
+ private
14
+
15
+ def attr_accessor_bycopy(*symbols)
16
+ symbols.each { |symbol| attr_bycopy(symbol, true) }
17
+ end
18
+
19
+ def attr_bycopy(symbol, writeable = false)
20
+ attr_reader symbol
21
+ attr_writer_bycopy(symbol) if writeable
22
+ end
23
+
24
+ def attr_writer_bycopy(*symbols)
25
+ symbols.each do |symbol|
26
+ self.module_eval %Q{
27
+ def #{symbol.id2name}=(value)
28
+ @#{symbol.id2name} = value.clone
29
+ rescue TypeError
30
+ @#{symbol.id2name} = value
31
+ end
32
+ }
33
+ end
34
+ end
35
+
36
+ end # class Module
@@ -0,0 +1,37 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ # Additions to String class for Unicode support.
12
+ class String
13
+
14
+ # Converts the receiver of the form "FooBar" to "foo_bar".
15
+ # Concretely, the receiver is split into words, each word lowercased, and the words are joined together using a lower-case separator. "Words" are considered to be runs of characters starting with an initial capital letter (note that words may begin with consecutive capital letters), and numbers may mark the start or the end of a word.
16
+ # Note that some information loss may be incurred; for example, "EOLToken" would be reduced to "eol_token".
17
+ def to_require_name
18
+ base = self.gsub(/([^A-Z_])([A-Z])/, '\1_\2') # insert an underscore before any initial capital letters
19
+ base.gsub!(/([A-Z])([A-Z])([^A-Z0-9_])/, '\1_\2\3') # consecutive capitals are words too, excluding any following capital that belongs to the next word
20
+ base.gsub!(/([^0-9_])(\d)/, '\1_\2') # numbers mark the start of a new word
21
+ base.gsub!(/(\d)([^0-9_])/, '\1_\2') # numbers also mark the end of a word
22
+ base.downcase # lowercase everything
23
+ end
24
+
25
+ # Converts the receiver of the form "foo_bar" to "FooBar".
26
+ # Specifically, the receiver is split into pieces delimited by underscores, each component is then converted to captial case (the first letter is capitalized and the remaining letters are lowercased) and finally the components are joined.
27
+ # Note that this method cannot recover information lost during a conversion using the require_name_from_classname method; for example, "EOL", when converted to "token", would be transformed back to "EolToken". Likewise, "Foo__bar" would be reduced to "foo__bar" and then in the reverse conversion would become "FooBar".
28
+ def to_class_name
29
+ self.split('_').collect { |component| component.capitalize}.join
30
+ end
31
+
32
+ # Returns a copy of the receiver with occurrences of \ replaced with \\, and occurrences of ' replaced with \'
33
+ def to_source_string
34
+ gsub(/[\\']/, '\\\\\&')
35
+ end
36
+
37
+ end # class String
@@ -0,0 +1,62 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # $Id$
3
+
4
+ require 'walrus'
5
+
6
+ module Test
7
+ module Unit
8
+
9
+ # See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/138320
10
+ # Usage:
11
+ #
12
+ # require 'test/unit'
13
+ # require 'walrus/additions/test/unit/error_collector'
14
+ #
15
+ # class TestClass < Test::Unit::TestCase
16
+ #
17
+ # include Test::Unit::ErrorCollector
18
+ #
19
+ # def test_method
20
+ # collecting_errors do
21
+ # assert false
22
+ # assert false
23
+ # end
24
+ # end
25
+ #
26
+ # end
27
+ #
28
+ module ErrorCollector
29
+
30
+ def collecting_errors
31
+ # save state prior to yielding to block
32
+ is_collecting = @is_collecting
33
+ @is_collecting = true
34
+ yield
35
+ ensure
36
+ # restore state on leaving block
37
+ @is_collecting = is_collecting
38
+ end
39
+
40
+ def raise(*)
41
+ super
42
+ rescue Test::Unit::AssertionFailedError
43
+ handle_error(:add_failure, $!)
44
+ rescue StandardError, ScriptError
45
+ handle_error(:add_error, $!)
46
+ end
47
+
48
+ def handle_error(method, error)
49
+ backtrace = error.backtrace
50
+ backtrace.shift # raise shouldn't appear in the backtrace
51
+ if @is_collecting
52
+ backtrace.slice!(5, 2) # remove collecting_errors and corresponding block
53
+ send(method, error.message, backtrace)
54
+ else
55
+ Kernel.raise(error, error.message, backtrace)
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,28 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Grammar
13
+
14
+ class CompileError < Exception
15
+
16
+ # take an optional hash (for packing extra info into exception?)
17
+ # position in AST/source file
18
+ # line number, column number
19
+ # filename
20
+ def initialize(message, info = {})
21
+ super message
22
+ end
23
+
24
+ end # class CompileError
25
+
26
+ end # class Grammar
27
+ end # module Walrus
28
+
@@ -0,0 +1,124 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id: /mirrors/Walrus/trunk/walrus/lib/walrus/compiler.rb 6709 2007-04-10T05:38:46.657919Z wincent $
8
+
9
+ require 'walrus'
10
+ require 'pathname'
11
+
12
+ module Walrus
13
+ class Compiler
14
+
15
+ BODY_INDENT = ' ' * 8
16
+ OUTSIDE_INDENT = ' ' * 6
17
+ DEFAULT_CLASS = 'DocumentSubclass'
18
+
19
+ # The public compiler class serves as the interface with the outside world. For thread-safety and concurrency, an inner, private Instance class is spawned in order to perform the actual compilation.
20
+ class Instance
21
+
22
+ def initialize(options)
23
+ @class_name = (options[:class_name] || DEFAULT_CLASS).to_s
24
+ @template_body = [] # will accumulate items for body, and joins them at the end of processing
25
+ @outside_body = [] # will accumulate items for outside of body, and joins them at the end of processing
26
+ end
27
+
28
+ def compile_subtree(subtree)
29
+ template_body = [] # local variable
30
+ outside_body = [] # local variable
31
+ subtree = [subtree] unless subtree.respond_to? :each
32
+ options = { :compiler_instance => self } # reset
33
+ subtree.each do |element|
34
+ # def/block and include directives may return two items
35
+ if element.kind_of? WalrusGrammar::DefDirective or element.kind_of? WalrusGrammar::IncludeDirective
36
+ inner, outer = element.compile(options)
37
+ outer.each { |line| outside_body << OUTSIDE_INDENT + line } if outer
38
+ inner.each { |line| template_body << BODY_INDENT + line } if inner
39
+ elsif element.instance_of? WalrusGrammar::ExtendsDirective # defines superclass and automatically invoke #super (super) at the head of the template_body
40
+ raise CompileError.new('#extends may be used only once per template') unless @extends_directive.nil?
41
+ raise CompileError.new('illegal #extends (#import already used in this template)') unless @import_directive.nil?
42
+ @extends_directive = element.compile(options)
43
+ elsif element.instance_of? WalrusGrammar::ImportDirective # defines superclass with no automatic invocation of #super on the template_body
44
+ raise CompileError.new('#import may be used only once per template') unless @import_directive.nil?
45
+ raise CompileError.new('illegal #import (#extends already used in this template)') unless @extends_directive.nil?
46
+ @import_directive = element.compile(options)
47
+ elsif element.kind_of? WalrusGrammar::Comment and element.column_start == 0 # special case if comment is only thing on input line
48
+ template_body << BODY_INDENT + element.compile(options)
49
+ options[:slurping] = true
50
+ next
51
+ else # everything else gets added to the template_body
52
+ element.compile(options).each { |line| template_body << BODY_INDENT + line } # indent by 6 spaces
53
+ end
54
+ options = { :compiler_instance => self } # reset
55
+ end
56
+ [template_body, outside_body]
57
+ end
58
+
59
+ def compile(tree)
60
+ inner, outer = compile_subtree(tree)
61
+ @template_body.concat inner if inner
62
+ @outside_body.concat outer if outer
63
+ if @import_directive
64
+ superclass_name = @import_directive.class_name
65
+ require_line = "require 'walrus/document'\n" + @import_directive.require_line
66
+ elsif @extends_directive
67
+ superclass_name = @extends_directive.class_name
68
+ require_line = "require 'walrus/document'\n" + @extends_directive.require_line
69
+ @template_body.unshift BODY_INDENT + "super # (invoked automatically due to Extends directive)\n"
70
+ else
71
+ superclass_name = 'Document'
72
+ require_line = "require 'walrus/document'"
73
+ end
74
+
75
+ <<-RETURN
76
+ \#!/usr/bin/env ruby
77
+ \# Generated #{Time.new.to_s} by Walrus version #{VERSION}
78
+
79
+ begin
80
+ require 'rubygems'
81
+ rescue LoadError
82
+ # installing Walrus via RubyGems is recommended
83
+ # otherwise Walrus must be installed in the RUBYLIB load path
84
+ end
85
+
86
+ #{require_line}
87
+
88
+ module Walrus
89
+
90
+ class WalrusGrammar
91
+
92
+ class #{@class_name} < #{superclass_name}
93
+
94
+ def template_body
95
+
96
+ #{@template_body.join}
97
+ end
98
+
99
+ #{@outside_body.join}
100
+ if __FILE__ == $0 # when run from the command line the default action is to call 'run'
101
+ new.run
102
+ end
103
+
104
+ end \# #{@class_name}
105
+
106
+ end \# WalrusGrammar
107
+
108
+ end \# Walrus
109
+
110
+ RETURN
111
+
112
+ end
113
+
114
+ end
115
+
116
+ # Walks the Abstract Syntax Tree, tree, that represents a parsed Walrus template.
117
+ # Returns a String that defines a Document subclass corresponding to the compiled version of the tree.
118
+ def compile(tree, options = {})
119
+ Instance.new(options).compile(tree)
120
+ end
121
+
122
+ end # class Compiler
123
+ end # module Walrus
124
+
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright 2007 Wincent Colaiuta
3
+ # This program is distributed in the hope that it will be useful, but WITHOUT
4
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6
+ # in the accompanying file, "LICENSE.txt", for more details.
7
+ #
8
+ # $Id: /mirrors/Walrus/trunk/walrus/lib/walrus/contrib/spec/walruscloth_spec.rb 6702 2007-04-09T15:04:40.448669Z wincent $
9
+
10
+ require 'rubygems'
11
+ require 'spec'
12
+ require File.join(File.dirname(__FILE__), '..', 'walruscloth')
13
+
14
+ describe 'using WalrusCloth' do
15
+
16
+ it 'should be able to create an unordered list' do
17
+ # => "<ul>\n\t<li>hello</li>\n\t</ul>"
18
+ WalrusCloth.new('* hello').to_html.should == RedCloth.new('* hello').to_html
19
+ end
20
+
21
+ it 'should be able to create an ordered list' do
22
+ # => "<ol>\n\t<li>hello</li>\n\t</ol>"
23
+ WalrusCloth.new('` hello').to_html.should == RedCloth.new('# hello').to_html
24
+ end
25
+
26
+ it 'should be able to nest lists' do
27
+ # => "<ol>\n\t<li>hello\n\t<ul>\n\t<li>world</li>\n\t</ol></li>\n\t</ul>"
28
+ WalrusCloth.new("` hello\n`* world").to_html.should == RedCloth.new("# hello\n#* world").to_html
29
+ end
30
+
31
+ end
32
+
@@ -0,0 +1,82 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'rubygems'
10
+ gem 'RedCloth', '= 3.0.4'; require 'redcloth'
11
+
12
+ # WalrusCloth is a RedCloth subclass that makes minimal modifications for ease of use with Walrus. Specifically, it makes two changes:
13
+ #
14
+ # 1. The hash or pound character (#) no longer indicates an ordered list; the backtick (`) character is used instead.
15
+ # 2. Only Textile rules are used by default, instead of Textile and Markdown.
16
+ #
17
+ # These changes are made because the hash character already has special meaning in Walrus as a directive marker. Textile is preferred over Markdown because it uses the hash character less extensively (in Markdown it is used as a heading indicator) and does not allow the backslash to be used as an escape marker (which again clashes with Walrus). Without these modifications it would be difficult to use RedCloth as a pre- or post-processor for Walrus templates because many characters would have to be specially escaped. This is particularly the case for the Walrus documentation itself where the documentation includes a lot of literal hash characters.
18
+ #
19
+ # I considered a number of possible workarounds to the problem, including making a fork of RedCloth. This fork basically consisted of a clean export of the latest RedCloth release with a project-wide replacement of "WalrusCloth" for "RedCloth" and "walruscloth" for "redcloth"; file names were also changed accordingly. Then the regular expressions that define Textile lists were modified. The benefit of this method was that there was no possibility of clashes with any installed version of RedCloth, but it was decidedly inelegant and the changes broke the RedCloth tests.
20
+ #
21
+ # In the end I decided to subclass RedCloth and override the list-detection regular expressions dynamically. This is somewhat cleaner and easier to maintain although it is still not a perfect solution (see limitations below). It's because of these limitations, together with the fact that I don't want to introduce a dependency on a third-party gem, that WalrusCloth is in the "contrib" subdirectory rather than in the Walrus core.
22
+ #
23
+ # Usage
24
+ # =====
25
+ #
26
+ # require 'walrus/contrib/walruscloth'
27
+ # WalrusCloth.new("` hello\n` world").to_html # note the space between the backtick and the list item content
28
+ # # => "<ul>\n\t<li>hello</li>\n\t\t<li>world</li>\n\t</ul>"
29
+ #
30
+ # Limitations
31
+ # ===========
32
+ #
33
+ # * Fragility: This technique could break for any future release of RedCloth if the way in which list-detection is implemented is changed.
34
+ # * Threading: Because this technique changes constants in the RedCloth namespace (albeit temporarily) it is not necessarily very "thread-friendly" if two threads are concurrently trying to use RedCloth and WalrusCloth concurrently. The only way to avoid this issues would be to reimplement the block_textile_lists entirely and that would again be a fragility consideration and a maintenance burden.
35
+ # * Warnings: This technique temporarily overrides constants and then restores them to their initial values; this would normally cause "already initialized constant" warnings but they are suppressed here by temporarily altering the $VERBOSE global variable, which is not very elegant.
36
+ # * Imparity: Given that this is only a partial override it is possible that some edge and corner cases will fail: for example, inspection of the RedCloth code indicates that it may be necessary to override the "blocks" method (and possibly others) to achieve total parity.
37
+ #
38
+ class WalrusCloth < RedCloth
39
+
40
+ def to_html(*rules)
41
+ rules = :textile if rules.empty?
42
+ begin
43
+ old_lists_re = RedCloth::LISTS_RE # save original values
44
+ old_lists_content_re = RedCloth::LISTS_CONTENT_RE
45
+ silently do # override
46
+ RedCloth::const_set('LISTS_RE', /^([`*]+?#{RedCloth::C} .*?)$(?![^`*])/m)
47
+ RedCloth::const_set('LISTS_CONTENT_RE', /^([`*]+)(#{RedCloth::A}#{RedCloth::C}) (.*)$/m)
48
+ end
49
+ super rules # process
50
+ ensure # restore original values
51
+ silently do
52
+ RedCloth::const_set('LISTS_RE', old_lists_re)
53
+ RedCloth::const_set('LISTS_CONTENT_RE', old_lists_content_re)
54
+ end
55
+ end
56
+ end
57
+
58
+ # "lT" presumably stands for "list type" (ordered or unordered)
59
+ def lT( text )
60
+ #text =~ /\#$/ ? 'o' : 'u'
61
+ text =~ /`$/ ? 'o' : 'u'
62
+ end
63
+
64
+ def hard_break( text )
65
+ #text.gsub!( /(.)\n(?!\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
66
+ text.gsub!( /(.)\n(?!\Z| *([`*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
67
+ end
68
+
69
+ private
70
+
71
+ # Nasty hack to prevent Ruby from emitting "already initialized constant" warnings when overriding constants.
72
+ # Sets $VERBOSE to nil, executes the passed block, then restores $VERBOSE to its previous state.
73
+ def silently &block
74
+ begin
75
+ verbose = $VERBOSE; $VERBOSE = nil # save
76
+ yield
77
+ ensure
78
+ $VERBOSE = verbose # restore
79
+ end
80
+ end
81
+
82
+ end # WalrusCloth