dfect 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/doc/intro.erb CHANGED
@@ -1,6 +1,33 @@
1
+ %#--
2
+ %# Copyright 2009 Suraj N. Kurapati
3
+ %# See the LICENSE file for details.
4
+ %#++
5
+
1
6
  % api_url = './api/index.html'
2
7
  % src_url = 'http://github.com/sunaku/' + $program
3
8
  % git_url = 'http://git-scm.com'
9
+ <%
10
+ competitors = {
11
+ 'assert{ 2.0 }' => 'http://assert2.rubyforge.org',
12
+ 'Verify' => 'http://www.ruby-forum.com/topic/183354',
13
+ 'Testy' => 'http://github.com/ahoward/testy/tree/master',
14
+ 'minitest' => 'http://blog.zenspider.com/minitest',
15
+ 'Context' => 'http://github.com/jeremymcanally/context',
16
+ 'Shoulda' => 'http://thoughtbot.com/projects/shoulda',
17
+ 'Bacon' => 'http://chneukirchen.org/repos/bacon/README',
18
+ 'test-spec' => 'http://test-spec.rubyforge.org/test-spec',
19
+ 'RSpec' => 'http://rspec.info',
20
+ 'Test::Unit' => 'http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/index.html',
21
+ }
22
+
23
+ def competitors.link_for key
24
+ if val = self[key]
25
+ "[#{key}](#{val})"
26
+ else
27
+ raise key
28
+ end
29
+ end
30
+ %>
4
31
 
5
32
  %|chapter "Introduction"
6
33
  %|project
@@ -14,16 +41,9 @@
14
41
  * It is implemented in a mere <%= `sloccount lib`[/^\d+/] %> lines of code.
15
42
 
16
43
  These features distinguish <%= $project %> from the competition:
