sinatra-base 1.0 → 1.4.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.
Files changed (101) hide show
  1. data/.yardopts +4 -0
  2. data/AUTHORS +15 -0
  3. data/CHANGES +524 -1
  4. data/Gemfile +82 -0
  5. data/LICENSE +1 -1
  6. data/README.de.rdoc +2093 -0
  7. data/README.es.rdoc +2091 -0
  8. data/README.fr.rdoc +2116 -0
  9. data/README.hu.rdoc +607 -0
  10. data/README.jp.rdoc +514 -23
  11. data/README.pt-br.rdoc +647 -0
  12. data/README.pt-pt.rdoc +646 -0
  13. data/README.rdoc +1580 -205
  14. data/README.ru.rdoc +2015 -0
  15. data/README.zh.rdoc +1816 -0
  16. data/Rakefile +110 -44
  17. data/examples/chat.rb +61 -0
  18. data/examples/simple.rb +3 -0
  19. data/examples/stream.ru +26 -0
  20. data/lib/sinatra.rb +0 -3
  21. data/lib/sinatra/base.rb +923 -393
  22. data/lib/sinatra/main.rb +9 -7
  23. data/lib/sinatra/showexceptions.rb +37 -4
  24. data/lib/sinatra/version.rb +3 -0
  25. data/sinatra-base.gemspec +15 -91
  26. data/test/base_test.rb +2 -2
  27. data/test/builder_test.rb +32 -2
  28. data/test/coffee_test.rb +92 -0
  29. data/test/contest.rb +62 -28
  30. data/test/creole_test.rb +65 -0
  31. data/test/delegator_test.rb +162 -0
  32. data/test/encoding_test.rb +20 -0
  33. data/test/erb_test.rb +25 -2
  34. data/test/extensions_test.rb +1 -1
  35. data/test/filter_test.rb +226 -8
  36. data/test/haml_test.rb +8 -2
  37. data/test/helper.rb +47 -0
  38. data/test/helpers_test.rb +1287 -80
  39. data/test/integration/app.rb +62 -0
  40. data/test/integration_helper.rb +208 -0
  41. data/test/integration_test.rb +82 -0
  42. data/test/less_test.rb +36 -6
  43. data/test/liquid_test.rb +59 -0
  44. data/test/mapped_error_test.rb +84 -7
  45. data/test/markaby_test.rb +80 -0
  46. data/test/markdown_test.rb +81 -0
  47. data/test/middleware_test.rb +1 -1
  48. data/test/nokogiri_test.rb +69 -0
  49. data/test/rack_test.rb +45 -0
  50. data/test/radius_test.rb +59 -0
  51. data/test/rdoc_test.rb +66 -0
  52. data/test/readme_test.rb +136 -0
  53. data/test/request_test.rb +13 -1
  54. data/test/response_test.rb +21 -2
  55. data/test/result_test.rb +5 -5
  56. data/test/route_added_hook_test.rb +1 -1
  57. data/test/routing_test.rb +328 -13
  58. data/test/sass_test.rb +48 -18
  59. data/test/scss_test.rb +88 -0
  60. data/test/server_test.rb +4 -3
  61. data/test/settings_test.rb +191 -21
  62. data/test/sinatra_test.rb +5 -1
  63. data/test/slim_test.rb +88 -0
  64. data/test/static_test.rb +89 -5
  65. data/test/streaming_test.rb +140 -0
  66. data/test/templates_test.rb +143 -4
  67. data/test/textile_test.rb +65 -0
  68. data/test/views/a/in_a.str +1 -0
  69. data/test/views/ascii.erb +2 -0
  70. data/test/views/b/in_b.str +1 -0
  71. data/test/views/calc.html.erb +1 -0
  72. data/test/views/explicitly_nested.str +1 -0
  73. data/test/views/hello.coffee +1 -0
  74. data/test/views/hello.creole +1 -0
  75. data/test/views/hello.liquid +1 -0
  76. data/test/views/hello.mab +1 -0
  77. data/test/views/hello.md +1 -0
  78. data/test/views/hello.nokogiri +1 -0
  79. data/test/views/hello.radius +1 -0
  80. data/test/views/hello.rdoc +1 -0
  81. data/test/views/hello.sass +1 -1
  82. data/test/views/hello.scss +3 -0
  83. data/test/views/hello.slim +1 -0
  84. data/test/views/hello.str +1 -0
  85. data/test/views/hello.textile +1 -0
  86. data/test/views/hello.yajl +1 -0
  87. data/test/views/layout2.liquid +2 -0
  88. data/test/views/layout2.mab +2 -0
  89. data/test/views/layout2.nokogiri +3 -0
  90. data/test/views/layout2.radius +2 -0
  91. data/test/views/layout2.slim +3 -0
  92. data/test/views/layout2.str +2 -0
  93. data/test/views/nested.str +1 -0
  94. data/test/views/utf8.erb +2 -0
  95. data/test/yajl_test.rb +80 -0
  96. metadata +126 -91
  97. data/lib/sinatra/tilt.rb +0 -746
  98. data/test/erubis_test.rb +0 -82
  99. data/test/views/error.erubis +0 -3
  100. data/test/views/hello.erubis +0 -1
  101. data/test/views/layout2.erubis +0 -2
