rdx 0.9.0.pre → 0.9.0.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README +186 -12
  3. data/TODO +18 -0
  4. data/examples/minimal/.rdx +1 -0
  5. data/examples/minimal/rakefile +5 -2
  6. data/examples/ruby-2.0.0-p0/install/core/BUGS +70 -0
  7. data/examples/ruby-2.0.0-p0/install/core/HALL_OF_SHAME +53 -0
  8. data/examples/ruby-2.0.0-p0/install/core/README +14 -4
  9. data/examples/ruby-2.0.0-p0/install/core/Rakefile +9 -4
  10. data/examples/ruby-2.0.0-p0/install/core/TODO +5 -0
  11. data/examples/ruby-2.0.0-p0/install/core/diffs/array.c.diff +8 -7
  12. data/examples/ruby-2.0.0-p0/install/core/diffs/encoding.c.diff +1 -1
  13. data/examples/ruby-2.0.0-p0/install/core/diffs/enumerator.c.diff +4 -12
  14. data/examples/ruby-2.0.0-p0/install/core/diffs/eval.c.diff +3 -5
  15. data/examples/ruby-2.0.0-p0/install/core/diffs/file.c.diff +2 -2
  16. data/examples/ruby-2.0.0-p0/install/core/diffs/gc.c.diff +5 -4
  17. data/examples/ruby-2.0.0-p0/install/core/diffs/hash.c.diff +4 -3
  18. data/examples/ruby-2.0.0-p0/install/core/diffs/object.c.diff +5 -4
  19. data/examples/ruby-2.0.0-p0/install/core/diffs/proc.c.diff +7 -6
  20. data/examples/ruby-2.0.0-p0/install/core/diffs/random.c.diff +3 -3
  21. data/examples/ruby-2.0.0-p0/install/core/diffs/rational.c.diff +21 -18
  22. data/examples/ruby-2.0.0-p0/install/core/diffs/ruby.c.diff +1 -1
  23. data/examples/ruby-2.0.0-p0/install/stdlib/DOCUMENTATION +22 -0
  24. data/examples/ruby-2.0.0-p0/install/stdlib/README +12 -4
  25. data/examples/ruby-2.0.0-p0/install/stdlib/Rakefile +10 -5
  26. data/examples/ruby-2.0.0-p0/install/stdlib/TODO +6 -0
  27. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/optparse.rb.diff +31 -11
  28. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/uri/common.rb.diff +8 -7
  29. data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/weakref.rb.diff +2 -2
  30. data/lib/rdx.rb +42 -92
  31. data/lib/rdx/assertions.rb +8 -9
  32. data/lib/rdx/binding.rb +2 -2
  33. data/lib/rdx/comment.rb +7 -5
  34. data/lib/rdx/convention.rb +10 -9
  35. data/lib/rdx/directive.rb +51 -26
  36. data/lib/rdx/example.rb +94 -68
  37. data/lib/rdx/generator.rb +1 -1
  38. data/lib/rdx/generator/rdoc.rb +5 -6
  39. data/lib/rdx/options.rb +7 -3
  40. data/lib/rdx/reporter.rb +17 -0
  41. data/lib/rdx/ruby_lex.rb +3 -3
  42. data/lib/rdx/runner.rb +1 -1
  43. data/lib/rdx/statement.rb +1 -1
  44. data/lib/rdx/store.rb +1 -1
  45. data/lib/rdx/task.rb +1 -1
  46. data/lib/rdx/text.rb +1 -1
  47. data/lib/rdx/version.rb +1 -1
  48. data/rakefile +43 -14
  49. metadata +23 -3
@@ -3,8 +3,9 @@ module RDX
3
3
 
4
4
  #
5
5
  # RDX uses the assertions of the standard testing framework of ruby, +Minitest+.
6
- # This module adapt its functionality to RDX's needs.
7
- # The most important new features are:
6
+ # This module adapt its functionality to RDX's needs,
7
+ # providing a layer of compatibility between all +Minitest+'s versions.
8
+ # Moreover new features are available. The most important ones are:
8
9
  # * #assert_equal_numeric: more powerful than +assert_equal+ if +Numeric+ are involved;
9
10
  # * #assert_string_match: perfect when comparing an actual +String+ with an expected +String+ or +Regexp+;
10
11
  # * #assert_msg_raised: checks the exception message in alternative of or along to the exception class;
@@ -20,16 +21,14 @@ module RDX
20
21
  begin
21
22
  gem 'minitest', '>= 5.0'
22
23
  require 'minitest/assertions'
