merb 0.0.1 → 0.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.
- data/Rakefile +1 -1
- data/doc/rdoc/classes/Merb.html +128 -0
- data/doc/rdoc/classes/Merb/Config.html +159 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/LICENSE.html +129 -0
- data/doc/rdoc/files/README.html +297 -0
- data/doc/rdoc/files/lib/merb_config_rb.html +101 -0
- data/doc/rdoc/files/lib/merb_rb.html +113 -0
- data/doc/rdoc/files/server_rb.html +122 -0
- data/doc/rdoc/fr_class_index.html +28 -0
- data/doc/rdoc/fr_file_index.html +31 -0
- data/doc/rdoc/fr_method_index.html +27 -0
- data/doc/rdoc/index.html +24 -0
- data/doc/rdoc/rdoc-style.css +208 -0
- data/examples/sample_app/app/controllers/noroutefound.rb +4 -0
- data/examples/sample_app/app/controllers/posts.rb +27 -0
- data/examples/sample_app/app/models/post.rb +2 -0
- data/examples/sample_app/app/views/posts/list.rhtml +13 -0
- data/examples/sample_app/app/views/posts/new.rhtml +36 -0
- data/examples/sample_app/app/views/posts/show.rhtml +12 -0
- data/examples/sample_app/conf/merb_init.rb +12 -1
- data/examples/sample_app/conf/router.rb +8 -2
- data/lib/merb.rb +1 -1
- data/lib/merb/merb_controller.rb +1 -3
- data/lib/merb/merb_handler.rb +43 -13
- data/test/unit/route_matcher_test.rb +16 -11
- metadata +27 -2
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
body {
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
4
|
+
font-size: 90%;
|
5
|
+
margin: 0;
|
6
|
+
margin-left: 40px;
|
7
|
+
padding: 0;
|
8
|
+
background: white;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
12
|
+
h1 { font-size: 150%; }
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
14
|
+
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
16
|
+
a:hover { background: #039; color: #eef; }
|
17
|
+
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
19
|
+
td > a {
|
20
|
+
background: transparent;
|
21
|
+
color: #039;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* and inside a section title */
|
26
|
+
.section-title > a {
|
27
|
+
background: transparent;
|
28
|
+
color: #eee;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* === Structural elements =================================== */
|
33
|
+
|
34
|
+
div#index {
|
35
|
+
margin: 0;
|
36
|
+
margin-left: -40px;
|
37
|
+
padding: 0;
|
38
|
+
font-size: 90%;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div#index a {
|
43
|
+
margin-left: 0.7em;
|
44
|
+
}
|
45
|
+
|
46
|
+
div#index .section-bar {
|
47
|
+
margin-left: 0px;
|
48
|
+
padding-left: 0.7em;
|
49
|
+
background: #ccc;
|
50
|
+
font-size: small;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
div#classHeader, div#fileHeader {
|
55
|
+
width: auto;
|
56
|
+
color: white;
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
58
|
+
margin: 0;
|
59
|
+
margin-left: -40px;
|
60
|
+
border-bottom: 3px solid #006;
|
61
|
+
}
|
62
|
+
|
63
|
+
div#classHeader a, div#fileHeader a {
|
64
|
+
background: inherit;
|
65
|
+
color: white;
|
66
|
+
}
|
67
|
+
|
68
|
+
div#classHeader td, div#fileHeader td {
|
69
|
+
background: inherit;
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
div#fileHeader {
|
75
|
+
background: #057;
|
76
|
+
}
|
77
|
+
|
78
|
+
div#classHeader {
|
79
|
+
background: #048;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
.class-name-in-header {
|
84
|
+
font-size: 180%;
|
85
|
+
font-weight: bold;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
div#bodyContent {
|
90
|
+
padding: 0 1.5em 0 1.5em;
|
91
|
+
}
|
92
|
+
|
93
|
+
div#description {
|
94
|
+
padding: 0.5em 1.5em;
|
95
|
+
background: #efefef;
|
96
|
+
border: 1px dotted #999;
|
97
|
+
}
|
98
|
+
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
100
|
+
color: #125;;
|
101
|
+
background: transparent;
|
102
|
+
}
|
103
|
+
|
104
|
+
div#validator-badges {
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
div#validator-badges img { border: 0; }
|
108
|
+
|
109
|
+
div#copyright {
|
110
|
+
color: #333;
|
111
|
+
background: #efefef;
|
112
|
+
font: 0.75em sans-serif;
|
113
|
+
margin-top: 5em;
|
114
|
+
margin-bottom: 0;
|
115
|
+
padding: 0.5em 2em;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/* === Classes =================================== */
|
120
|
+
|
121
|
+
table.header-table {
|
122
|
+
color: white;
|
123
|
+
font-size: small;
|
124
|
+
}
|
125
|
+
|
126
|
+
.type-note {
|
127
|
+
font-size: small;
|
128
|
+
color: #DEDEDE;
|
129
|
+
}
|
130
|
+
|
131
|
+
.xxsection-bar {
|
132
|
+
background: #eee;
|
133
|
+
color: #333;
|
134
|
+
padding: 3px;
|
135
|
+
}
|
136
|
+
|
137
|
+
.section-bar {
|
138
|
+
color: #333;
|
139
|
+
border-bottom: 1px solid #999;
|
140
|
+
margin-left: -20px;
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
.section-title {
|
145
|
+
background: #79a;
|
146
|
+
color: #eee;
|
147
|
+
padding: 3px;
|
148
|
+
margin-top: 2em;
|
149
|
+
margin-left: -30px;
|
150
|
+
border: 1px solid #999;
|
151
|
+
}
|
152
|
+
|
153
|
+
.top-aligned-row { vertical-align: top }
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
155
|
+
|
156
|
+
/* --- Context section classes ----------------------- */
|
157
|
+
|
158
|
+
.context-row { }
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
162
|
+
|
163
|
+
/* --- Method classes -------------------------- */
|
164
|
+
.method-detail {
|
165
|
+
background: #efefef;
|
166
|
+
padding: 0;
|
167
|
+
margin-top: 0.5em;
|
168
|
+
margin-bottom: 1em;
|
169
|
+
border: 1px dotted #ccc;
|
170
|
+
}
|
171
|
+
.method-heading {
|
172
|
+
color: black;
|
173
|
+
background: #ccc;
|
174
|
+
border-bottom: 1px solid #666;
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
176
|
+
}
|
177
|
+
.method-signature { color: black; background: inherit; }
|
178
|
+
.method-name { font-weight: bold; }
|
179
|
+
.method-args { font-style: italic; }
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
181
|
+
|
182
|
+
/* --- Source code sections -------------------- */
|
183
|
+
|
184
|
+
a.source-toggle { font-size: 90%; }
|
185
|
+
div.method-source-code {
|
186
|
+
background: #262626;
|
187
|
+
color: #ffdead;
|
188
|
+
margin: 1em;
|
189
|
+
padding: 0.5em;
|
190
|
+
border: 1px dashed #999;
|
191
|
+
overflow: hidden;
|
192
|
+
}
|
193
|
+
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
195
|
+
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
197
|
+
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
199
|
+
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
class Posts < Merb::Controller
|
3
|
+
template_dir :posts
|
4
|
+
|
5
|
+
def new(args={})
|
6
|
+
unless @params.to_s.empty?
|
7
|
+
@post = Post.create( :title => @params[:title], :body => @params[:body])
|
8
|
+
render 'show'
|
9
|
+
else
|
10
|
+
render
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def show(args={})
|
15
|
+
@post = Post.find @params[:id]
|
16
|
+
render
|
17
|
+
end
|
18
|
+
|
19
|
+
def list(args={})
|
20
|
+
@posts = Post.find :all
|
21
|
+
render
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"<html><body>Post controller, no mathing action</body></html>"
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>New Post</title>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
|
7
|
+
|
8
|
+
<h2>Make a post doofus.</h2>
|
9
|
+
|
10
|
+
<form action="/posts/new" method="post">
|
11
|
+
|
12
|
+
<p>
|
13
|
+
<label for="post_title">
|
14
|
+
|
15
|
+
Title
|
16
|
+
|
17
|
+
</label>
|
18
|
+
<input type="text" size="30" name="title" id="post_title" />
|
19
|
+
</p>
|
20
|
+
|
21
|
+
<p>
|
22
|
+
<label for="post_body">
|
23
|
+
|
24
|
+
Body
|
25
|
+
|
26
|
+
</label>
|
27
|
+
<textarea cols="20" id="post_body" name="body" rows="20"></textarea>
|
28
|
+
</p>
|
29
|
+
|
30
|
+
|
31
|
+
<p>
|
32
|
+
<input name="commit" type="submit" value="Upload Asset" />
|
33
|
+
</p>
|
34
|
+
</form>
|
35
|
+
</body>
|
36
|
+
</html>
|
@@ -1,3 +1,14 @@
|
|
1
1
|
puts "merb init called"
|
2
2
|
|
3
|
-
# add your own ruby code here for app initialization and load path stuff
|
3
|
+
# add your own ruby code here for app initialization and load path stuff
|
4
|
+
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
ActiveRecord::Base.establish_connection(
|
8
|
+
:adapter => 'mysql',
|
9
|
+
:username => 'root',
|
10
|
+
:password => 'xxxxxxx',
|
11
|
+
:database => 'merb'
|
12
|
+
)
|
13
|
+
|
14
|
+
Dir[Merb::Server.config[:merb_root]+"/app/models/*.rb"].each { |m| require m }
|
@@ -1,7 +1,13 @@
|
|
1
|
+
puts "Compiling routes: \n"
|
2
|
+
|
1
3
|
Merb::RouteMatcher.prepare do |r|
|
2
4
|
r.add '/foo/:bar/baz/:id', :class => 'Test', :method => 'foo'
|
3
5
|
r.add '/hey/:there/you/:guys', :class => 'Test', :method => 'hello'
|
6
|
+
r.add '/upload/start', :class => 'Upload', :method => 'start'
|
7
|
+
r.add '/posts/:method', :class => 'Posts'
|
4
8
|
r.add '/:class/:method/:id', {}
|
5
9
|
r.add '/:class/:method', {}
|
6
|
-
|
7
|
-
|
10
|
+
end
|
11
|
+
|
12
|
+
m = Merb::RouteMatcher.new
|
13
|
+
puts m.compiled_statement
|
data/lib/merb.rb
CHANGED
data/lib/merb/merb_controller.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
module Merb
|
2
2
|
|
3
3
|
class Controller
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :status, :headers
|
5
5
|
# Stolen from Camping without a twinge of remorse ;)
|
6
6
|
def initialize(req, env, method=(env['REQUEST_METHOD']||"GET")) #:nodoc:
|
7
|
-
@response_code = 200
|
8
|
-
@content_type = 'text/html'
|
9
7
|
env = MerbHash[env.to_hash]
|
10
8
|
puts env.inspect if $DEBUG
|
11
9
|
puts req.inspect if $DEBUG
|
data/lib/merb/merb_handler.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
class MerbHandler < Mongrel::HttpHandler
|
2
|
-
|
2
|
+
|
3
3
|
def process(request, response)
|
4
4
|
if response.socket.closed?
|
5
5
|
return
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
begin
|
9
|
+
controller, method, args = handle(request)
|
9
10
|
output = if (controller && controller.kind_of?(Merb::Controller))
|
10
11
|
if method
|
11
12
|
( args ? controller.send( method, args ) : controller.send(method) )
|
@@ -13,21 +14,50 @@ class MerbHandler < Mongrel::HttpHandler
|
|
13
14
|
controller.to_s
|
14
15
|
end
|
15
16
|
else
|
16
|
-
|
17
|
-
"<html><body>Error: no merb controller found for this url.</body></html>"
|
17
|
+
nil
|
18
18
|
end
|
19
|
-
response_code = controller.response_code
|
20
|
-
content_type = controller.content_type
|
21
19
|
rescue Exception => e
|
22
|
-
|
23
|
-
|
20
|
+
response.start(500) do |head,out|
|
21
|
+
head["Content-Type"] = "text/html"
|
22
|
+
out <<"<html><h2>Merb Error!</h2><pre>#{ e.message } - (#{ e.class })" <<
|
24
23
|
"\n" << "#{(e.backtrace or []).join('\n')}</pre></html>"
|
24
|
+
end
|
25
|
+
return
|
25
26
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
|
28
|
+
unless output
|
29
|
+
response.start(404) do |head,out|
|
30
|
+
head["Content-Type"] = "text/html"
|
31
|
+
out << "<html><body>Error: no merb controller found for this url.</body></html>"
|
32
|
+
end
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
sendfile, clength = nil
|
37
|
+
response.status = controller.status
|
38
|
+
controller.headers.each do |k, v|
|
39
|
+
if k =~ /^X-SENDFILE$/i
|
40
|
+
sendfile = v
|
41
|
+
elsif k =~ /^CONTENT-LENGTH$/i
|
42
|
+
clength = v.to_i
|
43
|
+
else
|
44
|
+
[*v].each do |vi|
|
45
|
+
response.header[k] = vi
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
if sendfile
|
51
|
+
response.send_status(File.size(sendfile))
|
52
|
+
response.send_header
|
53
|
+
response.send_file(sendfile)
|
54
|
+
else
|
55
|
+
response.send_status(output.length)
|
56
|
+
response.send_header
|
57
|
+
response.write(output)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
31
61
|
|
32
62
|
def handle(request)
|
33
63
|
path = request.params["PATH_INFO"].sub(/\/+/, '/')
|