17
- * [assert{ 2.0 }](http://assert2.rubyforge.org)
18
- * [Verify](http://www.ruby-forum.com/topic/183354)
19
- * [Testy](http://www.ruby-forum.com/topic/182798)
20
- * [minitest](http://blog.zenspider.com/minitest)
21
- * [Context](http://github.com/jeremymcanally/context)
22
- * [Shoulda](http://thoughtbot.com/projects/shoulda)
23
- * [Bacon](http://chneukirchen.org/repos/bacon/README)
24
- * [test-spec](http://test-spec.rubyforge.org/test-spec)
25
- * [RSpec](http://rspec.info)
26
- * [Test::Unit](http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/index.html)
44
+
45
+ %|competitors.keys.sort_by {|name| name.downcase }.each do |name|
46
+ * <%= competitors.link_for name %>
27
47
 
28
48
  %|paragraph "Etymology"
29
49
  <%= $project %> is named after the D F E C T methods it provides.
@@ -32,10 +52,26 @@
32
52
 
33
53
  This wordplay is similar to [Mnesia](http://www.erlang.org/doc/apps/mnesia/index.html)'s play on the word "amnesia", whereby the intentional omission of the letter "A" indicates forgetfulness---the key characteristic of having amnesia. Clever!
34
54
 
55
+ %|section "Motivation"
56
+ The basic premise of <%= $project %> is that, when a failure occurs, I want to be put inside an interactive debugger where I have the freedom to properly scrutinize the state of my program and determine the root cause of the failure.
57
+
58
+ Other testing libraries do not fulfill this need. Instead, they simply report each failed assertion along with a stack trace (if I am lucky) and abruptly terminate my program.
59
+
60
+ This deliberate separation of *fault* (my program being in an erroneous state) and *cause* (the source code of my program which caused the fault) reduces me to a primitive and laborious investigative technique known as "[printf debugging](http://oopweb.com/CPP/Documents/DebugCPP/Volume/techniques.html#PRINTF)".
61
+
62
+ If you are not the least bit *unsettled* by those two words, then recall your first encounter with [IRB, the interactive Ruby shell](http://tryruby.hobix.com/): remember how you would enter code expressions and IRB would *instantly* evaluate them and show you the result?
63
+
64
+ What an immense productivity boost! A *stark contrast* to the endless toil of wrapping every such experiment in standard boilerplate (`public static void`...), saving the result to a correctly named file, invoking the C/C++/Java compiler, and finally executing the binary---only to be greeted by a [segfault](http://en.wikipedia.org/wiki/Segmentation_fault). ;-)
65
+
66
+ I exaggerate, for the sake of entertainment, of course. But my point is that the Ruby testing libraries of today have (thus far) limited our productivity by orphaning us from the nurturing environment of IRB and shooing us off to a barren desert of antiquated techniques. How cruel!
67
+
68
+ And that, I say, is why <%= $project %> is essential to Ruby developers today. It reunites us with our playful, interactive, *real-time* IRB roots and, with unwavering tenacity, enables us to investigate failures *productively*!
69
+
35
70
  %|section "Logistics"
36
71
  * <%= xref "History", "Release notes" %> --- history of project releases.
37
72
  * [Source code](<%= src_url %>) --- obtain via [Git](<%= git_url %>) or browse online.
38
73
  * [API reference](<%= api_url %>) --- documentation for source code.
74
+ * [Project home](<%= $website %>) --- the <%= $project %> project home page.
39
75
 
40
76
  To get help or provide feedback, simply
41
77
  <%= xref "License", "contact the author(s)" %>.
@@ -80,8 +116,8 @@
80
116
  </tbody>
81
117
  </table>
82
118
 
83
- %|section "License"
84
- %< "../LICENSE"
119
+ %|paragraph "License"
120
+ %< "../LICENSE"
85
121
 
86
122
  %|section "Credits"
87
123
  <%= $project %> is made possible by
data/doc/setup.erb CHANGED
@@ -1,3 +1,8 @@
1
+ %#--
2
+ %# Copyright 2009 Suraj N. Kurapati
3
+ %# See the LICENSE file for details.
4
+ %#++
5
+
1
6
  %|chapter "Setup"
2
7
  %|section "Requirements"
3
8
  Your system needs the following software to run <%= $project %>.
@@ -13,22 +18,6 @@
13
18
 
14
19
  gem install <%= $program %>
15
20
 
16
- %|section "Manifest"
17
- You will see the following items inside <%= $project %>'s installation
18
- directory:
19
-
20
- * <tt>lib/</tt>
21
-
22
- * <tt><%= $program %>.rb</tt> --- the main <%= $project %> library.
23
-
24
- * <tt><%= $program %>/</tt>
25
-
26
- * <tt>auto.rb</tt> --- automates test execution.
27
-
28
- * <tt>doc/</tt>
29
-
30
- * <tt>api/</tt> --- API reference documentation.
31
-
32
- * <tt>index.erb</tt> --- source of this user manual.
21
+ If you want to develop <%= $project %>, run this command:
33
22
 
34
- * <tt>LICENSE</tt> --- copyright notice and legal conditions.
23
+ gem install <%= $program %> --development
data/doc/usage.erb CHANGED
@@ -1,3 +1,8 @@
1
+ %#--
2
+ %# Copyright 2009 Suraj N. Kurapati
3
+ %# See the LICENSE file for details.
4
+ %#++
5
+
1
6
  % dfect_api = 'api/classes/Dfect.html'
2
7
 
3
8
  %|chapter "Usage"
data/lib/dfect.rb CHANGED
@@ -12,8 +12,16 @@ require 'yaml'
12
12
  # Work around this by representing a class by its name.
13
13
  #
14
14
  class Class #:nodoc: all
15
+ alias __to_yaml__ to_yaml
16
+ undef to_yaml
17
+
15
18
  def to_yaml opts = {}
16
- name.to_yaml opts
19
+ begin
20
+ __to_yaml__
21
+ rescue TypeError => e
22
+ warn e
23
+ self.name.to_yaml opts
24
+ end
17
25
  end
18
26
  end
19
27
 
@@ -77,7 +85,7 @@ module Dfect
77
85
  # during assertion failures so
78
86
  # the user can investigate them.
79
87
  #
80
- # The default value is $DEBUG.
88
+ # The default value is true.
81
89
  #
82
90
  # [:quiet]
83
91
  # Do not print the report
@@ -219,7 +227,7 @@ module Dfect
219
227
  # T( "computers do not doublethink" ) { 2 + 2 != 5 } # passes
220
228
  #
221
229
  def T message = nil, &block
222
- assert_block :assert, message, &block
230
+ assert_yield :assert, message, &block
223
231
  end
224
232
 
225
233
  ##
@@ -245,7 +253,7 @@ module Dfect
245
253
  # T!( "computers do not doublethink" ) { 2 + 2 == 5 } # passes
246
254
  #
247
255
  def T! message = nil, &block
248
- assert_block :negate, message, &block
256
+ assert_yield :negate, message, &block
249
257
  end
250
258
 
251
259
  ##
@@ -270,7 +278,7 @@ module Dfect
270
278
  # T?( "computers do not doublethink" ) { 2 + 2 != 5 } # => true
271
279
  #
272
280
  def T? message = nil, &block
273
- assert_block :sample, message, &block
281
+ assert_yield :sample, message, &block
274
282
  end
275
283
 
276
284
  alias F T!
@@ -519,16 +527,21 @@ module Dfect
519
527
  ##
520
528
  # Executes all tests defined thus far and stores the results in #report.
521
529
  #
522
- def run
530
+ # ==== Parameters
531
+ #
532
+ # [continue]
533
+ # If true, results from previous executions will not be cleared.
534
+ #
535
+ def run continue = true
523
536
  # clear previous results
524
- @exec_stats.clear
525
- @exec_trace.clear
526
- @test_stack.clear
537
+ unless continue
538
+ @exec_stats.clear
539
+ @exec_trace.clear
540
+ @test_stack.clear
541
+ end
527
542
 
528
543
  # make new results
529
- catch :stop_dfect_execution do
530
- execute
531
- end
544
+ catch(:stop_dfect_execution) { execute }
532
545
 
533
546
  # print new results
534
547
  puts @report.to_yaml unless @options[:quiet]
@@ -544,7 +557,7 @@ module Dfect
544
557
 
545
558
  private
546
559
 
547
- def assert_block mode, message = nil, &block
560
+ def assert_yield mode, message = nil, &block
548
561
  raise ArgumentError, 'block must be given' unless block
549
562
 
550
563
  message ||=
@@ -886,7 +899,7 @@ module Dfect
886
899
  #:startdoc:
887
900
  end
888
901
 
889
- @options = {:debug => $DEBUG, :quiet => false}
902
+ @options = {:debug => true, :quiet => false}
890
903
 
891
904
  @exec_stats = Hash.new {|h,k| h[k] = 0 }
892
905
  @exec_trace = []
data/lib/dfect/mini.rb ADDED
@@ -0,0 +1,91 @@
1
+ # MiniTest emulation layer.
2
+ #--
3
+ # Copyright 2009 Suraj N. Kurapati
4
+ # See the LICENSE file for details.
5
+ #++
6
+
7
+ require 'dfect'
8
+ require 'dfect/unit'
9
+ require 'dfect/spec'
10
+
11
+ module Kernel
12
+ instance_methods(false).each do |meth|
13
+ if meth =~ /^assert_not/
14
+ alias_method 'refute' + $', meth
15
+ end
16
+ end
17
+ end
18
+
19
+ {
20
+ :must => :assert,
21
+ :wont => :refute,
22
+ }.
23
+ each do |outer, inner|
24
+ file, line = __FILE__, __LINE__ ; eval %{
25
+ class Object
26
+ def #{outer}_be_close_to other, message = nil
27
+ #{inner}_in_delta self, other, nil, message
28
+ end
29
+
30
+ def #{outer}_be_empty message = nil
31
+ #{inner}_empty self, message
32
+ end
33
+
34
+ def #{outer}_be_instance_of _class, message = nil
35
+ #{inner}_instance_of _class, self, message
36
+ end
37
+
38
+ def #{outer}_be_kind_of _class, message = nil
39
+ #{inner}_kind_of _class, self, message
40
+ end
41
+
42
+ def #{outer}_be_nil message = nil
43
+ #{inner}_nil self, message
44
+ end
45
+
46
+ def #{outer}_be_same_as other, message = nil
47
+ #{inner}_same self, other, message
48
+ end
49
+
50
+ def #{outer}_be_within_delta other, delta = nil, message = nil
51
+ #{inner}_in_delta self, other, delta, message
52
+ end
53
+
54
+ alias #{outer}_be_within_epsilon #{outer}_be_within_delta
55
+
56
+ def #{outer}_equal expected, message = nil
57
+ #{inner}_equal expected, self, message
58
+ end
59
+
60
+ def #{outer}_include item, message = nil
61
+ #{inner}_include item, self, message
62
+ end
63
+
64
+ def #{outer}_match pattern, message = nil
65
+ #{inner}_match pattern, self, message
66
+ end
67
+
68
+ def #{outer}_raise *args, &block
69
+ #{inner}_raise(*args, &block)
70
+ end
71
+
72
+ def #{outer}_respond_to query, message = nil
73
+ #{inner}_respond_to self, query, message
74
+ end
75
+
76
+ def #{outer}_send query, *args
77
+ #{inner}_send self, query, *args
78
+ end
79
+ end
80
+
81
+ class Proc
82
+ def #{outer}_raise *args
83
+ #{inner}_raise(*args, &self)
84
+ end
85
+
86
+ def #{outer}_throw symbol, message = nil
87
+ #{inner}_throw symbol, message, &self
88
+ end
89
+ end
90
+ }, binding, file, line
91
+ end
data/lib/dfect/spec.rb ADDED
@@ -0,0 +1,39 @@
1
+ # RSpec emulation layer.
2
+ #--
3
+ # Copyright 2009 Suraj N. Kurapati
4
+ # See the LICENSE file for details.
5
+ #++
6
+
7
+ require 'dfect'
8
+ require 'delegate'
9
+
10
+ module Kernel
11
+ def describe *args, &block
12
+ Dfect.D args.join(' '), &block
13
+ end
14
+
15
+ alias context describe
16
+ alias it describe
17
+
18
+ def before what, &block
19
+ meth =
20
+ case what
21
+ when :each then :<
22
+ when :all then :<<
23
+ else raise ArgumentError, what
24
+ end
25
+
26
+ Dfect.send meth, &block
27
+ end
28
+
29
+ def after what, &block
30
+ meth =
31
+ case what
32
+ when :each then :>
33
+ when :all then :>>
34
+ else raise ArgumentError, what
35
+ end
36
+
37
+ Dfect.send meth, &block
38
+ end
39
+ end
data/lib/dfect/unit.rb ADDED
@@ -0,0 +1,105 @@
1
+ # Test::Unit emulation layer.
2
+ #--
3
+ # Copyright 2009 Suraj N. Kurapati
4
+ # See the LICENSE file for details.
5
+ #++
6
+
7
+ require 'dfect'
8
+
9
+ module Kernel
10
+ def setup &block
11
+ Dfect.<(&block)
12
+ end
13
+
14
+ def teardown &block
15
+ Dfect.>(&block)
16
+ end
17
+
18
+ [
19
+ [:assert, nil, nil ],
20
+ [:assert_not, '!', 'not '],
21
+ ].
22
+ each do |prefix, polarity, action|
23
+ file, line = __FILE__, __LINE__ ; eval %{
24
+ def #{prefix} boolean, message = nil
25
+ Dfect.T#{polarity}(message) { boolean }
26
+ end
27
+
28
+ def #{prefix}_block message = nil, &block
29
+ Dfect.T#{polarity}(&block)
30
+ end
31
+
32
+ def #{prefix}_empty collection, message = nil
33
+ message ||= 'collection must #{action}be empty'
34
+ Dfect.T#{polarity}(message) { collection.empty? }
35
+ end
36
+
37
+ def #{prefix}_equal actual, expected, message = nil
38
+ message ||= 'actual must #{action}equal expected'
39
+ Dfect.T#{polarity}(message) { actual == expected }
40
+ end
41
+
42
+ def #{prefix}_in_delta expected, actual, delta = nil, message = nil
43
+ message ||= 'actual must #{action}be within delta of expected'
44
+ delta ||= 0.001
45
+
46
+ Dfect.T#{polarity}(message) { Math.abs(expected - actual) <= Math.abs(delta) }
47
+ end
48
+
49
+ alias #{prefix}_in_epsilon #{prefix}_in_delta
50
+
51
+ def #{prefix}_include item, collection, message = nil
52
+ message ||= 'collection must #{action}include item'
53
+ Dfect.T#{polarity}(messsage) { collection.include? item }
54
+ end
55
+
56
+ def #{prefix}_instance_of _class, object, message = nil
57
+ message ||= 'object must #{action}be an instance of class'
58
+ Dfect.T#{polarity}(message) { object.instance_of? _class }
59
+ end
60
+
61
+ def #{prefix}_kind_of _class, object, message = nil
62
+ message ||= 'object must #{action}be a kind of class'
63
+ Dfect.T#{polarity}(message) { object.kind_of? _class }
64
+ end
65
+
66
+ def #{prefix}_nil object, message = nil
67
+ message ||= 'object must #{action}be nil'
68
+ Dfect.T#{polarity}(message) { object == nil }
69
+ end
70
+
71
+ def #{prefix}_match pattern, string, message = nil
72
+ message ||= 'string must #{action}match pattern'
73
+ Dfect.T#{polarity}(message) { string =~ pattern }
74
+ end
75
+
76
+ def #{prefix}_same expected, actual, message = nil
77
+ message ||= 'actual must #{action}be same as expected'
78
+ Dfect.T#{polarity}(message) { actual.equal? expected }
79
+ end
80
+
81
+ def #{prefix}_operator object, operator, operand, message = nil
82
+ message ||= 'object must #{action}support operator with operand'
83
+ Dfect.T#{polarity} { object.__send__ operator, operand }
84
+ end
85
+
86
+ def #{prefix}_raise *args, &block
87
+ Dfect.E#{polarity}(args.pop, *args, &block)
88
+ end
89
+
90
+ def #{prefix}_respond_to object, query, message = nil
91
+ message ||= 'object must #{action}respond to query'
92
+ Dfect.T#{polarity}(message) { object.respond_to? query }
93
+ end
94
+
95
+ def #{prefix}_throw symbol, message = nil, &block
96
+ Dfect.C#{polarity}(message, symbol, &block)
97
+ end
98
+
99
+ def #{prefix}_send object, query, *args
100
+ response = object.__send__(query, *args)
101
+ Dfect.T#{polarity} { response }
102
+ end
103
+ }, binding, file, line
104
+ end
105
+ end