24
+ include Minitest::Assertions
23
25
  rescue Gem::LoadError
24
26
  gem 'minitest'
25
27
  require 'minitest/unit'
26
- ::Minitest = ::MiniTest unless Object.const_defined?(:Minitest) # For minitest < 2.12
28
+ mt = Object.const_defined?(:Minitest) ? Minitest : MiniTest # For minitest < 2.12
29
+ include mt::Assertions # :nodoc:
27
30
  end
28
31
 
29
- include Minitest::Assertions
30
-
31
- extend self
32
-
33
32
  PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, SystemExit] # :nodoc:
34
33
 
35
34
  # Doesn't count assertions (done in CodeObject::Runnable#trace_assertion).
@@ -246,7 +245,7 @@ module RDX
246
245
  assert_output_but normalize, '', '', out_msg, err_msg, &blk
247
246
  end
248
247
 
249
- # Overrided to implicitly call #normalize_values.
248
+ # Overridden to implicitly call #normalize_values.
250
249
  def assert_silent *args, &blk
251
250
  assert_silent_but nil, *args, &blk
252
251
  end
@@ -375,7 +374,7 @@ module RDX
375
374
 
376
375
  #
377
376
  # Returns _exp_ and _act_ in an +Array+ normalized through the block given.
378
- # This method can be overridded to modify the normalization.
377
+ # This method can be overridden to modify the normalization.
379
378
  #
380
379
  def normalize_values exp, act, &normalize
381
380
  if normalize
@@ -62,7 +62,7 @@ module RDX
62
62
  # * +include+ and +define_method+ are redefined to better reproduce this environment.
63
63
  #
64
64
  # These lead to the fact that almost all new definitions - intentional top-level constants and global
65
- # variables are excluded - are restricted to that binding. All of this without sacrifycing efficiency.
65
+ # variables are excluded - are restricted to that binding. All of this without sacrificing efficiency.
66
66
  #
67
67
  # :rdx: toplevel
68
68
  #
@@ -95,7 +95,7 @@ module RDX
95
95
  # $global_var # => true
96
96
  # # Clean up:
97
97
  # Object.send :remove_const, :TOP_LEVEL_CONST # => true
98
- # $global_var = nil # Even if it isn't truely removed...
98
+ # $global_var = nil # Even if it isn't truly removed...
99
99
  #
100
100
  # These features makes #pseudo_toplevel_binding the favourite by RDX.
101
101
  #
@@ -67,13 +67,17 @@ module RDX
67
67
  examples.select(&:active?)
68
68
  end
69
69
 
70
- #
71
- # :category: API
70
+ #
71
+ # :section: API
72
+ #
73
+
72
74
  #
73
75
  # Disables the directives of the given _names_ that are +implicit?+ in _section_.
74
76
  # If no name is given, all of them are disabled.
77
+ # If _section_ is +nil+, nothing will happen.
75
78
  #
76
79
  def disable_implicit_directives_in section, *names
80
+ return if section.nil?
77
81
  implicit_dirs = directives.select{ |dir| dir.implicit?(section) }
78
82
  unless names.empty?
79
83
  names.map!{ |dir_name| store.directive(dir_name) } # directive classes
@@ -83,8 +87,6 @@ module RDX
83
87
  end
84
88
 
85
89
  #
86
- # :category: API
87
- #
88
90
  # Disables the directives of the given _names_ that are +implicit?+ in this comment.
89
91
  # If no name is given, all of them are disabled.
90
92
  #
@@ -320,7 +322,7 @@ module RDX
320
322
  end
321
323
 
322
324
  #
323
- # Every commment seen by the parser is checked for the presence of conventions:
325
+ # Every comment seen by the parser is checked for the presence of conventions:
324
326
  # if they are in places where they will not be executed a warning will be generated.
325
327
  # This is done in text sections (see PlainText#check_missing_conventions) and in
326
328
  # examples that won't be part of the documentation output (see Example#check_non_documenting).
@@ -24,7 +24,7 @@ module RDX
24
24
  #
25
25
  # == A tour on the existing conventions
26
26
  #
27
- # The most important *default* conventions (and some derivates for literals) currently are:
27
+ # The most important *default* conventions (and some derivatives for literals) currently are:
28
28
  # * ::result_eval: checks the result
29
29
  # [1,2,3].pop(2) # => [2,3]
30
30
  # * ::output_literal: checks the output
@@ -269,7 +269,7 @@ module RDX
269
269
  # #process_statement and #process_expectation) and is executed in the context of
270
270
  # (with +self+ as) the corresponding Example - class that includes the Assertion module,
