qed 1.0.0 → 1.1.0
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.
- data/{LICENSE → COPYING} +2 -2
- data/MANIFEST +2 -16
- data/README.rdoc +58 -21
- data/bin/qed +13 -13
- data/demo/01_spec.qed +6 -3
- data/doc/qedoc/index.html +13 -10
- data/lib/qed.rb +4 -3
- data/lib/qed/document.rb +9 -10
- data/lib/qed/{utilities/extract.rb → extract.rb} +0 -0
- data/lib/qed/script.rb +7 -1
- data/meta/requires +2 -0
- data/meta/version +1 -1
- metadata +25 -15
- data/lib/qed/assertion.rb +0 -23
- data/lib/qed/doubles/mock.rb +0 -94
- data/lib/qed/doubles/spy.rb +0 -191
- data/lib/qed/doubles/stub.rb +0 -94
- data/lib/qed/expectation.rb +0 -60
- data/lib/qed/grammar/assert.rb +0 -104
- data/lib/qed/grammar/expect.rb +0 -121
- data/lib/qed/grammar/legacy/assert.rb +0 -291
- data/lib/qed/grammar/should.rb +0 -52
- data/lib/qed/utilities/monitor.rb +0 -23
data/lib/qed/assertion.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
module QED
|
2
|
-
|
3
|
-
# = Assertion
|
4
|
-
#
|
5
|
-
# This is the core class of the whole specification system.
|
6
|
-
#
|
7
|
-
class Assertion < Exception
|
8
|
-
|
9
|
-
def initialize(message, backtrace=nil)
|
10
|
-
super(message)
|
11
|
-
set_backtrace(backtrace) if backtrace
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_str
|
15
|
-
message.to_s.strip
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
# Copyright (c) 2008 Tiger Ops
|
23
|
-
|
data/lib/qed/doubles/mock.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
module QED
|
2
|
-
|
3
|
-
# = Mock
|
4
|
-
#
|
5
|
-
class Mock < Module
|
6
|
-
attr :object
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
super()
|
10
|
-
@table = {}
|
11
|
-
end
|
12
|
-
|
13
|
-
#
|
14
|
-
def __table__ ; @table ; end
|
15
|
-
|
16
|
-
# TODO: Ruby has retry, but I need continue!
|
17
|
-
def method_missing(meth, *args, &block)
|
18
|
-
table = @table
|
19
|
-
interface = [meth, args, block_given?]
|
20
|
-
|
21
|
-
table[interface] = nil
|
22
|
-
|
23
|
-
define_method(meth) do |*args|
|
24
|
-
result = super
|
25
|
-
result.assert == table[interface]
|
26
|
-
return result
|
27
|
-
end
|
28
|
-
|
29
|
-
Setter.new(table, interface)
|
30
|
-
end
|
31
|
-
|
32
|
-
#
|
33
|
-
class Setter
|
34
|
-
def initialize(table, interface)
|
35
|
-
@table = table
|
36
|
-
@interface = interface
|
37
|
-
end
|
38
|
-
|
39
|
-
def ==(result)
|
40
|
-
@table[@interface] = result
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# = Mock::Delegator
|
45
|
-
#
|
46
|
-
class Delegator
|
47
|
-
instance_methods(true).each{ |m| protected m unless m.to_s =~ /^__/ }
|
48
|
-
|
49
|
-
def initialize(object, mock_module)
|
50
|
-
@instance_delegate = object
|
51
|
-
extend(mock_module)
|
52
|
-
end
|
53
|
-
|
54
|
-
def method_missing(s, *a, &b)
|
55
|
-
@instance_delegate.__send__(s, *a, &b)
|
56
|
-
end
|
57
|
-
end#class Delegator
|
58
|
-
|
59
|
-
end#class Mock
|
60
|
-
|
61
|
-
class ::Object
|
62
|
-
# Create mock object.
|
63
|
-
def mock(mock_module=nil)
|
64
|
-
if mock_module
|
65
|
-
Mock::Delegator.new(self, mock_module)
|
66
|
-
else
|
67
|
-
@_mock ||= Mock.new
|
68
|
-
extend(@_mock)
|
69
|
-
@_mock
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# We can't remove the module per-say. So we have to
|
74
|
-
# just neuter it. This is a very weak solution, but
|
75
|
-
# it will suffice for the moment.
|
76
|
-
#--
|
77
|
-
# TODO: Use Carats for #unmix.
|
78
|
-
#++
|
79
|
-
def remove_mock(mock_module=nil)
|
80
|
-
mock_module ||= @_mock
|
81
|
-
obj = self
|
82
|
-
mod = Module.new
|
83
|
-
mock_module.__table__.each do |interface, result|
|
84
|
-
meth = interface[0]
|
85
|
-
mod.module_eval do
|
86
|
-
define_method(meth, &obj.class.instance_method(meth).bind(obj))
|
87
|
-
end
|
88
|
-
end
|
89
|
-
extend(mod)
|
90
|
-
end
|
91
|
-
end#class ::Object
|
92
|
-
|
93
|
-
end#module Quarry
|
94
|
-
|
data/lib/qed/doubles/spy.rb
DELETED
@@ -1,191 +0,0 @@
|
|
1
|
-
raise "Spy class is under construction"
|
2
|
-
|
3
|
-
module QED
|
4
|
-
|
5
|
-
# = Spy
|
6
|
-
#
|
7
|
-
# Spy (aka DuckHunter) is a decoy object which is dropped into
|
8
|
-
# methods which records the calls made against it --hence a method probe.
|
9
|
-
# Of course, it is not perfect --an inescapable matter it seems for any
|
10
|
-
# internal probe. There are a couple of issues related to conditionals.
|
11
|
-
# Since the method test for a certain condition against the decoy, how
|
12
|
-
# is the decoy to respond? Thus ceratin paths in the code may never get
|
13
|
-
# exceuted and thus go unmapped. If Ruby had better conditional reflection
|
14
|
-
# (i.e. if 'if', 'case', 'unless', 'when', etc. were true methods) then
|
15
|
-
# this could be fixed by making the Probe reentrant, mapping out variant
|
16
|
-
# true/false/nil replies. The likely insurmountable problem though is the
|
17
|
-
# Halting problem. A probe can cause some methods to complete execution.
|
18
|
-
# It's pretty rare, but it can happen and little can be done about it (I think).
|
19
|
-
#
|
20
|
-
# Note, the alternative to this kind of probe is a program that examines, rather
|
21
|
-
# then executes, the code. This would circumvent the above problems, but run
|
22
|
-
# into difficulties with dynamic evals. It would also be more complicated,
|
23
|
-
# but might prove a better means in the future.
|
24
|
-
#
|
25
|
-
# This script is provided for experimetnal purposes. Please inform the author
|
26
|
-
# if you find ways to improve it or put it to an interesting use.
|
27
|
-
#
|
28
|
-
# == Synopsis
|
29
|
-
#
|
30
|
-
# require 'methodprobe'
|
31
|
-
#
|
32
|
-
# def amethod(x)
|
33
|
-
# x + 1
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# p method(:amethod).signiture
|
37
|
-
# p method(:amethod).signiture(:class)
|
38
|
-
# p method(:amethod).signiture(:pretty)
|
39
|
-
#
|
40
|
-
# produces
|
41
|
-
#
|
42
|
-
# [["+"]]
|
43
|
-
# [{"+"=>[["Fixnum"]]}]
|
44
|
-
# [["+( Fixnum )"]]
|
45
|
-
#
|
46
|
-
class Spy
|
47
|
-
|
48
|
-
def self.duckcall
|
49
|
-
begin
|
50
|
-
yield
|
51
|
-
rescue TypeError => e
|
52
|
-
self.send(e.message)
|
53
|
-
retry
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
attr_reader :ducks, :decoys
|
58
|
-
|
59
|
-
def initialize
|
60
|
-
@ducks, @decoys = {}, {}
|
61
|
-
end
|
62
|
-
|
63
|
-
def initialize_copy(from)
|
64
|
-
initialize
|
65
|
-
end
|
66
|
-
|
67
|
-
def method_missing(aSym, *args)
|
68
|
-
aSymStr = aSym.to_s
|
69
|
-
|
70
|
-
# This will happen the first time
|
71
|
-
@ducks[aSymStr] ||= [] #unless @ducks[aSymStr]
|
72
|
-
@ducks[aSymStr] << args.collect { |a| "#{a.class}" }
|
73
|
-
|
74
|
-
decoy = self.dup
|
75
|
-
|
76
|
-
@decoys[aSymStr] ||= [] #unless @decoys[aSymStr]
|
77
|
-
@decoys[aSymStr] << decoy
|
78
|
-
|
79
|
-
# build proxy?
|
80
|
-
#begin
|
81
|
-
# d = <<-HERE
|
82
|
-
# def self.#{aSymStr}(*args)
|
83
|
-
# # This will happen the subsequent times
|
84
|
-
# @ducks["#{aSymStr}"] << args.collect { |a| #{'"#{a.class}"'} }
|
85
|
-
# @ducks["#{aSymStr}"].uniq!
|
86
|
-
# decoy = self.dup
|
87
|
-
# @decoys["#{aSymStr}"] = [] unless @decoys["#{aSymStr}"]
|
88
|
-
# @decoys["#{aSymStr}"] << decoy
|
89
|
-
# decoy
|
90
|
-
# end
|
91
|
-
# HERE
|
92
|
-
# instance_eval d
|
93
|
-
#rescue SyntaxError
|
94
|
-
# puts "This error may be avoidable by returning the failing duck type as the error message."
|
95
|
-
# raise
|
96
|
-
#end
|
97
|
-
|
98
|
-
decoy
|
99
|
-
end
|
100
|
-
|
101
|
-
end # class MethodProbe
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
class ::Method
|
107
|
-
|
108
|
-
# Outputs migration information.
|
109
|
-
def migration
|
110
|
-
parameters = []; argc = self.arity
|
111
|
-
if argc > 0
|
112
|
-
argc.times { parameters << Quarry::Probe.new }
|
113
|
-
Probe.duckcall { self.call(*parameters) }
|
114
|
-
elsif argc < 0
|
115
|
-
raise "(NYI) method takes unlimited arguments"
|
116
|
-
end
|
117
|
-
return parameters
|
118
|
-
end
|
119
|
-
private :migration
|
120
|
-
|
121
|
-
# Outputs signiture information.
|
122
|
-
def signature(detail=nil)
|
123
|
-
ds = []
|
124
|
-
case detail
|
125
|
-
when :complete, :all, :full
|
126
|
-
ds = migration
|
127
|
-
when :class, :with_class
|
128
|
-
migration.each { |dh| ds << dh.ducks }
|
129
|
-
when :pp, :pretty, :prettyprint, :pretty_print
|
130
|
-
migration.each do |dh|
|
131
|
-
responders = []
|
132
|
-
dh.ducks.each do |responder, argss|
|
133
|
-
argss.each { |args| responders << "#{responder}( #{args.join(',')} )" }
|
134
|
-
end
|
135
|
-
ds << responders
|
136
|
-
end
|
137
|
-
else
|
138
|
-
migration.each { |dh| ds << dh.ducks.keys }
|
139
|
-
end
|
140
|
-
return ds
|
141
|
-
end
|
142
|
-
|
143
|
-
end
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
=begin test
|
150
|
-
|
151
|
-
require 'test/unit'
|
152
|
-
|
153
|
-
# " I am a Duck Hunter ! "
|
154
|
-
|
155
|
-
class TC_MethodProbe < Test::Unit::TestCase
|
156
|
-
|
157
|
-
# fixture
|
158
|
-
def amethod(x)
|
159
|
-
x + 1
|
160
|
-
end
|
161
|
-
|
162
|
-
def test_signiture_default
|
163
|
-
assert_nothing_raised {
|
164
|
-
method(:amethod).signature
|
165
|
-
}
|
166
|
-
end
|
167
|
-
|
168
|
-
def test_signiture_with_class
|
169
|
-
assert_nothing_raised {
|
170
|
-
method(:amethod).signature(:class)
|
171
|
-
}
|
172
|
-
end
|
173
|
-
|
174
|
-
def test_signiture_pp
|
175
|
-
assert_nothing_raised {
|
176
|
-
method(:amethod).signature(:pp)
|
177
|
-
}
|
178
|
-
end
|
179
|
-
|
180
|
-
def test_signiture_all
|
181
|
-
assert_nothing_raised {
|
182
|
-
method(:amethod).signature(:complete)
|
183
|
-
}
|
184
|
-
end
|
185
|
-
|
186
|
-
end
|
187
|
-
|
188
|
-
=end
|
189
|
-
|
190
|
-
# Copyright (c) 2004,2008 Thomas Sawyer
|
191
|
-
|
data/lib/qed/doubles/stub.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
module QED
|
2
|
-
|
3
|
-
# = Stub
|
4
|
-
#
|
5
|
-
class Stub < Module
|
6
|
-
attr :object
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
super()
|
10
|
-
@table = {}
|
11
|
-
end
|
12
|
-
|
13
|
-
#
|
14
|
-
def __table__ ; @table ; end
|
15
|
-
|
16
|
-
#
|
17
|
-
def method_missing(meth, *args, &block)
|
18
|
-
table = @table
|
19
|
-
interface = [meth, args, block_given?]
|
20
|
-
|
21
|
-
table[interface] = nil
|
22
|
-
|
23
|
-
define_method(meth) do |*args|
|
24
|
-
table[interface]
|
25
|
-
end
|
26
|
-
|
27
|
-
Setter.new(table, interface)
|
28
|
-
end
|
29
|
-
|
30
|
-
#
|
31
|
-
class Setter
|
32
|
-
def initialize(table, interface)
|
33
|
-
@table = table
|
34
|
-
@interface = interface
|
35
|
-
end
|
36
|
-
|
37
|
-
def ==(result)
|
38
|
-
@table[@interface] = result
|
39
|
-
end
|
40
|
-
end#class Setter
|
41
|
-
|
42
|
-
# = Stub::Delegator
|
43
|
-
#
|
44
|
-
class Delegator
|
45
|
-
instance_methods(true).each{ |m| protected m unless m.to_s =~ /^__/ }
|
46
|
-
|
47
|
-
def initialize(object, stub_module)
|
48
|
-
@instance_delegate = object
|
49
|
-
extend(stub_module)
|
50
|
-
end
|
51
|
-
|
52
|
-
def method_missing(s, *a, &b)
|
53
|
-
@instance_delegate.__send__(s, *a, &b)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
end#class Stub
|
58
|
-
|
59
|
-
class ::Object
|
60
|
-
|
61
|
-
# Create a new stub.
|
62
|
-
def stub(stub_module=nil)
|
63
|
-
if stub_module
|
64
|
-
Stub::Delegator.new(self, stub_module)
|
65
|
-
else
|
66
|
-
@_stub ||= Stub.new
|
67
|
-
extend(@_stub)
|
68
|
-
@_stub
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# We can't remove the module per-say. So we have to
|
73
|
-
# just neuter it. This is a very weak solution, but
|
74
|
-
# it will suffice for the moment.
|
75
|
-
#--
|
76
|
-
# TODO: Use Carats for #unmix.
|
77
|
-
#++
|
78
|
-
def remove_stub(stub_module=nil)
|
79
|
-
stub_module ||= @_stub
|
80
|
-
obj = self
|
81
|
-
mod = Module.new
|
82
|
-
stub_module.__table__.each do |interface, result|
|
83
|
-
meth = interface[0]
|
84
|
-
mod.module_eval do
|
85
|
-
define_method(meth, &obj.class.instance_method(meth).bind(obj))
|
86
|
-
end
|
87
|
-
end
|
88
|
-
extend(mod)
|
89
|
-
end
|
90
|
-
|
91
|
-
end#class ::Object
|
92
|
-
|
93
|
-
end#module Quarry
|
94
|
-
|
data/lib/qed/expectation.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
module QED
|
2
|
-
|
3
|
-
require 'qed/assertion'
|
4
|
-
|
5
|
-
# = Expectation
|
6
|
-
#
|
7
|
-
# Expectation is an Assertion Functor.
|
8
|
-
#
|
9
|
-
class Expectation
|
10
|
-
|
11
|
-
hide = instance_methods.select{ |m| m.to_s !~ /^__/ }
|
12
|
-
hide.each{ |m| protected m }
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
# New Expectation.
|
17
|
-
#
|
18
|
-
def initialize(delegate, ioc={}) #, backtrace)
|
19
|
-
@delegate = delegate
|
20
|
-
@negate = ioc[:negate]
|
21
|
-
@message = ioc[:message]
|
22
|
-
@backtrace = ioc[:backtrace] || caller #[1..-1]
|
23
|
-
end
|
24
|
-
|
25
|
-
# Converts missing method into an Assertion.
|
26
|
-
#
|
27
|
-
def method_missing(sym, *a, &b)
|
28
|
-
test = @delegate.__send__(sym, *a, &b)
|
29
|
-
|
30
|
-
if (@negate ? test : !test)
|
31
|
-
msg = @message || __msg__(sym, *a, &b)
|
32
|
-
error = Assertion.new(msg)
|
33
|
-
error.set_backtrace(@backtrace)
|
34
|
-
raise error
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Puts together a suitable error message.
|
39
|
-
#
|
40
|
-
def __msg__(m, *a, &b)
|
41
|
-
if @negate
|
42
|
-
"! #{@delegate.inspect} #{m} #{a.collect{|x| x.inspect}.join(',')}"
|
43
|
-
else
|
44
|
-
"#{@delegate.inspect} #{m} #{a.collect{|x| x.inspect}.join(',')}"
|
45
|
-
end
|
46
|
-
#self.class.message(m)[@delegate, *a] )
|
47
|
-
end
|
48
|
-
|
49
|
-
# TODO: Ultimately better messages would be nice ?
|
50
|
-
#
|
51
|
-
#def self.message(op,&block)
|
52
|
-
# @message ||= {}
|
53
|
-
# block ? @message[op.to_sym] = block : @message[op.to_sym]
|
54
|
-
#end
|
55
|
-
#
|
56
|
-
#message(:==){ |*a| "Expected #{a[0].inspect} to be equal to #{a[1].inspect}" }
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
|