merb 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README +64 -80
- data/Rakefile +25 -12
- data/bin/merb +2 -223
- data/examples/README_EXAMPLES +10 -0
- data/examples/skeleton.tar +0 -0
- data/lib/merb.rb +48 -21
- data/lib/merb/core_ext.rb +12 -2
- data/lib/merb/core_ext/merb_class.rb +21 -21
- data/lib/merb/core_ext/merb_kernel.rb +60 -0
- data/lib/merb/core_ext/merb_object.rb +14 -0
- data/lib/merb/core_ext/merb_string.rb +3 -13
- data/lib/merb/generators/merb_app/merb_app.rb +33 -0
- data/lib/merb/merb_constants.rb +7 -0
- data/lib/merb/merb_controller.rb +31 -23
- data/lib/merb/merb_drb_server.rb +6 -60
- data/lib/merb/merb_exceptions.rb +162 -2
- data/lib/merb/merb_handler.rb +8 -19
- data/lib/merb/merb_mailer.rb +60 -0
- data/lib/merb/merb_router.rb +1 -1
- data/lib/merb/merb_server.rb +240 -0
- data/lib/merb/merb_upload_handler.rb +1 -1
- data/lib/merb/merb_view_context.rb +11 -6
- data/lib/merb/mixins/basic_authentication_mixin.rb +11 -13
- data/lib/merb/mixins/controller_mixin.rb +12 -6
- data/lib/merb/mixins/form_control_mixin.rb +94 -0
- data/lib/merb/mixins/render_mixin.rb +50 -24
- data/lib/merb/mixins/view_context_mixin.rb +122 -0
- data/lib/merb/session/merb_ar_session.rb +13 -14
- data/lib/merb/session/merb_memory_session.rb +105 -0
- metadata +13 -132
- data/examples/app_skeleton/Rakefile +0 -82
- data/examples/app_skeleton/dist/app/helpers/global_helper.rb +0 -6
- data/examples/app_skeleton/dist/conf/merb.yml +0 -11
- data/examples/app_skeleton/dist/conf/merb_init.rb +0 -16
- data/examples/app_skeleton/dist/conf/mup.conf +0 -5
- data/examples/app_skeleton/dist/conf/router.rb +0 -19
- data/examples/app_skeleton/scripts/merb_stop +0 -13
- data/examples/app_skeleton/scripts/new_migration +0 -21
- data/examples/app_skeleton/test/test_helper.rb +0 -1
- data/examples/sample_app/Rakefile +0 -82
- data/examples/sample_app/dist/app/controllers/files.rb +0 -31
- data/examples/sample_app/dist/app/controllers/posts.rb +0 -71
- data/examples/sample_app/dist/app/controllers/test.rb +0 -40
- data/examples/sample_app/dist/app/helpers/global_helper.rb +0 -7
- data/examples/sample_app/dist/app/helpers/posts_helper.rb +0 -4
- data/examples/sample_app/dist/app/models/comment.rb +0 -3
- data/examples/sample_app/dist/app/models/post.rb +0 -4
- data/examples/sample_app/dist/app/views/files/progress.jerb +0 -3
- data/examples/sample_app/dist/app/views/files/start.herb +0 -62
- data/examples/sample_app/dist/app/views/files/upload.herb +0 -6
- data/examples/sample_app/dist/app/views/layout/application.herb +0 -61
- data/examples/sample_app/dist/app/views/layout/foo.herb +0 -6
- data/examples/sample_app/dist/app/views/posts/_comments.herb +0 -11
- data/examples/sample_app/dist/app/views/posts/comment.jerb +0 -1
- data/examples/sample_app/dist/app/views/posts/list.herb +0 -5
- data/examples/sample_app/dist/app/views/posts/new.herb +0 -37
- data/examples/sample_app/dist/app/views/posts/show.herb +0 -37
- data/examples/sample_app/dist/app/views/posts/xml_test.xerb +0 -3
- data/examples/sample_app/dist/app/views/shared/_test.herb +0 -1
- data/examples/sample_app/dist/app/views/test/foo.herb +0 -2
- data/examples/sample_app/dist/app/views/test/hello.herb +0 -5
- data/examples/sample_app/dist/app/views/test/json.jerb +0 -1
- data/examples/sample_app/dist/conf/merb.yml +0 -11
- data/examples/sample_app/dist/conf/merb_init.rb +0 -24
- data/examples/sample_app/dist/conf/mup.conf +0 -5
- data/examples/sample_app/dist/conf/router.rb +0 -19
- data/examples/sample_app/dist/public/images/bg.jpg +0 -0
- data/examples/sample_app/dist/public/images/book.gif +0 -0
- data/examples/sample_app/dist/public/images/booksmall.gif +0 -0
- data/examples/sample_app/dist/public/images/greenright.jpg +0 -0
- data/examples/sample_app/dist/public/images/louiecon.gif +0 -0
- data/examples/sample_app/dist/public/images/menu.gif +0 -0
- data/examples/sample_app/dist/public/images/menuleft.gif +0 -0
- data/examples/sample_app/dist/public/images/menuright.gif +0 -0
- data/examples/sample_app/dist/public/images/mountain.jpg +0 -0
- data/examples/sample_app/dist/public/images/n3.jpg +0 -0
- data/examples/sample_app/dist/public/images/nautica.jpg +0 -0
- data/examples/sample_app/dist/public/javascripts/application.js +0 -0
- data/examples/sample_app/dist/public/javascripts/effects.js +0 -975
- data/examples/sample_app/dist/public/javascripts/mup.js +0 -113
- data/examples/sample_app/dist/public/javascripts/prototype.js +0 -2264
- data/examples/sample_app/dist/public/stylesheets/merb.css +0 -277
- data/examples/sample_app/dist/public/test.html +0 -5
- data/examples/sample_app/dist/schema/migrations/001_add_comments_to_posts.rb +0 -22
- data/examples/sample_app/dist/schema/migrations/002_add_sessions_table.rb +0 -14
- data/examples/sample_app/dist/schema/schema.rb +0 -28
- data/examples/sample_app/foo.txt +0 -0
- data/examples/sample_app/log/merb.4000.pid +0 -1
- data/examples/sample_app/script/merb_stop +0 -13
- data/examples/sample_app/script/new_migration +0 -21
- data/examples/sample_app/test/test_helper.rb +0 -1
- data/lib/merb/mixins/javascript_mixin.rb +0 -147
- data/lib/merb/session/merb_drb_session.rb +0 -65
- data/test/test_helper.rb +0 -1
- data/test/unit/route_matcher_test.rb +0 -46
data/lib/merb/merb_drb_server.rb
CHANGED
@@ -3,72 +3,18 @@ require File.dirname(__FILE__)+'/merb_upload_progress'
|
|
3
3
|
|
4
4
|
module Merb
|
5
5
|
|
6
|
-
class
|
7
|
-
|
6
|
+
class DrbServiceProvider
|
8
7
|
include DRbUndumped
|
9
8
|
|
10
9
|
class << self
|
11
|
-
|
12
|
-
def setup(opts={})
|
13
|
-
@opts = opts
|
14
|
-
@sessions = Hash.new
|
15
|
-
@timestamps = Hash.new
|
16
|
-
@mutex = Mutex.new
|
17
|
-
@session_ttl = opts.fetch(:session_ttl, 15*60) # default 15 minutes
|
18
|
-
start_timer
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
def create(opts={})
|
23
|
-
self[opts[:sess_id]] = opts[:data]
|
24
|
-
end
|
25
|
-
|
26
|
-
def [](key)
|
27
|
-
@mutex.synchronize {
|
28
|
-
@timestamps[key] = Time.now
|
29
|
-
@sessions[key]
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
def []=(key, val)
|
34
|
-
@mutex.synchronize {
|
35
|
-
@timestamps[key] = Time.now
|
36
|
-
@sessions[key] = val
|
37
|
-
}
|
38
|
-
end
|
39
|
-
|
40
|
-
def delete(key)
|
41
|
-
@mutex.synchronize {
|
42
|
-
@sessions.delete(key)
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
def reap_old_sessions
|
47
|
-
@timestamps.each do |key,stamp|
|
48
|
-
if stamp + @session_ttl < Time.now
|
49
|
-
delete(key)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
GC.start
|
53
|
-
end
|
54
|
-
|
55
|
-
def start_timer
|
56
|
-
Thread.new do
|
57
|
-
sleep @session_ttl
|
58
|
-
reap_old_sessions
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def sessions
|
63
|
-
@sessions
|
64
|
-
end
|
65
10
|
|
66
11
|
def upload_progress
|
67
|
-
::Merb::UploadProgress.new
|
68
|
-
end
|
12
|
+
@upload_progress ||= ::Merb::UploadProgress.new
|
13
|
+
end
|
69
14
|
|
70
|
-
end
|
15
|
+
end
|
71
16
|
|
72
|
-
end
|
17
|
+
end
|
18
|
+
|
73
19
|
|
74
20
|
end
|
data/lib/merb/merb_exceptions.rb
CHANGED
@@ -1,4 +1,164 @@
|
|
1
|
+
begin
|
2
|
+
require 'coderay'
|
3
|
+
rescue LoadError => ex
|
4
|
+
end
|
5
|
+
|
1
6
|
module Merb
|
2
|
-
class
|
3
|
-
class
|
7
|
+
class MerbError < StandardError; end
|
8
|
+
class Noroutefound < MerbError; end
|
9
|
+
class MissingControllerFile < MerbError; end
|
10
|
+
class MerbControllerError < MerbError; end
|
11
|
+
|
12
|
+
# format exception message for browser display
|
13
|
+
def self.html_exception(e)
|
14
|
+
::Merb::Server.show_error ? ErrorResponse.new(e).out : "500 Internal Server Error!"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.exception(e)
|
18
|
+
"#{ e.message } - (#{ e.class })\n" <<
|
19
|
+
"#{(e.backtrace or []).join("\n")}"
|
20
|
+
end
|
21
|
+
|
22
|
+
class ErrorResponse
|
23
|
+
def initialize error
|
24
|
+
@error = error
|
25
|
+
end
|
26
|
+
|
27
|
+
def out
|
28
|
+
error = @error
|
29
|
+
backtrace = @error.backtrace
|
30
|
+
|
31
|
+
colors = []
|
32
|
+
min = 104
|
33
|
+
max = 255
|
34
|
+
step = -((max - min) / backtrace.size).abs
|
35
|
+
max.step(min, step) do |color|
|
36
|
+
colors << color
|
37
|
+
end
|
38
|
+
|
39
|
+
backtrace.map! do |line|
|
40
|
+
file, lineno, meth = line.scan(/(.*?):(\d+)(?::in `(.*?)')?/).first
|
41
|
+
lines = __caller_lines__(file, lineno, 5)
|
42
|
+
[ lines, lines.object_id.abs, file, lineno, meth ]
|
43
|
+
end
|
44
|
+
|
45
|
+
error_page(colors, error, *backtrace)
|
46
|
+
end
|
47
|
+
|
48
|
+
# this method offers highlighting for the sourcecode-chunks from the
|
49
|
+
# traceback, just gem install coderay
|
50
|
+
def error_page(colors, title, *backtrace)
|
51
|
+
@backtrace = backtrace
|
52
|
+
@colors = colors
|
53
|
+
@title = title
|
54
|
+
@coderay = Object.constants.include?('CodeRay')
|
55
|
+
|
56
|
+
|
57
|
+
template =
|
58
|
+
<<-HEREDOC
|
59
|
+
<html>
|
60
|
+
<head>
|
61
|
+
<title><%= @title %></title>
|
62
|
+
<style type="text/css">
|
63
|
+
<!--
|
64
|
+
h1.main {
|
65
|
+
text-align: center;
|
66
|
+
}
|
67
|
+
table.main {
|
68
|
+
background: #000;
|
69
|
+
}
|
70
|
+
table.main tr.head {
|
71
|
+
background: #fee;
|
72
|
+
width: 100%;
|
73
|
+
}
|
74
|
+
table.main tr.source_container {
|
75
|
+
display: none;
|
76
|
+
}
|
77
|
+
tr.source_container div {
|
78
|
+
width: 100%;
|
79
|
+
overflow: auto;
|
80
|
+
}
|
81
|
+
tr.source_container div table {
|
82
|
+
background: #ddd;
|
83
|
+
width: 100%;
|
84
|
+
}
|
85
|
+
tr.source_container div table tr {
|
86
|
+
text-align:center;
|
87
|
+
}
|
88
|
+
tr.source_container div table tr.source {
|
89
|
+
text-align:left;
|
90
|
+
}
|
91
|
+
tr a {
|
92
|
+
color: black;
|
93
|
+
}
|
94
|
+
div.source {
|
95
|
+
background: #fff;
|
96
|
+
}
|
97
|
+
-->
|
98
|
+
<% if @coderay %>
|
99
|
+
<%= CodeRay::Encoders[:html]::CSS.new.stylesheet %>
|
100
|
+
<% end %>
|
101
|
+
</style>
|
102
|
+
<script type="text/javascript">
|
103
|
+
$ = function(el){
|
104
|
+
if(el === null || el === undefined)
|
105
|
+
throw("Argument for $() must be a domRef/domId");
|
106
|
+
if( el.constructor === String )
|
107
|
+
el = document.getElementById(el);
|
108
|
+
if(el === null || !el.nodeType)
|
109
|
+
throw("Argument for $() not found in document tree.");
|
110
|
+
return el;
|
111
|
+
}
|
112
|
+
|
113
|
+
var toggle = function(el){
|
114
|
+
el = $(el);
|
115
|
+
var visible = el.style.display != 'none'; // visible? boolean
|
116
|
+
if(visible){
|
117
|
+
el.style.display = 'none'; // hide
|
118
|
+
}else{
|
119
|
+
el.style.display = ''; // unhide
|
120
|
+
}
|
121
|
+
}
|
122
|
+
</script>
|
123
|
+
</head>
|
124
|
+
<body>
|
125
|
+
<span style="float:left;">
|
126
|
+
<img src="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAJQAA/+4ADkFk\nb2JlAGTAAAAAAf/bAIQADQkJCQoJDQoKDRMMCwwTFhENDREWGhUVFhUVGhkU\nFhUVFhQZGR0fIB8dGScnKionJzk4ODg5QEBAQEBAQEBAQAEODAwOEA4RDw8R\nFA4RDhQVERISERUgFRUXFRUgKB0ZGRkZHSgjJiAgICYjLCwoKCwsNzc1NzdA\nQEBAQEBAQEBA/8AAEQgAJgAtAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAA\nAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoL\nEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVS\nwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePz\nRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAIC\nAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLh\ncoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSF\ntJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMR\nAD8A9OVDK6xRQYa02axuEBvnB7x8Fm/W36x19HqoxmAvyswkMraHFwY2N7va\nCe/5Vy/Seu29RvdXaI2CW6EBw4OhGnZAk9Einrbuvn03Oaw1lvmCCP8ANXPW\n9Zz7shlrM9zKBLnN3Fmg1gnj8An61m14eCbAN9j4ZVWJJc5x2gQPivO3ZnUM\nXLtfY8by73sDmuHw9pPCZRPVNgdH13F+teJU51WbZpX9O4xpPEho4juug9Wr\n0vW3t9Lbv9SRt2xO7dxEL5+blW5I2W2FrdsSJJgdj4r0P1W/+Nf6Un1p9PZJ\nnf8AaPU2+P0fwThdVaLF3TlfXZvUsr63ZIpZY4Y9VDKTWwuIY5vqEe3uXFx+\nSn0XBupy9t+loqDXy1zTJLST7tefJbVDLsjLycwO9Sy/09ANQafUJP8A4IrG\nQGufXltEAjZYPA900kkeCRoXA+sHSeoTXn41xJxnB9bY3e4HRcTbVsfB2h7j\ntDWkkAT7jrPjC9FzCMfpJZU5wDGgN7wNI4HZcJdiNrvP2t+62SNg9vedxnRO\nj2WyQfZy2oOA5kbfGedF0jb8w/Uq2ra/25NcGD9F1dk6/BqrYNODY5rrve4+\n2rGpBcR3Mr0j9iVf83vscD1J3bZMep/NelM+Hsn5oqa3RG0uuf6b9j9dsCRI\n+lx4haGT9g1FgZ6nc0n/AKrSEkko/Kg7vO9XtsxzV+y6a8xjtxu+hWWwPY0f\npBMnv2XN52ZmbyLunYocCZNl1bpdENmS0wOdUkkPsT9rL6rfbf8AnJiPzvT+\nzfpPVrZ6ezb6Ttv0e26OTzC9U3uk+z88ACRu+hz8YSSR6q6P/9k=\n"/>
|
127
|
+
</span>
|
128
|
+
<h1><%= @title %></h1>
|
129
|
+
<table class="main">
|
130
|
+
<tr class="head">
|
131
|
+
<td>File</td><td>Line</td><td>Method</td>
|
132
|
+
</tr>
|
133
|
+
<% @backtrace.each do |lines, hash, file, lineno, meth| %>
|
134
|
+
<tr id="line_<%= hash %>" style="background:rgb(104,104,<%= @colors.shift %>);">
|
135
|
+
<td><a href='#' onclick="toggle('source_<%= hash %>'); return false"><%= file %></a></td><td><%= lineno %></td><td><%= meth %></td>
|
136
|
+
</tr>
|
137
|
+
<tr id="source_<%= hash %>" <%= @coderay? " class='CodeRay' " : ''%> style="display:none;">
|
138
|
+
<td colspan="3">
|
139
|
+
<div class="source">
|
140
|
+
<table>
|
141
|
+
<tr><td colspan='2'><a href='txmt://open?url=file://<%=file%>&line=<%=lineno%>'>Open in TextMate</a></td></tr>
|
142
|
+
<% lines.each do |llineno, lcode, lcurrent| %>
|
143
|
+
<tr class="source"<%= 'style="background:#faa;"' if lcurrent %>>
|
144
|
+
<td><%= llineno %></td>
|
145
|
+
<td>
|
146
|
+
<%= @coderay ? CodeRay.scan(lcode, :ruby).html : "<pre>\#{lcode}</pre>" %>
|
147
|
+
</td>
|
148
|
+
</tr>
|
149
|
+
<% end %>
|
150
|
+
</table>
|
151
|
+
</div>
|
152
|
+
</td>
|
153
|
+
</tr>
|
154
|
+
<% end %>
|
155
|
+
</table>
|
156
|
+
</body>
|
157
|
+
</html>
|
158
|
+
HEREDOC
|
159
|
+
tmpl = Erubis::MEruby.new template
|
160
|
+
tmpl.result(binding)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
4
164
|
end
|
data/lib/merb/merb_handler.rb
CHANGED
@@ -67,18 +67,17 @@ class MerbHandler < Mongrel::HttpHandler
|
|
67
67
|
@guard.synchronize {
|
68
68
|
controller.dispatch(action)
|
69
69
|
}
|
70
|
-
rescue
|
70
|
+
rescue Object => e
|
71
71
|
response.start(500) do |head,out|
|
72
72
|
head["Content-Type"] = "text/html"
|
73
|
-
MERB_LOGGER.info(exception(e))
|
74
|
-
out << html_exception(e)
|
73
|
+
MERB_LOGGER.info(Merb.exception(e))
|
74
|
+
out << Merb.html_exception(e)
|
75
75
|
end
|
76
76
|
return
|
77
77
|
end
|
78
78
|
|
79
79
|
sendfile, clength = nil
|
80
80
|
response.status = controller.status
|
81
|
-
|
82
81
|
# check for the X-SENDFILE header from your Merb::Controller
|
83
82
|
# and serve the file directly instead of buffering.
|
84
83
|
controller.headers.each do |k, v|
|
@@ -117,9 +116,10 @@ class MerbHandler < Mongrel::HttpHandler
|
|
117
116
|
else
|
118
117
|
MERB_LOGGER.info("Response status: #{response.status}\nComplete Request took: #{Time.now - start} seconds\n\n")
|
119
118
|
# render response from successful controller
|
120
|
-
|
119
|
+
body = (controller.body.to_s rescue '')
|
120
|
+
response.send_status(body.length)
|
121
121
|
response.send_header
|
122
|
-
response.write(
|
122
|
+
response.write(body)
|
123
123
|
end
|
124
124
|
end
|
125
125
|
end
|
@@ -131,7 +131,7 @@ class MerbHandler < Mongrel::HttpHandler
|
|
131
131
|
# [controller, action]
|
132
132
|
def handle(request)
|
133
133
|
path = request.params[Mongrel::Const::PATH_INFO].sub(/\/+/, '/')
|
134
|
-
path = path[0..-2] if (path[-1] == ?/)
|
134
|
+
path = path[0..-2] if (path[-1] == ?/) && path.size > 1
|
135
135
|
route = Merb::RouteMatcher.new.route_request(path)
|
136
136
|
[ instantiate_controller(route[:controller], request.body, request.params, route),
|
137
137
|
route[:action] ]
|
@@ -142,7 +142,7 @@ class MerbHandler < Mongrel::HttpHandler
|
|
142
142
|
# into a new object passing in the request and response.
|
143
143
|
# this is where your Merb::Controller is instantiated.
|
144
144
|
def instantiate_controller(controller_name, req, env, params)
|
145
|
-
if !File.exist?(
|
145
|
+
if !File.exist?(DIST_ROOT+"/app/controllers/#{controller_name.snake_case}.rb")
|
146
146
|
raise Merb::MissingControllerFile
|
147
147
|
end
|
148
148
|
begin
|
@@ -154,15 +154,4 @@ class MerbHandler < Mongrel::HttpHandler
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
|
-
# format exception message for browser display
|
158
|
-
def html_exception(e)
|
159
|
-
"<html><body><h2>Merb Error!</h2><p>#{ e.message } - (#{ e.class })\n" <<
|
160
|
-
"#{(e.backtrace or []).join('<br />')}</p></body></html>"
|
161
|
-
end
|
162
|
-
|
163
|
-
def exception(e)
|
164
|
-
"#{ e.message } - (#{ e.class })\n" <<
|
165
|
-
"#{(e.backtrace or []).join("\n")}"
|
166
|
-
end
|
167
|
-
|
168
157
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'mailfactory'
|
5
|
+
rescue LoadError
|
6
|
+
puts "You need to install the mailfactory gem to use Merb::Mailer"
|
7
|
+
MERB_LOGGER.fatal "You need to install the mailfactory gem to use Merb::Mailer"
|
8
|
+
end
|
9
|
+
|
10
|
+
module Merb
|
11
|
+
class Mailer
|
12
|
+
|
13
|
+
shared_accessor :config
|
14
|
+
|
15
|
+
def sendmail
|
16
|
+
sendmail = IO.popen("sendmail #{@mail.to}", 'w+')
|
17
|
+
sendmail.puts @mail.to_s
|
18
|
+
sendmail.close
|
19
|
+
end
|
20
|
+
|
21
|
+
# :plain, :login, or :cram_md5
|
22
|
+
def net_smtp
|
23
|
+
Net::SMTP.start(config[:host], config[:port].to_i, config[:domain],
|
24
|
+
config[:user], config[:pass], (config[:auth].intern||:plain)) { |smtp|
|
25
|
+
smtp.send_message(@mail.to_s, @mail.from, @mail.to)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def deliver!
|
30
|
+
config == :sendmail ? sendmail : net_smtp
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(o={})
|
34
|
+
self.config = :sendmail if config.nil?
|
35
|
+
@mail = returning MailFactory.new() do |m|
|
36
|
+
m.to = o[:to]
|
37
|
+
m.from = o[:from]
|
38
|
+
m.subject = o[:subject]
|
39
|
+
m.text = o[:body]
|
40
|
+
m.html = o[:html] if o[:html]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
=begin
|
47
|
+
m = Merb::Mailer.new :to => 'foo@bar.com',
|
48
|
+
:from => 'bar@foo.com',
|
49
|
+
:subject => 'Welcome to whatever!',
|
50
|
+
:body => partial(:sometemplate)
|
51
|
+
m.deliver!
|
52
|
+
|
53
|
+
Merb::Mailer.config = {
|
54
|
+
:host=>'smtp.yourserver.com',
|
55
|
+
:port=>'25',
|
56
|
+
:user=>'user',
|
57
|
+
:pass=>'pass',
|
58
|
+
:auth=>:plain # :plain, :login, or :cram_md5, default :plain
|
59
|
+
}
|
60
|
+
=end
|
data/lib/merb/merb_router.rb
CHANGED
@@ -69,7 +69,7 @@ module Merb
|
|
69
69
|
return ' when /\A\/([^\/;.,?]+)(?:\/?\Z|\/([^\/;.,?]+)\/?)(?:\/?\Z|\/([^\/;.,?]+)\/?)\Z/
|
70
70
|
@sections[:controller] = $1
|
71
71
|
@sections[:action] = $2 || \'index\'
|
72
|
-
@sections[:id] = $3
|
72
|
+
@sections[:id] = $3 if $3
|
73
73
|
return @sections'<<"\n"
|
74
74
|
end
|
75
75
|
code, count = '', 0
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'yaml'
|
5
|
+
require 'erubis'
|
6
|
+
|
7
|
+
module Merb
|
8
|
+
|
9
|
+
class Config
|
10
|
+
def self.setup
|
11
|
+
defaults = {
|
12
|
+
:host => "0.0.0.0",
|
13
|
+
:port => "4000",
|
14
|
+
:allow_reloading => true,
|
15
|
+
:merb_root => Dir.pwd,
|
16
|
+
:template_ext => {:html => :herb, :js => :jerb, :xml => :xerb},
|
17
|
+
:cache_templates => false
|
18
|
+
}
|
19
|
+
begin
|
20
|
+
options = defaults.merge(YAML.load(Erubis::Eruby.new(IO.read("#{defaults[:merb_root]}/dist/conf/merb.yml")).result))
|
21
|
+
rescue
|
22
|
+
options = defaults
|
23
|
+
end
|
24
|
+
|
25
|
+
options
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Server
|
30
|
+
|
31
|
+
class << self
|
32
|
+
|
33
|
+
def merb_config
|
34
|
+
options = Merb::Config.setup
|
35
|
+
|
36
|
+
opts = OptionParser.new do |opts|
|
37
|
+
opts.banner = "Usage: merb [fdcphmisl] [argument]"
|
38
|
+
opts.define_head "Merb Mongrel+ Erb. Lightweight replacement for ActionPack"
|
39
|
+
opts.separator '*'*80
|
40
|
+
opts.separator 'If no flags are given, Merb starts in the foreground on port 4000'
|
41
|
+
opts.separator '*'*80
|
42
|
+
|
43
|
+
opts.on("-f", "--config-file FILENAME", "This flag is for adding extra config files for things like the upload progress module") do |config|
|
44
|
+
options[:config] = config
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("-d", "--daemonize", "This will run a single merb in the background") do |config|
|
48
|
+
options[:daemonize] = true
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("-c", "--cluster-nodes NUM_MERBS", "Number of merb daemons to run") do |nodes|
|
52
|
+
options[:cluster] = nodes
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("-p", "--port PORTNUM", "Port to run merb on, defaults to 4000") do |port|
|
56
|
+
options[:port] = port
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("-h", "--host HOSTNAME", "Host to bind to(default is all IP's)") do |host|
|
60
|
+
options[:host] = host
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-m", "--merb-root MERB_ROOT", "the path to the MERB_ROOT for the app you want to run") do |merb_root|
|
64
|
+
options[:merb_root] = File.expand_path(merb_root)
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on("-i", "--irb-console", "This flag will start merb in irb console mode. All your models and other classes will be available for you in an irb session.") do |console|
|
68
|
+
options[:console] = true
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.on("-s", "--drb-server-port PORTNUM", "This is the port number to run the drb daemon on for sessions and uplod progress monitoring.") do |drb_port|
|
72
|
+
options[:drb_server_port] = drb_port
|
73
|
+
end
|
74
|
+
|
75
|
+
opts.on("-l", "--log-level LEVEL", "Log levels can be set to any of these options: DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN") do |loglevel|
|
76
|
+
options[:log_level] = loglevel
|
77
|
+
end
|
78
|
+
|
79
|
+
opts.on("-e", "--environment STRING", "Run merb in the correct mode(development, production, testing)") do |env|
|
80
|
+
options[:environment] = env
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on("-g", "--generate-app PATH", "Generate a fresh merb app at PATH") do |path|
|
84
|
+
options[:generate] = path || Dir.pwd
|
85
|
+
end
|
86
|
+
|
87
|
+
opts.on("-?", "--help", "Show this help message") do
|
88
|
+
puts opts
|
89
|
+
exit
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
opts.parse!(@@merb_raw_opts)
|
95
|
+
|
96
|
+
|
97
|
+
@@merb_opts = options
|
98
|
+
unless options[:generate] || options[:console]
|
99
|
+
puts %{Merb started with these options:}
|
100
|
+
puts @@merb_opts.to_yaml; puts
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def initialize_merb
|
105
|
+
require 'merb'
|
106
|
+
require @@merb_opts[:merb_root]+'/dist/conf/router.rb'
|
107
|
+
require @@merb_opts[:merb_root]+'/dist/conf/merb_init.rb'
|
108
|
+
end
|
109
|
+
|
110
|
+
def run
|
111
|
+
@@merb_raw_opts = ARGV
|
112
|
+
merb_config
|
113
|
+
|
114
|
+
case @@merb_opts[:environment].to_s
|
115
|
+
when 'development'
|
116
|
+
@@merb_opts[:allow_reloading] ||= true
|
117
|
+
@@merb_opts[:show_error] ||= true
|
118
|
+
when 'production'
|
119
|
+
@@merb_opts[:allow_reloading] = false
|
120
|
+
@@merb_opts[:show_error] ||= false
|
121
|
+
@@merb_opts[:cache_templates] = true
|
122
|
+
when 'test'
|
123
|
+
@@merb_opts[:allow_reloading] ||= true
|
124
|
+
@@merb_opts[:show_error] ||= true
|
125
|
+
else
|
126
|
+
@@merb_opts[:allow_reloading] ||= true
|
127
|
+
@@merb_opts[:show_error] ||= true
|
128
|
+
end
|
129
|
+
|
130
|
+
@@merb_opts[:dist_root] = @@merb_opts[:merb_root]+'/dist'
|
131
|
+
$LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/app/controllers') )
|
132
|
+
$LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/app/models') )
|
133
|
+
$LOAD_PATH.unshift( File.join(@@merb_opts[:dist_root] , '/lib') )
|
134
|
+
|
135
|
+
if @@merb_opts[:generate]
|
136
|
+
require 'merb/generators/merb_app/merb_app'
|
137
|
+
::Merb::AppGenerator.run @@merb_opts[:generate]
|
138
|
+
exit!
|
139
|
+
end
|
140
|
+
|
141
|
+
if @@merb_opts[:console]
|
142
|
+
initialize_merb
|
143
|
+
ARGV.clear # Avoid passing args to IRB
|
144
|
+
require 'irb'
|
145
|
+
require 'irb/completion'
|
146
|
+
def exit
|
147
|
+
exit!
|
148
|
+
end
|
149
|
+
if File.exists? ".irbrc"
|
150
|
+
ENV['IRBRC'] = ".irbrc"
|
151
|
+
end
|
152
|
+
IRB.start
|
153
|
+
exit!
|
154
|
+
end
|
155
|
+
|
156
|
+
if @@merb_opts[:drb_server_port]
|
157
|
+
puts "Starting merb drb server on port: #{@@merb_opts[:drb_server_port]}"
|
158
|
+
start(@@merb_opts[:drb_server_port], :drbserver_start)
|
159
|
+
end
|
160
|
+
|
161
|
+
if @@merb_opts[:cluster]
|
162
|
+
delete_pidfiles
|
163
|
+
@@merb_opts[:port].to_i.upto(@@merb_opts[:port].to_i+@@merb_opts[:cluster].to_i-1) do |port|
|
164
|
+
puts "Starting merb server on port: #{port}"
|
165
|
+
start(port)
|
166
|
+
end
|
167
|
+
elsif @@merb_opts[:daemonize]
|
168
|
+
delete_pidfiles(@@merb_opts[:port])
|
169
|
+
start(@@merb_opts[:port])
|
170
|
+
else
|
171
|
+
initialize_merb
|
172
|
+
trap('TERM') { exit }
|
173
|
+
mongrel_start(@@merb_opts[:port])
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
def store_pid(pid,port)
|
179
|
+
File.open("#{@@merb_opts[:merb_root]}/log/merb.#{port}.pid", 'w'){|f| f.write("#{Process.pid}\n")}
|
180
|
+
end
|
181
|
+
|
182
|
+
def start(port,what=:mongrel_start)
|
183
|
+
fork do
|
184
|
+
Process.setsid
|
185
|
+
exit if fork
|
186
|
+
if what == :mongrel_start
|
187
|
+
store_pid(Process.pid, port)
|
188
|
+
else
|
189
|
+
store_pid(Process.pid, "drb.#{port}")
|
190
|
+
end
|
191
|
+
Dir.chdir @@merb_opts[:merb_root]
|
192
|
+
File.umask 0000
|
193
|
+
STDIN.reopen "/dev/null"
|
194
|
+
STDOUT.reopen "/dev/null", "a"
|
195
|
+
STDERR.reopen STDOUT
|
196
|
+
trap("TERM") { exit }
|
197
|
+
send(what, port)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def delete_pidfiles(portor_star='*')
|
202
|
+
Dir["#{@@merb_opts[:merb_root]}/log/merb.#{portor_star}.pid"].each do |pid|
|
203
|
+
FileUtils.rm(pid) rescue nil
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def drbserver_start(port)
|
208
|
+
puts "Starting merb drb server on port: #{port}"
|
209
|
+
require 'merb/merb_drb_server'
|
210
|
+
DRb.start_service("druby://#{@@merb_opts[:host]}:#{port}", Merb::DrbServiceProvider)
|
211
|
+
DRb.thread.join
|
212
|
+
end
|
213
|
+
|
214
|
+
def mongrel_start(port)
|
215
|
+
@@merb_opts[:port] = port
|
216
|
+
initialize_merb
|
217
|
+
|
218
|
+
mconfig = Mongrel::Configurator.new :host => (@@merb_opts[:host]||"0.0.0.0"), :port => (port ||4000) do
|
219
|
+
yconfig = YAML.load(Erubis::Eruby.new(IO.read(File.expand_path(@@merb_opts[:config]))).result) if @@merb_opts[:config]
|
220
|
+
listener do
|
221
|
+
uri( "/", :handler => MerbUploadHandler.new(yconfig), :in_front => true) if @@merb_opts[:config]
|
222
|
+
uri "/", :handler => MerbHandler.new(@@merb_opts[:dist_root]+'/public')
|
223
|
+
uri "/favicon.ico", :handler => Mongrel::Error404Handler.new("")
|
224
|
+
end
|
225
|
+
|
226
|
+
trap("INT") { stop }
|
227
|
+
run
|
228
|
+
end
|
229
|
+
mconfig.join
|
230
|
+
end
|
231
|
+
|
232
|
+
def config
|
233
|
+
@@merb_opts
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
end # Server
|
239
|
+
|
240
|
+
end # Merb
|