walrus 0.1

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.
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
@@ -0,0 +1,356 @@
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/runner.rb 6751 2007-04-12T16:56:29.067618Z wincent $
8
+
9
+ require 'walrus'
10
+ require 'fileutils'
11
+ require 'optparse'
12
+ require 'ostruct'
13
+ require 'pathname'
14
+ require 'rubygems'
15
+ require 'wopen3'
16
+
17
+ module Walrus
18
+
19
+ class Runner
20
+
21
+ class Error < Exception ; end
22
+
23
+ class ArgumentError < Error ; end
24
+
25
+ def initialize
26
+
27
+ @options = OpenStruct.new
28
+ @options.output_dir = nil
29
+ @options.input_extension = 'tmpl'
30
+ @options.output_extension = 'html'
31
+ @options.recurse = false
32
+ @options.backup = true
33
+ @options.force = false
34
+ @options.debug = false
35
+ @options.halt = false
36
+ @options.dry = false
37
+ @options.verbose = false
38
+
39
+ @command = nil # "compile", "fill" (saves to disk), "run" (prints to standard out)
40
+ @inputs = [] # list of input files and/or directories
41
+ parser = OptionParser.new do |o|
42
+
43
+ o.banner = "Usage: #{o.program_name} command input-file(s)-or-directory/ies [options]"
44
+ o.separator ''
45
+ o.separator ' _____________'
46
+ o.separator ' / \\'
47
+ o.separator " / o o \\ #{o.program_name}"
48
+ o.separator ' | b | Command-line front-end for the Walrus templating system'
49
+ o.separator ' \\ ~-----~ / Copyright 2007 Wincent Colaiuta'
50
+ o.separator ' \\ / / \\ \\ /'
51
+ o.separator ' / /-----\\ \\'
52
+ o.separator ' |_/ \\_|'
53
+ o.separator ''
54
+ o.separator 'Commands: compile -- compile templates to Ruby code'
55
+ o.separator ' fill -- runs compiled templates, writing output to disk'
56
+ o.separator ' run -- runs compiled templates, printing output to standard output'
57
+ o.separator ''
58
+
59
+ o.on('-o', '--output-dir DIR', 'Output directory (when filling)', 'defaults to same directory as input file') do |opt|
60
+ @options.output_dir = Pathname.new(opt)
61
+ end
62
+
63
+ o.on('-i', '--input-extension EXT', 'Extension for input file(s)', 'default: tmpl') do |opt|
64
+ @options.input_extension = opt
65
+ end
66
+
67
+ o.on('-e', '--output-extension EXT', 'Extension for output file(s) (when filling)', 'default: html') do |opt|
68
+ @options.output_extension = opt
69
+ end
70
+
71
+ o.on('-R', 'Search subdirectories recursively for input files', 'default: on') do |opt|
72
+ @options.recurse = opts
73
+ end
74
+
75
+ o.on('-b', '--[no-]backup', 'Make backups before overwriting', 'default: on') do |opt|
76
+ @options.backup = opt
77
+ end
78
+
79
+ o.on('-f', '--force', 'Force a recompile (when filling)', 'default: off (files only recompiled if source newer than output)') do |opt|
80
+ @options.force = opt
81
+ end
82
+
83
+ o.on('--halt', 'Halts on encountering an error (even a non-fatal error)', 'default: off') do |opt|
84
+ @options.halt = opt
85
+ end
86
+
87
+ o.on('-t', '--test', 'Performs a "dry" (test) run', 'default: off') do |opt|
88
+ @options.dry = opt
89
+ end
90
+
91
+ o.on('-d', '--debug', 'Print debugging information to standard error', 'default: off') do |opt|
92
+ @options.debug = opt
93
+ end
94
+
95
+ o.on('-v', '--verbose', 'Run verbosely', 'default: off') do |opt|
96
+ @options.verbose = opt
97
+ end
98
+
99
+ o.separator ''
100
+
101
+ o.on_tail('-h', '--help', 'Show this message') do
102
+ $stderr.puts o
103
+ exit
104
+ end
105
+
106
+ o.on_tail('--version', 'Show version') do
107
+ $stderr.puts 'Walrus ' + Walrus::VERSION
108
+ exit
109
+ end
110
+
111
+ end
112
+
113
+ begin
114
+ parser.parse!
115
+ rescue OptionParser::InvalidOption => e
116
+ raise ArgumentError.new(e)
117
+ end
118
+
119
+ parser.order! do |item|
120
+ if @command.nil? : @command = item # get command first ("compile", "fill" or "run")
121
+ else @inputs << Pathname.new(item) # all others (and there must be at least one) are file or directory names
122
+ end
123
+ end
124
+
125
+ raise ArgumentError.new('no command specified') if @command.nil?
126
+ raise ArgumentError.new('no inputs specified') unless @inputs.length > 0
127
+ end
128
+
129
+ def run
130
+ log "Beginning processing: #{Time.new.to_s}."
131
+
132
+ # TODO: flush memoizing cache after each file
133
+
134
+ expand(@inputs).each do |input|
135
+ case @command
136
+ when 'compile'
137
+ log "Compiling '#{input}'."
138
+ compile(input)
139
+ when 'fill'
140
+ log "Filling '#{input}'."
141
+ compile_if_needed(input)
142
+ begin
143
+ write_string_to_path(get_output(input), filled_output_path_for_input(input))
144
+ rescue Exception => e
145
+ handle_error(e)
146
+ end
147
+ when 'run'
148
+ log "Running '#{input}'."
149
+ compile_if_needed(input)
150
+ begin
151
+ printf('%s', get_output(input))
152
+ $stdout.flush
153
+ rescue Exception => e
154
+ handle_error(e)
155
+ end
156
+ else
157
+ raise ArgumentError.new("unrecognized command '#{@command}'")
158
+ end
159
+ end
160
+ log "Processing complete: #{Time.new.to_s}."
161
+ end
162
+
163
+ # Expects an array of Pathname objects.
164
+ # Directory inputs are themselves recursively expanded if the "recurse" option is set to true; otherwise only their top-level entries are expanded.
165
+ # Returns an expanded array of Pathname objects.
166
+ def expand(inputs)
167
+ expanded = []
168
+ inputs.each do |input|
169
+ if input.directory?
170
+ input.entries.each do |entry|
171
+ if entry.directory?
172
+ if @options.recurse
173
+ expanded.concat expand(entry.entries)
174
+ end
175
+ else # not a directory
176
+ expanded << entry
177
+ end
178
+ end
179
+ else # not a directory
180
+ expanded << input
181
+ end
182
+ end
183
+ expanded
184
+ end
185
+
186
+ def compile_if_needed(input)
187
+ compile(input, false)
188
+ end
189
+
190
+ def compiled_path_older_than_source_path(compiled_path, source_path)
191
+ begin
192
+ compiled = File.mtime(compiled_path)
193
+ source = File.mtime(source_path)
194
+ rescue SystemCallError # perhaps one of them doesn't exist
195
+ return true
196
+ end
197
+ compiled < source
198
+ end
199
+
200
+ def compile(input, force = true)
201
+ template_source_path = template_source_path_for_input(input)
202
+ compiled_path = compiled_source_path_for_input(input)
203
+ if force or @options.force or not compiled_path.exist? or compiled_path_older_than_source_path(compiled_path, template_source_path)
204
+ begin
205
+ template = Template.new(template_source_path)
206
+ rescue Exception => e
207
+ handle_error("failed to read input template '#{template_source_path}' (#{e.to_s})")
208
+ return
209
+ end
210
+
211
+ begin
212
+ compiled = template.compile
213
+ rescue Grammar::ParseError => e
214
+ handle_error("failed to compile input template '#{template_source_path}' (#{e.to_s})")
215
+ return
216
+ end
217
+
218
+ write_string_to_path(compiled, compiled_path, true)
219
+
220
+ end
221
+
222
+ end
223
+
224
+ def get_output(input)
225
+ if @options.dry
226
+ "(no output: dry run)\n"
227
+ else
228
+ # use Wopen3 (backticks choke if there is a space in the path, open3 throws away the exit status)
229
+ output = ''
230
+ Wopen3.popen3([compiled_source_path_for_input(input).realpath, '']) do |stdin, stdout, stderr|
231
+ threads = []
232
+ threads << Thread.new(stdout) do |out|
233
+ out.each { |line| output << line }
234
+ end
235
+ threads << Thread.new(stderr) do |err|
236
+ err.each { |line| STDERR.puts line }
237
+ end
238
+ threads.each { |thread| thread.join }
239
+ end
240
+ status = $?.exitstatus
241
+ raise SystemCallError.new("non-zero exit status (#{status})") if status != 0
242
+ output
243
+ end
244
+ end
245
+
246
+ def write_string_to_path(string, path, executable = false)
247
+
248
+ if @options.dry
249
+ log "Would write '#{path}' (dry run)."
250
+ else
251
+
252
+ unless path.dirname.exist?
253
+ begin
254
+ log "Creating directory '#{path.dirname}'."
255
+ FileUtils.mkdir_p path.dirname
256
+ rescue SystemCallError => e
257
+ handle_error(e)
258
+ return
259
+ end
260
+ end
261
+
262
+ log "Writing '#{path}'."
263
+ begin
264
+ File.open(path, "a+") do |f|
265
+ if not File.zero? path and @options.backup
266
+ log "Making backup of existing file at '#{path}'."
267
+ dir, base = path.split
268
+ FileUtils.cp path, dir + "#{base.to_s}.bak"
269
+ end
270
+ f.flock File::LOCK_EX
271
+ f.truncate 0
272
+ f.write string
273
+ f.chmod 0744 if executable
274
+ end
275
+ rescue SystemCallError => e
276
+ handle_error(e)
277
+ end
278
+ end
279
+ end
280
+
281
+ def adjusted_output_path(path)
282
+ if @options.output_dir
283
+ if path.absolute?
284
+ path = @options.output_dir + path.to_s.sub(/\A\//, '')
285
+ else
286
+ path = @options.output_dir + path
287
+ end
288
+ else
289
+ path
290
+ end
291
+ end
292
+
293
+ # If "input" already has the right extension it is returned unchanged.
294
+ # If the "input extension" is zero-length then "input" is returned unchanged.
295
+ # Otherwise the "input extension" is added to "input" and returned.
296
+ def template_source_path_for_input(input)
297
+ return input if input.extname == ".#{@options.input_extension}" # input already has the right extension
298
+ return input if @options.input_extension.length == 0 # zero-length extension, nothing to add
299
+ dir, base = input.split
300
+ dir + "#{base.to_s}.#{@options.input_extension}" # otherwise, add extension and return
301
+ end
302
+
303
+ def compiled_source_path_for_input(input)
304
+
305
+ # remove input extension if present
306
+ if input.extname == ".#{@options.input_extension}" and @options.input_extension.length > 0
307
+ dir, base = input.split
308
+ input = dir + base.basename(base.extname)
309
+ end
310
+
311
+ # add rb as an extension
312
+ dir, base = input.split
313
+ dir + "#{base.to_s}.rb"
314
+ end
315
+
316
+ def filled_output_path_for_input(input)
317
+
318
+ # remove input extension if present
319
+ if input.extname == ".#{@options.input_extension}" and @options.input_extension.length > 0
320
+ dir, base = input.split
321
+ input = dir + base.basename(base.extname)
322
+ end
323
+
324
+ # add output extension if appropriate
325
+ if @options.output_extension.length > 0
326
+ dir, base = input.split
327
+ adjusted_output_path(dir + "#{base.to_s}.#{@options.output_extension}")
328
+ else
329
+ adjusted_output_path(input)
330
+ end
331
+
332
+ end
333
+
334
+ private
335
+
336
+ # Writes "message" to standard error if user supplied the "--verbose" switch.
337
+ def log(message)
338
+ if @options.verbose
339
+ $stderr.puts message
340
+ end
341
+ end
342
+
343
+ # If the user supplied the "--halt" switch raises an Runner::Error exception based on "message". Otherwise merely prints "message" to the standard error.
344
+ def handle_error(message)
345
+ if @options.halt
346
+ raise Error.new(message)
347
+ else
348
+ $stderr.puts message
349
+ end
350
+ end
351
+
352
+
353
+ end # class Runner
354
+
355
+ end # module Walrus
356
+
@@ -0,0 +1,75 @@
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/template.rb 6730 2007-04-11T13:48:51.166868Z wincent $
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Template
13
+
14
+ attr_reader :base_text
15
+
16
+ # If initialized using a Pathname or File, returns the pathname. Otherwise returns nil.
17
+ attr_reader :origin
18
+
19
+ # Accepts input of class String, Pathname or File
20
+ def initialize(input)
21
+ raise ArgumentError if input.nil?
22
+ if input.respond_to? :read # should work with Pathname or File
23
+ @base_text = input.read
24
+ @origin = input.to_s
25
+ else
26
+ @base_text = input.to_s.clone
27
+ end
28
+ end
29
+
30
+ # The fill method returns a string containing the output produced when executing the compiled template.
31
+ def fill
32
+ @filled ||= instance_eval(compiled)
33
+ end
34
+
35
+ def filled
36
+ fill
37
+ end
38
+
39
+ # Parses template, returning compiled input (suitable for writing to disk).
40
+ def compile
41
+ @parser ||= Parser.new
42
+ @compiled ||= @parser.compile(@base_text, :class_name => class_name, :origin => @origin)
43
+ end
44
+
45
+ # Returns the compiled text of the receiver
46
+ def compiled
47
+ compile
48
+ end
49
+
50
+ # Prints output obtained by running the compiled template.
51
+ def run
52
+ p fill
53
+ end
54
+
55
+ def class_name
56
+ if @class_name
57
+ @class_name
58
+ else
59
+ if @origin.nil? : @class_name = Compiler::DEFAULT_CLASS # "DocumentSubclass"
60
+ else @class_name = strip_extensions(@origin).to_class_name
61
+ end
62
+ end
63
+ end
64
+
65
+ def strip_extensions(path)
66
+ extension = File.extname(path)
67
+ if extension != "" # recurse
68
+ strip_extensions File.basename(path, extension)
69
+ else # no more extensions
70
+ path
71
+ end
72
+ end
73
+
74
+ end # class Template
75
+ end # module Walrus
@@ -0,0 +1,24 @@
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/walrus_grammar/assignment_expression.rb 6701 2007-04-09T14:55:55.352472Z wincent $
8
+
9
+ require 'walrus/parser.rb' # make sure that RawText class has been defined prior to extending it
10
+
11
+ module Walrus
12
+ class WalrusGrammar
13
+
14
+ class AssignmentExpression
15
+
16
+ def compile(options = {})
17
+ @lvalue.source_text + '=' + @expression.source_text
18
+ end
19
+
20
+ end # class AssignmentExpression
21
+
22
+ end # class WalrusGrammar
23
+ end # Walrus
24
+
@@ -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/parser.rb' # make sure that RawText class has been defined prior to extending it
10
+
11
+ module Walrus
12
+ class WalrusGrammar
13
+
14
+ class BlockDirective
15
+
16
+ # Returns a string containing the compiled (Ruby) version of receiver.
17
+ def compile(options = {})
18
+ inner, outer = super
19
+ inner = '' if inner.nil?
20
+ inner << "lookup_and_accumulate_placeholder(#{@identifier.to_s.to_sym.inspect})\n"
21
+ [inner, outer]
22
+ end
23
+
24
+ end # class BlockDirective
25
+
26
+ end # class WalrusGrammar
27
+ end # Walrus
28
+
@@ -0,0 +1,24 @@
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/parser.rb' # make sure that RawText class has been defined prior to extending it
10
+
11
+ module Walrus
12
+ class WalrusGrammar
13
+
14
+ class Comment
15
+
16
+ def compile(options = {})
17
+ '# Comment:' + @lexeme.to_s + "\n"
18
+ end
19
+
20
+ end
21
+
22
+ end # class WalrusGrammar
23
+ end # Walrus
24
+
@@ -0,0 +1,64 @@
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/walrus_grammar/def_directive.rb 6719 2007-04-10T15:00:33.886928Z wincent $
8
+
9
+ require 'walrus/parser.rb' # make sure that RawText class has been defined prior to extending it
10
+
11
+ module Walrus
12
+ class WalrusGrammar
13
+
14
+ class DefDirective
15
+
16
+ # Returns a string containing the compiled (Ruby) version of receiver.
17
+ def compile(options = {})
18
+ internal = ''
19
+
20
+ if @params == []
21
+ external = "def #{@identifier.to_s}\n"
22
+ else
23
+ # this will work for the simple case where params are plain identifiers
24
+ params = (@params.kind_of? Array) ? @params : [@params]
25
+ param_list = params.collect { |param| param.compile }.join(', ')
26
+ external = "def #{@identifier.to_s}(#{param_list})\n"
27
+ end
28
+
29
+ nested = nil
30
+
31
+ if @content.respond_to? :each : content = @content
32
+ else content = [@content]
33
+ end
34
+
35
+ content.each do |element|
36
+ if element.kind_of? WalrusGrammar::DefDirective # must handle nested def blocks here
37
+ inner, outer = element.compile(options)
38
+ nested = ['', ''] if nested.nil?
39
+ external << inner if inner
40
+ nested[1] << "\n" + outer
41
+ else
42
+ # again, may wish to forget the per-line indenting here if it breaks sensitive directive types
43
+ # (#ruby blocks for example, which might have here documents)
44
+ element.compile(options).each do |lines| # may return a single line or an array of lines
45
+ lines.each { |line| external << ' ' + line }
46
+ end
47
+ end
48
+ end
49
+
50
+ external << "end\n\n"
51
+
52
+ if nested
53
+ external << nested[1]
54
+ end
55
+
56
+ internal = nil if internal == '' # better to return nil than an empty string here (which would get indented needlessly)
57
+ [internal, external]
58
+ end
59
+
60
+ end # class DefDirective
61
+
62
+ end # class WalrusGrammar
63
+ end # Walrus
64
+
@@ -0,0 +1,44 @@
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/walrus_grammar/echo_directive.rb 6701 2007-04-09T14:55:55.352472Z wincent $
8
+
9
+ require 'walrus/parser.rb' # make sure that RawText class has been defined prior to extending it
10
+
11
+ module Walrus
12
+ class WalrusGrammar
13
+
14
+ class EchoDirective
15
+
16
+ def compile(options = {})
17
+
18
+ if @expression.respond_to? :each
19
+ expression = @expression
20
+ else
21
+ expression = [@expression]
22
+ end
23
+
24
+ # TODO: potentially include line, col and file name info in the comments generated by the compiler
25
+
26
+ compiled = ''
27
+ first = true
28
+ expression.each do |expr|
29
+ if first
30
+ compiled << "accumulate(instance_eval { %s }) # Echo directive\n" % expr.compile
31
+ first = false
32
+ else
33
+ compiled << "accumulate(instance_eval { %s }) # Echo directive (continued)\n" % expr.compile
34
+ end
35
+ end
36
+ compiled
37
+
38
+ end
39
+
40
+ end # class EchoDirective
41
+
42
+ end # class WalrusGrammar
43
+ end # Walrus
44
+
@@ -0,0 +1,24 @@
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/parser.rb' # make sure that RawText class has been defined prior to extending it
10
+
11
+ module Walrus
12
+ class WalrusGrammar
13
+
14
+ class EscapeSequence
15
+
16
+ def compile(options = {})
17
+ "accumulate(%s) \# EscapeSequence\n" % @lexeme.to_s.dump
18
+ end
19
+
20
+ end
21
+
22
+ end # class WalrusGrammar
23
+ end # Walrus
24
+
@@ -0,0 +1,44 @@
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/parser.rb' # make sure that the class has been defined prior to extending it
10
+ require 'ostruct'
11
+
12
+ module Walrus
13
+ class WalrusGrammar
14
+
15
+ class ImportDirective
16
+
17
+ # Returns an OpenStruct encapsulating information about the receiver for use by the compiler
18
+ def compile(options = {})
19
+ info = OpenStruct.new
20
+ path = Pathname.new @class_name.lexeme.to_s
21
+
22
+ if path.absolute?
23
+ # it will work just fine as it is
24
+ info.class_name = path.basename.to_s.to_class_name
25
+ info.require_line = "require '#{path.to_s}'"
26
+ else
27
+ dir, base = path.split
28
+ info.class_name = base.to_s.to_class_name
29
+ if dir.to_s == '.'
30
+ # desired template is in the same directory
31
+ info.require_line = "require File.join(File.dirname(__FILE__), '#{base.to_s}').to_s"
32
+ else
33
+ # desired template is in a relative directory
34
+ info.require_line = "require File.join(File.dirname(__FILE__), '#{dir.to_s}', '#{base.to_s}').to_s"
35
+ end
36
+ end
37
+ info
38
+ end
39
+
40
+ end # class ImportDirective
41
+
42
+ end # class WalrusGrammar
43
+ end # Walrus
44
+