Capcode 0.1.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.
@@ -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