271
271
  # providing full access to Minitest framework. This allows to customize the assertion methods
272
- # for only some examples (through some directives), but mantains an unified and coherent
272
+ # for only some examples (through some directives), but maintains an unified and coherent
273
273
  # behaviour between statements inside it.
274
274
  #
275
275
  define_processor :process_assertion
@@ -309,6 +309,7 @@ module RDX
309
309
  def use_with(*args,&blk)
310
310
  if @configuration
311
311
  @configuration.call(*args,&blk)
312
+ # TODO: handle derivative conventions
312
313
  elsif !args.empty? || blk
313
314
  raise "#{self} does not accept a configuration"
314
315
  end
@@ -544,7 +545,7 @@ module RDX
544
545
  # Both the strings +a+ and +b+ have the same content;
545
546
  # if the <tt>=></tt> prompt always maps to an +assert_equal+ the assertion would pass...
546
547
  # But it's really what we mean, what we want to bring out from the example?
547
- # That sounds much more like "it returns the object _labelled_ +a+"
548
+ # That sounds much more like "it returns the object _referenced_ _by_ +a+"
548
549
  # then "it returns an object _equal_ _to_ +a+".
549
550
  #
550
551
  # Expectation format::
@@ -837,7 +838,7 @@ module RDX
837
838
  # # 'a' => 2
838
839
  # # } # does these spaces really matter? And the order in which pairs are listed?
839
840
  # File.expand_path 'a' #=> "#{Dir.pwd}/a" # interpolation of values not allowed
840
- # (1..1000).first 100 #=> (1..100).to_a # shorthands not allowed
841
+ # (1..1000).first 100 #=> (1..100).to_a # shorthand not allowed
841
842
  # "abc \0\0".unpack('a3a3') #=> ["abc", " \000\000"]
842
843
  # # the second string should be: " \0\0"
843
844
  #
@@ -870,7 +871,7 @@ module RDX
870
871
  # :singleton-method:
871
872
  #
872
873
  # Derived from ::result_inspect::
873
- # The aim is to reduce discrepances due to float calculations and representations,
874
+ # The aim is to reduce discrepancies due to float calculations and representations,
874
875
  # one of the things that ::result_numeric does for ::result_eval (but
875
876
  # here this is done in strings).
876
877
  #
@@ -1022,7 +1023,7 @@ module RDX
1022
1023
  # Description::
1023
1024
  # Recognizes the class and the message of the exception raised by the statement.
1024
1025
  # The message is interpreted literally, without any evaluation:
1025
- # to remove little discrepances Text#normalize_exception_message is used.
1026
+ # to remove little discrepancies Text#normalize_exception_message is used.
1026
1027
  # The class (if given), message and +false+ are sent to Assertions#assert_msg_raised.
1027
1028
  #
1028
1029
  # 1.odd?(true) # raises ArgumentError: wrong number of arguments (1 for 0)
@@ -1060,7 +1061,7 @@ module RDX
1060
1061
  #
1061
1062
  # Description::
1062
1063
  # Recognizes the class and the message of the exception raised by the statement.
1063
- # The message is evalued, thus avoiding any sort of levellation: this enables
1064
+ # The message is evalued, thus avoiding any sort of levelling: this enables
1064
1065
  # a more formal approach in contrast to ::error_literal.
1065
1066
  # The class (if given) and message are sent to Assertions#assert_msg_raised.
1066
1067
  #
@@ -1079,7 +1080,7 @@ module RDX
1079
1080
  process_statement{ |code| lambda{ eval(code) } }
1080
1081
  process_expectation do |content|
1081
1082
  cls,msg = Text.split_exception_string(content,:class_message)
1082
- # :message_class is not allowed, since a valid statement can end with a parhentesis...
1083
+ # :message_class is not allowed, since a valid statement can end with a parenthesis...
1083
1084
  cls &&= toplevel_scope.const_get(cls)
1084
1085
  msg &&= eval(msg)
1085
1086
  [cls,msg]
@@ -1139,7 +1140,7 @@ module RDX
1139
1140
  # * we don't care about the result obtained, but we have anyhow to evaluate the code;
1140
1141
  # * we do care about it, but other conventions aren't suitable in these circumstances.
1141
1142
  #
1142
- # The latter situation is more intresting.
1143
+ # The latter situation is more interesting.
1143
1144
  # Consider the following (from <tt>time.c</tt>):
1144
1145
  #
1145
1146
  # t = Time.now # 2007-11-19 08:18:31 -0600
@@ -19,11 +19,11 @@ module RDX
19
19
  #
