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,1432 @@
1
+
2
+ module RDX
3
+
4
+ #
5
+ # == When to use directives?
6
+ #
7
+ # Conventions work fine when all the processing steps are no longer than a single statement,
8
+ # but what if we want to interact with other examples, or in general with other sections of the comment?
9
+ #
10
+ # Perhaps we may want to not execute an example, to interpret one as the output of the
11
+ # previous, to locally change some of the assertions methods, to run it in a temporary directory,
12
+ # to simulate a bash environment, and so on...
13
+ #
14
+ # *Directives* allow all of this: they <b>work on a larger scale</b> (usually operate on other examples and
15
+ # the comment, but can also influence different comments and even other directives!),
16
+ # <b>making possible to treat your comments, text sections and examples differently from the standard way</b>.
17
+ #
18
+ # == Which directives are available?
19
+ #
20
+ # There are many directives, subdivided for functionality:
21
+ # * Activation/Deactivation: like ::on, ::off, ::skip, ::if, ::lazy;
22
+ # * Input/Output/Error: the most useful is ::stdout;
23
+ # * Context change: they can change the binding, current directory, execution in time
24
+ # (like ::setup and ::teardown), simulate a ::bash session;
25
+ # * Assertion customization: to mention ::float
26
+ # * Miscellanous: insert comments, ::disable_warnings, ...
27
+ # All the directives already defined are documented as Directive's class methods
28
+ # (even if technically they aren't) in the relative sections.
29
+ #
30
+ # If these aren't enough, you can *edit* them or even *define* your own directives
31
+ # in the Specification.
32
+ #
33
+ # But before this you'll need to know other few things...
34
+ #
35
+ # == How to use directives?
36
+ #
37
+ # Directives come in two flavours: _explicit_ and _implicit_.
38
+ #
39
+ # We can insert an <b>explicit directive</b> in a comment through the <b>documentation generator tool</b>.
40
+ # First we have to tell it - using its directive syntax - that we have an RDX directive;
41
+ # the rest (parameter for the generator tool) is parsed by Directive.split, that returns a directive
42
+ # name and optionally its parameter.
43
+ # For an example with the +rdoc+ generator see the "Directives" section in ::RDoc.
44
+ #
45
+ # There is also the nice way to insert them *implicitly* in the comment, <b>without the need
46
+ # of the user to use the specific generator tool</b>. This is done recognizing specific patterns
47
+ # in plain text sections or examples. For instance ::stdout is automatically inserted if a plain text
48
+ # section consists - simplifying a bit - of the string 'produces:' (this pattern was so common in the
49
+ # Ruby Core that I thought implicit directives were a fundamental feature), while ::bash can detect an
50
+ # example starting with the bash prompt "<tt>$ </tt>" (since it isn't valid ruby syntax).
51
+ #
52
+ # == What are directives?
53
+ #
54
+ # Directives are classes (subclassing Directive), and each appearance in the comments generates
55
+ # a corresponding instance.
56
+ #
57
+ # For this reason the class methods are used to define the behaviour of the directive
58
+ # (the most important is ::define), while the instance ones allow to query
59
+ # informations about their status (the #parameter, if it's #implicit?, some stored #metadata)
60
+ # and retrive neighbour sections in the comment (the most used is #next_example).
61
+ #
62
+ class Directive < CodeObject
63
+
64
+ #
65
+ # :category: Internal
66
+ #
67
+ # Splits _string_ (which is the parameter of the +rdx+ directive for the generator)
68
+ # into a directive name and its parameter.
69
+ #
70
+ # The name consists of the first sequence of printable (non-space) characters -
71
+ # may even be the empty string -; the parameter is anything that follows after the
72
+ # first spaces - even this may be empty too.
73
+ #
74
+ def Directive.split string
75
+ string.to_str.strip.match(/\A\s*(\S*)\s*(.*)\z/m).captures
76
+ end
77
+
78
+ # :stopdoc:
79
+
80
+ def Directive.validate_name name
81
+ name = name.to_str
82
+ raise "Invalid directive name: `#{name}'" if name =~ /\s/
83
+ name.downcase
84
+ end
85
+
86
+ def Directive.join dir, param
87
+ dir = validate_name dir
88
+ param = param.to_str
89
+ return param.empty? ? dir : "#{dir} #{param}"
90
+ end
91
+
92
+ # :startdoc:
93
+
94
+ class << self
95
+
96
+ # The first name which with the directive is defined (not influenced by aliases).
97
+ attr_reader :name
98
+
99
+ # Hash of arbitrary metadata. This will be copied into each instance.
100
+ attr_reader :metadata
101
+
102
+ # :stopdoc:
103
+
104
+ def to_s
105
+ "RDX::Directive:#{name}"
106
+ end
107
+ alias inspect to_s
108
+
109
+ def verify_status
110
+ public_instance_methods(false).include?(:execute) or
111
+ raise "Directive behaviour not defined (use `define')"
112
+ end
113
+ private :verify_status
114
+
115
+ def has_implicit?
116
+ !@implicit[:text].empty? or !@implicit[:example].empty?
117
+ end
118
+
119
+ def find_implicit_in type, text
120
+ text = text.to_str
121
+ @implicit[type].each do |pattern|
122
+ md = text.match(pattern)
123
+ next unless md
124
+ param = md[1]
125
+ l_no = 1 + md.pre_match.count("\n") + md[0][/\A\s*/].count("\n")
126
+ result = [param, l_no]
127
+ yield(*result) if block_given?
128
+ return result
129
+ end
130
+ return false
131
+ end
132
+
133
+ # :startdoc:
134
+
135
+ #
136
+ # :call-seq:
137
+ # define{ || ... }
138
+ # define{ |dir| ... }
139
+ #
140
+ # Defines the action of the directive: the block will be called from each instance generated from
141
+ # an occurrence of this directive in a comment.
142
+ #
143
+ # If the block takes no arguments, it directly becomes the body of that instance method
144
+ # (so that +self+ is that directive instance in the block).
145
+ # Otherwise it will be yielded the directive instance as a parameter,
146
+ # without changing the block's context.
147
+ #
148
+ # In both ways, you should use the instance methods of Directive to access its
149
+ # its status and retrive neighbour sections. At this point you will need the API
150
+ # provided by the CodeObject class and its descendants - mainly the Example one -
151
+ # to shape their behaviour to your needs.
152
+ #
153
+ def define &execution
154
+ if execution.arity == 0
155
+ define_method :execute do
156
+ trace_execution{ instance_eval(&execution) }
157
+ end
158
+ else
159
+ define_method :execute do
160
+ trace_execution{ execution.call(self) }
161
+ end
162
+ end
163
+ end
164
+
165
+ #
166
+ # :category: Internal
167
+ #
168
+ # Registers the given block as a configuration for the implicit recognization:
169
+ # this centralizes the building procedure, allowing the user to supply
170
+ # (through ::use_implicit_with) only the desired parameters - often some particular
171
+ # pattern or word. The block should call ::find_in_text or ::find_in_example.
172
+ #
173
+ # After this ::default_implicit_configuration is called.
174
+ #
175
+ # This configuration can be defined for built-in directives;
176
+ # user-defined ones often do not need this step.
177
+ #
178
+ def configure_implicit &implicit_configuration
179
+ @implicit_configuration = implicit_configuration
180
+ default_implicit_configuration
181
+ end
182
+
183
+ #
184
+ # Calls the configuration +Proc+ (if registered through ::configure_implicit)
185
+ # with the given arguments. In this way you can add new behaviour according to
186
+ # an existing scheme.
187
+ #
188
+ # This method can be called from the Specification.
189
+ #
190
+ # Returns +self+, allowing to chain other methods.
191
+ #
192
+ def use_implicit_with(*args,&blk)
193
+ if @implicit_configuration
194
+ @implicit_configuration.call(*args,&blk)
195
+ elsif !args.empty? || blk
196
+ raise "#{self} does not accept an implicit configuration"
197
+ end
198
+ return self
199
+ end
200
+
201
+ # Clears the patterns for the implicit search.
202
+ def clear_implicit_patterns
203
+ @implicit = { :text=>[], :example=>[] }
204
+ end
205
+
206
+ #
207
+ # Restores the default configuration for the implicit recognization of this
208
+ # directive. First calls ::clear_implicit_patterns, then
209
+ # calls the block supplied to ::configure_implicit without parameters
210
+ # (so its arity should allow this).
211
+ #
212
+ def default_implicit_configuration
213
+ clear_implicit_patterns
214
+ use_implicit_with()
215
+ end
216
+
217
+ #
218
+ # Registers the Regexp to match the text of a non-example section.
219
+ # If there is a match, the directive is implicitly added in the comment
220
+ # without consuming any text.
221
+ #
222
+ def find_in_text regexp
223
+ raise 'Invalid Regexp pattern' unless regexp.is_a?(Regexp)
224
+ @implicit[:text] << regexp
225
+ end
226
+
227
+ #
228
+ # Registers the Regexp to match the code of an example.
229
+ # If there is a match, the directive is implicitly added in the comment
230
+ # without consuming any text.
231
+ #
232
+ def find_in_example regexp
233
+ raise 'Invalid Regexp pattern' unless regexp.is_a?(Regexp)
234
+ @implicit[:example] << regexp
235
+ end
236
+
237
+ end
238
+
239
+ #
240
+ # This module is included into the Specification and allows the interaction
241
+ # with the Directive objects in use: you can define new ones, create aliases,
242
+ # remove those already in use or simply modify some of their features.
243
+ #
244
+ # It also extends the Directive class, so that the built-in directives
245
+ # are defined in the same way.
246
+ # This provides a good starting point: just look at the core definitions
247
+ # to learn something very quickly. Anyway in the Directive class
248
+ # you can find the details on how directive work.
249
+ #
250
+ module SpecificationHelper
251
+
252
+ # :stopdoc:
253
+
254
+ attr_reader :directives
255
+ private :directives
256
+
257
+ def known_directives
258
+ directives.dup
259
+ end
260
+
261
+ # :startdoc:
262
+
263
+ # Returns the Directive with the given _name_ or +nil+ if it isn't defined.
264
+ def directive_defined? name
265
+ name = Directive.validate_name name
266
+ directives[name]
267
+ end
268
+
269
+ #
270
+ # Returns the Directive with the given _name_ or raises an exception if it isn't defined.
271
+ # You can now use class methods of Directive to modify its features.
272
+ #
273
+ def directive name
274
+ directive_defined?(name) or
275
+ raise Error, "Undefined directive `#{name}'"
276
+ end
277
+
278
+ #
279
+ # :call-seq:
280
+ # define_directive(name){ || action } -> directive
281
+ # define_directive(name){ |dir_class| setup } -> directive
282
+ # define_directive(name,directive) -> directive
283
+ #
284
+ # Defines a directive class (subclass of Directive) with the given _name_.
285
+ #
286
+ # In the first form the block (that takes no argument) will be sent to ::define,
287
+ # thus it directly becomes the action of the directive.
288
+ # In the second form the block is yielded the directive class itself, allowing
289
+ # other methods to be called on it (the user must explicitly call +define+).
290
+ # In the last form associates _name_ to _directive_.
291
+ #
292
+ # In all cases the directive class is returned.
293
+ #
294
+ # If the defined directive name ends with "<tt>!</tt>", and if the corresponding
295
+ # directive without the trailing bang is already defined these two classes will
296
+ # share the same #metadata. This strategy is used when the actions they perform
297
+ # are the same, differing only in the targets on which they operate.
298
+ #
299
+ def define_directive name, dir=nil, &definition
300
+ defined = directive_defined?(name) and
301
+ raise "Directive `#{defined.name}' already defined!"
302
+ if definition.nil?
303
+ raise "Invalid directive: #{dir.inspect}" unless dir.is_a?(Class) && dir < Directive
304
+ else
305
+ if name.end_with?('!') && simil_dir=directive_defined?(name.chomp '!')
306
+ metadata = simil_dir.metadata
307
+ else
308
+ metadata = {}
309
+ end
310
+ dir = Class.new(Directive) do
311
+ @name = name.freeze
312
+ @metadata = metadata # Of the class itself
313
+ clear_implicit_patterns
314
+ if definition.arity == 0
315
+ define &definition
316
+ else
317
+ definition.call(self)
318
+ end
319
+ verify_status
320
+ end
321
+ end
322
+ return directives[name] = dir
323
+ end
324
+
325
+ # Creates an alias _new_name_ for the directive named _old_name_.
326
+ def alias_directive new_name, old_name
327
+ define_directive new_name, directive(old_name)
328
+ end
329
+
330
+ # Removes the given _name_ from the list of known directives.
331
+ def undefine_directive name
332
+ name = Directive.validate_name name
333
+ !!directives.delete(name)
334
+ end
335
+
336
+ # Removes the directive _dir_ (or the one associated to that name) from the list of directives.
337
+ def remove_directive dir
338
+ dir = directive(dir) unless dir.is_a?(Class) && dir < Directive
339
+ !!directives.delete_if{ |_,d| d == dir }
340
+ end
341
+
342
+ end
343
+
344
+ @directives = {}
345
+ extend SpecificationHelper
346
+ class << self # :nodoc:
347
+ alias known known_directives
348
+ alias get directive
349
+ alias [] directive
350
+ end
351
+
352
+ def initialize comment, text='', relative_line_no=1 # :nodoc:
353
+ @comment = comment
354
+ super(text,relative_line_no) # initializes metadata
355
+ @metadata.update self.class.metadata
356
+ end
357
+
358
+ # The +name+ of the class.
359
+ def name
360
+ self.class.name
361
+ end
362
+
363
+ # The SourceFile this directive is into.
364
+ def source_file
365
+ comment.source_file
366
+ end
367
+
368
+ # The Comment this directive is into.
369
+ attr_reader :comment
370
+ alias parent comment
371
+
372
+ # Returns +self+
373
+ def directive
374
+ self
375
+ end
376
+
377
+ # Returns +nil+ if it wasn't given, the +String+ otherwise.
378
+ def parameter
379
+ text.empty? ? nil : text
380
+ end
381
+ alias param parameter
382
+
383
+ #
384
+ # Split #parameter on spaces, returning an +Array+ of them.
385
+ # If _remove_commas_ is true, from each parameter is removed the trailing comma
386
+ # (so that this resembles a list of parameters in a method call).
387
+ #
388
+ def parameters remove_commas=true
389
+ return [] unless parameter
390
+ result = parameter.split(/\s+/)
391
+ result.map!{ |param| param.chomp(',') } if remove_commas
392
+ result
393
+ end
394
+ alias params parameters
395
+
396
+ #
397
+ # Has this directive been detected implicitly?
398
+ # If _in_sections_ is given, it specifies the sections in which the search takes place.
399
+ #
400
+ def implicit?(*in_sections)
401
+ in_sections = comment.sections if in_sections.empty?
402
+ # An implicit directive is "over" some other section
403
+ in_sections.find{ |sec| sec.line_range.cover?(self.line_no) }
404
+ end
405
+
406
+ #
407
+ # :section: API
408
+ #
409
+
410
+ # Uses +:directive+ as the default type of warning.
411
+ def warn msg=nil, type=:directive, frame=nil
412
+ super
413
+ end
414
+
415
+ # Meaningful default values are provided.
416
+ def eval code, binding=Binding.pseudo_toplevel, filename=file_name, lineno=line_no # :doc:
417
+ pwd = Dir.pwd
418
+ Kernel.eval(code,binding,filename,lineno)
419
+ ensure
420
+ Dir.chdir(pwd) unless Dir.pwd==pwd
421
+ end
422
+ private :eval
423
+
424
+ # Deactivate this directive so that it won't have any effect.
425
+ def deactivate!
426
+ define_singleton_method(:execute){}
427
+ end
428
+ alias deactivate deactivate!
429
+
430
+ #
431
+ # :section: Accessing related sections
432
+ #
433
+
434
+ def section_index # :nodoc:
435
+ @section_index ||= comment.sections.find_index{ |sec| sec.line_no >= self.line_no } ||
436
+ comment.sections.size-1
437
+ end
438
+ private :section_index
439
+
440
+ # Returns the Comment#enclosed_comments for the #comment.
441
+ # If a block is given, it's yielded each of them in turn.
442
+ def all_enclosed_comments(&blk)
443
+ ary = comment.enclosed_comments
444
+ ary.each(&blk) if blk
445
+ ary
446
+ end
447
+
448
+ # Returns the Comment#sections of the #comment.
449
+ # If a block is given, it's yielded each of them in turn.
450
+ def all_sections(&blk)
451
+ ary = comment.sections
452
+ if blk
453
+ warn 'This directive affects also sections before' unless prev_sections.empty?
454
+ ary.each(&blk)
455
+ end
456
+ ary
457
+ end
458
+
459
+ # Returns the Comment#examples of the #comment.
460
+ # If a block is given, it's yielded each of them in turn.
461
+ def all_examples &blk
462
+ ary = all_sections.select(&:example?)
463
+ if blk
464
+ warn 'This directive affects also examples before' unless prev_examples.empty?
465
+ ary.each(&blk)
466
+ end
467
+ ary
468
+ end
469
+
470
+ # Returns the Comment#plain_texts of the #comment.
471
+ # If a block is given, it's yielded each of them in turn.
472
+ def all_texts &blk
473
+ ary = all_sections.select(&:text?)
474
+ if blk
475
+ warn 'This directive affects also texts before' unless prev_texts.empty?
476
+ ary.each(&blk)
477
+ end
478
+ ary
479
+ end
480
+
481
+ # Returns the +sections+ of the #comment that are before this directive.
482
+ # If a block is given, it's yielded each of them in turn.
483
+ def prev_sections(&blk)
484
+ ary = all_sections.take(section_index)
485
+ if blk
486
+ warn 'No sections before this directive' if ary.empty?
487
+ ary.each(&blk)
488
+ end
489
+ ary
490
+ end
491
+
492
+ # Returns the +examples+ of the #comment that are before this directive.
493
+ # If a block is given, it's yielded each of them in turn.
494
+ def prev_examples &blk
495
+ ary = prev_sections.select(&:example?)
496
+ if blk
497
+ warn 'No examples before this directive' if ary.empty?
498
+ ary.each(&blk)
499
+ end
500
+ ary
501
+ end
502
+
503
+ # Returns the +plain_texts+ of the #comment that are before this directive.
504
+ # If a block is given, it's yielded each of them in turn.
505
+ def prev_texts &blk
506
+ ary = prev_sections.select(&:text?)
507
+ if blk
508
+ warn 'No texts before this directive' if ary.empty?
509
+ ary.each(&blk)
510
+ end
511
+ ary
512
+ end
513
+
514
+ # Returns the +sections+ of the #comment that are after this directive.
515
+ # If a block is given, it's yielded each of them in turn.
516
+ def next_sections(&blk)
517
+ ary = all_sections.drop(section_index)
518
+ if blk
519
+ warn 'No sections after this directive' if ary.empty?
520
+ ary.each(&blk)
521
+ end
522
+ return ary
523
+ end
524
+
525
+ # Returns the +examples+ of the #comment that are after this directive.
526
+ # If a block is given, it's yielded each of them in turn.
527
+ def next_examples &blk
528
+ ary = next_sections.select(&:example?)
529
+ if blk
530
+ warn 'No examples after this directive' if ary.empty?
531
+ ary.each(&blk)
532
+ end
533
+ ary
534
+ end
535
+
536
+ # Returns the +plain_texts+ of the #comment that are after this directive.
537
+ # If a block is given, it's yielded each of them in turn.
538
+ def next_texts &blk
539
+ ary = next_sections.select(&:text?)
540
+ if blk
541
+ warn 'No texts after this directive' if ary.empty?
542
+ ary.each(&blk)
543
+ end
544
+ ary
545
+ end
546
+
547
+ # Returns the +section+ of the #comment just after this directive.
548
+ def next_section
549
+ next_sections.first
550
+ end
551
+
552
+ # Returns the +example+ of the #comment just after this directive.
553
+ def next_example
554
+ next_examples.first or
555
+ raise "Couldn't apply directive, missing example after"
556
+ end
557
+
558
+ # Returns the +plain_text+ of the #comment just after this directive.
559
+ def next_text
560
+ next_texts.first or
561
+ raise "Couldn't apply directive, missing text after"
562
+ end
563
+
564
+ # Returns the +section+ of the #comment just before this directive.
565
+ def prev_section
566
+ prev_sections.last
567
+ end
568
+
569
+ # Returns the +example+ of the #comment just before this directive.
570
+ def prev_example
571
+ prev_examples.last or
572
+ raise "Couldn't apply directive, missing example before"
573
+ end
574
+
575
+ # Returns the +plain_text+ of the #comment just after this directive.
576
+ def prev_text
577
+ prev_texts.last or
578
+ raise "Couldn't apply directive, missing text before"
579
+ end
580
+
581
+ #
582
+ # :section: Directives: Activation/Deactivation
583
+ #
584
+
585
+ ##
586
+ # :singleton-method:
587
+ # :call-seq:
588
+ # on
589
+ # "" (empty string)
590
+ #
591
+ # Turns on execution of examples. Often used after an ::off directive.
592
+ #
593
+ # An example (from <tt>array.c</tt>):
594
+ # :rdx: off
595
+ # /*
596
+ # * [...]
597
+ # * a = ["a", "b", "c"]
598
+ # * :rdx: off
599
+ # * a.cycle { |x| print x } # prints abcabcabc... forever
600
+ # * :rdx:
601
+ # * a.cycle(2) { |x| print x } # prints abcabc
602
+ # * [...]
603
+ # */
604
+ # static VALUE
605
+ # rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
606
+ #
607
+ # Note::
608
+ # This may also be used in a non-documenting comment (see Comment#documenting),
609
+ # with the purpouse of executing additional examples other than the ones in the documentation output.
610
+ #
611
+ define_directive 'on' do
612
+ next_examples{ |ex| ex.activate true }
613
+ end
614
+ alias_directive '', 'on'
615
+
616
+ ##
617
+ # :singleton-method:
618
+ # :call-seq:
619
+ # off [-]
620
+ #
621
+ # Turns off execution of examples (see the ::on directive for an example).
622
+ #
623
+ # Note::
624
+ # If the parameter is (or starts with) a hypen, only the immediately following
625
+ # example is deactivated; the execution will continue regularly,
626
+ # according to the effect of other directives after it.
627
+ #
628
+ define_directive 'off' do
629
+ if param && param[0] == '-'
630
+ next_example.deactivate true
631
+ else
632
+ next_examples{ |ex| ex.deactivate true }
633
+ end
634
+ end
635
+
636
+ ##
637
+ # :singleton-method:
638
+ # :call-seq:
639
+ # skip [motivation]
640
+ #
641
+ # Skips the execution of the immediately following example (through Example#whole_skip)
642
+ # reporting the optional _motivation_.
643
+ #
644
+ # The cause (and type) of this skip is a simple +TODO+ in RDX,
645
+ # in a lighter way than an explicit failure.
646
+ #
647
+ # An example:
648
+ # # Sorts a collection in descending order.
649
+ # # :rdx: skip write an example
650
+ # def reverse_sort enum
651
+ # enum.sort.reverse
652
+ # end
653
+ #
654
+ # Note::
655
+ # This directive may even be used before a text section: in this case nothing is
656
+ # really skipped, but it will anyhow be showed in the report.
657
+ #
658
+ define_directive 'skip' do
659
+ sect = next_section
660
+ msg,type = param,:TODO
661
+ if sect && sect.example?
662
+ next_example.whole_skip(msg, type, relative_line_no)
663
+ else
664
+ skip msg, type
665
+ end
666
+ end
667
+
668
+ ##
669
+ # :singleton-method:
670
+ # :call-seq:
671
+ # bug [details]
672
+ # buggy [details]
673
+ # is_buggy [details]
674
+ #
675
+ # Signals a bug in the library reporting _details_: use this directive above an example
676
+ # that _should_ work as declared.
677
+ # Use this only if you can't fix it, otherwise the explicit failure is better.
678
+ #
679
+ # An example (from <tt>encoding.c</tt>):
680
+ # :rdx: off
681
+ # /*
682
+ # * Search the encoding with specified <i>name</i>.
683
+ # * <i>name</i> should be a string or symbol.
684
+ # * Encoding.find("US-ASCII") #=> Encoding::US_ASCII
685
+ # * :rdx: bug symbols aren't accepted
686
+ # * Encoding.find(:Shift_JIS) #=> Encoding::Shift_JIS
687
+ # * [...]
688
+ # */
689
+ # static VALUE
690
+ # enc_find(VALUE klass, VALUE enc)
691
+ #
692
+ # Note::
693
+ # This works in a way similar to ::skip, but used +BUG+ as the skip type.
694
+ #
695
+ define_directive 'bug' do
696
+ next_example.whole_skip param, :BUG, relative_line_no
697
+ end
698
+ alias_directive 'buggy', 'bug'
699
+ alias_directive 'is_buggy', 'buggy'
700
+
701
+ ##
702
+ # :singleton-method:
703
+ # :call-seq:
704
+ # if condition
705
+ #
706
+ # If _condition_ evals to a true value the next example is executed regularly,
707
+ # otherwise it's skipped.
708
+ #
709
+ # An example:
710
+ # # The code will show a demonstration of +fork+:
711
+ # # :rdx: if Process.respond_to? :fork
712
+ # # puts 'In parent'
713
+ # # fork do
714
+ # # puts 'In child'
715
+ # # end
716
+ # # puts 'Back in parent'
717
+ # module Kernel; end
718
+ #
719
+ # Note::
720
+ # The condition is often platform-dependent,
721
+ # in order to make tests portable between different operating systems
722
+ # (hence the type of this skip is +LACKING+).
723
+ #
724
+ define_directive 'if' do
725
+ if eval(param)
726
+ next_example.activate
727
+ else
728
+ next_example.whole_skip param, :LACKING, relative_line_no
729
+ end
730
+ end
731
+
732
+ ##
733
+ # :singleton-method:
734
+ # :call-seq:
735
+ # lazy
736
+ # is_slow
737
+ #
738
+ # Run the next example only when necessary (see Example#lazy).
739
+ # This directive is often used when the example shows performance penalities.
740
+ #
741
+ # An example (from <tt>re.rdoc</tt>):
742
+ # :rdx: off
743
+ # == Performance
744
+ # Certain pathological combinations of constructs can lead to abysmally bad
745
+ # performance.
746
+ # [...]
747
+ # s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
748
+ # #=> "aaaaaaaaaaaaaaaaaaaaaaaaadaaaac"
749
+ # [...]
750
+ # However, the following pattern takes appreciably longer:
751
+ # \:rdx: is_slow
752
+ # /(b|a+)*c/ =~ s #=> 26
753
+ #
754
+ define_directive 'lazy' do
755
+ next_example.lazy relative_line_no
756
+ end
757
+ alias_directive 'is_slow', 'lazy'
758
+
759
+ #
760
+ # :section: Directives: Input/Output/Error
761
+ #
762
+
763
+ ##
764
+ # :singleton-method:
765
+ # :call-seq:
766
+ # stdout
767
+ # output
768
+ #
769
+ # Interprets the next example as the expected output of the previuos one
770
+ # (see Example#produces_on_stdout).
771
+ #
772
+ # Implicit detection::
773
+ # Recognized in a text section containing only <tt>produces:</tt>
774
+ # (html emphasized tags are allowed).
775
+ #
776
+ # An example:
777
+ # # Kernel#puts writes to <tt>$stdout</tt> its arguments.
778
+ # # puts 'one', 'two', 'three...'
779
+ # # produces:
780
+ # # one
781
+ # # two
782
+ # # three...
783
+ # module Kernel; end
784
+ #
785
+ # Note::
786
+ # If the output is only one line it can be passed as a parameter to this directive
787
+ # (and it's probably described in a text section)
788
+ #
789
+ define_directive 'stdout' do |dir|
790
+ dir.define do
791
+ output = param || next_example
792
+ prev_example.produces_on_stdout output, relative_line_no
793
+ end
794
+ dir.configure_implicit do |base=/[Pp]roduces:?/, allow_emphatized=true|
795
+ pat = Regexp.union(base)
796
+ pat = Text.add_html_tags pat, nil, 'em', 'i' if allow_emphatized
797
+ dir.find_in_text /\A\s*#{pat}\s*\z/
798
+ end
799
+ end
800
+ alias_directive 'output', 'stdout'
801
+
802
+ ##
803
+ # :singleton-method:
804
+ # :call-seq:
805
+ # indicative_output
806
+ #
807
+ # Ignores the next example and the output produced by the previuos one.
808
+ #
809
+ # An example:
810
+ # #
811
+ # # The following code will output the first 1000 prime numbers.
812
+ # # require 'Prime'
813
+ # # Prime.first(1000).each{ |prime| puts prime }
814
+ # # The result:
815
+ # # :rdx: indicative_output
816
+ # # 2
817
+ # # 3
818
+ # # 5
819
+ # # 7
820
+ # # ... other 994 prime numbers ...
821
+ # # 7907
822
+ # # 7919
823
+ # module Prime; end
824
+ #
825
+ define_directive 'indicative_output' do
826
+ next_example.deactivate!
827
+ prev_example.outputs //
828
+ end
829
+
830
+ ##
831
+ # :singleton-method:
832
+ # :call-seq:
833
+ # stderr
834
+ #
835
+ # Interprets the next example as the expected output of the previuos one
836
+ # (see Example#produces_on_stderr).
837
+ #
838
+ # An example (from <tt>enumerator.c</tt>):
839
+ # :rdx: off
840
+ # /*
841
+ # * [...]
842
+ # * Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum
843
+ # * instead.
844
+ # * e = Enumerator.new(ObjectSpace, :each_object)
845
+ # * #-> ObjectSpace.enum_for(:each_object)
846
+ # * produces on stderr:
847
+ # * :rdx: stderr
848
+ # * warning: Enumerator.new without a block is deprecated; use Object#to_enum
849
+ # * [...]
850
+ # */
851
+ # static VALUE
852
+ # enumerator_initialize(int argc, VALUE *argv, VALUE obj)
853
+ #
854
+ define_directive 'stderr' do
855
+ output = param || next_example
856
+ prev_example.produces_on_stderr output, relative_line_no
857
+ end
858
+
859
+ ##
860
+ # :singleton-method:
861
+ # :call-seq:
862
+ # stdin
863
+ # input
864
+ #
865
+ # Interprets the previous example as the input for the next one.
866
+ #
867
+ # An example (from <tt>vm_eval.c</tt>):
868
+ # :rdx: off
869
+ # /*
870
+ # * [...]
871
+ # * When the following input
872
+ # * First line given
873
+ # * Second line given
874
+ # * Last line given
875
+ # * Quit!
876
+ # * is given into this program
877
+ # * :rdx: stdin
878
+ # * loop do
879
+ # * line = gets
880
+ # * break if !line or line =~ /^[qQ]/
881
+ # * puts "Got: #{line}"
882
+ # * end
883
+ # * produces:
884
+ # * Got: First line given
885
+ # * Got: Second line given
886
+ # * Got: Last line given
887
+ # * [...]
888
+ # */
889
+ # static VALUE
890
+ # rb_f_loop(VALUE self)
891
+ #
892
+ define_directive 'stdin' do
893
+ input = param || prev_example
894
+ next_example.take_input_from input
895
+ end
896
+ alias_directive 'input', 'stdin'
897
+
898
+ ##
899
+ # :singleton-method:
900
+ # :call-seq:
901
+ # exception
902
+ # error
903
+ #
904
+ # :rdx: no_warnings conventions
905
+ # Interprets the next example as the description of the exception
906
+ # raised by previous one (see Example#raises).
907
+ #
908
+ # Implicit detection::
909
+ # Recognized in a text section containing only <tt>raises the exception:</tt>
910
+ # (or simply <tt>raises:</tt>).
911
+ #
912
+ # An example:
913
+ # # Kernel#raise will raise a RuntimeError with the given message:
914
+ # # raise 'Boom!'
915
+ # # raises the exception:
916
+ # # Boom! (RuntimeError)
917
+ # module Kernel; end
918
+ #
919
+ # Note::
920
+ # If the parameter is given it's treated as the exception's class name.
921
+ # This can be useful if the message is negligible, but we don't want to
922
+ # rely on an error convention.
923
+ #
924
+ define_directive 'exception' do |dir|
925
+ dir.define do
926
+ error = param || next_example
927
+ prev_example.raises error, relative_line_no
928
+ end
929
+ dir.configure_implicit do |base=/[Rr]aises?(?: the exception)?:?/, allow_emphatized=true|
930
+ pat = Regexp.union base
931
+ pat = Text.add_html_tags pat, nil, 'em', 'i' if allow_emphatized
932
+ dir.find_in_text /\A\s*#{pat}\s*\z/
933
+ end
934
+ end
935
+ alias_directive 'error', 'exception'
936
+
937
+ ##
938
+ # :singleton-method:
939
+ # :call-seq:
940
+ # write_file relative_name
941
+ #
942
+ # Writes the content of the next example to the specified file _relative_name_
943
+ # (see Example#write_to_file).
944
+ #
945
+ # Implicit detection::
946
+ # Recognized in an example beginning with a comment <tt># File: </tt> _relative_name_.
947
+ #
948
+ # An example:
949
+ # # IO.foreach iterates over the lines (according to <tt>$/</tt>) of the given file.
950
+ # # # File: lines.txt
951
+ # # This is line 1
952
+ # # this is line 2
953
+ # # and so on...
954
+ # # From the application:
955
+ # # enum = IO.foreach 'lines.txt'
956
+ # # enum.next.chomp #=> "This is line 1"
957
+ # # enum.next.chomp #=> "This is line 2"
958
+ # # enum.next.chomp #=> "and so on..."
959
+ # class IO; end
960
+ #
961
+ define_directive 'write_file' do |dir|
962
+ dir.define do
963
+ next_example.write_to_file param, relative_line_no do |content|
964
+ content.slice! /\A.*\n/ if implicit?
965
+ content
966
+ end
967
+ end
968
+ dir.configure_implicit do |base=/(?:[Ii]n +)?[Ff]ile[: ]/, fname=/\S+/|
969
+ dir.find_in_example /\A\s*#[ \t]*#{base}[ \t]*(#{fname})[ \t]*$/
970
+ end
971
+ end
972
+
973
+ ##
974
+ # :singleton-method:
975
+ # :call-seq:
976
+ # check_file relative_name
977
+ #
978
+ # Compares the next example against the content of the specified file _relative_name_
979
+ # (see Example#check_file_content).
980
+ #
981
+ # An example:
982
+ # # IO#puts writes the given argument to +ios+ along with a record separator.
983
+ # # f = File.new 'out', 'w'
984
+ # # f.puts 'line 1'
985
+ # # f.puts 'line 2'
986
+ # # f.puts 'line 1000' # 1,2,3 was boring...
987
+ # # Now the file +out+ will contian:
988
+ # # :rdx: check_file out
989
+ # # line 1
990
+ # # line 2
991
+ # # line 1000
992
+ # class IO; end
993
+ #
994
+ define_directive 'check_file' do
995
+ next_example.check_file_content param, relative_line_no
996
+ end
997
+
998
+ #
999
+ # :section: Directives: Context change
1000
+ #
1001
+
1002
+ ##
1003
+ # :singleton-method:
1004
+ # :call-seq:
1005
+ # new_binding
1006
+ #
1007
+ # Changes the binding of the following examples to a new empty one
1008
+ # (specifically to Binding.pseudo_toplevel).
1009
+ #
1010
+ # An example (from <tt>re.c</tt>):
1011
+ # :rdx: off
1012
+ # /*
1013
+ # * [...]
1014
+ # * If <code>=~</code> is used with a regexp literal with named captures,
1015
+ # * captured strings (or nil) is assigned to local variables named by
1016
+ # * the capture names.
1017
+ # * /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ " x = y "
1018
+ # * lhs #=> "x"
1019
+ # * rhs #=> "y"
1020
+ # * [...]
1021
+ # * :rdx: new_binding
1022
+ # * :rdx: # Without this directive those local variables are already defined
1023
+ # * The assignment does not occur if the regexp is not a literal.
1024
+ # * re = /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/
1025
+ # * re =~ " x = y "
1026
+ # * lhs # error: undefined local variable
1027
+ # * rhs # error: undefined local variable
1028
+ # * [...]
1029
+ # */
1030
+ # VALUE
1031
+ # rb_reg_match(VALUE re, VALUE str)
1032
+ #
1033
+ define_directive 'new_binding' do
1034
+ new_binding = Binding.pseudo_toplevel
1035
+ next_examples{ |ex| ex.set_binding new_binding }
1036
+ end
1037
+
1038
+ ##
1039
+ # :singleton-method:
1040
+ # :call-seq:
1041
+ # toplevel
1042
+ #
1043
+ # The default binding for the execution isn't the true toplevel one
1044
+ # (see CodeObject::Runnable::Startable#prepare_binding),
1045
+ # however some examples don't have sense under this condition.
1046
+ # This directive changes the binding of the following examples to a copy
1047
+ # of the toplevel one (specifically to Binding.toplevel).
1048
+ #
1049
+ # An example (from <tt>struct.c</tt>):
1050
+ # :rdx: off
1051
+ # /*
1052
+ # * [...]
1053
+ # * <code>Struct::new</code> returns a new <code>Class</code> object,
1054
+ # * which can then be used to create specific instances of the new
1055
+ # * structure.
1056
+ # * [...]
1057
+ # * :rdx: toplevel
1058
+ # * # Create a structure named by its constant
1059
+ # * Customer = Struct.new(:name, :address) #=> Customer
1060
+ # * Customer.new("Dave", "123 Main") # > #<struct Customer name="Dave", address="123 Main">
1061
+ # *-- rdx
1062
+ # * Without this directive we should write <tt>::Customer</tt> instead of <tt>Customer</tt>;
1063
+ # * this can confuse the reader, bacause normally it's not necessary.
1064
+ # * Now clean-up step:
1065
+ # * Object.send :remove_const, :Customer
1066
+ # *++
1067
+ # */
1068
+ # static VALUE
1069
+ # rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
1070
+ #
1071
+ # Note::
1072
+ # It's user's responsibilty to clean up all the necessary
1073
+ # (usually using private rdx sections).
1074
+ #
1075
+ define_directive 'toplevel' do
1076
+ toplevel_binding = Binding.toplevel
1077
+ next_examples{ |ex| ex.set_binding toplevel_binding }
1078
+ end
1079
+
1080
+ ##
1081
+ # :singleton-method:
1082
+ # :call-seq:
1083
+ # before_require
1084
+ #
1085
+ # Runs the next example before requiring the full set of libraries.
1086
+ # This turns handy if you are modifying the core and you want
1087
+ # to show the differences provided by your patch.
1088
+ #
1089
+ # An example (from <tt>mathn.rb</tt>):
1090
+ # # [...]
1091
+ # # mathn features late rounding and lacks truncation of intermediate results:
1092
+ # # Without mathn:
1093
+ # # :rdx: before_require
1094
+ # # 20 / 9 * 3 * 14 / 7 * 3 / 2 # => 18
1095
+ # # With mathn:
1096
+ # # 20 / 9 * 3 * 14 / 7 * 3 / 2 # => 20
1097
+ # # [...]
1098
+ # class Numeric; end
1099
+ #
1100
+ define_directive 'before_require' do
1101
+ next_example.run_before_require
1102
+ end
1103
+
1104
+ ##
1105
+ # :singleton-method:
1106
+ # :call-seq:
1107
+ # setup
1108
+ #
1109
+ # Uses the next example as a setup for the comment, that will run
1110
+ # before every Comment#enclosed_comments.
1111
+ #
1112
+ # An example (from <tt>cmath.rb</tt>):
1113
+ # # [...]
1114
+ # # In the following examples we assume that CMath is included at toplevel for the sake of clarity:
1115
+ # # :rdx: setup
1116
+ # # include CMath
1117
+ # # Square root of a negative number is a complex number.
1118
+ # # sqrt(-9) #=> 0+3.0i
1119
+ # # [...]
1120
+ # module CMath
1121
+ # ##
1122
+ # # Returns the natural logarithm of Complex. If a second argument is given,
1123
+ # # it will be the base of logarithm.
1124
+ # # log(Complex(0,0)) # > (-Infinity+0.0i)
1125
+ # #--
1126
+ # # This works thanks to the above setup
1127
+ # def log(*args)
1128
+ # #[...]
1129
+ # end
1130
+ # end
1131
+ #
1132
+ define_directive 'setup' do
1133
+ next_example.use_as_setup
1134
+ end
1135
+
1136
+ ##
1137
+ # :singleton-method:
1138
+ # :call-seq:
1139
+ # teardown
1140
+ #
1141
+ # Uses the next example as a teardown for the comment, that will run
1142
+ # after every Comment#enclosed_comments.
1143
+ #
1144
+ # See +setup+ for an example.
1145
+ #
1146
+ define_directive 'teardown' do
1147
+ next_example.use_as_teardown
1148
+ end
1149
+
1150
+ ##
1151
+ # :singleton-method:
1152
+ # :call-seq:
1153
+ # in_tmpdir
1154
+ #
1155
+ # Runs the next example in a temporary directory (see Example#run_in_tmpdir).
1156
+ #
1157
+ # An example (from <tt>encoding.c</tt>):
1158
+ # :rdx: off
1159
+ # /*
1160
+ # * [...]
1161
+ # * While writing the file, the internal encoding is not specified as it is
1162
+ # * only necessary for reading. While reading the file both the internal and
1163
+ # * external encoding must be specified to obtain the correct result:
1164
+ # * :rdx: in_tmpdir
1165
+ # * string = "R\u00E9sum\u00E9"
1166
+ # * open("transcoded.txt", "w:ISO-8859-1") do |io|
1167
+ # * io.write(string)
1168
+ # * end
1169
+ # * puts File.binread("transcoded.txt").dump
1170
+ # * [...]
1171
+ # * produces:
1172
+ # * "R\xE9sum\xE9"
1173
+ # * [...]
1174
+ # */
1175
+ # void
1176
+ # Init_Encoding(void)
1177
+ #
1178
+ define_directive 'in_tmpdir' do
1179
+ next_example.run_in_tmpdir
1180
+ end
1181
+
1182
+ ##
1183
+ # :singleton-method:
1184
+ # :call-seq:
1185
+ # in_tmpdir!
1186
+ #
1187
+ # Same as ::in_tmpdir, but applies to the whole comment.
1188
+ #
1189
+ define_directive 'in_tmpdir!' do
1190
+ comment.run_in_tmpdir
1191
+ end
1192
+
1193
+ ##
1194
+ # :singleton-method:
1195
+ # :call-seq:
1196
+ # in_tmpdir!!
1197
+ #
1198
+ # Same as ::in_tmpdir, but applies to #all_enclosed_comments
1199
+ # (on which operate +setup+ and +teardown+).
1200
+ #
1201
+ define_directive 'in_tmpdir!!' do
1202
+ all_enclosed_comments(&:run_in_tmpdir)
1203
+ end
1204
+
1205
+ ##
1206
+ # :singleton-method:
1207
+ # :call-seq:
1208
+ # bash default_prompt=/\$\s/, continuation_prompt=/>\s/
1209
+ #
1210
+ # Interprets the next example as a bash command-line session
1211
+ # (see Example#on_bash_mode).
1212
+ #
1213
+ # Implicit detection::
1214
+ # Recognized in an example that begins with the default prompt (the predefined
1215
+ # isn't syntattically correct in Ruby, so we can safely avoid ambiguous situations).
1216
+ #
1217
+ # An example (from <tt>optparse.rb</tt>):
1218
+ # # [...]
1219
+ # # We give options from the command line:
1220
+ # # $ ruby example.rb -h
1221
+ # # Usage: example.rb [options] [arguments...]
1222
+ # # -v, --[no-]verbose Run verbosely
1223
+ # # $ ruby example.rb -v
1224
+ # # options = {:verbose=>true}
1225
+ # # ARGV = []
1226
+ # # [...]
1227
+ # class OptionParser; end
1228
+ #
1229
+ # Note::
1230
+ # If the output includes the default or continuation prompt you should change
1231
+ # them (or supply +nil+ if you don't want) with the explicit directive:
1232
+ # :rdx: off
1233
+ # # This is the result in the command line (<tt>" </tt> is the continuation prompt):
1234
+ # # :rdx: bash nil, '" '
1235
+ # # $ ruby <<EOS
1236
+ # # " puts "> Hello world!"
1237
+ # # " EOS
1238
+ # # > Hello world!
1239
+ # class Shell; end
1240
+ #
1241
+ define_directive 'bash' do |dir|
1242
+ dir.metadata[:default_prompt] = /\$\s/
1243
+ dir.metadata[:continuation_prompt] = />\s/
1244
+ dir.define do
1245
+ default_prompt,continuation_prompt = param && eval("[#{param}]")
1246
+ default_prompt ||= metadata[:default_prompt]
1247
+ continuation_prompt ||= metadata[:continuation_prompt]
1248
+ next_example.on_bash_mode default_prompt, continuation_prompt
1249
+ end
1250
+ dir.configure_implicit do |prompt=dir.metadata[:default_prompt]|
1251
+ prompt = prompt.is_a?(Regexp) ? prompt.to_s : Regexp.escape(prompt.to_str)
1252
+ dir.find_in_example /\A\s*^#{prompt}/
1253
+ end
1254
+ end
1255
+
1256
+ #
1257
+ # :section: Directives: Assertions customization
1258
+ #
1259
+
1260
+ ##
1261
+ # :singleton-method:
1262
+ # :call-seq:
1263
+ # float digits=3
1264
+ #
1265
+ # Sets the next example on floating-point mode (see Example#on_float_mode)
1266
+ # passing _digits_ (default to 3, value stored in the #metadata as +:digits+).
1267
+ #
1268
+ # An example (from <tt>math.c</tt>):
1269
+ # :rdx: off
1270
+ # /*
1271
+ # * [...]
1272
+ # * If +x+ isn't too large we have that:
1273
+ # * :rdx: float
1274
+ # * log_gamma,sgn_gamma = Math.lgamma(x)
1275
+ # * log_gamma #=> Math.log(Math.gamma(x).abs)
1276
+ # * sgn_gamma #=> Math.gamma(x) < 0 ? -1 : 1
1277
+ # * otherwise Math.gamma(x) will overflow (yielding Infinity),
1278
+ # * while Math.lgamma(x) does not
1279
+ # */
1280
+ # static VALUE
1281
+ # math_lgamma(VALUE obj, VALUE x)
1282
+ #
1283
+ # Note::
1284
+ # This directive covers the holes leaved by Convention::result_numeric.
1285
+ #
1286
+ define_directive 'float' do |dir_class|
1287
+ dir_class.metadata[:digits] = 3
1288
+ dir_class.define do
1289
+ digits = param ? Integer(param) : metadata[:digits]
1290
+ next_example.on_float_mode(digits)
1291
+ end
1292
+ end
1293
+
1294
+ ##
1295
+ # :singleton-method:
1296
+ # :call-seq:
1297
+ # float! digits=3
1298
+ #
1299
+ # Same as ::float but applies to the whole comment.
1300
+ #
1301
+ define_directive 'float!' do
1302
+ digits = param ? Integer(param) : metadata[:digits]
1303
+ all_examples{ |ex| ex.on_float_mode(digits) }
1304
+ end
1305
+
1306
+ ##
1307
+ # :singleton-method:
1308
+ # :call-seq:
1309
+ # indicative_numbers
1310
+ #
1311
+ # Sets the next example on indicative numbers mode
1312
+ # (see Example#on_indicative_numbers_mode).
1313
+ #
1314
+ # An example (from <tt>benchmark.rb</tt>):
1315
+ # :rdx: off
1316
+ # # :rdx: indicative_numbers
1317
+ # # n = 50000
1318
+ # # Benchmark.bm(7) do |x|
1319
+ # # x.report("for:") { for i in 1..n; a = "1"; end }
1320
+ # # x.report("times:") { n.times do ; a = "1"; end }
1321
+ # # x.report("upto:") { 1.upto(n) do ; a = "1"; end }
1322
+ # # end
1323
+ # # Produces:
1324
+ # # user system total real
1325
+ # # for: 1.050000 0.000000 1.050000 ( 0.503462)
1326
+ # # times: 1.533333 0.016667 1.550000 ( 0.735473)
1327
+ # # upto: 1.500000 0.016667 1.516667 ( 0.711239)
1328
+ # module Benchmark; end
1329
+ #
1330
+ define_directive 'indicative_numbers' do
1331
+ next_example.on_indicative_numbers_mode
1332
+ end
1333
+
1334
+ ##
1335
+ # :singleton-method:
1336
+ # :call-seq:
1337
+ # indicative_numbers!
1338
+ #
1339
+ # Same as ::indicative_numbers, but applies to the whole comment.
1340
+ #
1341
+ define_directive 'indicative_numbers!' do
1342
+ all_examples(&:on_indicative_numbers_mode)
1343
+ end
1344
+
1345
+ #
1346
+ # :section: Directives: Miscellaneous
1347
+ #
1348
+
1349
+ ##
1350
+ # :singleton-method:
1351
+ # :call-seq:
1352
+ # # comment
1353
+ #
1354
+ # Insert a comment (probably about some RDX detail).
1355
+ #
1356
+ # Note::
1357
+ # For the directive syntax at least one space is required after the hash,
1358
+ # which happens to be the directive name.
1359
+ #
1360
+ define_directive '#' do end
1361
+
1362
+ ##
1363
+ # :singleton-method:
1364
+ # :call-seq:
1365
+ # disable_warnings *types
1366
+ # no_warnings *types
1367
+ #
1368
+ # Disables the given _types_ of warnings for the next section
1369
+ # (see CodeObject#disable_warnings).
1370
+ #
1371
+ # An example:
1372
+ # :rdx: off
1373
+ # # :rdx: no_warnings convention
1374
+ # # The hash-rocket notation, <tt>#=></tt>, indicates the result of a statement:
1375
+ # # 1+1 #=> 2
1376
+ # class Convention; end
1377
+ #
1378
+ define_directive 'disable_warnings' do
1379
+ next_section.disable_warnings *params
1380
+ end
1381
+ alias_directive 'no_warnings', 'disable_warnings'
1382
+
1383
+ ##
1384
+ # :singleton-method:
1385
+ # :call-seq:
1386
+ # disable_warnings! *types
1387
+ # no_warnings! *types
1388
+ #
1389
+ # Same as ::disable_warnings, but applies to the whole comment.
1390
+ #
1391
+ define_directive 'disable_warnings!' do
1392
+ comment.disable_warnings *params
1393
+ end
1394
+ alias_directive 'no_warnings!', 'disable_warnings!'
1395
+
1396
+ ##
1397
+ # :singleton-method:
1398
+ # :call-seq:
1399
+ # discard_output
1400
+ #
1401
+ # Ignores the uncaptured output produced by the next example - otherwise a warning will be generated.
1402
+ #
1403
+ # An example:
1404
+ # :rdx: off
1405
+ # # The following code will output the first 1000 prime numbers:
1406
+ # # :rdx: discard_output
1407
+ # # require 'Prime'
1408
+ # # Prime.first(1000).each{ |prime| puts prime }
1409
+ # module Prime; end
1410
+ #
1411
+ # Note::
1412
+ # This directive actually suppresses the +stdout+ type of warning.
1413
+ #
1414
+ define_directive 'discard_output' do
1415
+ next_example.disable_warnings 'stdout'
1416
+ end
1417
+
1418
+ ##
1419
+ # :singleton-method:
1420
+ # :call-seq:
1421
+ # disable_implicit *names
1422
+ #
1423
+ # Disables the given _names_ of implicit directives in the next section
1424
+ # (see Comment#disable_implicit_directives_in).
1425
+ #
1426
+ define_directive 'disable_implicit' do
1427
+ comment.disable_implicit_directives_in next_section, *params
1428
+ end
1429
+
1430
+ end
1431
+
1432
+ end