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.
- checksums.yaml +4 -4
- data/README +186 -12
- data/TODO +18 -0
- data/examples/minimal/.rdx +1 -0
- data/examples/minimal/rakefile +5 -2
- data/examples/ruby-2.0.0-p0/install/core/BUGS +70 -0
- data/examples/ruby-2.0.0-p0/install/core/HALL_OF_SHAME +53 -0
- data/examples/ruby-2.0.0-p0/install/core/README +14 -4
- data/examples/ruby-2.0.0-p0/install/core/Rakefile +9 -4
- data/examples/ruby-2.0.0-p0/install/core/TODO +5 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/array.c.diff +8 -7
- data/examples/ruby-2.0.0-p0/install/core/diffs/encoding.c.diff +1 -1
- data/examples/ruby-2.0.0-p0/install/core/diffs/enumerator.c.diff +4 -12
- data/examples/ruby-2.0.0-p0/install/core/diffs/eval.c.diff +3 -5
- data/examples/ruby-2.0.0-p0/install/core/diffs/file.c.diff +2 -2
- data/examples/ruby-2.0.0-p0/install/core/diffs/gc.c.diff +5 -4
- data/examples/ruby-2.0.0-p0/install/core/diffs/hash.c.diff +4 -3
- data/examples/ruby-2.0.0-p0/install/core/diffs/object.c.diff +5 -4
- data/examples/ruby-2.0.0-p0/install/core/diffs/proc.c.diff +7 -6
- data/examples/ruby-2.0.0-p0/install/core/diffs/random.c.diff +3 -3
- data/examples/ruby-2.0.0-p0/install/core/diffs/rational.c.diff +21 -18
- data/examples/ruby-2.0.0-p0/install/core/diffs/ruby.c.diff +1 -1
- data/examples/ruby-2.0.0-p0/install/stdlib/DOCUMENTATION +22 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/README +12 -4
- data/examples/ruby-2.0.0-p0/install/stdlib/Rakefile +10 -5
- data/examples/ruby-2.0.0-p0/install/stdlib/TODO +6 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/optparse.rb.diff +31 -11
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/uri/common.rb.diff +8 -7
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/weakref.rb.diff +2 -2
- data/lib/rdx.rb +42 -92
- data/lib/rdx/assertions.rb +8 -9
- data/lib/rdx/binding.rb +2 -2
- data/lib/rdx/comment.rb +7 -5
- data/lib/rdx/convention.rb +10 -9
- data/lib/rdx/directive.rb +51 -26
- data/lib/rdx/example.rb +94 -68
- data/lib/rdx/generator.rb +1 -1
- data/lib/rdx/generator/rdoc.rb +5 -6
- data/lib/rdx/options.rb +7 -3
- data/lib/rdx/reporter.rb +17 -0
- data/lib/rdx/ruby_lex.rb +3 -3
- data/lib/rdx/runner.rb +1 -1
- data/lib/rdx/statement.rb +1 -1
- data/lib/rdx/store.rb +1 -1
- data/lib/rdx/task.rb +1 -1
- data/lib/rdx/text.rb +1 -1
- data/lib/rdx/version.rb +1 -1
- data/rakefile +43 -14
- metadata +23 -3
data/lib/rdx/assertions.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
|
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
|
-
#
|
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
|
377
|
+
# This method can be overridden to modify the normalization.
|
379
378
|
#
|
380
379
|
def normalize_values exp, act, &normalize
|
381
380
|
if normalize
|
data/lib/rdx/binding.rb
CHANGED
@@ -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
|
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
|
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
|
#
|
data/lib/rdx/comment.rb
CHANGED
@@ -67,13 +67,17 @@ module RDX
|
|
67
67
|
examples.select(&:active?)
|
68
68
|
end
|
69
69
|
|
70
|
-
|
71
|
-
|
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
|
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).
|
data/lib/rdx/convention.rb
CHANGED
@@ -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
|
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
|
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
|
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 #
|
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
|
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
|
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
|
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
|
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
|
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
|
data/lib/rdx/directive.rb
CHANGED
@@ -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
|
23
|
-
# * Context change: they can change the binding, current directory,
|
24
|
-
# (
|
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
|
-
# *
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
#
|
1231
|
-
#
|
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
|
-
|
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)
|
data/lib/rdx/example.rb
CHANGED
@@ -54,7 +54,7 @@ module RDX
|
|
54
54
|
not @active.nil?
|
55
55
|
end
|
56
56
|
|
57
|
-
# Will this example be
|
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
|
-
|
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
|
-
|
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
|
-
|
244
|
+
enhance_running do |orig_running|
|
216
245
|
trace_assertion :multiline_output_literal, comment.location(l_no) do
|
217
|
-
assert_output_but
|
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
|
-
|
234
|
-
|
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
|
-
|
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
|
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
|
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=
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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 :
|
442
|
-
private :
|
443
|
-
def initialize
|
444
|
-
@
|
445
|
-
@
|
446
|
-
@
|
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
|
-
|
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
|
-
# *
|
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
|
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
|
-
|
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
|