20
20
  # There are many directives, subdivided for functionality:
21
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;
22
+ # * Input/Output/Error: the most useful are ::stdout and ::write_file;
23
+ # * Context change: they can change the binding (::new_binding, ::toplevel), current directory (::in_tmpdir),
24
+ # execution in time (::setup and ::teardown), simulate a ::bash session;
25
25
  # * Assertion customization: to mention ::float
26
- # * Miscellanous: insert comments, ::disable_warnings, ...
26
+ # * Miscellaneous: insert comments (::#), ::disable_warnings, ...
27
27
  # All the directives already defined are documented as Directive's class methods
28
28
  # (even if technically they aren't) in the relative sections.
29
29
  #
@@ -57,7 +57,7 @@ module RDX
57
57
  # For this reason the class methods are used to define the behaviour of the directive
58
58
  # (the most important is ::define), while the instance ones allow to query
59
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).
60
+ # and retrieve neighbour sections in the comment (the most used is #next_example).
61
61
  #
62
62
  class Directive < CodeObject
63
63
 
@@ -146,18 +146,27 @@ module RDX
146
146
  # without changing the block's context.
147
147
  #
148
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
149
+ # its status and retrieve neighbour sections. At this point you will need the API
150
150
  # provided by the CodeObject class and its descendants - mainly the Example one -
151
151
  # to shape their behaviour to your needs.
152
+ #
153
+ # *Note*: explicit and implicit directives won't conflict on the same example
154
+ # thanks to #hide_implicit_similar.
152
155
  #
153
156
  def define &execution
154
157
  if execution.arity == 0
155
158
  define_method :execute do
156
- trace_execution{ instance_eval(&execution) }
159
+ trace_execution do
160
+ hide_implicit_similar unless implicit?
161
+ instance_eval(&execution)
162
+ end
157
163
  end
158
164
  else
159
165
  define_method :execute do
160
- trace_execution{ execution.call(self) }
166
+ trace_execution do
167
+ hide_implicit_similar unless implicit?
168
+ execution.call(self)
169
+ end
161
170
  end
162
171
  end
163
172
  end
@@ -165,7 +174,7 @@ module RDX
165
174
  #
166
175
  # :category: Internal
167
176
  #
168
- # Registers the given block as a configuration for the implicit recognization:
177
+ # Registers the given block as a configuration for the implicit recognition:
169
178
  # this centralizes the building procedure, allowing the user to supply
170
179
  # (through ::use_implicit_with) only the desired parameters - often some particular
171
180
  # pattern or word. The block should call ::find_in_text or ::find_in_example.
@@ -204,7 +213,7 @@ module RDX
204
213
  end
205
214
 
206
215
  #
207
- # Restores the default configuration for the implicit recognization of this
216
+ # Restores the default configuration for the implicit recognition of this
208
217
  # directive. First calls ::clear_implicit_patterns, then
209
218
  # calls the block supplied to ::configure_implicit without parameters
210
219
  # (so its arity should allow this).
@@ -403,6 +412,20 @@ module RDX
403
412
  in_sections.find{ |sec| sec.line_range.cover?(self.line_no) }
404
413
  end
405
414
 
415
+ #
416
+ # :section: Internal
417
+ #
418
+
419
+ #
420
+ # This method will be called whenever an explicit directive is used.
421
+ # Implicit ones of the same type are disabled from the #next_example,
422
+ # so that they won't interfere.
423
+ #
424
+ def hide_implicit_similar # :doc:
425
+ comment.disable_implicit_directives_in next_examples.first, self.name
426
+ end
427
+ private :hide_implicit_similar
428
+
406
429
  #
407
430
  # :section: API
408
431
  #
@@ -433,7 +456,7 @@ module RDX
433
456
 
434
457
  def section_index # :nodoc:
435
458
  @section_index ||= comment.sections.find_index{ |sec| sec.line_no >= self.line_no } ||
436
- comment.sections.size-1
459
+ comment.sections.size
437
460
  end
438
461
  private :section_index
439
462
 
@@ -606,7 +629,7 @@ module RDX
606
629
  #
607
630
  # Note::
608
631
  # 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.
632
+ # with the purpose of executing additional examples other than the ones in the documentation output.
610
633
  #
611
634
  define_directive 'on' do
612
635
  next_examples{ |ex| ex.activate true }
@@ -621,7 +644,7 @@ module RDX
621
644
  # Turns off execution of examples (see the ::on directive for an example).
622
645
  #
623
646
  # Note::
