bryanlarsen-rubydoctest 1.0.2

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,54 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'lines'
5
+
6
+ module RubyDocTest
7
+ class SpecialDirective < Lines
8
+ NAMES = ["doctest:", "it:", "!!!", "doctest_require:"]
9
+ NAMES_FOR_RX = NAMES.map{ |n| Regexp.escape(n) }.join("|")
10
+
11
+ # === Test
12
+ #
13
+ # doctest: The name of the directive should be detected in the first line
14
+ # >> s = RubyDocTest::SpecialDirective.new(["doctest: Testing Stuff", "Other Stuff"])
15
+ # >> s.name
16
+ # => "doctest:"
17
+ #
18
+ # doctest: "it:" is a valid directive
19
+ # >> s = RubyDocTest::SpecialDirective.new(["it: should test stuff"])
20
+ # >> s.name
21
+ # => "it:"
22
+ def name
23
+ if m = lines.first.match(/^#{Regexp.escape(indentation)}(#{NAMES_FOR_RX})/)
24
+ m[1]
25
+ end
26
+ end
27
+
28
+ # === Test
29
+ #
30
+ # doctest: The value of the directive should be detected in the first line
31
+ # >> s = RubyDocTest::SpecialDirective.new(["doctest: Testing Stuff", "Other Stuff"])
32
+ # >> s.value
33
+ # => "Testing Stuff"
34
+ #
35
+ # >> s = RubyDocTest::SpecialDirective.new([" # doctest: Testing Stuff", " # Other Stuff"])
36
+ # >> s.value
37
+ # => "Testing Stuff"
38
+ #
39
+ # doctest: Multiple lines for the directive value should work as well
40
+ # >> s = RubyDocTest::SpecialDirective.new(["doctest: Testing Stuff", " On Two Lines"])
41
+ # >> s.value
42
+ # => "Testing Stuff\nOn Two Lines"
43
+ #
44
+ # doctest: "it" should also work as a directive
45
+ # >> s = RubyDocTest::SpecialDirective.new(["it: should do something"])
46
+ # >> s.value
47
+ # => "should do something"
48
+ def value
49
+ if m = lines.join("\n").match(/^#{Regexp.escape(indentation)}(#{NAMES_FOR_RX})(.*)/m)
50
+ m[2].strip
51
+ end
52
+ end
53
+ end
54
+ end
data/lib/statement.rb ADDED
@@ -0,0 +1,81 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubydoctest'
5
+ require 'lines'
6
+
7
+ module RubyDocTest
8
+ class EvaluationError < Exception
9
+ attr_reader :statement, :original_exception
10
+ def initialize(statement, original_exception)
11
+ @statement, @original_exception = statement, original_exception
12
+ end
13
+ end
14
+
15
+ class Statement < Lines
16
+
17
+ attr_reader :actual_result
18
+
19
+ # === Tests
20
+ #
21
+ # doctest: The FILENAME ruby constant should be replaced by the name of the file
22
+ # >> __FILE__[/statement\.rb$/]
23
+ # => "statement.rb"
24
+ def initialize(doc_lines, line_index = 0, file_name = nil)
25
+ @file_name = file_name
26
+ super(doc_lines, line_index)
27
+ end
28
+
29
+ # === Tests
30
+ #
31
+ # doctest: A statement should parse out a '>>' irb prompt
32
+ # >> s = RubyDocTest::Statement.new([">> a = 1"])
33
+ # >> s.source_code
34
+ # => "a = 1"
35
+ #
36
+ # doctest: More than one line should get included, if indentation so indicates
37
+ # >> s = RubyDocTest::Statement.new([">> b = 1 +", " 1", "not part of the statement"])
38
+ # >> s.source_code
39
+ # => "b = 1 +\n1"
40
+ #
41
+ # doctest: Lines indented by ?> should have the ?> removed.
42
+ # >> s = RubyDocTest::Statement.new([">> b = 1 +", "?> 1"])
43
+ # >> s.source_code
44
+ # => "b = 1 +\n1"
45
+ def source_code
46
+ lines.first =~ /^#{Regexp.escape(indentation)}>>\s(.*)$/
47
+ first = [$1]
48
+ remaining = (lines[1..-1] || [])
49
+ (first + remaining).join("\n")
50
+ end
51
+
52
+ # === Test
53
+ #
54
+ # doctest: Evaluating a multi-line statement should be ok
55
+ # >> s = RubyDocTest::Statement.new([">> b = 1 +", " 1", "not part of the statement"])
56
+ # >> s.evaluate
57
+ # => 2
58
+ #
59
+ # doctest: Evaluating a syntax error should raise an EvaluationError
60
+ # >> s = RubyDocTest::Statement.new([">> b = 1 +"])
61
+ # >> begin s.evaluate; :fail; rescue RubyDocTest::EvaluationError; :ok end
62
+ # => :ok
63
+ def evaluate
64
+ sc = source_code.gsub("__FILE__", @file_name.inspect)
65
+ if RubyDocTest.verbose
66
+ puts "EVAL: #{sc}"
67
+ end
68
+ @actual_result = eval(sc, TOPLEVEL_BINDING, __FILE__, __LINE__)
69
+ if RubyDocTest.verbose
70
+ puts "RESULT: #{@actual_result}"
71
+ end
72
+ @actual_result
73
+ rescue Exception => e
74
+ if RubyDocTest.trace
75
+ raise e.class, e.to_s + "\n" + e.backtrace.first
76
+ else
77
+ raise EvaluationError.new(self, e)
78
+ end
79
+ end
80
+ end
81
+ end
data/lib/test.rb ADDED
@@ -0,0 +1,29 @@
1
+ module RubyDocTest
2
+ # This is the top-level 'test' container that holds an optional description and one
3
+ # or more CodeBlock objects.
4
+ class Test
5
+ attr_accessor :description
6
+ attr_reader :code_blocks, :passed
7
+
8
+ def initialize(description, code_blocks)
9
+ @description, @code_blocks = description, code_blocks
10
+ end
11
+
12
+ def pass?
13
+ @passed = @code_blocks.all?{ |c| c.pass? }
14
+ end
15
+
16
+ def first_failed
17
+ @code_blocks.detect{ |cb| !cb.pass? }
18
+ end
19
+
20
+ def actual_result
21
+ first_failed.actual_result.inspect
22
+ end
23
+
24
+ def expected_result
25
+ first_failed.expected_result
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,72 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "rubydoctest"
3
+ s.version = "1.0.2"
4
+
5
+ s.specification_version = 2 if s.respond_to? :specification_version=
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Duane Johnson", "Tom Locke", "Dr Nic Williams"]
9
+ s.date = "2008-12-06"
10
+ s.default_executable = "rubydoctest"
11
+ s.description = "Ruby version of Python's doctest tool, but a bit different."
12
+ s.email = ["duane.johnson@gmail.com"]
13
+ s.executables = ["rubydoctest"]
14
+ s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "PostInstall.txt", "README.txt", "website/index.txt"]
15
+ manifest = <<-MANIFEST
16
+ History.txt
17
+ License.txt
18
+ Manifest.txt
19
+ PostInstall.txt
20
+ README.txt
21
+ Rakefile
22
+ bin/rubydoctest
23
+ config/hoe.rb
24
+ config/requirements.rb
25
+ lib/code_block.rb
26
+ lib/doctest_require.rb
27
+ lib/lines.rb
28
+ lib/result.rb
29
+ lib/rubydoctest.rb
30
+ lib/rubydoctest/version.rb
31
+ lib/runner.rb
32
+ lib/special_directive.rb
33
+ lib/statement.rb
34
+ lib/test.rb
35
+ rubydoctest.gemspec
36
+ script/console
37
+ script/destroy
38
+ script/generate
39
+ script/rstakeout
40
+ script/txt2html
41
+ setup.rb
42
+ tasks/deployment.rake
43
+ tasks/doctests.rake
44
+ tasks/environment.rake
45
+ tasks/website.rake
46
+ textmate/DocTest (Markdown).textmate
47
+ textmate/DocTest (Ruby).textmate
48
+ textmate/DocTest (Text).textmate
49
+ website/index.html
50
+ website/index.txt
51
+ website/javascripts/rounded_corners_lite.inc.js
52
+ website/stylesheets/screen.css
53
+ website/template.html.erb
54
+ MANIFEST
55
+ s.files = manifest.strip.split("\n").map{|m| m.strip}
56
+ s.has_rdoc = true
57
+ s.homepage = %q{http://rubydoctest.rubyforge.org}
58
+ s.post_install_message = %q{
59
+ rubydoctest comes as an executable that takes a file or directory:
60
+
61
+ rubydoctest .
62
+ rubydoctest simple.doctest
63
+
64
+
65
+ }
66
+ s.rdoc_options = ["--main", "README.txt"]
67
+ s.require_paths = ["lib"]
68
+ s.rubyforge_project = %q{rubydoctest}
69
+ s.rubygems_version = %q{1.1.1}
70
+ s.summary = %q{Ruby version of Python's doctest tool, but a bit different.}
71
+ s.test_files = []
72
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/rubydoctest.rb'}"
9
+ puts "Loading rubydoctest gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
data/script/rstakeout ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ##
4
+ # Originally by Mike Clark.
5
+ #
6
+ # From http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Monitor/StakingOutFileChanges.rdoc
7
+ #
8
+ # Runs a user-defined command when files are modified.
9
+ #
10
+ # Like autotest, but more customizable. This is useful when you want to do
11
+ # something other than run tests. For example, generate a PDF book, run
12
+ # a single test, or run a legacy Test::Unit suite in an app that also
13
+ # has an rSpec suite.
14
+ #
15
+ # Can use Ruby's Dir[] to get file glob. Quote your args to take advantage of this.
16
+ #
17
+ # rstakeout 'rake test:recent' **/*.rb
18
+ # => Only watches Ruby files one directory down (no quotes)
19
+ #
20
+ # rstakeout 'rake test:recent' '**/*.rb'
21
+ # => Watches all Ruby files in all directories and subdirectories
22
+ #
23
+ # Modified (with permission) by Geoffrey Grosenbach to call growlnotify for
24
+ # rspec and Test::Unit output.
25
+ #
26
+ # See the PeepCode screencast on rSpec or other blog articles for instructions on
27
+ # setting up growlnotify.
28
+
29
+ def growl(title, msg, img, pri=0, sticky="")
30
+ system "growlnotify -n autotest --image ~/.autotest_images/#{img} -p #{pri} -m #{msg.inspect} #{title} #{sticky}"
31
+ end
32
+
33
+ def self.growl_fail(output)
34
+ growl "FAIL", "#{output}", "fail.png", 2
35
+ end
36
+
37
+ def self.growl_pass(output)
38
+ growl "Pass", "#{output}", "pass.png"
39
+ end
40
+
41
+ command = ARGV.shift
42
+ files = {}
43
+
44
+ ARGV.each do |arg|
45
+ Dir[arg].each { |file|
46
+ files[file] = File.mtime(file)
47
+ }
48
+ end
49
+
50
+ puts "Watching #{files.keys.join(', ')}\n\nFiles: #{files.keys.length}"
51
+
52
+ trap('INT') do
53
+ puts "\nQuitting..."
54
+ exit
55
+ end
56
+
57
+
58
+ loop do
59
+
60
+ sleep 1
61
+
62
+ changed_file, last_changed = files.find { |file, last_changed|
63
+ File.mtime(file) > last_changed
64
+ }
65
+
66
+ if changed_file
67
+ files[changed_file] = File.mtime(changed_file)
68
+ puts "=> #{changed_file} changed, running #{command}"
69
+ args = ""
70
+ args += ARGV.last == '--pass-as-arg' ? changed_file : ""
71
+ args += ARGV.last == '--pass-as-env' ? "CHANGED=#{changed_file}" : ""
72
+ puts "Executing: #{command} #{args}"
73
+ results = `#{command} #{args}`
74
+ puts results
75
+
76
+ if results.include? 'tests'
77
+ output = results.slice(/(\d+)\s+tests?,\s*(\d+)\s+assertions?,\s*(\d+)\s+failures?(,\s*(\d+)\s+errors)?/)
78
+ if output
79
+ $~[3].to_i + $~[5].to_i > 0 ? growl_fail(output) : growl_pass(output)
80
+ end
81
+ else
82
+ output = results.slice(/(\d+)\s+examples?,\s*(\d+)\s+failures?(,\s*(\d+)\s+not implemented)?/)
83
+ if output
84
+ $~[2].to_i > 0 ? growl_fail(output) : growl_pass(output)
85
+ end
86
+ end
87
+ # TODO Generic growl notification for other actions
88
+
89
+ puts "=> done"
90
+ end
91
+
92
+ end
data/script/txt2html ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ GEM_NAME = 'rubydoctest' # what ppl will type to install your gem
4
+ RUBYFORGE_PROJECT = 'rubydoctest'
5
+
6
+ require 'rubygems'
7
+ begin
8
+ require 'newgem'
9
+ require 'rubyforge'
10
+ rescue LoadError
11
+ puts "\n\nGenerating the website requires the newgem RubyGem"
12
+ puts "Install: gem install newgem\n\n"
13
+ exit(1)
14
+ end
15
+ require 'redcloth'
16
+ require 'syntax/convertors/html'
17
+ require 'erb'
18
+ require File.dirname(__FILE__) + "/../lib/#{GEM_NAME}/version.rb"
19
+
20
+ version = Rubydoctest::VERSION::STRING
21
+ download = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
22
+
23
+ def rubyforge_project_id
24
+ RubyForge.new.autoconfig["group_ids"][RUBYFORGE_PROJECT]
25
+ end
26
+
27
+ class Fixnum
28
+ def ordinal
29
+ # teens
30
+ return 'th' if (10..19).include?(self % 100)
31
+ # others
32
+ case self % 10
33
+ when 1: return 'st'
34
+ when 2: return 'nd'
35
+ when 3: return 'rd'
36
+ else return 'th'
37
+ end
38
+ end
39
+ end
40
+
41
+ class Time
42
+ def pretty
43
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
44
+ end
45
+ end
46
+
47
+ def convert_syntax(syntax, source)
48
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
49
+ end
50
+
51
+ if ARGV.length >= 1
52
+ src, template = ARGV
53
+ template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb')
54
+ else
55
+ puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html")
56
+ exit!
57
+ end
58
+
59
+ template = ERB.new(File.open(template).read)
60
+
61
+ title = nil
62
+ body = nil
63
+ File.open(src) do |fsrc|
64
+ title_text = fsrc.readline
65
+ body_text_template = fsrc.read
66
+ body_text = ERB.new(body_text_template).result(binding)
67
+ syntax_items = []
68
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
69
+ ident = syntax_items.length
70
+ element, syntax, source = $1, $2, $3
71
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
72
+ "syntax-temp-#{ident}"
73
+ }
74
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
75
+ body = RedCloth.new(body_text).to_html
76
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
77
+ end
78
+ stat = File.stat(src)
79
+ created = stat.ctime
80
+ modified = stat.mtime
81
+
82
+ $stdout << template.result(binding)