@@ -8,16 +8,16 @@ module Sinatra
8
8
  # on this path by default.
9
9
  set :app_file, caller_files.first || $0
10
10
 
11
- set :run, Proc.new { $0 == app_file }
11
+ set :run, Proc.new { File.expand_path($0) == File.expand_path(app_file) }
12
12
 
13
13
  if run? && ARGV.any?
14
14
  require 'optparse'
15
15
  OptionParser.new { |op|
16
- op.on('-x') { set :lock, true }
17
- op.on('-e env') { |val| set :environment, val.to_sym }
18
- op.on('-s server') { |val| set :server, val }
19
- op.on('-p port') { |val| set :port, val.to_i }
20
- op.on('-o addr') { |val| set :bind, val }
16
+ op.on('-p port', 'set the port (default is 4567)') { |val| set :port, Integer(val) }
17
+ op.on('-o addr', 'set the host (default is 0.0.0.0)') { |val| set :bind, val }
18
+ op.on('-e env', 'set the environment (default is development)') { |val| set :environment, val.to_sym }
19
+ op.on('-s server', 'specify rack server/handler (default is thin)') { |val| set :server, val }
20
+ op.on('-x', 'turn on the mutex lock (default is off)') { set :lock, true }
21
21
  }.parse!(ARGV.dup)
22
22
  end
23
23
  end
@@ -25,4 +25,6 @@ module Sinatra
25
25
  at_exit { Application.run! if $!.nil? && Application.run? }
26
26
  end
27
27
 
28
- include Sinatra::Delegator
28
+ # include would include the module in Object
29
+ # extend only extends the `main` object
30
+ extend Sinatra::Delegator
@@ -1,12 +1,45 @@
1
1
  require 'rack/showexceptions'
2
2
 
3
3
  module Sinatra
4
+ # Sinatra::ShowExceptions catches all exceptions raised from the app it
5
+ # wraps. It shows a useful backtrace with the sourcefile and clickable
6
+ # context, the whole Rack environment and the request data.
7
+ #
8
+ # Be careful when you use this on public-facing sites as it could reveal
9
+ # information helpful to attackers.
4
10
  class ShowExceptions < Rack::ShowExceptions
11
+ @@eats_errors = Object.new
12
+ def @@eats_errors.flush(*) end
13
+ def @@eats_errors.puts(*) end
14
+
5
15
  def initialize(app)
6
16
  @app = app
7
17
  @template = ERB.new(TEMPLATE)
8
18
  end
9
19
 
20
+ def call(env)
21
+ @app.call(env)
22
+ rescue Exception => e
23
+ errors, env["rack.errors"] = env["rack.errors"], @@eats_errors
24
+
25
+ if respond_to?(:prefers_plain_text?) and prefers_plain_text?(env)
26
+ content_type = "text/plain"
27
+ body = [dump_exception(e)]
28
+ else
29
+ content_type = "text/html"
30
+ body = pretty(env, e)
31
+ end
32
+
33
+ env["rack.errors"] = errors
34
+
35
+ [500,
36
+ {"Content-Type" => content_type,
37
+ "Content-Length" => Rack::Utils.bytesize(body.join).to_s},
38
+ body]
39
+ end
40
+
41
+ private
42
+
10
43
  def frame_class(frame)