624
- # If the parameter is (or starts with) a hypen, only the immediately following
647
+ # If the parameter is (or starts with) a hyphen, only the immediately following
625
648
  # example is deactivated; the execution will continue regularly,
626
649
  # according to the effect of other directives after it.
627
650
  #
@@ -736,7 +759,7 @@ module RDX
736
759
  # is_slow
737
760
  #
738
761
  # Run the next example only when necessary (see Example#lazy).
739
- # This directive is often used when the example shows performance penalities.
762
+ # This directive is often used when the example shows performance penalties.
740
763
  #
741
764
  # An example (from <tt>re.rdoc</tt>):
742
765
  # :rdx: off
@@ -766,7 +789,7 @@ module RDX
766
789
  # stdout
767
790
  # output
768
791
  #
769
- # Interprets the next example as the expected output of the previuos one
792
+ # Interprets the next example as the expected output of the previous one
770
793
  # (see Example#produces_on_stdout).
771
794
  #
772
795
  # Implicit detection::
@@ -784,7 +807,7 @@ module RDX
784
807
  #
785
808
  # Note::
786
809
  # 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)
810
+ # (and it's probably described in a text section).
788
811
  #
789
812
  define_directive 'stdout' do |dir|
790
813
  dir.define do
@@ -804,7 +827,7 @@ module RDX
804
827
  # :call-seq:
805
828
  # indicative_output
806
829
  #
807
- # Ignores the next example and the output produced by the previuos one.
830
+ # Ignores the next example and the output produced by the previous one.
808
831
  #
809
832
  # An example:
810
833
  # #
@@ -832,7 +855,7 @@ module RDX
832
855
  # :call-seq:
833
856
  # stderr
834
857
  #
835
- # Interprets the next example as the expected output of the previuos one
858
+ # Interprets the next example as the expected output of the previous one
836
859
  # (see Example#produces_on_stderr).
837
860
  #
838
861
  # An example (from <tt>enumerator.c</tt>):
@@ -984,7 +1007,7 @@ module RDX
984
1007
  # # f.puts 'line 1'
985
1008
  # # f.puts 'line 2'
986
1009
  # # f.puts 'line 1000' # 1,2,3 was boring...
987
- # # Now the file +out+ will contian:
1010
+ # # Now the file +out+ will contain:
988
1011
  # # :rdx: check_file out
989
1012
  # # line 1
990
1013
  # # line 2
@@ -1069,7 +1092,7 @@ module RDX
1069
1092
  # rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
1070
1093
  #
1071
1094
  # Note::
1072
- # It's user's responsibilty to clean up all the necessary
1095
+ # It's user's responsibility to clean up all the necessary
1073
1096
  # (usually using private rdx sections).
1074
1097
  #
1075
1098
  define_directive 'toplevel' do
@@ -1205,14 +1228,14 @@ module RDX
1205
1228
  ##
1206
1229
  # :singleton-method:
1207
1230
  # :call-seq:
1208
- # bash default_prompt=/\$\s/, continuation_prompt=/>\s/
1231
+ # bash default_prompt=/\$\s/, continuation_prompt=/>\s/, output_prompt=""
1209
1232
  #
1210
1233
  # Interprets the next example as a bash command-line session
1211
1234
  # (see Example#on_bash_mode).
1212
1235
  #
1213
1236
  # Implicit detection::
1214
1237
  # 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).
1238
+ # isn't syntactically correct in Ruby, so we can safely avoid ambiguous situations).
1216
1239
  #
1217
1240
  # An example (from <tt>optparse.rb</tt>):
1218
1241
  # # [...]
@@ -1227,8 +1250,8 @@ module RDX
1227
1250
  # class OptionParser; end
1228
1251
  #
1229
1252
  # 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:
1253
+ # You can use the explicit directive to change values for all these prompts
1254
+ # (or supply +nil+ if you want to keep the default).
1232
1255
  # :rdx: off
1233
1256
  # # This is the result in the command line (<tt>" </tt> is the continuation prompt):
1234
1257
  # # :rdx: bash nil, '" '
@@ -1241,11 +1264,13 @@ module RDX
1241
1264
  define_directive 'bash' do |dir|
1242
1265
  dir.metadata[:default_prompt] = /\$\s/
1243
1266
  dir.metadata[:continuation_prompt] = />\s/
1267
+ dir.metadata[:output_prompt] = ''
1244
1268
  dir.define do
1245
- default_prompt,continuation_prompt = param && eval("[#{param}]")
1269
+ default_prompt,continuation_prompt,output_prompt = param && eval("[#{param}]")
1246
1270
  default_prompt ||= metadata[:default_prompt]
