rdx 0.9.0.pre

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 (122) hide show
  1. checksums.yaml +7 -0
  2. data/.rdx +20 -0
  3. data/README +19 -0
  4. data/bin/rdx +7 -0
  5. data/examples/minimal/.rdx +8 -0
  6. data/examples/minimal/README +10 -0
  7. data/examples/minimal/lib/other_conventions.rb +64 -0
  8. data/examples/minimal/lib/the_basics.rb +94 -0
  9. data/examples/minimal/lib/using_directives.rb +66 -0
  10. data/examples/minimal/rakefile +27 -0
  11. data/examples/ruby-2.0.0-p0/README +7 -0
  12. data/examples/ruby-2.0.0-p0/install/core/.rdx +6 -0
  13. data/examples/ruby-2.0.0-p0/install/core/README +19 -0
  14. data/examples/ruby-2.0.0-p0/install/core/Rakefile +61 -0
  15. data/examples/ruby-2.0.0-p0/install/core/diffs/array.c.diff +166 -0
  16. data/examples/ruby-2.0.0-p0/install/core/diffs/bignum.c.diff +11 -0
  17. data/examples/ruby-2.0.0-p0/install/core/diffs/class.c.diff +36 -0
  18. data/examples/ruby-2.0.0-p0/install/core/diffs/compar.c.diff +11 -0
  19. data/examples/ruby-2.0.0-p0/install/core/diffs/complex.c.diff +301 -0
  20. data/examples/ruby-2.0.0-p0/install/core/diffs/cont.c.diff +65 -0
  21. data/examples/ruby-2.0.0-p0/install/core/diffs/dir.c.diff +147 -0
  22. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/re.rdoc.diff +328 -0
  23. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/security.rdoc.diff +8 -0
  24. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/standard_library.rdoc.diff +0 -0
  25. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax.rdoc.diff +0 -0
  26. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/assignment.rdoc.diff +160 -0
  27. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/calling_methods.rdoc.diff +130 -0
  28. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/control_expressions.rdoc.diff +254 -0
  29. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/exceptions.rdoc.diff +0 -0
  30. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/literals.rdoc.diff +54 -0
  31. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/methods.rdoc.diff +157 -0
  32. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/miscellaneous.rdoc.diff +91 -0
  33. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/modules_and_classes.rdoc.diff +161 -0
  34. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/precedence.rdoc.diff +8 -0
  35. data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/refinements.rdoc.diff +146 -0
  36. data/examples/ruby-2.0.0-p0/install/core/diffs/encoding.c.diff +276 -0
  37. data/examples/ruby-2.0.0-p0/install/core/diffs/enum.c.diff +281 -0
  38. data/examples/ruby-2.0.0-p0/install/core/diffs/enumerator.c.diff +479 -0
  39. data/examples/ruby-2.0.0-p0/install/core/diffs/error.c.diff +143 -0
  40. data/examples/ruby-2.0.0-p0/install/core/diffs/eval.c.diff +47 -0
  41. data/examples/ruby-2.0.0-p0/install/core/diffs/eval_jump.c.diff +23 -0
  42. data/examples/ruby-2.0.0-p0/install/core/diffs/file.c.diff +752 -0
  43. data/examples/ruby-2.0.0-p0/install/core/diffs/gc.c.diff +195 -0
  44. data/examples/ruby-2.0.0-p0/install/core/diffs/hash.c.diff +84 -0
  45. data/examples/ruby-2.0.0-p0/install/core/diffs/iseq.c.diff +354 -0
  46. data/examples/ruby-2.0.0-p0/install/core/diffs/load.c.diff +53 -0
  47. data/examples/ruby-2.0.0-p0/install/core/diffs/marshal.c.diff +98 -0
  48. data/examples/ruby-2.0.0-p0/install/core/diffs/math.c.diff +110 -0
  49. data/examples/ruby-2.0.0-p0/install/core/diffs/numeric.c.diff +103 -0
  50. data/examples/ruby-2.0.0-p0/install/core/diffs/object.c.diff +295 -0
  51. data/examples/ruby-2.0.0-p0/install/core/diffs/pack.c.diff +18 -0
  52. data/examples/ruby-2.0.0-p0/install/core/diffs/parse.y.diff +23 -0
  53. data/examples/ruby-2.0.0-p0/install/core/diffs/proc.c.diff +155 -0
  54. data/examples/ruby-2.0.0-p0/install/core/diffs/random.c.diff +126 -0
  55. data/examples/ruby-2.0.0-p0/install/core/diffs/range.c.diff +49 -0
  56. data/examples/ruby-2.0.0-p0/install/core/diffs/rational.c.diff +312 -0
  57. data/examples/ruby-2.0.0-p0/install/core/diffs/re.c.diff +207 -0
  58. data/examples/ruby-2.0.0-p0/install/core/diffs/ruby.c.diff +21 -0
  59. data/examples/ruby-2.0.0-p0/install/core/diffs/signal.c.diff +67 -0
  60. data/examples/ruby-2.0.0-p0/install/core/diffs/sprintf.c.diff +29 -0
  61. data/examples/ruby-2.0.0-p0/install/core/diffs/string.c.diff +73 -0
  62. data/examples/ruby-2.0.0-p0/install/core/diffs/struct.c.diff +20 -0
  63. data/examples/ruby-2.0.0-p0/install/core/diffs/time.c.diff +691 -0
  64. data/examples/ruby-2.0.0-p0/install/core/diffs/transcode.c.diff +435 -0
  65. data/examples/ruby-2.0.0-p0/install/core/diffs/variable.c.diff +62 -0
  66. data/examples/ruby-2.0.0-p0/install/core/diffs/vm_backtrace.c.diff +164 -0
  67. data/examples/ruby-2.0.0-p0/install/core/diffs/vm_eval.c.diff +99 -0
  68. data/examples/ruby-2.0.0-p0/install/core/diffs/vm_method.c.diff +17 -0
  69. data/examples/ruby-2.0.0-p0/install/core/diffs/vm_trace.c.diff +393 -0
  70. data/examples/ruby-2.0.0-p0/install/stdlib/.rdx +6 -0
  71. data/examples/ruby-2.0.0-p0/install/stdlib/README +19 -0
  72. data/examples/ruby-2.0.0-p0/install/stdlib/Rakefile +53 -0
  73. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/abbrev.rb.diff +77 -0
  74. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/base64.rb.diff +42 -0
  75. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/benchmark.rb.diff +144 -0
  76. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/cmath.rb.diff +52 -0
  77. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/forwardable.rb.diff +150 -0
  78. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/mathn.rb.diff +58 -0
  79. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/matrix.rb.diff +657 -0
  80. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/observer.rb.diff +31 -0
  81. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/optparse.rb.diff +147 -0
  82. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/ostruct.rb.diff +78 -0
  83. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/prime.rb.diff +52 -0
  84. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/pstore.rb.diff +110 -0
  85. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/scanf.rb.diff +100 -0
  86. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/securerandom.rb.diff +144 -0
  87. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/set.rb.diff +637 -0
  88. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/shellwords.rb.diff +66 -0
  89. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/singleton.rb.diff +37 -0
  90. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/tempfile.rb.diff +104 -0
  91. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/thread.rb.diff +38 -0
  92. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/time.rb.diff +140 -0
  93. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/tmpdir.rb.diff +52 -0
  94. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/uri.rb.diff +39 -0
  95. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/uri/common.rb.diff +237 -0
  96. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/weakref.rb.diff +36 -0
  97. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/yaml/store.rb.diff +27 -0
  98. data/examples/ruby-2.0.0-p0/rakefile +165 -0
  99. data/lib/rdx.rb +331 -0
  100. data/lib/rdx/assertions.rb +484 -0
  101. data/lib/rdx/binding.rb +151 -0
  102. data/lib/rdx/code_object.rb +598 -0
  103. data/lib/rdx/comment.rb +338 -0
  104. data/lib/rdx/convention.rb +1174 -0
  105. data/lib/rdx/directive.rb +1432 -0
  106. data/lib/rdx/example.rb +679 -0
  107. data/lib/rdx/generator.rb +112 -0
  108. data/lib/rdx/generator/rdoc.rb +1006 -0
  109. data/lib/rdx/options.rb +359 -0
  110. data/lib/rdx/plain_text.rb +65 -0
  111. data/lib/rdx/reporter.rb +421 -0
  112. data/lib/rdx/ruby_lex.rb +324 -0
  113. data/lib/rdx/runner.rb +309 -0
  114. data/lib/rdx/source_file.rb +94 -0
  115. data/lib/rdx/specification.rb +194 -0
  116. data/lib/rdx/statement.rb +248 -0
  117. data/lib/rdx/store.rb +119 -0
  118. data/lib/rdx/task.rb +361 -0
  119. data/lib/rdx/text.rb +688 -0
  120. data/lib/rdx/version.rb +15 -0
  121. data/rakefile +64 -0
  122. metadata +203 -0
