public
Rubygem
Description: Merb Core: All you need. None you don't.
Homepage: http://www.merbivore.com
Clone URL: git://github.com/wycats/merb-core.git
Search Repo:
Merge git://github.com/techbelly/merb-core

Conflicts:

  spec/public/reloading/reload_spec.rb
ezmobius (author)
Tue May 13 17:46:33 -0700 2008
commit  78ae5652ecce8f6f6bf09e5608f3aa394ab638be
tree    9440c84a14dcd8cd5844e13d37104d1969161904
parent  137889807100ed854a43e663ae2ea33fb2eea6ce parent  354595e4fb785618a487f9d7eefbfbd1b61dff55
...
578
579
580
 
 
 
 
 
 
 
 
 
 
 
 
 
581
582
583
584
585
586
587
588
589
590
591
 
 
592
 
593
594
595
...
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
 
 
 
 
 
 
 
598
599
600
601
602
603
604
0
@@ -578,18 +578,27 @@
0
 
0
 class Merb::BootLoader::ReloadClasses < Merb::BootLoader
0
 
0
+ class TimedExecutor
0
+ def self.every(seconds, &block)
0
+ Thread.abort_on_exception = true
0
+ Thread.new do
0
+ loop do
0
+ sleep( seconds )
0
+ block.call
0
+ end
0
+ Thread.exit
0
+ end
0
+ end
0
+ end
0
+
0
   # Setup the class reloader if it's been specified in config.
0
   def self.run
0
     return unless Merb::Config[:reload_classes]
0
 
0
- Thread.abort_on_exception = true
0
- Thread.new do
0
- loop do
0
- sleep( Merb::Config[:reload_time] || 0.5 )
0
- reload
0
- end
0
- Thread.exit
0
+ TimedExecutor.every(Merb::Config[:reload_time] || 0.5) do
0
+ reload
0
     end
0
+
0
   end
0
 
0
   # Reloads all files.
...
11
12
13
 
 
 
 
 
14
15
...
11
12
13
14
15
16
17
18
19
20
0
@@ -11,6 +11,11 @@
0
     autoload :Runner, "merb-core/rack/adapter/runner"
0
     autoload :Thin, "merb-core/rack/adapter/thin"
0
     autoload :WEBrick, "merb-core/rack/adapter/webrick"
0
+
0
+ autoload :Deferral, "merb-core/rack/apps/deferral"
0
+ autoload :MerbApplication, "merb-core/rack/apps/merb_application"
0
+ autoload :PathPrefix, "merb-core/rack/apps/path_prefix"
0
+ autoload :Static, "merb-core/rack/apps/static"
0
   end # Rack
0
 end # Merb
...
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
3
4
5
 
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
 
 
 
 
 
 
 
 
 
91
92
93
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
26
27
28
29
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
32
33
34
35
36
37
38
39
40
41
 
42
0
@@ -1,94 +1,43 @@
0
 module Merb
0
+ module Rack
0
+ class AbstractMiddleware
0
+
0
+ def initialize(app)
0
+ @app = app
0
+ end
0
+
0
+ def deferred?(env)
0
+ @app.deferred?(env)
0
+ end
0
+
0
+ def call(env)
0
+ @app.call(env)
0
+ end
0
+
0
+ end
0
+ end
0
+end
0
+
0
+
0
+module Merb
0
   
0
   module Rack
0
 
0
- class Application
0
+ class Application < Merb::Rack::AbstractMiddleware
0
       # ==== Parameters
0
       # options<Hash>::
0
       # Options for creating a new application. Currently ignored.
0
       def initialize(options={})
