qed 1.0.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.
@@ -0,0 +1,94 @@
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
+
@@ -0,0 +1,191 @@
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
+
@@ -0,0 +1,94 @@
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
+
@@ -0,0 +1,60 @@
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
+
@@ -0,0 +1,104 @@
1
+ module QED
2
+
3
+ require 'qed/expectation'
4
+
5
+ module Grammar
6
+
7
+ # = Assert Nomenclature
8
+ #
9
+ module Assert
10
+
11
+ # Assert a operational relationship.
12
+ #
13
+ # 4.assert == 3
14
+ #
15
+ # If only a single test argument is given then
16
+ # #assert simple validates that it evalutate to true.
17
+ # An optional message argument can be given in this
18
+ # case which will be used instead of the deafult message.
19
+ #
20
+ # assert(4==3, "not the same thing")
21
+ #
22
+ # In block form, #assert ensures the block evalutes
23
+ # truthfully, i.e. not as nil or false.
24
+ #
25
+ # assert{ 4==3 }
26
+ #
27
+ # If an argument is given with a block, #assert compares
28
+ # the argument to the result of evaluating the block.
29
+ #
30
+ # assert(4){ 3 }
31
+ #
32
+ # #assert compares the expected value and the actual
33
+ # value with regular equality <code>#==</code>.
34
+ #
35
+ def assert(test=Exception, msg=nil, &block)
36
+ if block
37
+ act = block.call
38
+ if test == Exception
39
+ raise Assertion.new(msg, caller) unless act
40
+ else
41
+ yes = (test == act)
42
+ msg = "#{exp}.equate? #{act}" unless msg
43
+ raise Assertion.new(msg, caller) unless yes
44
+ end
45
+ elsif test != Exception
46
+ msg = "failed assertion (no message given)" unless msg
47
+ raise Assertion.new(msg, caller) unless test
48
+ else
49
+ return Expectation.new(self, :backtrace=>caller)
50
+ end
51
+ end
52
+
53
+ # Assert not an operational relationship.
54
+ # Read it as "assert not".
55
+ #
56
+ # 4.assert! == 4
57
+ #
58
+ # See #assert.
59
+ #
60
+ # AUHTOR'S NOTE: This method would not be necessary
61
+ # if Ruby would allow +!=+ to be define as a method,
62
+ # or at least +!+ as a unary method.
63
+ #
64
+ def assert!(test=Exception, msg=nil, &block)
65
+ if block
66
+ act = block.call
67
+ if test == Exception
68
+ raise Assertion.new(msg, caller) if act
69
+ else
70
+ yes = (test == act)
71
+ msg = "#{exp}.equate? #{act}" unless msg
72
+ raise Assertion.new(msg, caller) if yes
73
+ end
74
+ elsif test != Exception
75
+ msg = "failed assertion (no message given)" unless msg
76
+ raise Assertion.new(msg, caller) if test
77
+ else
78
+ return Expectation.new(self, :negate=>true, :backtrace=>caller)
79
+ end
80
+
81
+ if test
82
+ msg = "failed assertion (no message given)" unless msg
83
+ raise Assertion.new(msg, caller) if test
84
+ else
85
+ return Expectation.new(self, :negate=>true, :backtrace=>caller)
86
+ end
87
+ end
88
+
89
+ # Same as #assert!.
90
+ #
91
+ # 4.refute == 4 #=> Assertion Error
92
+ #
93
+ alias_method :refute, :assert!
94
+
95
+ end
96
+
97
+ end
98
+
99
+ class ::Object #:nodoc:
100
+ include Grammar::Assert
101
+ end
102
+
103
+ end
104
+