1247
1271
  continuation_prompt ||= metadata[:continuation_prompt]
1248
- next_example.on_bash_mode default_prompt, continuation_prompt
1272
+ output_prompt ||= metadata[:output_prompt]
1273
+ next_example.on_bash_mode default_prompt, continuation_prompt, output_prompt
1249
1274
  end
1250
1275
  dir.configure_implicit do |prompt=dir.metadata[:default_prompt]|
1251
1276
  prompt = prompt.is_a?(Regexp) ? prompt.to_s : Regexp.escape(prompt.to_str)
@@ -54,7 +54,7 @@ module RDX
54
54
  not @active.nil?
55
55
  end
56
56
 
57
- # Will this example be runned?
57
+ # Will this example be run?
58
58
  def active?
59
59
  @active
60
60
  end
@@ -63,6 +63,67 @@ module RDX
63
63
  # :section: API
64
64
  #
65
65
 
66
+ #
67
+ # :call-seq:
68
+ # enhance_normalization{ |exp,act| ... -> [new_exp,new_act] }
69
+ #
70
+ # Prepends the block processor (which receives and should return _exp_ and _act_)
71
+ # to the actual #normalize_values method, allowing to enhance its functionality.
72
+ #
73
+ #-- rdx
74
+ # an_example = RDX::Example.allocate
75
+ # def an_example.normalize_values(exp,act); p [exp,act]; end
76
+ #++
77
+ # an_example.enhance_normalization do |exp,act| # <- receives the values to be compared
78
+ # # -> Add your customization here! <-
79
+ # # say that don't want to see differences in floats:
80
+ # new_exp = new_act = 0.0 if exp.is_a?(Float) && act.is_a?(Float)
81
+ # [new_exp, new_act] # <- return them (from the block) in a two-element array
82
+ # # After this block the regular normalize_values is called
83
+ # end
84
+ #-- rdx
85
+ # :rdx:
86
+ # an_example.normalize_values(1.99,2.0) #=> [0.0, 0.0]
87
+ # :rdx: output [0.0, 0.0]
88
+ #++
89
+ #
90
+ def enhance_normalization &enhancement
91
+ orig_level = method(:normalize_values)
92
+ define_singleton_method :normalize_values do |exp,act,&normalizing_proc|
93
+ exp,act = enhancement.call(exp,act).to_ary
94
+ orig_level.call exp, act, &normalizing_proc
95
+ end
96
+ end
97
+
98
+ #
99
+ # :call-seq:
100
+ # enhance_running{ |orig_run| ... orig_run.call ... }
101
+ #
102
+ # Replaces the #run method with the given block.
103
+ # This receives the original +Method+ as a block parameter,
104
+ # allowing to call it somewhere (although this is not necessary).
105
+ #
106
+ #-- rdx
107
+ # an_example = RDX::Example.allocate
108
+ # def an_example.run; puts "out"; end
109
+ #++
110
+ # an_example.enhance_running do |orig_run| # <- receives the original method
111
+ # # -> This block will become the new run method <-
112
+ # # say that we want to discard $stdout and $stderr:
113
+ # RDX::Util.change_ostreams nil, nil do # check out the documentation if you want...
114
+ # orig_run.call # <- the original method gets wrapped in this block
115
+ # end
116
+ # end
117
+ #-- rdx
118
+ # an_example.run # >> ""
119
+ #
120
+ def enhance_running &enhancement #! rename
121
+ orig_run = method(:run)
122
+ define_singleton_method :run do
123
+ enhancement.call(orig_run)
124
+ end
125
+ end
126
+
66
127
  # Returns +true+. This method should be used instead of _section_<tt>.is_a?(Example)</tt>.
67
128
  def example?
68
129
  true
@@ -116,36 +177,6 @@ module RDX
116
177
  super msg, type, comment.location(l_no)
117
178
  end
118
179
 
119
- #
120
- # Marks this example as deliberately buggy. This means that:
121
- # * failures and errors are ordinary: they are not reported;
122
- # * successes are unexpected: a warning of type +bug+ will
123
- # be reported along with the success.
124
- #
125
- def is_buggy
126
- activate
127
- dont_register = lambda{ |*| }
128
- define_singleton_method :build_children do
129
- super()
130
- define_singleton_method :register_failure, dont_register
131
- define_singleton_method :register_error, dont_register
132
- define_singleton_method :register_success do |*args|
133
- warn 'Bug not detected: the assertion passes', :bug
134
- super(*args)
135
- end
136
- statements.each do |stmnt|
137
- stmnt.define_singleton_method :register_error, dont_register
138
- end
139
- statements.flat_map(&:children).each do |expct|
140
- expct.define_singleton_method :register_failure, dont_register
141
- expct.define_singleton_method :register_success do |*args|
142
- warn 'Bug not detected: the assertion passes', :bug if assertion?
143
- super(*args)
144
- end
145
- end
146
- end
147
- end
148
-
149
180
  # Activates this example and calls +super+.