0
- @static_server = ::Rack::File.new Merb.dir_for(:public)
0
- if prefix = ::Merb::Config[:path_prefix]
0
- @path_prefix = /^#{Regexp.escape(prefix)}/
0
- end
0
- end
0
-
0
- # ==== Parameters
0
- # env<Hash>:: Environment variables to pass on to the application.
0
- #
0
- # ==== Returns
0
- # true or false::
0
- def deferred?(env)
0
- strip_path_prefix(env) if @path_prefix # Strip out the path_prefix if one was set
0
- path = env['PATH_INFO'] ? env['PATH_INFO'].chomp('/') : ""
0
- if path =~ Merb.deferred_actions
0
- Merb.logger.info! "Deferring Request: #{path}"
0
- true
0
- else
0
- false
0
- end
0
- end
0
-
0
- # ==== Parameters
0
- # env<Hash>:: Environment variables to pass on to the application.
0
- #
0
- # ==== Returns
0
- # Array[Array]::
0
- # A 3 element tuple consisting of response status, headers and body.
0
- def call(env)
0
- strip_path_prefix(env) if @path_prefix # Strip out the path_prefix if one was set
0
- path = env['PATH_INFO'] ? env['PATH_INFO'].chomp('/') : ""
0
- cached_path = (path.empty? ? 'index' : path) + '.html'
0
- Merb.logger.info "Request: #{path}"
0
- if file_exist?(path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the file if it's there and the request method is GET or HEAD
0
- serve_static(env)
0
- elsif file_exist?(cached_path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the page cache if it's there and the request method is GET or HEAD
0
- env['PATH_INFO'] = cached_path
0
- serve_static(env)
0
- else # No static file, let Merb handle it
0
- if path =~ /favicon\.ico/
0
- return [404, {"Content-Type"=>"text/html"}, "404 Not Found."]
0
- end
0
- begin
0
- controller = ::Merb::Dispatcher.handle(env)
0
- rescue Object => e
0
- return [500, {"Content-Type"=>"text/html"}, e.message + "<br/>" + e.backtrace.join("<br/>")]
0
- end
0
- Merb.logger.info "\n\n"
0
- Merb.logger.flush
0
- [controller.status, controller.headers, controller.body]
0
- end
0
- end
0
-
0
- # ==== Parameters
0
- # path<String>:: The path to the file relative to the server root.
0
- #
0
- # ==== Returns
0
- # Boolean:: True if file exists under the server root and is readable.
0
- def file_exist?(path)
0
- full_path = ::File.join(@static_server.root, ::Merb::Request.unescape(path))
0
- ::File.file?(full_path) && ::File.readable?(full_path)
0
- end
0
-
0
- # ==== Parameters
0
- # env<Hash>:: Environment variables to pass on to the server.
0
- def serve_static(env)
0
- env["PATH_INFO"] = ::Merb::Request.unescape(env["PATH_INFO"])
0
- @static_server.call(env)
0
- end
0
-
0
- # ==== Parameters
0
- # env<Hash>:: Environment variables to pass on to the server.
0
- def strip_path_prefix(env)
0
- ['PATH_INFO', 'REQUEST_URI'].each do |path_key|
0
- if env[path_key] =~ @path_prefix
0
- env[path_key].sub!(@path_prefix, '')
0
- env[path_key] = '/' if env[path_key].empty?
0
- end
0
- end
0
- end
0
-
0
+ @app = ::Rack::Builder.new {
0
+ if prefix = ::Merb::Config[:path_prefix]
0
+ use Merb::Rack::PathPrefix, prefix
0
+ end
0
+ use Merb::Rack::Deferral
0
+ use Merb::Rack::Static, Merb.dir_for(:public)
0
+ run Merb::Rack::MerbApplication.new
0
+ }.to_app
0
+ end
0
     end
0
   end
0
-end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0
@@ -1 +1,18 @@
0
+module Merb
0
+ module Rack
0
+ class Deferral < Merb::Rack::AbstractMiddleware
0
+
0
+ def deferred?(env)
0
+ path = env['PATH_INFO'] ? env['PATH_INFO'].chomp('/') : ""
0
+ if path =~ Merb.deferred_actions
0
+ Merb.logger.info! "Deferring Request: #{path}"
0
+ true
0
+ else
0
+ false
0
+ end
0
+ end
0
+
0
+ end
0
+ end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0
@@ -1 +1,19 @@
0
+module Merb
0
+ module Rack
0
+ class MerbApplication
0
+
0
+ def call(env)
0
+ begin
0
+ controller = ::Merb::Dispatcher.handle(env)
0
+ rescue Object => e
0
+ return [500, {"Content-Type"=>"text/html"}, e.message + "<br/>" + e.backtrace.join("<br/>")]
0
+ end
0
+ Merb.logger.info "\n\n"
0
+ Merb.logger.flush
0
+ [controller.status, controller.headers, controller.body]
0
+ end
0
+
0
+ end
0
+ end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
0
@@ -1 +1,32 @@
0
+module Merb
0
+ module Rack
0
+ class PathPrefix < Merb::Rack::AbstractMiddleware
0
+
0
+ def initialize(app, path_prefix = nil)
0
+ super(app)
0
+ @path_prefix = /^#{Regexp.escape(path_prefix)}/
0
+ end
0
+
0
+ def deferred?(env)
0
+ strip_path_prefix(env)
0
+ @app.deferred?(env)
0
+ end
0
+
0
+ def call(env)
0
+ strip_path_prefix(env)
0
+ @app.call(env)
0
+ end
0
+
0
+ def strip_path_prefix(env)
0
+ ['PATH_INFO', 'REQUEST_URI'].each do |path_key|
0
+ if env[path_key] =~ @path_prefix
0
+ env[path_key].sub!(@path_prefix, '')
0
+ env[path_key] = '/' if env[path_key].empty?
0
+ end
0
+ end
0
+ end
0
+
0
+ end
0
+ end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
0
@@ -1 +1,46 @@
0
+module Merb
0
+ module Rack
0
+ class Static < Merb::Rack::AbstractMiddleware
0
+
0
+ def initialize(app,directory)
0
+ super(app)
0
+ @static_server = ::Rack::File.new directory
0
+ end
0
+
0
+ def call(env)
0
+ path = env['PATH_INFO'] ? env['PATH_INFO'].chomp('/') : ""
0
+ cached_path = (path.empty? ? 'index' : path) + '.html'
0
+
0
+ if file_exist?(path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the file if it's there and the request method is GET or HEAD
0
+ serve_static(env)
0
+ elsif file_exist?(cached_path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the page cache if it's there and the request method is GET or HEAD
0
+ env['PATH_INFO'] = cached_path
0
+ serve_static(env)
0
+ elsif path =~ /favicon\.ico/
0
+ return [404, {"Content-Type"=>"text/html"}, "404 Not Found."]
0
+ else
0
+ @app.call(env)
0
+ end
0
+ end
0
+
0
+ # ==== Parameters
0
+ # path<String>:: The path to the file relative to the server root.
0
+ #
0
+ # ==== Returns
0
+ # Boolean:: True if file exists under the server root and is readable.
0
+ def file_exist?(path)
0
+ full_path = ::File.join(@static_server.root, ::Merb::Request.unescape(path))
0
+ ::File.file?(full_path) && ::File.readable?(full_path)
0
+ end
0
+
0
+ # ==== Parameters
0
+ # env<Hash>:: Environment variables to pass on to the server.
0
+ def serve_static(env)
0
+ env["PATH_INFO"] = ::Merb::Request.unescape(env["PATH_INFO"])
0
+ @static_server.call(env)
0
+ end
0
+
0
+ end
0
+ end
0
+end
...
1
 
 
 
 
 
 
 
 
 
 
 
 
 
2
3
4
5
6
7
8
9
 
 
 
 
 
 
 
 
 
 
 
 
10
 
 
11
 
 
12
13
14
15
 
16
17
18
19
...
20
21
22
23
24
 
 
 
25
26
 
 
 
 
 
 
27
28
29
30
31
32
...
31
32
33
34
 
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 
 
 
49
50
51
52
53
54
55
56
 
 
57
58
59
60
...
61
62
63
64
 
 
65
66
67
68
69
70
...
73
74
75
76
77
78
79
 
 
80
81
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
 
 
 
 
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 
 
38
39
40
41
42
...
43
44
45
 
 
46
47
48
49
 
50
51
52
53
54
55
56
57
58
59
60
61
...
60
61
62
 
63
64
 
 
 
65
66
67
68
69
70
 
 
 
 
71
72
73
74
75
76
77
78
79
 
 
80
81
82
83
84
85
...
86
87
88
 
89
90
91
 
 
92
93
94
...
97
98
99
 
 
 
 
100
101
102
103
0
@@ -1,18 +1,41 @@
0
 require File.join(File.dirname(__FILE__), "..", "..", "spec_helper")
0
+
0
+class MockTimedExecutor
0
+ def self.every(seconds, &block)
0
+ @@scheduled_action = block
0
+ end
0
+ def self.run_task
0
+ @@scheduled_action.call
0
+ end
0
+end
0
+
0
+RealTimedExecutor = Merb::BootLoader::ReloadClasses::TimedExecutor
0
+Merb::BootLoader::ReloadClasses::TimedExecutor = MockTimedExecutor
0
+
0
 Merb.start :environment => 'test',
0
            :merb_root => File.dirname(__FILE__) / "directory"
0
 
0
-describe "The reloader" do
0
- SLEEP_TIME = 1
0
-
0
- def reload!
0
- Merb::BootLoader::ReloadClasses.reload
0
+describe "TimedExecutor" do
0
+ it "should call a block of code repeatedly in the background" do
0
+ list_of_things = []
0
+
0
+ RealTimedExecutor.every(0.1) do
0
+ list_of_things << "Something"
0
+ end
0
+
0
+ sleep 0.5
0
+
0
+ list_of_things.should_not be_empty
0
+ list_of_things.size.should > 1
0
   end
0
+
0
+end
0
 
0
+describe "The reloader" do
0
+
0
   before :all do
0
     @reload_file = File.dirname(__FILE__) / "directory" / "app" / "controllers" / "reload.rb"
0
- File.open(@reload_file, "w") do |f|
0
- @text = <<-END
0
+ @text = <<-END
0
 
0
         class Reloader < Application
0
         end
0
0
@@ -20,10 +43,16 @@
0
         class Hello < Application
0
         end
0
       END
0
- f.puts @text
0
- end
0
+ update_file @text
0
+ MockTimedExecutor.run_task
0
+ end
0
 
0
- sleep SLEEP_TIME
0
+ def update_file(contents)
0
+ mtime = File.mtime(@reload_file)
0
+ f = File.open(@reload_file, "w") do |f|
0
+ f.puts contents
0
+ end
0
+ FileUtils.touch(@reload_file, :mtime => mtime + 30)
0
   end
0
 
0
   it "should reload files that were changed" do
0
0
0
0
@@ -31,29 +60,25 @@
0
     defined?(Reloader).should_not be_nil
0
     defined?(Reloader2).should be_nil
0
 
0
- sleep SLEEP_TIME
0
+ update_file <<-END
0
 
0
- File.open(@reload_file, "w") do |f|
0
- f.puts <<-END
0
-
0
         class Reloader < Application
0
         end
0
 
0
         class Reloader2
0
         end
0
       END
0
- end
0
-
0
- sleep SLEEP_TIME
0
-
0
+
0
+ MockTimedExecutor.run_task
0
+
0
     defined?(Hello).should be_nil
0
     defined?(Reloader).should_not be_nil
0
     defined?(Reloader2).should_not be_nil
0
   end
0
 
0
   it "should remove classes for _abstract_subclasses" do
0
- File.open(@reload_file, "w") do |f|
0
- f.puts <<-END
0
+
0
+ update_file <<-END
0
 
0
         class Reloader < Application
0
         end
0
0
@@ -61,10 +86,9 @@
0
         class Reloader2 < Application
0
         end
0
       END
0
- end
0
+
0
+ MockTimedExecutor.run_task
0
 
0
- sleep SLEEP_TIME
0
-
0
     Merb::AbstractController._abstract_subclasses.should include("Reloader")
0
     Merb::AbstractController._abstract_subclasses.should include("Reloader2")
0
     defined?(Hello).should be_nil
0
@@ -73,10 +97,8 @@
0
   end
0
 
0
   after :each do
0
- sleep SLEEP_TIME
0
- File.open(@reload_file, "w") do |f|
0
- f.puts @text
0
- end
0
+ update_file @text
0
+ MockTimedExecutor.run_task
0
   end
0
 end

Comments

    No one has commented yet.