11
44
  if frame.filename =~ /lib\/sinatra.*\.rb/
12
45
  "framework"
@@ -18,7 +51,7 @@ module Sinatra
18
51
  end
19
52
  end
20
53
 
21
- TEMPLATE = <<HTML
54
+ TEMPLATE = <<-HTML # :nodoc:
22
55
  <!DOCTYPE html>
23
56
  <html>
24
57
  <head>
@@ -141,7 +174,7 @@ TEMPLATE = <<HTML
141
174
  <body>
142
175
  <div id="wrap">
143
176
  <div id="header">
144
- <img src="/__sinatra__/500.png" alt="application error" height="161" width="313" />
177
+ <img src="<%= env['SCRIPT_NAME'] %>/__sinatra__/500.png" alt="application error" height="161" width="313" />
145
178
  <div id="summary">
146
179
  <h1><strong><%=h exception.class %></strong> at <strong><%=h path %>
147
180
  </strong></h1>
@@ -219,7 +252,7 @@ TEMPLATE = <<HTML
219
252
 
220
253
  <div id="get">
221
254
  <h3 id="get-info">GET</h3>
222
- <% unless req.GET.empty? %>
255
+ <% if req.GET and not req.GET.empty? %>
223
256
  <table class="req">
224
257
  <tr>
225
258
  <th>Variable</th>
@@ -240,7 +273,7 @@ TEMPLATE = <<HTML
240
273
 
241
274
  <div id="post">
242
275
  <h3 id="post-info">POST</h3>
243
- <% unless req.POST.empty? %>
276
+ <% if req.POST and not req.POST.empty? %>
244
277
  <table class="req">
245
278
  <tr>
246
279
  <th>Variable</th>
@@ -0,0 +1,3 @@
1
+ module Sinatra
2
+ VERSION = '1.4.0'
3
+ end
@@ -1,94 +1,18 @@
1
- Gem::Specification.new do |s|
2
- s.specification_version = 2 if s.respond_to? :specification_version=
3
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
2
+ require 'sinatra/version'
4
3
 
5
- s.name = 'sinatra-base'
6
- s.version = '1.0'
7
- s.date = '2010-03-23'
4
+ Gem::Specification.new 'sinatra-base', Sinatra::VERSION do |s|
5
+ s.description = "Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort."
6
+ s.summary = "Classy web-development dressed in a DSL"
7
+ s.authors = ["Blake Mizerany", "Ryan Tomayko", "Simon Rozet", "Konstantin Haase"]
8
+ s.email = "sinatrarb@googlegroups.com"
9
+ s.homepage = "http://www.sinatrarb.com/"
10
+ s.files = `git ls-files`.split("\n") - %w[.gitignore .travis.yml]
11
+ s.test_files = s.files.select { |p| p =~ /^test\/.*_test.rb/ }
12
+ s.extra_rdoc_files = s.files.select { |p| p =~ /^README/ } << 'LICENSE'
13
+ s.rdoc_options = %w[--line-numbers --inline-source --title Sinatra --main README.rdoc]
8
14
 
