gisele 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,264 @@
1
+ require 'spec_helper'
2
+ module Gisele::Language
3
+ describe Grammar, "ast" do
4
+
5
+ let(:grammar){ Gisele::Language::Grammar }
6
+
7
+ def ast(text, rule, consume = true)
8
+ grammar.parse(text, :root => rule, :consume => consume).value
9
+ end
10
+
11
+ describe "the bool_expr rule" do
12
+
13
+ it 'returns expected ast on simple expressions' do
14
+ expected = [:and, [:varref, "diagKnown"], [:varref, "platLow"]]
15
+ ast("diagKnown and platLow", :bool_expr).should eq(expected)
16
+ end
17
+
18
+ it 'respects priorities' do
19
+ expected = [:or, [:and, [:varref, "diagKnown"], [:varref, "platLow"]], [:varref, "platHigh"]]
20
+ ast("diagKnown and platLow or platHigh", :bool_expr).should eq(expected)
21
+ end
22
+
23
+ it 'supports double negations' do
24
+ expected = [:not, [:not, [:varref, "diagKnown"]]]
25
+ ast("not not(diagKnown)", :bool_expr).should eq(expected)
26
+ end
27
+
28
+ end # bool_expr
29
+
30
+ describe 'the event_commalist rule' do
31
+
32
+ it 'parses singleton lists as expected' do
33
+ expr = 'Diagnosis:start'
34
+ expected = ["Diagnosis:start"]
35
+ ast(expr, :event_commalist).should eq(expected)
36
+ end
37
+
38
+ it 'parses non empty lists as expected' do
39
+ expr = 'Diagnosis:start, an_event'
40
+ expected = ["Diagnosis:start", "an_event"]
41
+ ast(expr, :event_commalist).should eq(expected)
42
+ end
43
+
44
+ end # event_commalist
45
+
46
+ describe 'the event_set rule' do
47
+
48
+ it 'parses non empty lists as expected' do
49
+ expr = '{Diagnosis:start, an_event}'
50
+ expected = [:event_set, "Diagnosis:start", "an_event"]
51
+ ast(expr, :event_set).should eq(expected)
52
+ end
53
+
54
+ end # event_set
55
+
56
+ describe "the fluent_def rule" do
57
+
58
+ it 'parses fluent definitions as expected' do
59
+ defn = "fluent diagKnown {Diagnosis:start, diagnosis}, {Treatment:end} initially false"
60
+ expected = [:fluent,
61
+ "diagKnown",
62
+ [:event_set, "Diagnosis:start", "diagnosis"],
63
+ [:event_set, "Treatment:end"],
64
+ false]
65
+ ast(defn, :fluent_def).should eq(expected)
66
+ end
67
+
68
+ it 'does not require the initial value' do
69
+ defn = "fluent diagKnown {Diagnosis:start, diagnosis}, {Treatment:end}"
70
+ expected = [:fluent,
71
+ "diagKnown",
72
+ [:event_set, "Diagnosis:start", "diagnosis"],
73
+ [:event_set, "Treatment:end"],
74
+ nil]
75
+ ast(defn, :fluent_def).should eq(expected)
76
+ end
77
+
78
+ end # fluent_def rule
79
+
80
+ describe "the trackvar_def rule" do
81
+
82
+ it 'parses tracking variable definitions as expected' do
83
+ defn = "trackvar mplus {Diagnosis:start}"
84
+ expected = [:trackvar,
85
+ "mplus",
86
+ [:event_set, "Diagnosis:start"],
87
+ [:event_set],
88
+ nil]
89
+ ast(defn, :trackvar_def).should eq(expected)
90
+ end
91
+
92
+ it 'supports obsolete events and initial value' do
93
+ defn = "trackvar mplus {Diagnosis:start}, {Treatment:end} initially true"
94
+ expected = [:trackvar,
95
+ "mplus",
96
+ [:event_set, "Diagnosis:start"],
97
+ [:event_set, "Treatment:end"],
98
+ true]
99
+ ast(defn, :trackvar_def).should eq(expected)
100
+ end
101
+
102
+ end # trackvar_def rule
103
+
104
+ describe "the task_call_statement rule" do
105
+
106
+ it 'parses as expected' do
107
+ ast("Diagnosis", :task_call_statement).should eq([:task_call, "Diagnosis"])
108
+ end
109
+
110
+ end # task_call_statement
111
+
112
+ describe "the statement_list rule" do
113
+
114
+ it 'parses a list of 2 elements' do
115
+ expr = "Task1 Task2"
116
+ expected = [[:task_call, "Task1"], [:task_call, "Task2"]]
117
+ ast(expr, :statement_list).should eq(expected)
118
+ end
119
+
120
+ it 'parses a list of 3 elements' do
121
+ expr = "Task1 Task2 Task3"
122
+ expected = [[:task_call, "Task1"], [:task_call, "Task2"], [:task_call, "Task3"]]
123
+ ast(expr, :statement_list).should eq(expected)
124
+ end
125
+
126
+ end # statement_list
127
+
128
+ describe "the par_statement rule" do
129
+
130
+ it 'parses as expected' do
131
+ expr = "par Task1 Task2 end"
132
+ expected = [:par, [:task_call, "Task1"], [:task_call, "Task2"]]
133
+ ast(expr, :par_statement).should eq(expected)
134
+ end
135
+
136
+ end # par_statement
137
+
138
+ describe "the seq_statement rule" do
139
+
140
+ it 'parses as expected' do
141
+ expr = "seq Task1 Task2 end"
142
+ expected = [:seq, [:task_call, "Task1"], [:task_call, "Task2"]]
143
+ ast(expr, :seq_statement).should eq(expected)
144
+ end
145
+
146
+ end # seq_statement
147
+
148
+ describe "the while_statement rule" do
149
+
150
+ it 'parses as expected' do
151
+ expr = "while goodCond Task1 end"
152
+ expected = \
153
+ [:while,
154
+ [:varref, "goodCond"],
155
+ [:task_call, "Task1"]]
156
+ ast(expr, :while_statement).should eq(expected)
157
+ end
158
+
159
+ it 'recognizes implicit sequences' do
160
+ expr = "while goodCond Task1 Task2 end"
161
+ expected = \
162
+ [:while,
163
+ [:varref, "goodCond"],
164
+ [:seq, [:task_call, "Task1"], [:task_call, "Task2"]]]
165
+ ast(expr, :while_statement).should eq(expected)
166
+ end
167
+
168
+ end # while_statement
169
+
170
+ describe "the else_clause rule" do
171
+
172
+ it 'parses as expected' do
173
+ expr = "else Task1 "
174
+ expected = \
175
+ [:else, [:task_call, "Task1"]]
176
+ ast(expr, :else_clause).should eq(expected)
177
+ end
178
+
179
+ end # else_clause
180
+
181
+ describe "the elsif_clause rule" do
182
+
183
+ it 'parses as expected' do
184
+ expr = "elsif goodCond Task1 "
185
+ expected = \
186
+ [:elsif, [:varref, "goodCond"], [:task_call, "Task1"]]
187
+ ast(expr, :elsif_clause).should eq(expected)
188
+ end
189
+
190
+ end # elsif_clause
191
+
192
+ describe "the if_statement rule" do
193
+
194
+ it 'parses as expected' do
195
+ expr = "if goodCond Task1 end"
196
+ expected = \
197
+ [:if, [:varref, "goodCond"], [:task_call, "Task1"]]
198
+ ast(expr, :if_statement).should eq(expected)
199
+ end
200
+
201
+ it 'supports a else clause' do
202
+ expr = "if goodCond Task1 else Task2 end"
203
+ expected = \
204
+ [:if,
205
+ [:varref, "goodCond"], [:task_call, "Task1"],
206
+ [:else, [:task_call, "Task2"]] ]
207
+ ast(expr, :if_statement).should eq(expected)
208
+ end
209
+
210
+ it 'supports elsif clauses' do
211
+ expr = "if goodCond Task1 elsif otherCond Task2 elsif stillAnother Task3 else Task4 end"
212
+ expected = \
213
+ [:if,
214
+ [:varref, "goodCond"], [:task_call, "Task1"],
215
+ [:elsif,
216
+ [:varref, "otherCond"], [:task_call, "Task2"]],
217
+ [:elsif,
218
+ [:varref, "stillAnother"], [:task_call, "Task3"]],
219
+ [:else,
220
+ [:task_call, "Task4"]] ]
221
+ ast(expr, :if_statement).should eq(expected)
222
+ end
223
+
224
+ end # if_statement
225
+
226
+ describe 'the task_refinement rule' do
227
+
228
+ it 'parses as expected' do
229
+ expr = "refinement Task1 end"
230
+ expected = [:task_call, "Task1"]
231
+ ast(expr, :task_refinement).should eq(expected)
232
+ end
233
+
234
+ end # task_refinement
235
+
236
+ describe 'the task_signature rule' do
237
+
238
+ it 'parses as expected' do
239
+ expr = "fluent diagKnown {}, {}\ntrackvar mplus {}"
240
+ expected = \
241
+ [ [:fluent, "diagKnown", [:event_set], [:event_set], nil],
242
+ [:trackvar, "mplus", [:event_set], [:event_set], nil]]
243
+ ast(expr, :task_signature).should eq(expected)
244
+ end
245
+
246
+ end # task_signature
247
+
248
+ describe 'the task_def rule' do
249
+
250
+ it 'parses as expected' do
251
+ expr = "task Task1 fluent diagKnown {}, {} refinement Task2 end end"
252
+ expected = \
253
+ [:task, "Task1",
254
+ [:signature,
255
+ [:fluent, "diagKnown", [:event_set], [:event_set], nil]],
256
+ [:refinement,
257
+ [:task_call, "Task2"]]]
258
+ ast(expr, :task_def).should eq(expected)
259
+ end
260
+
261
+ end # task_def
262
+
263
+ end
264
+ end
@@ -0,0 +1,329 @@
1
+ require 'spec_helper'
2
+ module Gisele::Language
3
+ describe Grammar do
4
+
5
+ let(:grammar){ Gisele::Language::Grammar }
6
+
7
+ def parse(text, rule, consume = true)
8
+ grammar.parse(text, :root => rule, :consume => consume)
9
+ end
10
+
11
+ ### Spacing
12
+
13
+ describe 'the spaces rule' do
14
+
15
+ it 'parses all kind of spaces' do
16
+ parse(' ', :spaces).should eq(' ')
17
+ parse("\t", :spaces).should eq("\t")
18
+ parse("\n", :spaces).should eq("\n")
19
+ parse(" \t\n", :spaces).should eq(" \t\n")
20
+ end
21
+
22
+ it 'enforces mandatory spacing' do
23
+ lambda{ parse('', :spaces) }.should raise_error(Citrus::ParseError)
24
+ end
25
+
26
+ end
27
+
28
+ describe 'the spacing rule' do
29
+
30
+ it 'parses all kind of spaces' do
31
+ parse(' ', :spacing).should eq(' ')
32
+ parse("\t", :spacing).should eq("\t")
33
+ parse("\n", :spacing).should eq("\n")
34
+ parse(" \t\n", :spacing).should eq(" \t\n")
35
+ end
36
+
37
+ it 'does not enforces mandatory spacing' do
38
+ parse('', :spacing).should eq('')
39
+ end
40
+
41
+ end
42
+
43
+ ### Literals
44
+
45
+ describe 'the boolean_literal rule' do
46
+
47
+ it 'parses booleans' do
48
+ parse('true', :boolean_literal).should eq('true')
49
+ parse('false', :boolean_literal).should eq('false')
50
+ end
51
+
52
+ it 'does not parses integers' do
53
+ lambda{ parse('0', :boolean_literal) }.should raise_error(Citrus::ParseError)
54
+ end
55
+
56
+ end
57
+
58
+ ### Names
59
+
60
+ describe 'the task_name rule' do
61
+
62
+ it 'parses correct task names' do
63
+ parse('A', :task_name).should eq('A')
64
+ parse('Diagnosis', :task_name).should eq('Diagnosis')
65
+ parse('TaskName', :task_name).should eq('TaskName')
66
+ parse('Task_Name', :task_name).should eq('Task_Name')
67
+ end
68
+
69
+ it 'raises on invalid task names' do
70
+ lambda{ parse('not_a_task_name', :task_name) }.should raise_error(Citrus::ParseError)
71
+ end
72
+
73
+ end # task_name
74
+
75
+ describe 'the variable_name rule' do
76
+
77
+ it 'parses correct variable names' do
78
+ parse('a', :variable_name).should eq('a')
79
+ parse('diagnosis', :variable_name).should eq('diagnosis')
80
+ parse('varName', :variable_name).should eq('varName')
81
+ end
82
+
83
+ it 'raises on invalid variable names' do
84
+ lambda{ parse('NotAVarName', :variable_name) }.should raise_error(Citrus::ParseError)
85
+ end
86
+
87
+ end # variable_name
88
+
89
+ describe 'the event_name rule' do
90
+
91
+ it 'parses correct event names' do
92
+ parse('a', :event_name).should eq('a')
93
+ parse('event', :event_name).should eq('event')
94
+ parse('event_name', :event_name).should eq('event_name')
95
+ end
96
+
97
+ it 'raises on invalid variable names' do
98
+ lambda{ parse('NotAnEventName', :event_name) }.should raise_error(Citrus::ParseError)
99
+ lambda{ parse('notAnEventName', :event_name) }.should raise_error(Citrus::ParseError)
100
+ end
101
+
102
+ end # event_name
103
+
104
+ ### Events
105
+
106
+ describe 'the task_start_or_end rule' do
107
+
108
+ it 'parses correct event names' do
109
+ parse('Task:start', :task_start_or_end).should eq('Task:start')
110
+ parse('Task:end', :task_start_or_end).should eq('Task:end')
111
+ end
112
+
113
+ it 'raises on simple task names' do
114
+ lambda{ parse('Task', :task_start_or_end) }.should raise_error(Citrus::ParseError)
115
+ end
116
+
117
+ end # task_start_or_end
118
+
119
+ describe 'the event rule' do
120
+
121
+ it 'parses correct events' do
122
+ parse('Task:start', :event).should eq('Task:start')
123
+ parse('Task:end', :event).should eq('Task:end')
124
+ parse('an_event', :event).should eq('an_event')
125
+ end
126
+
127
+ it 'raises on invalid event names' do
128
+ lambda{ parse('Task', :event) }.should raise_error(Citrus::ParseError)
129
+ end
130
+
131
+ end # event
132
+
133
+ describe 'the event_commalist rule' do
134
+
135
+ it 'parses a singleton list' do
136
+ parse('Task:start', :event_commalist).should eq('Task:start')
137
+ end
138
+
139
+ it 'parses multiple events' do
140
+ parse('Task:start, an_event', :event_commalist).should eq('Task:start, an_event')
141
+ end
142
+
143
+ it 'recognizes invalid events' do
144
+ lambda{ parse('Task:start, NotAnEvent', :event_commalist) }.should raise_error(Citrus::ParseError)
145
+ end
146
+
147
+ end # event_commalist
148
+
149
+ describe 'the event_set rule' do
150
+
151
+ it 'parses empty sets' do
152
+ parse('{}', :event_set).should eq('{}')
153
+ parse('{ }', :event_set).should eq('{ }')
154
+ end
155
+
156
+ it 'parses event singletons' do
157
+ parse('{Task:start}', :event_set).should eq('{Task:start}')
158
+ parse('{ Task:start }', :event_set).should eq('{ Task:start }')
159
+ end
160
+
161
+ it 'recognizes invalid events in the set' do
162
+ lambda{ parse('{Task:start, NotAnEvent}', :event_set) }.should raise_error(Citrus::ParseError)
163
+ end
164
+
165
+ end # event_set
166
+
167
+ ### Variables
168
+
169
+ describe 'the fluent_def rule' do
170
+
171
+ it 'parses valid fluent definitions' do
172
+ defn = 'fluent diagKnown {Diagnosis:start}, {Treatment:end} initially false'
173
+ parse(defn, :fluent_def).should eq(defn)
174
+ end
175
+
176
+ it 'supports a missing initial value' do
177
+ defn = 'fluent diagKnown {Diagnosis:start}, {Treatment:end}'
178
+ parse(defn, :fluent_def).should eq(defn)
179
+ end
180
+
181
+ it 'supports empty sets for events' do
182
+ defn = 'fluent diagKnown {}, {} initially true'
183
+ parse(defn, :fluent_def).should eq(defn)
184
+ end
185
+
186
+ end # fluent_def
187
+
188
+ describe 'the trackvar_def rule' do
189
+
190
+ it 'parses valid tracking variable definitions' do
191
+ defn = 'trackvar plateletLow {BloodTest:end}'
192
+ parse(defn, :trackvar_def).should eq(defn)
193
+ end
194
+
195
+ it 'supports an optional initial value' do
196
+ defn = 'trackvar plateletLow {BloodTest:end} initially false'
197
+ parse(defn, :trackvar_def).should eq(defn)
198
+ end
199
+
200
+ it 'supports optional obsolete events' do
201
+ defn = 'trackvar plateletLow {BloodTest:end}, {Chemotherapy:end}'
202
+ parse(defn, :trackvar_def).should eq(defn)
203
+ end
204
+
205
+ end # trackvar_def
206
+
207
+ describe 'the bool_expr rule' do
208
+
209
+ it 'parses single variable references' do
210
+ parse('diagKnown', :bool_expr).should eq('diagKnown')
211
+ end
212
+
213
+ it 'parses boolean literals' do
214
+ parse('true', :bool_expr).should eq('true')
215
+ parse('false', :bool_expr).should eq('false')
216
+ end
217
+
218
+ it 'parses negated expression' do
219
+ parse('not diagKnown', :bool_expr).should eq('not diagKnown')
220
+ parse('not true', :bool_expr).should eq('not true')
221
+ parse('not false', :bool_expr).should eq('not false')
222
+ end
223
+
224
+ it 'parses or expressions' do
225
+ parse('diagKnown or platLow', :bool_expr).should eq('diagKnown or platLow')
226
+ end
227
+
228
+ it 'parses and expressions' do
229
+ parse('diagKnown and platLow', :bool_expr).should eq('diagKnown and platLow')
230
+ end
231
+
232
+ it 'parses complex expressions' do
233
+ expr = 'diagKnown and (platLow or not(metastased and mplus))'
234
+ parse(expr, :bool_expr).should eq(expr)
235
+ end
236
+
237
+ end # bool_expr
238
+
239
+ ### Process statements
240
+
241
+ describe 'the par_statement rule' do
242
+
243
+ it 'parses a single parallel statement' do
244
+ expr = 'par Task1 Task2 end'
245
+ parse(expr, :par_statement).should eq(expr)
246
+ end
247
+
248
+ end # par_statement
249
+
250
+ describe 'the seq_statement rule' do
251
+
252
+ it 'parses a single sequence statement' do
253
+ expr = 'seq Task1 Task2 end'
254
+ parse(expr, :seq_statement).should eq(expr)
255
+ end
256
+
257
+ end # seq_statement
258
+
259
+ describe 'the while_statement rule' do
260
+
261
+ it 'parses a single while statement' do
262
+ expr = 'while badCond Task end'
263
+ parse(expr, :while_statement).should eq(expr)
264
+ end
265
+
266
+ end # while_statement
267
+
268
+ describe 'the if_statement rule' do
269
+
270
+ it 'parses a single if statement' do
271
+ expr = 'if goodCond Task end'
272
+ parse(expr, :if_statement).should eq(expr)
273
+ end
274
+
275
+ it 'supports an optional else' do
276
+ expr = 'if goodCond GoodTask else BadTask end'
277
+ parse(expr, :if_statement).should eq(expr)
278
+ end
279
+
280
+ it 'supports an optional elsif clauses' do
281
+ expr = 'if goodCond GoodTask elsif otherCond OtherTask elsif yetAnother BadTask end'
282
+ parse(expr, :if_statement).should eq(expr)
283
+ end
284
+
285
+ end # if_statement
286
+
287
+ describe 'the process_statement rule' do
288
+
289
+ it 'parses a simple process statement' do
290
+ expr = <<-PROCESS.strip
291
+ DoSomething
292
+ if goodCond
293
+ DoForGood
294
+ else
295
+ DoForBad
296
+ end
297
+ CleanDesk
298
+ PROCESS
299
+ parse(expr, :process_statement).should eq(expr)
300
+ end
301
+
302
+ end # process_statement
303
+
304
+ describe 'the task_def rule' do
305
+
306
+ it 'parses a simple task definition' do
307
+ taskdef = <<-TASKDEF.strip
308
+ task Process
309
+ refinement Diagnosis end
310
+ end
311
+ TASKDEF
312
+ parse(taskdef, :task_def).should eq(taskdef)
313
+ end
314
+
315
+ it 'supports optional variable definitions in the signature' do
316
+ taskdef = <<-TASKDEF.strip
317
+ task Process
318
+ fluent diagKnown {Diagnosis:start}, {} initially false
319
+ trackvar mplus {Diagnosis:end}
320
+ refinement Diagnosis end
321
+ end
322
+ TASKDEF
323
+ parse(taskdef, :task_def).should eq(taskdef)
324
+ end
325
+
326
+ end
327
+
328
+ end
329
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ module Gisele::Language
3
+ describe Parser do
4
+
5
+ fixture_files('tasks/**/*.gis').each do |file|
6
+ if file.sub_ext(".ast").exist?
7
+
8
+ it "returns the expected ast on #{file}" do
9
+ parsed = Parser.parse(file)
10
+ expected = Kernel::eval(file.sub_ext(".ast").read, TOPLEVEL_BINDING, file.sub_ext(".ast").to_s)
11
+ parsed.should eq(expected)
12
+ end
13
+
14
+ else
15
+
16
+ it "parses #{file} without error" do
17
+ parsed = Parser.parse(file)
18
+ parsed.should be_a(Array)
19
+ parsed.first.should eq(:task)
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ describe Gisele do
3
+
4
+ it "has a version number" do
5
+ Gisele.const_defined?(:VERSION).should be_true
6
+ end
7
+
8
+ end
@@ -0,0 +1,75 @@
1
+ # Installs a rake task for debuging the announcement mail.
2
+ #
3
+ # This file installs the 'rake debug_mail' that flushes an announcement mail
4
+ # for your library on the standard output. It is automatically generated
5
+ # by Noe from your .noespec file, and should therefore be configured there,
6
+ # under the variables/rake_tasks/debug_mail entry, as illustrated below:
7
+ #
8
+ # variables:
9
+ # rake_tasks:
10
+ # debug_mail:
11
+ # rx_changelog_sections: /^#/
12
+ # nb_changelog_sections: 1
13
+ # ...
14
+ #
15
+ # If you have specific needs requiring manual intervention on this file,
16
+ # don't forget to set safe-override to false in your noe specification:
17
+ #
18
+ # template-info:
19
+ # manifest:
20
+ # tasks/debug_mail.rake:
21
+ # safe-override: false
22
+ #
23
+ # The mail template used can be found in debug_mail.txt. That file may be
24
+ # changed to tune the mail you want to send. If you do so, don't forget to
25
+ # add a manifest entry in your .noespec file to avoid overriding you
26
+ # changes. The mail template uses wlang, with parentheses for block
27
+ # delimiters.
28
+ #
29
+ # template-info:
30
+ # manifest:
31
+ # tasks/debug_mail.txt:
32
+ # safe-override: false
33
+ #
34
+ desc "Debug the release announcement mail"
35
+ task :debug_mail do
36
+ begin
37
+ require 'wlang'
38
+ rescue LoadError
39
+ abort "wlang is not available. Try 'gem install wlang'"
40
+ end
41
+ require 'yaml'
42
+
43
+ # Check that a .noespec file exists
44
+ noespec_file = File.expand_path('../../gisele.noespec', __FILE__)
45
+ unless File.exists?(noespec_file)
46
+ raise "Unable to find .noespec project file, sorry."
47
+ end
48
+
49
+ # Load it as well as variables and options
50
+ noespec = YAML::load(File.read(noespec_file))
51
+ vars = noespec['variables'] || {}
52
+
53
+ # Changes are taken from CHANGELOG
54
+ logs = Dir[File.expand_path("../../CHANGELOG.*", __FILE__)]
55
+ unless logs.size == 1
56
+ abort "Unable to find a changelog file"
57
+ end
58
+
59
+ # Load interesting changesets
60
+ changes, end_found = [], 0
61
+ File.readlines(logs.first).select{|line|
62
+ if line =~ /^# /
63
+ break if end_found >= 1
64
+ end_found += 1
65
+ end
66
+ changes << line
67
+ }
68
+ vars['changes'] = changes.join
69
+
70
+ # WLang template
71
+ template = File.expand_path('../debug_mail.txt', __FILE__)
72
+
73
+ # Let's go!
74
+ $stdout << WLang::file_instantiate(template, vars, "wlang/active-text")
75
+ end