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.
- checksums.yaml +7 -0
- data/.rdx +20 -0
- data/README +19 -0
- data/bin/rdx +7 -0
- data/examples/minimal/.rdx +8 -0
- data/examples/minimal/README +10 -0
- data/examples/minimal/lib/other_conventions.rb +64 -0
- data/examples/minimal/lib/the_basics.rb +94 -0
- data/examples/minimal/lib/using_directives.rb +66 -0
- data/examples/minimal/rakefile +27 -0
- data/examples/ruby-2.0.0-p0/README +7 -0
- data/examples/ruby-2.0.0-p0/install/core/.rdx +6 -0
- data/examples/ruby-2.0.0-p0/install/core/README +19 -0
- data/examples/ruby-2.0.0-p0/install/core/Rakefile +61 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/array.c.diff +166 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/bignum.c.diff +11 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/class.c.diff +36 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/compar.c.diff +11 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/complex.c.diff +301 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/cont.c.diff +65 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/dir.c.diff +147 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/re.rdoc.diff +328 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/security.rdoc.diff +8 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/standard_library.rdoc.diff +0 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax.rdoc.diff +0 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/assignment.rdoc.diff +160 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/calling_methods.rdoc.diff +130 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/control_expressions.rdoc.diff +254 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/exceptions.rdoc.diff +0 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/literals.rdoc.diff +54 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/methods.rdoc.diff +157 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/miscellaneous.rdoc.diff +91 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/modules_and_classes.rdoc.diff +161 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/precedence.rdoc.diff +8 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/refinements.rdoc.diff +146 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/encoding.c.diff +276 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/enum.c.diff +281 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/enumerator.c.diff +479 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/error.c.diff +143 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/eval.c.diff +47 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/eval_jump.c.diff +23 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/file.c.diff +752 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/gc.c.diff +195 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/hash.c.diff +84 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/iseq.c.diff +354 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/load.c.diff +53 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/marshal.c.diff +98 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/math.c.diff +110 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/numeric.c.diff +103 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/object.c.diff +295 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/pack.c.diff +18 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/parse.y.diff +23 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/proc.c.diff +155 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/random.c.diff +126 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/range.c.diff +49 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/rational.c.diff +312 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/re.c.diff +207 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/ruby.c.diff +21 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/signal.c.diff +67 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/sprintf.c.diff +29 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/string.c.diff +73 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/struct.c.diff +20 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/time.c.diff +691 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/transcode.c.diff +435 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/variable.c.diff +62 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/vm_backtrace.c.diff +164 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/vm_eval.c.diff +99 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/vm_method.c.diff +17 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/vm_trace.c.diff +393 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/.rdx +6 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/README +19 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/Rakefile +53 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/abbrev.rb.diff +77 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/base64.rb.diff +42 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/benchmark.rb.diff +144 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/cmath.rb.diff +52 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/forwardable.rb.diff +150 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/mathn.rb.diff +58 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/matrix.rb.diff +657 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/observer.rb.diff +31 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/optparse.rb.diff +147 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/ostruct.rb.diff +78 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/prime.rb.diff +52 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/pstore.rb.diff +110 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/scanf.rb.diff +100 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/securerandom.rb.diff +144 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/set.rb.diff +637 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/shellwords.rb.diff +66 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/singleton.rb.diff +37 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/tempfile.rb.diff +104 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/thread.rb.diff +38 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/time.rb.diff +140 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/tmpdir.rb.diff +52 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/uri.rb.diff +39 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/uri/common.rb.diff +237 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/weakref.rb.diff +36 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/yaml/store.rb.diff +27 -0
- data/examples/ruby-2.0.0-p0/rakefile +165 -0
- data/lib/rdx.rb +331 -0
- data/lib/rdx/assertions.rb +484 -0
- data/lib/rdx/binding.rb +151 -0
- data/lib/rdx/code_object.rb +598 -0
- data/lib/rdx/comment.rb +338 -0
- data/lib/rdx/convention.rb +1174 -0
- data/lib/rdx/directive.rb +1432 -0
- data/lib/rdx/example.rb +679 -0
- data/lib/rdx/generator.rb +112 -0
- data/lib/rdx/generator/rdoc.rb +1006 -0
- data/lib/rdx/options.rb +359 -0
- data/lib/rdx/plain_text.rb +65 -0
- data/lib/rdx/reporter.rb +421 -0
- data/lib/rdx/ruby_lex.rb +324 -0
- data/lib/rdx/runner.rb +309 -0
- data/lib/rdx/source_file.rb +94 -0
- data/lib/rdx/specification.rb +194 -0
- data/lib/rdx/statement.rb +248 -0
- data/lib/rdx/store.rb +119 -0
- data/lib/rdx/task.rb +361 -0
- data/lib/rdx/text.rb +688 -0
- data/lib/rdx/version.rb +15 -0
- data/rakefile +64 -0
- metadata +203 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
|
2
|
+
module RDX
|
3
|
+
|
4
|
+
#
|
5
|
+
# Represents a parsed source file.
|
6
|
+
#
|
7
|
+
class SourceFile < CodeObject
|
8
|
+
|
9
|
+
# Absolute path for file
|
10
|
+
attr_reader :absolute_path
|
11
|
+
alias file_name absolute_path
|
12
|
+
|
13
|
+
# Conventionally the line number is <tt>1</tt>.
|
14
|
+
def line_no
|
15
|
+
1
|
16
|
+
end
|
17
|
+
|
18
|
+
# The +Array+ of contained Comments.
|
19
|
+
attr_reader :comments
|
20
|
+
alias children comments
|
21
|
+
|
22
|
+
# :stopdoc:
|
23
|
+
|
24
|
+
attr_reader :reportables
|
25
|
+
|
26
|
+
def initialize(absolute_path)
|
27
|
+
super(nil)
|
28
|
+
@absolute_path = absolute_path
|
29
|
+
@comments = []
|
30
|
+
@reportables = nil
|
31
|
+
@reportables_hash = Hash.new{ |hash,cmt| hash[cmt] = [] } # comment => reportables_ary
|
32
|
+
end
|
33
|
+
|
34
|
+
def <=> other
|
35
|
+
return nil unless self.class == other.class
|
36
|
+
self.absolute_path <=> other.absolute_path
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_comment comment
|
40
|
+
@comments << comment
|
41
|
+
return self
|
42
|
+
end
|
43
|
+
def remove_comment comment
|
44
|
+
@comments.delete comment
|
45
|
+
return self
|
46
|
+
end
|
47
|
+
|
48
|
+
def register reportable, code_object
|
49
|
+
@reportables_hash[code_object.comment] << reportable
|
50
|
+
end
|
51
|
+
|
52
|
+
def collect_reportables
|
53
|
+
return @reportables if @reportables
|
54
|
+
@reportables = []
|
55
|
+
@reportables_hash.to_a.sort_by(&:first).each do |comment,reportables|
|
56
|
+
@reportables.concat reportables.sort_by(&:line_no)
|
57
|
+
end
|
58
|
+
@reportables_hash = nil
|
59
|
+
@reportables
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def build_self
|
65
|
+
uniq_comments
|
66
|
+
end
|
67
|
+
|
68
|
+
# Remove RDX comments pointing at the same location
|
69
|
+
# (for example RDoc creates more comments for ruby methods pointing at the same c-function)
|
70
|
+
# TODO: move to generator/rdoc
|
71
|
+
def uniq_comments
|
72
|
+
result = []
|
73
|
+
map = @comments.group_by(&:line_no)
|
74
|
+
map.delete(nil) # line number not set
|
75
|
+
map.each_value do |cmts|
|
76
|
+
if cmts.size == 1 # no conflict
|
77
|
+
result << cmts.first
|
78
|
+
else
|
79
|
+
doc,ndoc = cmts.partition(&:documenting)
|
80
|
+
if doc.empty?
|
81
|
+
result << ndoc.first
|
82
|
+
elsif ndoc.empty? || doc.size==1
|
83
|
+
result << doc.first
|
84
|
+
else # ambiguous situation
|
85
|
+
result << doc.first
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
@comments.replace result
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
|
2
|
+
module RDX
|
3
|
+
|
4
|
+
#
|
5
|
+
# Allows you to specify the conventions and directives used in your files.
|
6
|
+
#
|
7
|
+
# If the root directory of your project has an <tt>.rdx</tt> file,
|
8
|
+
# it's evalued as ruby code: this should return a Specification.
|
9
|
+
# Otherwise (or if there isn't such file) the ::default will be used and
|
10
|
+
# this class falls in the background.
|
11
|
+
#
|
12
|
+
# In that file you should indeed use <tt>RDX::Specification.new</tt> passing
|
13
|
+
# a block, that is allowed to modify its state (see ::new).
|
14
|
+
#
|
15
|
+
class Specification
|
16
|
+
|
17
|
+
include Convention::SpecificationHelper
|
18
|
+
|
19
|
+
include Directive::SpecificationHelper
|
20
|
+
|
21
|
+
#
|
22
|
+
# :category: Internal
|
23
|
+
#
|
24
|
+
# Loads the Specification from the given _file_ name.
|
25
|
+
# This is by default the <tt>.rdx</tt> file at the top level in the project directory.
|
26
|
+
#
|
27
|
+
def self.load file
|
28
|
+
file &&= file.dup.untaint
|
29
|
+
if file && File.file?(file)
|
30
|
+
opts = Object.const_defined?(:Encoding) ? { :mode => 'r:UTF-8:-' } : {}
|
31
|
+
code = File.read(file,opts).untaint
|
32
|
+
begin
|
33
|
+
spec = eval code, binding, file
|
34
|
+
if Specification === spec
|
35
|
+
spec.file = file.to_s
|
36
|
+
return spec
|
37
|
+
end
|
38
|
+
warn "[#{file}] isn't a #{self} (#{spec.class} instead).\nUsing default settings."
|
39
|
+
rescue SignalException, SystemExit
|
40
|
+
raise
|
41
|
+
rescue SyntaxError, Exception => e
|
42
|
+
warn "Invalid #{self} in [#{file}]: #{e}\nUsing default settings."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# :category: Internal
|
50
|
+
#
|
51
|
+
# Returns a new specification containing only the default initialization.
|
52
|
+
#
|
53
|
+
def self.default
|
54
|
+
new()
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# :call-seq:
|
59
|
+
# new{ || ... }
|
60
|
+
# new{ |spec| ... }
|
61
|
+
#
|
62
|
+
# Creates a new Specification initialized with #default_conventions
|
63
|
+
# and #default_directives.
|
64
|
+
#
|
65
|
+
# If the block takes no argument it will be executed in the context
|
66
|
+
# of the specification instance, otherwise this will simply be yielded.
|
67
|
+
#
|
68
|
+
# The instance methods of the Specification allow its customization
|
69
|
+
# (but only during the execution of the block).
|
70
|
+
# These facilities are provided by the included modules
|
71
|
+
# Convention::SpecificationHelper (with a few enhancements) and
|
72
|
+
# Directive::SpecificationHelper.
|
73
|
+
#
|
74
|
+
def initialize(&blk)
|
75
|
+
@file = nil
|
76
|
+
@known_conventions = Convention.list
|
77
|
+
@used_conventions = []
|
78
|
+
default_conventions
|
79
|
+
default_directives
|
80
|
+
if blk
|
81
|
+
if blk.arity == 0
|
82
|
+
instance_eval(&blk)
|
83
|
+
else
|
84
|
+
blk.call(self)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
finalize
|
88
|
+
end
|
89
|
+
|
90
|
+
def conventions # :nodoc:
|
91
|
+
@known_conventions
|
92
|
+
end
|
93
|
+
private :conventions
|
94
|
+
|
95
|
+
#
|
96
|
+
# :category: Internal
|
97
|
+
#
|
98
|
+
# Sets up the list of the default conventions.
|
99
|
+
# It's as if the content of this method would be
|
100
|
+
# at the beginning of each specification.
|
101
|
+
#
|
102
|
+
def default_conventions # :doc:
|
103
|
+
use_convention :eval
|
104
|
+
use_convention :result_eval
|
105
|
+
use_convention :result_same
|
106
|
+
use_convention :result_numeric
|
107
|
+
use_convention :result_string
|
108
|
+
use_convention :result_instance_of
|
109
|
+
use_convention :output_literal
|
110
|
+
use_convention :error_literal
|
111
|
+
use_convention :throws
|
112
|
+
end
|
113
|
+
private :default_conventions
|
114
|
+
|
115
|
+
#
|
116
|
+
# :category: Internal
|
117
|
+
#
|
118
|
+
# Sets up the list of the default directives.
|
119
|
+
# All the directives defined are automatically used.
|
120
|
+
#
|
121
|
+
def default_directives # :doc:
|
122
|
+
@directives = Directive.known
|
123
|
+
end
|
124
|
+
private :default_directives
|
125
|
+
|
126
|
+
#
|
127
|
+
# Returns _conv_ if it's already a Convention; otherwise calls +super+.
|
128
|
+
# You can now use instance methods of Convention to modify its features.
|
129
|
+
#
|
130
|
+
def convention conv
|
131
|
+
conv.is_a?(Convention) ? conv : super
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
# Uses the #convention _conv_ during the run, returning this convention.
|
136
|
+
#
|
137
|
+
# You can than chain some methods to modify its behaviour, such as
|
138
|
+
# Convention#use_with (or better its alias +with+) or
|
139
|
+
# Convention#edit.
|
140
|
+
#
|
141
|
+
# For example this line in the specification
|
142
|
+
# :rdx: off
|
143
|
+
# use_convention(:result_eval).with '->'
|
144
|
+
# will associate the <tt>-></tt> prompt to Convention::result_eval.
|
145
|
+
#
|
146
|
+
def use_convention conv
|
147
|
+
conv = convention(conv)
|
148
|
+
@used_conventions << conv unless @used_conventions.include?(conv)
|
149
|
+
return conv
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Removes the #convention _conv_ during the run.
|
154
|
+
# The convention is still defined and may be restored through #use_convention.
|
155
|
+
#
|
156
|
+
def dont_use_convention conv
|
157
|
+
@used_conventions.delete convention(conv)
|
158
|
+
return nil
|
159
|
+
end
|
160
|
+
|
161
|
+
# Use this convention once it's defined through +super+.
|
162
|
+
def define_convention(*)
|
163
|
+
use_convention super
|
164
|
+
end
|
165
|
+
|
166
|
+
# Don't use this convention once it's undefined through +super+.
|
167
|
+
def undefine_convention(*)
|
168
|
+
dont_use_convention super
|
169
|
+
end
|
170
|
+
alias remove_convention undefine_convention
|
171
|
+
|
172
|
+
# :stopdoc:
|
173
|
+
|
174
|
+
def original?
|
175
|
+
file.nil?
|
176
|
+
end
|
177
|
+
|
178
|
+
def finalize
|
179
|
+
return self if @used_conventions.frozen?
|
180
|
+
@known_conventions.replace @used_conventions
|
181
|
+
sort_conventions
|
182
|
+
@known_conventions.each(&:freeze).freeze
|
183
|
+
@directives.each(&:freeze).freeze
|
184
|
+
# Now (public) methods available
|
185
|
+
class << self # :nodoc:
|
186
|
+
public :conventions
|
187
|
+
attr_reader :directives
|
188
|
+
attr_accessor :file
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
|
2
|
+
module RDX
|
3
|
+
|
4
|
+
#
|
5
|
+
# Represents a toplevel statement in an example.
|
6
|
+
#
|
7
|
+
# For instance the following Example is composed by three +Statement+ objects:
|
8
|
+
#
|
9
|
+
# :rdx: off
|
10
|
+
#
|
11
|
+
# statement_1
|
12
|
+
# statement +
|
13
|
+
# 2
|
14
|
+
# if true
|
15
|
+
# else
|
16
|
+
# statement
|
17
|
+
# 3
|
18
|
+
# end # ends here
|
19
|
+
#
|
20
|
+
class Statement < CodeObject::Runnable
|
21
|
+
|
22
|
+
# The SourceFile this statement is into.
|
23
|
+
def source_file
|
24
|
+
comment.source_file
|
25
|
+
end
|
26
|
+
|
27
|
+
# The Comment this statement belongs to.
|
28
|
+
def comment
|
29
|
+
example.comment
|
30
|
+
end
|
31
|
+
|
32
|
+
# The Example this statement belongs to.
|
33
|
+
attr_reader :example
|
34
|
+
alias parent example
|
35
|
+
|
36
|
+
# Returns +self+.
|
37
|
+
def statement
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# The Expectation of this stetement (may be +nil+ if invalid).
|
42
|
+
attr_reader :expectation
|
43
|
+
|
44
|
+
# Contains only the expectation.
|
45
|
+
def children
|
46
|
+
[expectation].compact
|
47
|
+
end
|
48
|
+
|
49
|
+
# The code of this statement.
|
50
|
+
def code
|
51
|
+
text
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(example,text,relative_line_no=1) # :nodoc:
|
55
|
+
@example = example
|
56
|
+
super(text,relative_line_no)
|
57
|
+
remove_magic_comment # encoding handled in example
|
58
|
+
@expectation = nil
|
59
|
+
end
|
60
|
+
|
61
|
+
# The Convention associated with the expectation.
|
62
|
+
def convention
|
63
|
+
expectation && expectation.convention
|
64
|
+
end
|
65
|
+
|
66
|
+
# Does the expectation an #assertion?
|
67
|
+
def assertion?
|
68
|
+
expectation && expectation.assertion?
|
69
|
+
end
|
70
|
+
|
71
|
+
# Adds the label "top_level_statement" to +super+
|
72
|
+
def location l_no=nil
|
73
|
+
super(l_no,'top_level_statement')
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# :section: Internal
|
78
|
+
#
|
79
|
+
|
80
|
+
# Computes the #actual_value and passes it to Expectation#run.
|
81
|
+
def run
|
82
|
+
expectation && expectation.run(actual_value)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Wraps the original method into #capture_exceptions.
|
86
|
+
def whole_run
|
87
|
+
capture_exceptions{ super }
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
#
|
93
|
+
# First RubyLex#extract_comments_from_statement is used to extract the comments.
|
94
|
+
# The final one is kept for #build_expectation, while those before are sent to #check_inner_conventions.
|
95
|
+
#
|
96
|
+
def build_self # :doc:
|
97
|
+
comments = RubyLex.extract_comments_from_statement(code)
|
98
|
+
# code must be valid since it was determined through RubyLex.statementize
|
99
|
+
last_comment = comments.pop
|
100
|
+
check_inner_conventions comments
|
101
|
+
build_expectation *last_comment
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# If a convention is determined inside the statement (while it isn't yet complete)
|
106
|
+
# a +ParseError+ will be raised.
|
107
|
+
#
|
108
|
+
def check_inner_conventions comments # :doc:
|
109
|
+
comments.find do |cmt,line_no|
|
110
|
+
cmt = Text.normalize_comment cmt
|
111
|
+
store.find_convention_in cmt do
|
112
|
+
raise ParseError.new 'Incomplete statement', line_no
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# First the last comment is normalized through Text#normalize_comment,
|
119
|
+
# then tries to find a convention that can accept this comment
|
120
|
+
# calling Convention#process_comment for the conventions in use.
|
121
|
+
#
|
122
|
+
# When one convention is found, an Expectation will be associated to this statement;
|
123
|
+
# the result of +process_comment+ will be stored into Expectation#expected_data.
|
124
|
+
#
|
125
|
+
# If the search fails, Convention.eval will be used
|
126
|
+
# (with the whole normalized comment as +expected_data+).
|
127
|
+
#
|
128
|
+
def build_expectation last_comment, line_no # :doc:
|
129
|
+
last_comment = Text.normalize_comment last_comment
|
130
|
+
conv,processed = store.find_convention_in(last_comment)
|
131
|
+
conv,processed = store.eval_convention,last_comment unless conv
|
132
|
+
@expectation = Expectation.new(self,conv,processed,line_no)
|
133
|
+
end
|
134
|
+
|
135
|
+
# This is obtained processing the #code through Convention#process_statement.
|
136
|
+
def actual_value # :doc:
|
137
|
+
trace_execution do
|
138
|
+
convention.call_process_statement(self,code)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Rescues the +StandardError+ and subclasses raised during the execution of the statement.
|
144
|
+
# If there is an #assertion? the error is reported
|
145
|
+
# (and it will not propagate, so that other statements of this examples can run).
|
146
|
+
# Otherwise it's re-raised and will be handled by Example#capture_exceptions.
|
147
|
+
#
|
148
|
+
def capture_exceptions # :doc:
|
149
|
+
yield
|
150
|
+
rescue => err
|
151
|
+
raise err unless assertion?
|
152
|
+
register_error err
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
#
|
160
|
+
# Represent an expectation of a statement.
|
161
|
+
# This is written as a comment at its end that has been accepted by one of defined conventions.
|
162
|
+
#
|
163
|
+
# For instance the statement in the next example
|
164
|
+
# 1 + 1 #=> 2
|
165
|
+
# has the expectation associated with the Convention::result_eval.
|
166
|
+
#
|
167
|
+
class Expectation < CodeObject::Runnable
|
168
|
+
|
169
|
+
# The SourceFile this expectation is into.
|
170
|
+
def source_file
|
171
|
+
comment.source_file
|
172
|
+
end
|
173
|
+
|
174
|
+
# The Comment this expectation is into.
|
175
|
+
def comment
|
176
|
+
example.comment
|
177
|
+
end
|
178
|
+
|
179
|
+
# The Example this expectation is into.
|
180
|
+
def example
|
181
|
+
statement.example
|
182
|
+
end
|
183
|
+
|
184
|
+
# The Statement of this expectation.
|
185
|
+
attr_reader :statement
|
186
|
+
alias parent statement
|
187
|
+
|
188
|
+
# Returns +self+.
|
189
|
+
def expectation
|
190
|
+
self
|
191
|
+
end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Does the convention process an assertion?
|
195
|
+
# For example Convention.eval doesn't assert anything.
|
196
|
+
#
|
197
|
+
def assertion?
|
198
|
+
!!convention.process_assertion
|
199
|
+
end
|
200
|
+
|
201
|
+
# The Convention of this expectation.
|
202
|
+
attr_reader :convention
|
203
|
+
|
204
|
+
# The result of Convention#process_comment.
|
205
|
+
attr_reader :expected_data
|
206
|
+
|
207
|
+
def initialize statement, convention, expected_data, relative_line_no=1 # :nodoc:
|
208
|
+
@statement = statement
|
209
|
+
@convention = convention
|
210
|
+
@expected_data = expected_data
|
211
|
+
super(nil,relative_line_no)
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
# :section: API
|
216
|
+
#
|
217
|
+
|
218
|
+
# The default type is the #convention's name.
|
219
|
+
def warn msg, type=convention.name, frame=nil
|
220
|
+
super
|
221
|
+
end
|
222
|
+
|
223
|
+
#
|
224
|
+
# :section: Internal
|
225
|
+
#
|
226
|
+
|
227
|
+
#
|
228
|
+
# Receives Statement#actual_value as _actual_value_, computes #expected_value
|
229
|
+
# and process the assertion through Convention#process_assertion.
|
230
|
+
#
|
231
|
+
def run actual_value
|
232
|
+
act,exp = actual_value,expected_value # compute expected now
|
233
|
+
trace_assertion convention.name do # then do the assertion
|
234
|
+
convention.call_process_assertion example, act, exp
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# This is obtained processing the #expected_data through Convention#process_expectation.
|
239
|
+
def expected_value # :doc:
|
240
|
+
trace_execution do
|
241
|
+
convention.call_process_expectation(self,expected_data)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
private :expected_value
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|