9
- s.description = "Classy web-development dressed in a DSL"
10
- s.summary = "Classy web-development dressed in a DSL"
11
-
12
- s.authors = ["Blake Mizerany", "Ryan Tomayko", "Simon Rozet"]
13
- s.email = "sinatrarb@googlegroups.com"
14
-
15
- # = MANIFEST =
16
- s.files = %w[
17
- AUTHORS
18
- CHANGES
19
- LICENSE
20
- README.jp.rdoc
21
- README.rdoc
22
- Rakefile
23
- lib/sinatra.rb
24
- lib/sinatra/base.rb
25
- lib/sinatra/images/404.png
26
- lib/sinatra/images/500.png
27
- lib/sinatra/main.rb
28
- lib/sinatra/showexceptions.rb
29
- lib/sinatra/tilt.rb
30
- sinatra-base.gemspec
31
- test/base_test.rb
32
- test/builder_test.rb
33
- test/contest.rb
34
- test/erb_test.rb
35
- test/erubis_test.rb
36
- test/extensions_test.rb
37
- test/filter_test.rb
38
- test/haml_test.rb
39
- test/helper.rb
40
- test/helpers_test.rb
41
- test/less_test.rb
42
- test/mapped_error_test.rb
43
- test/middleware_test.rb
44
- test/public/favicon.ico
45
- test/request_test.rb
46
- test/response_test.rb
47
- test/result_test.rb
48
- test/route_added_hook_test.rb
49
- test/routing_test.rb
50
- test/sass_test.rb
51
- test/server_test.rb
52
- test/settings_test.rb
53
- test/sinatra_test.rb
54
- test/static_test.rb
55
- test/templates_test.rb
56
- test/views/error.builder
57
- test/views/error.erb
58
- test/views/error.erubis
59
- test/views/error.haml
60
- test/views/error.sass
61
- test/views/foo/hello.test
62
- test/views/hello.builder
63
- test/views/hello.erb
64
- test/views/hello.erubis
65
- test/views/hello.haml
66
- test/views/hello.less
67
- test/views/hello.sass
68
- test/views/hello.test
69
- test/views/layout2.builder
70
- test/views/layout2.erb
71
- test/views/layout2.erubis
72
- test/views/layout2.haml
73
- test/views/layout2.test
74
- ]
75
- # = MANIFEST =
76
-
77
- s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/}
78
-
79
- s.extra_rdoc_files = %w[README.rdoc LICENSE]
80
- s.add_dependency 'rack', '>= 1.0'
81
- s.add_development_dependency 'shotgun', '>= 0.6', '< 1.0'
82
- s.add_development_dependency 'rack-test', '>= 0.3.0'
83
- s.add_development_dependency 'haml'
84
- s.add_development_dependency 'builder'
85
- s.add_development_dependency 'erubis'
86
- s.add_development_dependency 'less'
87
-
88
- s.has_rdoc = true
89
- s.homepage = "http://sinatra.rubyforge.org"
90
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Sinatra", "--main", "README.rdoc"]
91
- s.require_paths = %w[lib]
92
- s.rubyforge_project = 'sinatra'
93
- s.rubygems_version = '1.1.1'
15
+ s.add_dependency 'rack', '~> 1.3', '>= 1.3.6'
16
+ s.add_dependency 'rack-protection', '~> 1.2'
17
+ s.add_dependency 'tilt', '~> 1.3', '>= 1.3.3'
94
18
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/helper'
1
+ require File.expand_path('../helper', __FILE__)
2
2
 
3
3
  class BaseTest < Test::Unit::TestCase
4
4
  def test_default
@@ -71,7 +71,7 @@ class BaseTest < Test::Unit::TestCase
71
71
  end
72
72
 
73
73
  it 'exposes the downstream app' do
74
- middleware = TestMiddleware.new(app)
74
+ middleware = TestMiddleware.new!(app)
75
75
  assert_same app, middleware.app
76
76
  end
77
77
 
@@ -1,10 +1,13 @@
1
- require File.dirname(__FILE__) + '/helper'
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
2
4
  require 'builder'
3
5
 
4
6
  class BuilderTest < Test::Unit::TestCase
5
- def builder_app(&block)
7
+ def builder_app(options = {}, &block)
6
8
  mock_app {
7
9
  set :views, File.dirname(__FILE__) + '/views'
10
+ set options
8
11
  get '/', &block
9
12
  }
10
13
  get '/'
@@ -16,6 +19,29 @@ class BuilderTest < Test::Unit::TestCase
16
19
  assert_equal %{<?xml version="1.0" encoding="UTF-8"?>\n}, body
17
20
  end
18
21
 