150
181
  def run_in_tmpdir
151
182
  activate
@@ -188,15 +219,14 @@ module RDX
188
219
  output.deactivate!
189
220
  output = output.text
190
221
  end
191
- orig_level = method(:normalize_values)
192
- define_singleton_method :normalize_values do |exp,act,&normalize|
222
+ enhance_normalization do |exp,act|
193
223
  if act.is_a?(String)
194
224
  act = act.dup
195
225
  act.gsub! /^#{Regexp.escape file_name}:(\d+): (?=warning: )/ do |matched|
196
226
  line_range.cover?($1.to_i) ? '' : matched
197
227
  end
198
228
  end
199
- orig_level.call(exp,act,&normalize)
229
+ [exp,act]
200
230
  end
201
231
  set_output nil, output, l_no
202
232
  end
@@ -210,11 +240,10 @@ module RDX
210
240
  #
211
241
  def set_output stdout, stderr, l_no=nil
212
242
  l_no ||= relative_line_no
213
- orig_run = method(:run)
214
243
  normalize = Text.method(:normalize_output).to_proc
215
- define_singleton_method :run do
244
+ enhance_running do |orig_running|
216
245
  trace_assertion :multiline_output_literal, comment.location(l_no) do
217
- assert_output_but(normalize,stdout,stderr){ orig_run.call }
246
+ assert_output_but normalize, stdout, stderr, &orig_running
218
247
  end
219
248
  end
220
249
  return self
@@ -230,9 +259,8 @@ module RDX
230
259
  input.deactivate!
231
260
  input = input.text
232
261
  end
233
- orig_run = method(:run)
234
- define_singleton_method :run do
235
- RDX::Util.change_stdin(input){ orig_run.call }
262
+ enhance_running do |orig_running|
263
+ RDX::Util.change_stdin input, &orig_running
236
264
  end
237
265
  return self
238
266
  end
@@ -262,13 +290,10 @@ module RDX
262
290
  end
263
291
  cls = toplevel_scope.const_get(cls) if cls.is_a?(String)
264
292
  l_no ||= relative_line_no
265
- orig_run = method(:run)
266
293
  normalize = Text.method(:normalize_exception_message).to_proc
267
- define_singleton_method :run do
294
+ enhance_running do |orig_running|
268
295
  trace_assertion :error_literal, comment.location(l_no) do
269
- assert_msg_raised_but normalize, msg, false, *cls do
270
- orig_run.call
271
- end
296
+ assert_msg_raised_but normalize, msg, false, *cls, &orig_running
272
297
  end
273
298
  end
274
299
  return self
@@ -309,7 +334,7 @@ module RDX
309
334
  return self
310
335
  end
311
336
 
312
- # Run this exemple in a full independent way from the parent comment.
337
+ # Run this example in a full independent way from the parent comment.
313
338
  def separate_from_comment
314
339
  deactivate! # will be deleted for sure from the comment
315
340
  build
@@ -337,15 +362,15 @@ module RDX
337
362
  #
338
363
  # Since this example is not executed #check_convention_patterns is called.
339
364
  #
340
- def write_to_file fname, l_no=relative_line_no
365
+ def write_to_file fname, l_no=nil, perform_convention_check=true
341
366
  activate
342
367
  fname = Pathname(fname)
343
368
  raise 'Absolute location not allowed' if fname.absolute?
344
369
  l_no ||= relative_line_no
345
- check_convention_patterns 'example not executable'
370
+ check_convention_patterns 'example not executable' if perform_convention_check
346
371
  comment.run_in_tmpdir
347
372
  skip_building
348
- define_singleton_method :run do
373
+ enhance_running do
349
374
  trace_execution comment.location(l_no) do
350
375
  content = self.text.dup
351
376
  content = yield(content) if block_given?
@@ -373,7 +398,7 @@ module RDX
373
398
  comment.run_in_tmpdir
374
399
  normalize = Text.method(:normalize_output).to_proc
375
400
  skip_building
376
- define_singleton_method :run do
401
+ enhance_running do
377
402
  trace_assertion :file_content, comment.location(l_no) do
