Capcode 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+
2
+ <HTML>
3
+ <HEAD>
4
+ <META HTTP-EQUIV="refresh" content="0;URL=files/README.html">
5
+ <TITLE>Capcode, the Documentation</TITLE>
6
+ </HEAD>
7
+ <BODY>
8
+ Click <a href="files/README.html">here</a> to open the docs.
9
+ </BODY>
10
+ </HTML>
Binary file
@@ -0,0 +1,106 @@
1
+
2
+ body {
3
+ font: normal 14px verdana,arial,'Bitstream Vera Sans',helvetica,sans-serif;
4
+ line-height: 160%;
5
+ padding: 0; margin: 0;
6
+ margin-bottom: 30px;
7
+ /* background-color: #402; */
8
+ background-color: #CCCC99;
9
+ }
10
+ h1, h2, h3, h4 {
11
+ font-family: Utopia, Georgia, serif;
12
+ font-weight: bold;
13
+ letter-spacing: -0.018em;
14
+ }
15
+ h1 { font-size: 24px; margin: .15em 1em 0 0 }
16
+ h2 { font-size: 24px }
17
+ h3 { font-size: 19px }
18
+ h4 { font-size: 17px; font-weight: normal; }
19
+ h4.ruled { border-bottom: solid 1px #CC9; }
20
+ h2.ruled { padding-top: 35px; border-top: solid 1px #AA5; }
21
+
22
+ /* Link styles */
23
+ :link, :visited {
24
+
25
+ }
26
+ :link:hover, :visited:hover {
27
+
28
+ }
29
+ #fullpage {
30
+ width: 720px;
31
+ padding-top: 20px;
32
+ margin: 0 auto;
33
+ }
34
+ .page_shade, .page {
35
+ border-left: 1px solid black;
36
+ border-right: 1px solid black;
37
+ border-bottom: 1px solid black;
38
+ background-color: #FFFFFF;
39
+ }
40
+ .page {
41
+ padding: 20px 35px;
42
+ }
43
+ .page .header {
44
+ float: right;
45
+ color: #777;
46
+ font-size: 10px;
47
+ }
48
+ .page h1, .page h2, .page h3 {
49
+ clear: both;
50
+ text-align: center;
51
+ }
52
+ #pager {
53
+ background-color: #EEEEAE;
54
+ border-top: 2px solid black;
55
+ border-left: 2px solid black;
56
+ border-right: 2px solid black;
57
+ border-bottom: 1px dashed #999966;
58
+ padding: 20px 0 20px 20px;
59
+ color: #666633;
60
+ font-size: 11px;
61
+ }
62
+ #pager :link, #pager :visited {
63
+ color: #8E2400;
64
+ padding: 0px 5px;
65
+ }
66
+ #pager :link:hover, #pager :visited:hover {
67
+ color: #8E2400;
68
+ }
69
+ #pagertd {
70
+ font-size: 11px;
71
+ }
72
+ #logo { float: left; }
73
+ #menu {
74
+ padding: 4px 12px;
75
+ margin: 0;
76
+ }
77
+ #menu h3 { padding: 0; margin: 0; }
78
+ #menu #links { float: right; }
79
+ pre { font-weight: bold; color: black; }
80
+ tt { color: #703; font-size: 12pt; }
81
+ .dyn-source {
82
+ background-color: #EEEEEE;
83
+ border: 1px solid #CCCCCC;
84
+ padding: 4px 8px;
85
+ margin: 0;
86
+ display: none; }
87
+ .dyn-source pre {
88
+ color: #000000;
89
+ font-size: 8pt;
90
+ font-familly: monospace;
91
+
92
+ }
93
+ .source-link { text-align: right; font-size: 8pt; }
94
+ .ruby-comment { color: black; font-style: italic }
95
+ .ruby-constant { color: #123456; font-weight: bold; }
96
+ .ruby-identifier { color: #005599; }
97
+ .ruby-ivar { color: orange; }
98
+ .ruby-keyword { color: red; font-weight: bold }
99
+ .ruby-node { color: #FFFFFF; }
100
+ .ruby-operator { color: #055005; }
101
+ .ruby-regexp { color: #DDFFDD; }
102
+ .ruby-value { color: #FFAAAA; font-style: italic }
103
+ .kw { color: red; font-weight: bold }
104
+ .cmt { color: green; font-style: italic }
105
+ .str { color: #EECCCC; font-style: italic }
106
+ .re { color: #EECCCC; }
Binary file
@@ -0,0 +1,16 @@
1
+ # Logfile created on Thu Mar 05 14:37:14 +0100 2009 by /
2
+ ::1 - - [05/Mar/2009 14:37:17] "GET / HTTP/1.1" 200 424 0.0134
3
+ ::1 - - [05/Mar/2009 14:37:17] "GET /favicon.ico HTTP/1.1" 200 424 0.0076
4
+ ::1 - - [05/Mar/2009 14:37:19] "GET /8650ac90-ebb8-012b-4e10-002332b2a7fc/2808417976 HTTP/1.1" 302 - 0.0083
5
+ ::1 - - [05/Mar/2009 14:37:19] "GET / HTTP/1.1" 200 246 0.0077
6
+ ::1 - - [05/Mar/2009 14:37:20] "GET HTTP/1.1" 200 280 0.0015
7
+ ::1 - - [05/Mar/2009 14:37:45] "POST HTTP/1.1" 500 101939 0.2057
8
+ ::1 - - [05/Mar/2009 14:37:56] "POST HTTP/1.1" 500 102076 0.1473
9
+ ::1 - - [05/Mar/2009 14:37:56] "GET /favicon.ico HTTP/1.1" 200 246 0.0068
10
+ ::1 - - [05/Mar/2009 14:37:59] "GET / HTTP/1.1" 200 246 0.0064
11
+ ::1 - - [05/Mar/2009 14:38:00] "GET HTTP/1.1" 200 280 0.0019
12
+ ::1 - - [05/Mar/2009 14:38:08] "POST HTTP/1.1" 302 - 0.0093
13
+ ::1 - - [05/Mar/2009 14:38:08] "GET / HTTP/1.1" 200 416 0.0110
14
+ ::1 - - [05/Mar/2009 14:38:45] "GET HTTP/1.1" 200 280 0.0030
15
+ ::1 - - [05/Mar/2009 14:39:23] "POST HTTP/1.1" 500 102140 0.1681
16
+ ::1 - - [05/Mar/2009 14:41:01] "GET / HTTP/1.1" 200 416 0.0081
@@ -0,0 +1,62 @@
1
+ $:.unshift( "../lib" )
2
+ require 'rubygems'
3
+ require 'capcode'
4
+ require 'couch_foo'
5
+
6
+ CouchFoo::Base.set_database(:host => "http://localhost:5984", :database => "my_blog")
7
+
8
+ class Story < CouchFoo::Base
9
+ property :title, String
10
+ property :body, String
11
+ property :date, String
12
+ end
13
+
14
+ module Capcode
15
+ class HTTPError
16
+ def r404(f)
17
+ "Pas glop !!! #{f} est inconnu !!!"
18
+ end
19
+ end
20
+
21
+ class Index < Route '/'
22
+ def get
23
+ r = "<html><body>"
24
+
25
+ story = Story.find( :all )
26
+
27
+ story.each do |s|
28
+ r += "<h2>#{s.title}</h2><small>#{s.date} - <a href='#{URL( Remove, s.id, s.rev )}'>Delete this entry</a></small><p>#{s.body}</p>"
29
+ end
30
+
31
+ r+"<hr /><a href='#{URL(Add)}'>Add a new entry</a></body></html>"
32
+ end
33
+ end
34
+
35
+ class Remove < Route '/remove/([^\/]*)/(.*)'
36
+ def get( id, rev )
37
+ Story.delete(id, rev)
38
+ redirect( Index )
39
+ end
40
+ end
41
+
42
+ class Add < Route '/add'
43
+ def get
44
+ '
45
+ <html><body>
46
+ <h1>Add a new entry</h1>
47
+ <form method="POST">
48
+ Titre : <input type="text" name="title"><br />
49
+ <textarea name="body"></textarea><br />
50
+ <input type="submit">
51
+ </form>
52
+ </body></html>
53
+ '
54
+ end
55
+ def post
56
+ Story.create( :title => params['title'], :body => params['body'], :date => Time.now.to_s )
57
+ redirect( Index )
58
+ end
59
+ end
60
+ end
61
+
62
+ Capcode.run( :port => 3001, :host => "localhost", :log => "blog.log" )
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <body>
3
+ <h1>Capcode hello !</h1>
4
+ </body>
5
+ </html>
@@ -0,0 +1,61 @@
1
+ $:.unshift( "../lib" )
2
+ require 'capcode'
3
+
4
+ module Capcode
5
+ module Helpers
6
+ def bold( &b )
7
+ "<b>"+yield+"</b>"
8
+ end
9
+ end
10
+ end
11
+
12
+ module Capcode
13
+ class HTTPError
14
+ def r404(f)
15
+ "Pas glop !!! #{f} est inconnu !!!"
16
+ end
17
+ end
18
+
19
+ class Hello < Route '/hello/(.*)'
20
+ def get( you )
21
+ you = "you" if you.nil?
22
+
23
+ session = { :user => you }
24
+
25
+ "Hello " + bold { you } + " it's '#{Time.now} !"
26
+ end
27
+ end
28
+
29
+ class Redir < Route '/r'
30
+ def get
31
+ redirect( Hello, "Greg" )
32
+ end
33
+ end
34
+
35
+ class Glop < Route '/glop/(.*)', '/glop/code/([^\/]*)/(.*)'
36
+ def get( r, v )
37
+ "Glop receive #{r}, type #{r.class} and #{v}, type #{v.class} from #{URL(Glop)}"
38
+ end
39
+ end
40
+
41
+ class Js < Route '/toto'
42
+ def get
43
+ json( { :some => 'json', :stuff => ['here'] } )
44
+ end
45
+ end
46
+
47
+ class Env < Route '/env'
48
+ def get
49
+ x = env.map do |k,v|
50
+ "#{k} => #{v}"
51
+ end.join( "<br />\n" )
52
+ x
53
+ end
54
+ end
55
+ end
56
+
57
+ Capcode.map( "/file" ) do
58
+ Rack::File.new( "." )
59
+ end
60
+
61
+ Capcode.run( :port => 3001, :host => "localhost" )
@@ -0,0 +1,47 @@
1
+ $:.unshift( "../lib" )
2
+ require 'capcode'
3
+
4
+ module Capcode
5
+ class HTTPError
6
+ def r404(f)
7
+ "#{f} not found !!!"
8
+ end
9
+ end
10
+
11
+ class Index < Route '/'
12
+ def get
13
+ redirect( Hello, session[:user] )
14
+ end
15
+ end
16
+
17
+ class Hello < Route '/hello/(.*)'
18
+ def get( you )
19
+ if you.nil?
20
+ redirect( WhoAreYou )
21
+ else
22
+ "
23
+ Hello #{you}<br />
24
+ Clic <a href='#{URL(Hello)}'>here</a> if hou want to change your name
25
+ "
26
+ end
27
+ end
28
+ end
29
+
30
+ class WhoAreYou < Route '/who_are_you'
31
+ def get
32
+ '
33
+ Please, enter your name :<br />
34
+ <form method="POST">
35
+ <input type="text", name="user"><br />
36
+ <input type="submit">
37
+ </form>
38
+ '
39
+ end
40
+ def post
41
+ session[:user] = params['user']
42
+ redirect( Index )
43
+ end
44
+ end
45
+ end
46
+
47
+ Capcode.run( :port => 3000, :host => "localhost" )
@@ -0,0 +1,293 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+ require 'json'
4
+ require 'logger'
5
+ require 'capcode/core_ext'
6
+
7
+ module Capcode
8
+ CAPCOD_VERION="0.2.0"
9
+ @@__ROUTES = {}
10
+
11
+ class ParameterError < ArgumentError
12
+ end
13
+
14
+ # Helpers contains methods available in your controllers
15
+ module Helpers
16
+ # Help you to return a JSON response
17
+ #
18
+ # module Capcode
19
+ # class JsonResponse < Route '/json/([^\/]*)/(.*)'
20
+ # def get( arg1, arg2 )
21
+ # json( { :1 => arg1, :2 => arg2 })
22
+ # end
23
+ # end
24
+ # end
25
+ def json( d )
26
+ @response['Content-Type'] = 'application/json'
27
+ d.to_json
28
+ end
29
+
30
+ # Send a redirect response
31
+ #
32
+ # module Capcode
33
+ # class Hello < Route '/hello/(.*)'
34
+ # def get( you )
35
+ # if you.nil?
36
+ # redirect( WhoAreYou )
37
+ # else
38
+ # ...
39
+ # end
40
+ # end
41
+ # end
42
+ # end
43
+ def redirect( klass, *a )
44
+ [302, {'Location' => URL(klass, *a)}, '']
45
+ end
46
+
47
+ # Builds an URL route to a controller or a path
48
+ #
49
+ # if you declare the controller Hello :
50
+ #
51
+ # module Capcode
52
+ # class Hello < Route '/hello/(.*)'
53
+ # ...
54
+ # end
55
+ # end
56
+ #
57
+ # then
58
+ #
59
+ # URL( Hello, "you" ) # => /hello/you
60
+ def URL( klass, *a )
61
+ path = nil
62
+ a = a.delete_if{ |x| x.nil? }
63
+
64
+ if klass.class == Class
65
+ Capcode.routes.each do |p, k|
66
+ path = p if k.class == klass
67
+ end
68
+ else
69
+ path = klass
70
+ end
71
+
72
+ path+((a.size>0)?("/"+a.join("/")):(""))
73
+ end
74
+ end
75
+
76
+ include Rack
77
+
78
+ # HTTPError help you to create your own 404, 500 and/or 501 response
79
+ #
80
+ # To create a custom 404 reponse, create a fonction HTTPError.r404 in
81
+ # your application :
82
+ #
83
+ # module Capcode
84
+ # class HTTPError
85
+ # def r404(f)
86
+ # "#{f} not found :("
87
+ # end
88
+ # end
89
+ # end
90
+ #
91
+ # Do the same (r500 and r501) to customize 500 and 501 errors
92
+ class HTTPError
93
+ def initialize(app)#:nodoc:
94
+ @app = app
95
+ end
96
+
97
+ def call(env) #:nodoc:
98
+ status, headers, body = @app.call(env)
99
+
100
+ if self.methods.include? "r#{status}"
101
+ body = self.call "r#{status}", env['REQUEST_PATH']
102
+ headers['Content-Length'] = body.length.to_s
103
+ end
104
+
105
+ [status, headers, body]
106
+ end
107
+ end
108
+
109
+ class << self
110
+ # Add routes to a controller class
111
+ #
112
+ # module Capcode
113
+ # class Hello < Route '/hello/(.*)', '/hello/([^#]*)#(.*)'
114
+ # def get( arg1, arg2 )
115
+ # ...
116
+ # end
117
+ # end
118
+ # end
119
+ #
120
+ # In the <tt>get</tt> method, you will receive the maximum of parameters declared
121
+ # by the routes. In this example, you will receive 2 parameters. So if you
122
+ # go to <tt>/hello/world#friend</tt> then <tt>arg1</tt> will be set to <tt>world</tt> and <tt>arg2</tt>
123
+ # will be set to <tt>friend</tt>. Now if you go to <tt>/hello/you</tt>, then <tt>arg1</tt> will
124
+ # be set to <tt>you</tt> and <tt>arg2</tt> will be set to <tt>nil</tt>
125
+ #
126
+ # If the regexp in the route does not match, all arguments will be <tt>nil</tt>
127
+ def Route *u
128
+ Class.new {
129
+ meta_def(:__urls__){
130
+ # < Route '/hello/world/([^\/]*)/id(\d*)', '/hello/(.*)'
131
+ # # => [ {'/hello/world' => '([^\/]*)/id(\d*)', '/hello' => '(.*)'}, 2, <Capcode::Klass> ]
132
+ h = {}
133
+ max = 0
134
+ u.each do |_u|
135
+ m = /\/([^\/]*\(.*)/.match( _u )
136
+ if m.nil?
137
+ h[_u] = ''
138
+ else
139
+ h[m.pre_match] = m.captures[0]
140
+ max = Regexp.new(m.captures[0]).number_of_captures if max < Regexp.new(m.captures[0]).number_of_captures
141
+ end
142
+ end
143
+ [h, max, self]
144
+ }
145
+
146
+ # Hash containing all the request parameters (GET or POST)
147
+ def params
148
+ @request.params
149
+ end
150
+
151
+ # Hash containing all the environment variables
152
+ def env
153
+ @env
154
+ end
155
+
156
+ # Hash session
157
+ def session
158
+ @env['rack.session']
159
+ end
160
+
161
+ # Return the Rack::Request object
162
+ def request
163
+ @request
164
+ end
165
+
166
+ # Return the Rack::Response object
167
+ def response
168
+ @response
169
+ end
170
+
171
+ def call( e ) #:nodoc:
172
+ @env = e
173
+ @response = Rack::Response.new
174
+ @request = Rack::Request.new(@env)
175
+
176
+ r = case @env["REQUEST_METHOD"]
177
+ when "GET"
178
+ sc = @request.script_name
179
+ sc = "/" if sc.size == 0
180
+ regexp = Regexp.new( self.class.__urls__[0][sc] )
181
+ nargs = self.class.__urls__[1]
182
+
183
+ args = regexp.match( Rack::Utils.unescape(@request.path_info).gsub( /^\//, "" ) )
184
+ if args.nil?
185
+ raise Capcode::ParameterError, "Path info `#{@request.path_info}' does not match route regexp `#{regexp.source}'"
186
+ else
187
+ args = args.captures
188
+ end
189
+
190
+ while args.size < nargs
191
+ args << nil
192
+ end
193
+
194
+ get( *args )
195
+ when "POST"
196
+ post
197
+ end
198
+ if r.respond_to?(:to_ary)
199
+ @response.status = r[0]
200
+ r[1].each do |k,v|
201
+ @response[k] = v
202
+ end
203
+ @response.body = r[2]
204
+ else
205
+ @response.write r
206
+ end
207
+
208
+ @response.finish
209
+ end
210
+
211
+ include Capcode::Helpers
212
+ }
213
+ end
214
+
215
+ # This method help you to map and URL to a Rack or What you want Helper
216
+ #
217
+ # Capcode.map( "/file" ) do
218
+ # Rack::File.new( "." )
219
+ # end
220
+ def map( r, &b )
221
+ @@__ROUTES[r] = yield
222
+ end
223
+
224
+ # Start your application.
225
+ #
226
+ # Options :
227
+ # * <tt>:port</tt> = Listen port
228
+ # * <tt>:host</tt> = Listen host
229
+ # * <tt>:server</tt> = Server type (webrick or mongrel)
230
+ # * <tt>:log</tt> = Output logfile (default: STDOUT)
231
+ # * <tt>:session</tt> = Session parameters. See Rack::Session for more informations
232
+ def run( args = {} )
233
+ conf = {
234
+ :port => args[:port]||3000,
235
+ :host => args[:host]||"localhost",
236
+ :server => args[:server]||nil,
237
+ :log => args[:log]||$stdout,
238
+ :session => args[:session]||{}
239
+ }
240
+
241
+ # Check that mongrel exists
242
+ if conf[:server].nil? || conf[:server] == "mongrel"
243
+ begin
244
+ require 'mongrel'
245
+ conf[:server] = "mongrel"
246
+ rescue LoadError
247
+ puts "!! could not load mongrel. Falling back to webrick."
248
+ conf[:server] = "webrick"
249
+ end
250
+ end
251
+
252
+ Capcode.constants.each do |k|
253
+ begin
254
+ if eval "Capcode::#{k}.public_methods(true).include?( '__urls__' )"
255
+ u, m, c = eval "Capcode::#{k}.__urls__"
256
+ u.keys.each do |_u|
257
+ @@__ROUTES[_u] = c.new
258
+ end
259
+ end
260
+ rescue => e
261
+ raise e.message
262
+ end
263
+ end
264
+
265
+ app = Rack::URLMap.new(@@__ROUTES)
266
+ app = Rack::Session::Cookie.new( app, conf[:session] )
267
+ app = Capcode::HTTPError.new(app)
268
+ app = Rack::ContentLength.new(app)
269
+ app = Rack::Lint.new(app)
270
+ app = Rack::ShowExceptions.new(app)
271
+ # app = Rack::Reloader.new(app) ## -- NE RELOAD QUE capcode.rb -- So !!!
272
+ app = Rack::CommonLogger.new( app, Logger.new(conf[:log]) )
273
+
274
+
275
+ case conf[:server]
276
+ when "mongrel"
277
+ puts "** Starting Mongrel on #{conf[:host]}:#{conf[:port]}"
278
+ Rack::Handler::Mongrel.run( app, {:Port => conf[:port], :Host => conf[:host]} ) { |server|
279
+ trap "SIGINT", proc { server.stop }
280
+ }
281
+ when "webrick"
282
+ puts "** Starting WEBrick on #{conf[:host]}:#{conf[:port]}"
283
+ Rack::Handler::WEBrick.run( app, {:Port => conf[:port], :BindAddress => conf[:host]} ) { |server|
284
+ trap "SIGINT", proc { server.shutdown }
285
+ }
286
+ end
287
+ end
288
+
289
+ def routes #:nodoc:
290
+ @@__ROUTES
291
+ end
292
+ end
293
+ end