@@ -0,0 +1,324 @@
1
+
2
+ module RDX
3
+
4
+ require 'rdoc'
5
+ require 'rdoc/ruby_token'
6
+ require 'rdoc/ruby_lex'
7
+
8
+ #
9
+ # Interface to the +RDoc::RubyLex+ tokenizer and parser.
10
+ #
11
+ module RubyLex
12
+
13
+ extend self
14
+
15
+ # :stopdoc:
16
+
17
+ # Matches a Ruby inline comment
18
+ RE_CMT = /#.*+\n/
19
+
20
+ # Matches a Ruby inline comment optionally preceded by spaces
21
+ RE_SP_CMT = /[^\S\n]*+#{RE_CMT.source}/o
22
+
23
+ # Matches trailing spaces of a line
24
+ RE_SP_NL = /[^\S\n]*+\n/
25
+
26
+ TkCOMMENT = RDoc::Parser::Ruby::TkCOMMENT
27
+ TkSPACE = RDoc::Parser::Ruby::TkSPACE
28
+ TkNL = RDoc::Parser::Ruby::TkNL
29
+ ERROR = RDoc::RubyLex::Error
30
+
31
+ # +tab_width+ does not matter in evaluation...
32
+ RDOC_OPTIONS = RDoc::Options.new
33
+
34
+ # :startdoc:
35
+
36
+ # Raises a +ParseError+ from the given exception and internal line number.
37
+ def raise_parse_error err, line_no=nil
38
+ msg = "Invalid ruby code"
39
+ error = ParseError.new msg
40
+ if err.is_a?(ERROR)
41
+ msg << ":\n" << err.message
42
+ error.line_no = line_no
43
+ end
44
+ raise error # this caller: assuming not debugging RDoc::RubyLex itself
45
+ end
46
+ private :raise_parse_error
47
+
48
+ # Generates a new +RDoc::RubyLex+ with the given _ruby_ as input.
49
+ def new_rdoc_scanner ruby
50
+ scanner = RDoc::RubyLex.new ruby, RDOC_OPTIONS
51
+ scanner.exception_on_syntax_error = true
52
+ scanner
53
+ end
54
+ private :new_rdoc_scanner
55
+
56
+ # Through <tt>RDoc::RubyLex.tokenize</tt> tokenizes the _ruby_ string and
57
+ # retunrs an array of +RDoc::RubyToken+.
58
+ # These are processed with #adjust_tokens if _adjust_tokens_ is +true+ (default).
59
+ # May raise a +ParseError+ if the input is invalid enough.
60
+ def tokenize ruby, adjust_tokens=true
61
+ ruby = ruby.to_str
62
+ scanner = new_rdoc_scanner ruby
63
+ tokens = []
64
+ begin
65
+ while token = scanner.token do
66
+ tokens << token
67
+ end
68
+ rescue => err
69
+ raise_parse_error err, scanner.line_no
70
+ end
71
+ tokens = adjust_tokens tokens if adjust_tokens
72
+ tokens.each{ |tk| yield tk } if block_given?
73
+ return tokens
74
+ end
75
+ private :tokenize
76
+
77
+ # The comments also include the trailing newline and any comment on
78
+ # successives lines until a blank one.
79
+ def adjust_tokens orig_tokens
80
+ tokens = []
81
+ current_tkcomment = comment_on_current_line = nil
82
+ space_tokens = []
83
+ orig_tokens.each do |tk|
84
+ if tk.instance_of?(TkCOMMENT) # Don't consider embedded documents
85
+ comment_on_current_line = true
86
+ next tokens.push(current_tkcomment = tk) unless current_tkcomment
87
+ current_tkcomment.text << space_tokens.map(&:text).join('') << tk.text
88
+ space_tokens.clear
89
+ elsif tk.is_a?(TkSPACE)
90
+ next tokens << tk unless current_tkcomment
91
+ # comment_on_current_line is false
92
+ space_tokens << tk
93
+ elsif tk.is_a?(TkNL) # there is for sure at the end of the tokens
94
+ next tokens << tk unless current_tkcomment
95
+ if comment_on_current_line
96
+ current_tkcomment.text << tk.text
97
+ comment_on_current_line = false
98
+ else
99
+ tokens.concat space_tokens
100
+ space_tokens.clear
101
+ current_tkcomment = nil
102
+ end
103
+ else
104
+ tokens << tk
105
+ current_tkcomment = nil
106
+ end
107
+ end
108
+ return tokens
109
+ end
110
+ private :adjust_tokens
111
+
112
+ #
113
+ # Doesn't interpret _string_ as ruby code and extracts
114
+ # potential ruby comments.
115
+ # The result is an array <tt>[ [comment,line_no],... ]</tt>.
116
+ #
117
+ # RDX::RubyLex.extract_potential_comments <<EOS
118
+ # This is not ruby :-( # potential comment
119
+ # # ...continuing... #
120
+ # other text
121
+ # # another comment
122
+ # EOS
123
+ # # => [
124
+ # # ["# potential comment\n# ...continuing... #\n", 1],
125
+ # # ["# another comment\n", 4]
126
+ # # ]
127
+ #
128
+ # If a block is supplied, it is yielded those results.
129
+ #
130
+ # This method never raises a +ParseError+.
131
+ #
132
+ def extract_potential_comments string
133
+ string = string.to_str
134
+ string = string.dup << "\n" unless string.end_with?("\n")
135
+ comments = []
136
+ string.scan /#{RE_CMT}#{RE_SP_CMT}*+/o do |comment|
137
+ md = Regexp.last_match
138
+ l_no = md.pre_match.count("\n") + 1
139
+ comments << [comment,l_no]
140
+ end
141
+ comments.each{ |(comment,line_no)| yield comment, line_no } if block_given?
142
+ return comments
143
+ end
144
+
145
+ #
146
+ # Extracts the comments in _ruby_ string and returns an
147
+ # array of arrays <tt>[ [comment,line_no],... ]</tt>.
148
+ # The comments also include the trailing newline and any comment
149
+ # on successives lines until a blank one.
150
+ #
151
+ # RDX::RubyLex.extract_comments <<EOS
152
+ # # This is Ruby!
153
+ #
154
+ # # This method simply returns the +Fixnum+ 2.
155
+ # def return_two
156
+ # 2 # of course
157
+ # # it returns two
158
+ # end
159
+ # EOS
160
+ # # => [
161
+ # # ["# This is Ruby!\n", 1],
162
+ # # ["# This method simply returns the +Fixnum+ 2.\n", 3],
163
+ # # ["# of course\n # it returns two\n", 5]
164
+ # # ]
165
+ #
166
+ # If a block is given, it is yielded those results.
167
+ #
168
+ # May raise a +ParseError+ if the input is invalid enough.
169
+ #
170
+ def extract_comments ruby
171
+ comments = []
172
+ tokenize ruby do |tk|
173
+ next unless tk.instance_of?(TkCOMMENT) # Don't capture embedded documents
174
+ comments << [tk.text,tk.line_no]
175
+ end
176
+ comments.each{ |(comment,line_no)| yield comment, line_no } if block_given?
177
+ return comments
178
+ end
179
+
180
+ # Subdivides the _ruby_ string into toplevel statements and returns an array
181
+ # <tt>[ [statement,line_no] ]</tt>.
182
+ # These are processed with #adjust_statements if _adjust_statements_ is +true+ (default).
183
+ # May raise a +ParseError+ if the input invalid enough.
184
+ def statementize ruby, adjust_statements=true
185
+ ruby = ruby.to_str
186
+ statements = []
187
+ scanner = new_rdoc_scanner ruby
188
+ begin
189
+ scanner.each_top_level_statement do |stmnt,l_no|
190
+ statements << [stmnt,l_no]
191
+ end
192
+ rescue => err
193
+ raise_parse_error err, scanner.line_no
194
+ end
195
+ statements = adjust_statements statements if adjust_statements
196
+ statements.each{ |stmnt| yield stmnt } if block_given?
197
+ return statements
198
+ end
199
+ private :statementize
200
+
201
+ # The statements also includes trailing comments until a blank line.
202
+ def adjust_statements orig_statements
203
+ statements = []
204
+ return statements if orig_statements.empty?
205
+ # The first statement is unchanged
206
+ statements.push(orig_statements.shift)
207
+ previous_statement = statements.first[0]
208
+ orig_statements.each do |stmnt,l_no|
209
+ if stmnt =~ /\A[^\S\n]*\./ # statement concatenation
210
+ previous_statement.concat stmnt
211
+ next
212
+ end
213
+ # For all the other statements move the leading spaces and comment to the previous statement
214
+ leading = stmnt.slice! /\A#{RE_SP_CMT}*+#{RE_SP_NL}*+/o
215
+ previous_statement.concat leading
216
+ l_no += leading.count("\n")
217
+ statements << [stmnt,l_no]
218
+ previous_statement = stmnt
219
+ end
220
+ return statements
221
+ end
222
+ private :adjust_statements
223
+
224
+ #
225
+ # Collects all top-level statements for _ruby_ string into an array
226
+ # <tt>[ [statement,line_no], ... ]</tt>. Each statement also includes
227
+ # trailing comments until a blank line.
228
+ #
229
+ # RDX::RubyLex.extract_statements <<EOS
230
+ # # beginning comment
231
+ # statement_1 # => result_1
232
+ # # other stuff...
233
+ # statement_2
234
+ # statement_3
235
+ # # => result_3
236
+ #
237
+ # # new block
238
+ # statement_4
239
+ # # => result_4
240
+ # EOS
241
+ # # => [
242
+ # # ["# beginning comment\nstatement_1 # => result_1\n# other stuff...\n", 1],
243
+ # # ["statement_2\n", 4],
244
+ # # ["statement_3\n # => result_3\n\n", 5],
245
+ # # ["# new block\nstatement_4\n# => result_4\n", 8]
246
+ # # ]
247
+ #
248
+ # If a block is given, it is yielded those results.
249
+ #
250
+ # May raise a +ParseError+ if the input is invalid enough.
251
+ #
252
+ def extract_statements ruby
253
+ statements = statementize ruby
254
+ statements.delete_if{ |stmnt,_| stmnt !~ /\S/ }
255
+ statements.each{ |(statement,line_no)| yield statement, line_no } if block_given?
256
+ return statements
257
+ end
258
+
259
+ #
260
+ # Returns the first statement for _ruby_ code.
261
+ # Until it's found may raise a +ParseError+ if the input is invalid enough.
262
+ #
263
+ # RDX::RubyLex.extract_first_statement <<EOS
264
+ # 'A ' +
265
+ # 'string'
266
+ # # statement ended succesfully!
267
+ # 0xqwerty: invalid input, but who cares now?
268
+ # EOS
269
+ # # => "'A ' +\n'string'\n# statement ended succesfully!\n"
270
+ #
271
+ def extract_first_statement ruby
272
+ ruby = ruby.to_str
273
+ scanner = new_rdoc_scanner ruby
274
+ begin
275
+ stmnt = scanner.each_top_level_statement{ |stmnt| break stmnt }
276
+ rescue => err
277
+ raise_parse_error err, scanner.line_no
278
+ end
279
+ while line = scanner.gets
280
+ break unless line =~ /\A#{RE_SP_CMT}/o
281
+ stmnt << line
282
+ end
283
+ stmnt
284
+ end
285
+
286
+ #
287
+ # Tokenizes _ruby_statement_ and returns an array of arrays <tt>[ [comment,line_no],... ]</tt>.
288
+ # The last element will always contain the comment at the end of the statement (an empty
289
+ # String if there isn't); all the others are indeed at positions of incomplete statement.
290
+ # RDX::RubyLex.extract_comments_from_statement <<EOS
291
+ # class AClass
292
+ # self # => AClass
293
+ # # Right, but the statement isn't yet complete!
294
+ # end
295
+ # # => AClass # Now it's ok!
296
+ # # other metadata...
297
+ # EOS
298
+ # # => [
299
+ # # ["# => AClass\n # Right, but the statement isn't yet complete!\n", 2],
300
+ # # ["# => AClass # Now it's ok!\n# other metadata...\n", 5]
301
+ # # ]
302
+ # RDX::RubyLex.extract_comments_from_statement <<EOS
303
+ # a_statement +
304
+ # without_comment\n
305
+ # EOS
306
+ # # => [ ["",2] ]
307
+ #
308
+ def extract_comments_from_statement ruby_statement
309
+ ruby_statement = ruby_statement.to_str.rstrip
310
+ tokens = tokenize ruby_statement
311
+ comments = []
312
+ tokens.each do |tk|
313
+ next unless tk.instance_of?(TkCOMMENT) # Don't capture embedded documents
314
+ comments << [tk.text,tk.line_no]
315
+ end
316
+ last_tk = tokens.last
317
+ comments << ['',last_tk.line_no] unless last_tk.instance_of?(TkCOMMENT)
318
+ comments.each{ |(comment,line_no)| yield comment, line_no } if block_given?
319
+ return comments
320
+ end
321
+
322
+ end
323
+
324
+ end
@@ -0,0 +1,309 @@
1
+
2
+ require 'rdx'
3
+
4
+ require 'rdx/code_object'
5
+ require 'rdx/reporter'
6
+
7
+ module RDX
8
+
9
+ #
10
+ # Coordinates all moving parts of RDX.
11
+ #
12
+ class Runner
13
+
14
+ # :stopdoc:
15
+
16
+ #
17
+ # Start and run RDX with the given _argv_
18
+ #
19
+ def self.run(argv)
20
+ new(argv).run
21
+ end
22
+
23
+ # Is RDX running?
24
+ def self.active?
25
+ !current.nil?
26
+ end
27
+
28
+ @current = nil
29
+ class << self
30
+ attr_reader :current
31
+ def current= runner
32
+ if runner && @current
33
+ raise Error, 'Only one instance of RDX is allowed to run'
34
+ end
35
+ @current = runner
36
+ end
37
+ end
38
+
39
+ ACTIONS = {
40
+ :initializing => [],
41
+ :ready => [:run],
42
+ :documenting => [:signal_start_parsing,
43
+ :signal_do_testing, :signal_start_generating],
44
+ :parsing => [:signal_end_parsing, :signal_start_parsing_file,
45
+ :signal_found_comment],
46
+ :parsing_file => [:signal_end_parsing_file, :signal_found_comment],
47
+ :testing => [],
48
+ :building => [],
49
+ :running_pre_tests => [],
50
+ :requiring_libs => [],
51
+ :running_post_tests => [],
52
+ :generating => [:signal_end_generating],
53
+ :reporting => [],
54
+ :finished => [],
55
+ }
56
+
57
+ def check_action action
58
+ actions = ACTIONS[@status]
59
+ return if actions && actions.include?(action.to_sym)
60
+ raise Error, "action #{action} request in #{@status.to_s}"
61
+ end
62
+ private :check_action
63
+
64
+ attr_reader :options
65
+
66
+ attr_reader :reporter
67
+
68
+ attr_reader :store
69
+
70
+ def initialize(argv)
71
+ @status = :initializing
72
+ setup_options(argv)
73
+ setup_reporter
74
+ setup_store
75
+ @status = :ready
76
+ end
77
+
78
+ def passed?
79
+ store.passed?
80
+ end
81
+ def self.passed?
82
+ active? && current.passed?
83
+ end
84
+
85
+ def verbose
86
+ options.verbose
87
+ end
88
+ def debug
89
+ options.debug
90
+ end
91
+
92
+ def puts *args # :nodoc:
93
+ reporter.puts *args
94
+ end
95
+ def print *args # :nodoc:
96
+ reporter.print *args
97
+ end
98
+
99
+ private
100
+
101
+ def setup_options(options)
102
+ options = Options.new(options) unless options.is_a?(Options)
103
+ @options = options
104
+ end
105
+
106
+ def setup_reporter
107
+ @reporter = Reporter[options.reporter].new(self)
108
+ end
109
+
110
+ def setup_store
111
+ rdx_file = File.expand_path('.rdx')
112
+ spec = Specification.load(rdx_file) || Specification.default
113
+ unless spec.original?
114
+ puts 'Conventions and/or directives changed according to the .rdx file'
115
+ @options.files.delete rdx_file # TODO: include in doc
116
+ end
117
+ @store = Store.new spec
118
+ end
119
+
120
+ def run
121
+ check_action __method__
122
+ Runner.current = self
123
+ generator = Generator[options.generator].new
124
+ documenting_hook do
125
+ generator.generate(options.generator_options,options.files)
126
+ end
127
+ reporting_hook
128
+ rescue Exception => exc
129
+ exc.set_backtrace RDX.filter_backtrace(exc.backtrace)
130
+ raise exc
131
+ ensure
132
+ Runner.current = nil
133
+ end
134
+ public :run
135
+
136
+ #
137
+ # === Singal and Hooks ===
138
+ #
139
+ # Must be called elsewhere -> public -> checks @status
140
+ #
141
+
142
+ def start_documenting_hook
143
+ puts
144
+ puts "This is RDX, version #{RDX::VERSION}"
145
+ puts
146
+ puts "Start documenting with #{options.generator}"
147
+ @status = :documenting
148
+ end
149
+
150
+ def signal_start_parsing
151
+ check_action __method__
152
+ puts 'Parsing files...'
153
+ @status = :parsing
154
+ end
155
+
156
+ def signal_start_parsing_file(filename)
157
+ check_action __method__
158
+ @status = :parsing_file
159
+ end
160
+
161
+ def signal_end_parsing_file filename, success=true
162
+ check_action __method__
163
+ @status = :parsing
164
+ end
165
+
166
+ def signal_end_parsing success=true, testing=success
167
+ check_action __method__
168
+ @status = :documenting
169
+ signal_do_testing if testing
170
+ end
171
+
172
+ def signal_do_testing
173
+ check_action __method__
174
+ prev_status = @status
175
+ @status = :testing
176
+ tmpdir = Dir.mktmpdir ['rdx', Time.now.strftime("-%H%M")]
177
+ begin
178
+ Dir.chdir tmpdir do
179
+ build_tests_hook
180
+ handle_dry_run_option
181
+ run_tests_hook
182
+ dispose_store # clear bindings and run GC, so that tmpdir is empty and can be safely deleted
183
+ end
184
+ ensure
185
+ FileUtils.remove_entry tmpdir, !debug
186
+ end
187
+ puts "Tests finished!"
188
+ @status = prev_status
189
+ end
190
+
191
+ def build_tests_hook
192
+ puts 'Building tests...'
193
+ @status = :building
194
+ store.build options.seed
195
+ end
196
+
197
+ def run_tests_hook
198
+ puts
199
+ reporter.on_testing do
200
+ reporter.puts "Running tests (seed=#{options.seed})", ''
201
+ run_pre_tests_hook
202
+ require_libs_hook
203
+ run_post_tests_hook
204
+ end
205
+ end
206
+
207
+ def handle_dry_run_option
208
+ return unless options.dry_run
209
+ CodeObject::Runnable.class_eval do
210
+ def trace_execution(*); end
211
+ def trace_assertion conv_name=nil, frame=location
212
+ register Detection.new(conv_name,frame)
213
+ end
214
+ end
215
+ end
216
+
217
+ def run_pre_tests_hook
218
+ @status = :running_pre_tests
219
+ reporter.run_pre_tests store.tests_before_require
220
+ end
221
+
222
+ def require_libs_hook
223
+ @status = :requiring_libs
224
+ lib_dirs = options.lib_dirs.reverse
225
+ $LOAD_PATH.unshift(*lib_dirs)
226
+ libs = options.libs
227
+ reporter.require_libs do
228
+ libs.each do |file|
229
+ reporter.require_lib(file){ require file }
230
+ end
231
+ end
232
+ end
233
+
234
+ def run_post_tests_hook
235
+ @status = :running_post_tests
236
+ reporter.run_post_tests store.tests_after_require
237
+ end
238
+
239
+ def dispose_store
240
+ store.dispose_bindings
241
+ GC.start
242
+ end
243
+
244
+ def signal_start_generating
245
+ check_action __method__
246
+ @status = :generating
247
+ puts "Generating documentation output..."
248
+ end
249
+
250
+ def signal_end_generating success=true
251
+ check_action __method__
252
+ @status = :documenting
253
+ end
254
+
255
+ def end_documenting_hook
256
+ puts "Documentation finished!"
257
+ end
258
+
259
+ def reporting_hook
260
+ @status = :reporting
261
+ reporter.show_report
262
+ end
263
+
264
+ # reset => :ready ???
265
+
266
+ # Block hooks & signals
267
+
268
+ def documenting_hook
269
+ reporter.on_documenting do
270
+ start_documenting_hook
271
+ yield
272
+ end_documenting_hook
273
+ end
274
+ end
275
+
276
+ def signal_parsing
277
+ signal_start_parsing
278
+ result = yield
279
+ signal_end_parsing
280
+ result
281
+ end
282
+
283
+ def signal_generating
284
+ unless options.doc_output
285
+ puts 'Generation of documentation output is disabled'
286
+ return
287
+ end
288
+ signal_start_generating
289
+ result = yield
290
+ signal_end_generating
291
+ result
292
+ end
293
+
294
+ # Define these as public signals and also in RDX::Runner and RDX.
295
+ # This methods do nothing if RDX isn't running.
296
+ private_instance_methods(false)
297
+ .concat(public_instance_methods(false))
298
+ .grep(/^signal_/) do |name|
299
+ public name
300
+ define_singleton_method name do |*args,&blk|
301
+ current && current.public_send(name,*args,&blk)
302
+ end
303
+ RDX.define_singleton_method name do |*args,&blk|
304
+ Runner.public_send(name,*args,&blk)
305
+ end
306
+ end
307
+ end
308
+
309
+ end