378
403
  act = fname.read
379
404
  exp = self.text
@@ -401,13 +426,12 @@ module RDX
401
426
  super(exp,act,*args,&blk)
402
427
  end
403
428
  end
404
- orig_level = method :normalize_values
405
- define_singleton_method :normalize_values do |exp,act,&normalize|
429
+ enhance_normalization do |exp,act|
406
430
  if exp.is_a?(String) && act.is_a?(String)
407
431
  exp = Text.normalize_floats(exp,digits)
408
432
  act = Text.normalize_floats(act,digits)
409
433
  end
410
- orig_level.call(exp,act,&normalize)
434
+ [exp,act]
411
435
  end
412
436
  end
413
437
 
@@ -419,33 +443,33 @@ module RDX
419
443
  #
420
444
  def on_indicative_numbers_mode
421
445
  activate
422
- orig_level = method :normalize_values
423
- define_singleton_method :normalize_values do |exp,act,&normalize|
446
+ enhance_normalization do |exp,act|
424
447
  if exp.is_a?(Numeric) && act.is_a?(Numeric)
425
448
  exp = act = 0
426
449
  elsif exp.is_a?(String) && act.is_a?(String)
427
450
  exp = Text.generalize_numerics(exp)
428
451
  act = Text.generalize_numerics(act)
429
452
  end
430
- orig_level.call(exp,act,&normalize)
453
+ [exp,act]
431
454
  end
432
455
  end
433
456
 
434
457
  class Bash # :nodoc:
435
458
  require 'open3'
436
459
  class << self
437
- # The system +bash+ command used by Directive::bash.
460
+ # The +bash+ system command used by Directive::bash.
438
461
  attr_accessor :bash
439
462
  end
440
463
  self.bash = 'bash'
441
- attr_reader :example, :default_prompt, :continuation_prompt
442
- private :example, :default_prompt, :continuation_prompt
443
- def initialize example, default_prompt, continuation_prompt
444
- @example = example
445
- @default_prompt = build_prompt default_prompt
446
- @continuation_prompt = build_prompt continuation_prompt
464
+ attr_reader :default_prompt, :continuation_prompt, :output_prompt
465
+ private :default_prompt, :continuation_prompt
466
+ def initialize default_prompt, continuation_prompt, output_prompt
467
+ @default_prompt = build_prompt(default_prompt)
468
+ @continuation_prompt = build_prompt(continuation_prompt)
469
+ @output_prompt = build_prompt(output_prompt.to_str)
447
470
  end
448
471
  def parse code
472
+ code = Text.strip_newlines(code,false)
449
473
  result = [] # [input,input_l_no,output,output_l_no]
450
474
  prev_status = nil
451
475
  code.each_line.with_index do |line,l_no|
@@ -465,6 +489,8 @@ module RDX
465
489
  raise ParseError.new "Default prompt `#{default_prompt}' not detected", l_no
466
490
  end
467
491
  current_elem[2] << line
492
+ else
493
+ raise ParseError.new "Unknown line `#{line}': no prompt detected", l_no
468
494
  end
469
495
  prev_status = status
470
496
  end
@@ -500,7 +526,7 @@ module RDX
500
526
  :start_input
501
527
  elsif line.slice!(continuation_prompt)
502
528
  :cont_input
503
- else
529
+ elsif line.slice!(output_prompt)
504
530
  :output
505
531
  end
506
532
  end
@@ -513,19 +539,19 @@ module RDX
513
539
  # The execution is interpreted according to the beginning of each line:
514
540
  # * _default_prompt_ starts a new bash command;
515
541
  # * _continuation_prompt_ continues the current command;
516
- # * otherwise specifies the output of the current command
542
+ # * _output_prompt_ specifies the output of the current command
517
543
  # (differences are reduced through Text#normalize_output).
518
544
  #
519
- def on_bash_mode default_prompt, continuation_prompt
545
+ def on_bash_mode default_prompt, continuation_prompt, output_prompt
520
546
  activate
521
547
  comment.run_in_tmpdir
522
- bash = Bash.new self, default_prompt, continuation_prompt
548
+ bash = Bash.new default_prompt, continuation_prompt, output_prompt
523
549
  io = nil
524
550
  define_singleton_method :build_self do
525
551
  io = bash.parse text
526
552
  end
527
553
  normalize = Text.method(:normalize_output).to_proc
528
- define_singleton_method :run do
554
+ enhance_running do
529
555
  return unless io
530
556
  io.each do |input,input_l_no,exp_out,out_l_no|
531
557
  begin