22
+ it 'defaults content type to xml' do
23
+ builder_app { builder 'xml.instruct!' }
24
+ assert ok?
25
+ assert_equal "application/xml;charset=utf-8", response['Content-Type']
26
+ end
27
+
28
+ it 'defaults allows setting content type per route' do
29
+ builder_app do
30
+ content_type :html
31
+ builder 'xml.instruct!'
32
+ end
33
+ assert ok?
34
+ assert_equal "text/html;charset=utf-8", response['Content-Type']
35
+ end
36
+
37
+ it 'defaults allows setting content type globally' do
38
+ builder_app(:builder => { :content_type => 'html' }) do
39
+ builder 'xml.instruct!'
40
+ end
41
+ assert ok?
42
+ assert_equal "text/html;charset=utf-8", response['Content-Type']
43
+ end
44
+
19
45
  it 'renders inline blocks' do
20
46
  builder_app {
21
47
  @name = "Frank & Mary"
@@ -63,3 +89,7 @@ class BuilderTest < Test::Unit::TestCase
63
89
  assert_raise(Errno::ENOENT) { get('/') }
64
90
  end
65
91
  end
92
+
93
+ rescue LoadError
94
+ warn "#{$!.to_s}: skipping builder tests"
95
+ end
@@ -0,0 +1,92 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
4
+ require 'coffee-script'
5
+ require 'execjs'
6
+
7
+ begin
8
+ ExecJS.compile '1'
9
+ rescue Exception
10
+ raise LoadError, 'unable to execute JavaScript'
11
+ end
12
+
13
+ class CoffeeTest < Test::Unit::TestCase
14
+ def coffee_app(options = {}, &block)
15
+ mock_app {
16
+ set :views, File.dirname(__FILE__) + '/views'
17
+ set(options)
18
+ get '/', &block
19
+ }
20
+ get '/'
21
+ end
22
+
23
+ it 'renders inline Coffee strings' do
24
+ coffee_app { coffee "alert 'Aye!'\n" }
25
+ assert ok?
26
+ assert body.include?("alert('Aye!');")
27
+ end
28
+
29
+ it 'defaults content type to javascript' do
30
+ coffee_app { coffee "alert 'Aye!'\n" }
31
+ assert ok?
32
+ assert_equal "application/javascript;charset=utf-8", response['Content-Type']
33
+ end
34
+
35
+ it 'defaults allows setting content type per route' do
36
+ coffee_app do
37
+ content_type :html
38
+ coffee "alert 'Aye!'\n"
39
+ end
40
+ assert ok?
41
+ assert_equal "text/html;charset=utf-8", response['Content-Type']
42
+ end
43
+
44
+ it 'defaults allows setting content type globally' do
45
+ coffee_app(:coffee => { :content_type => 'html' }) do
46
+ coffee "alert 'Aye!'\n"
47
+ end
48
+ assert ok?
49
+ assert_equal "text/html;charset=utf-8", response['Content-Type']
50
+ end
51
+
52
+ it 'renders .coffee files in views path' do
53
+ coffee_app { coffee :hello }
54
+ assert ok?
55
+ assert_include body, "alert(\"Aye!\");"
56
+ end
57
+
58
+ it 'ignores the layout option' do
59
+ coffee_app { coffee :hello, :layout => :layout2 }
60
+ assert ok?
61
+ assert_include body, "alert(\"Aye!\");"
62
+ end
63
+
64
+ it "raises error if template not found" do
65
+ mock_app {
66
+ get('/') { coffee :no_such_template }
67
+ }
68
+ assert_raise(Errno::ENOENT) { get('/') }
69
+ end
70
+
71
+ it "passes coffee options to the coffee engine" do
72
+ coffee_app { coffee "alert 'Aye!'\n", :no_wrap => true }
73
+ assert ok?
74
+ assert_body "alert('Aye!');"
75
+ end
76
+
77
+ it "passes default coffee options to the coffee engine" do
78
+ mock_app do
79
+ set :coffee, :no_wrap => true # default coffee style is :nested
80
+ get '/' do
81
+ coffee "alert 'Aye!'\n"
82
+ end
83
+ end
84
+ get '/'
85
+ assert ok?
86
+ assert_body "alert('Aye!');"
87
+ end
88
+ end
89
+
90
+ rescue LoadError
91
+ warn "#{$!.to_s}: skipping coffee tests"
92
+ end
@@ -1,38 +1,67 @@
1
+ # Copyright (c) 2009 Damian Janowski and Michel Martens for Citrusbyte
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
1
20
  require "test/unit"
2
21
 
3
- # Test::Unit loads a default test if the suite is empty, and the only
4
- # purpose of that test is to fail. As having empty contexts is a common
5
- # practice, we decided to overwrite TestSuite#empty? in order to
6
- # allow them. Having a failure when no tests have been defined seems
7
- # counter-intuitive.
22
+ # Test::Unit loads a default test if the suite is empty, whose purpose is to
23
+ # fail. Since having empty contexts is a common practice, we decided to
24
+ # overwrite TestSuite#empty? in order to allow them. Having a failure when no
25
+ # tests have been defined seems counter-intuitive.
8
26
  class Test::Unit::TestSuite
9
- unless method_defined?(:empty?)
10
- def empty?
11
- false
12
- end
27
+ def empty?
28
+ false
13
29
  end
14
30
  end
15
31
 
16
- # We added setup, test and context as class methods, and the instance
17
- # method setup now iterates on the setup blocks. Note that all setup
18
- # blocks must be defined with the block syntax. Adding a setup instance
19
- # method defeats the purpose of this library.
32
+ # Contest adds +teardown+, +test+ and +context+ as class methods, and the
33
+ # instance methods +setup+ and +teardown+ now iterate on the corresponding
34
+ # blocks. Note that all setup and teardown blocks must be defined with the
35
+ # block syntax. Adding setup or teardown instance methods defeats the purpose
36
+ # of this library.
20
37
  class Test::Unit::TestCase
21
- def self.setup(&block)
22
- setup_blocks << block
38
+ def self.setup(&block) setup_blocks << block end
39
+ def self.teardown(&block) teardown_blocks << block end
40
+ def self.setup_blocks() @setup_blocks ||= [] end
41
+ def self.teardown_blocks() @teardown_blocks ||= [] end
42
+
43
+ def setup_blocks(base = self.class)
44
+ setup_blocks base.superclass if base.superclass.respond_to? :setup_blocks
45
+ base.setup_blocks.each do |block|
46
+ instance_eval(&block)
47
+ end
23
48
  end
24
49
 
25
- def setup
26
- self.class.setup_blocks.each do |block|
50
+ def teardown_blocks(base = self.class)
51
+ teardown_blocks base.superclass if base.superclass.respond_to? :teardown_blocks
52
+ base.teardown_blocks.each do |block|
27
53
  instance_eval(&block)
28
54
  end
29
55
  end
30
56
 
31
- def self.context(name, &block)
32
- subclass = Class.new(self.superclass)
33
- subclass.setup_blocks.unshift(*setup_blocks)
34
- subclass.class_eval(&block)
35
- const_set(context_name(name), subclass)
57
+ alias setup setup_blocks
58
+ alias teardown teardown_blocks
59
+
60
+ def self.context(*name, &block)
61
+ subclass = Class.new(self)
62
+ remove_tests(subclass)
63
+ subclass.class_eval(&block) if block_given?
64
+ const_set(context_name(name.join(" ")), subclass)
36
65
  end
37
66
 
38
67
  def self.test(name, &block)
@@ -46,12 +75,10 @@ class Test::Unit::TestCase
46
75
 
47
76
  private
48
77
 
49
- def self.setup_blocks
50
- @setup_blocks ||= []
51
- end
52
-
53
78
  def self.context_name(name)
54
- "Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}".to_sym
79
+ # "Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}".to_sym
80
+ name = "Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}"
81
+ name.tr(" ", "_").to_sym
55
82
  end
56
83
 
57
84
  def self.test_name(name)
@@ -59,6 +86,13 @@ private
59
86
  end
60
87
 
61
88
  def self.sanitize_name(name)
62
- name.gsub(/\W+/, ' ').strip
89
+ # name.gsub(/\W+/, ' ').strip
90
+ name.gsub(/\W+/, ' ')
91
+ end
92
+
93
+ def self.remove_tests(subclass)
94
+ subclass.public_instance_methods.grep(/^test_/).each do |meth|
95
+ subclass.send(:undef_method, meth.to_sym)
96
+ end
63
97
  end
64
98
  end