camping 2.0 → 2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -0
- data/Rakefile +21 -3
- data/bin/camping +2 -85
- data/book/51_upgrading +17 -0
- data/lib/camping-unabridged.rb +56 -16
- data/lib/camping.rb +37 -32
- data/lib/camping/mab.rb +2 -0
- data/lib/camping/reloader.rb +39 -45
- data/lib/camping/server.rb +217 -130
- data/lib/camping/session.rb +5 -6
- data/lib/camping/template.rb +17 -0
- data/test/app_markup.rb +51 -0
- data/test/app_route_generating.rb +22 -0
- data/test/app_sessions.rb +46 -0
- data/test/app_simple.rb +97 -0
- data/test/test_helper.rb +51 -0
- metadata +9 -16
- data/doc/api.html +0 -1953
- data/doc/book.html +0 -73
- data/doc/book/01_introduction.html +0 -57
- data/doc/book/02_getting_started.html +0 -573
- data/doc/book/51_upgrading.html +0 -146
- data/doc/created.rid +0 -1
- data/doc/images/Camping.gif +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/permalink.gif +0 -0
- data/doc/index.html +0 -148
- data/doc/js/camping.js +0 -79
- data/doc/js/jquery.js +0 -32
- data/doc/rdoc.css +0 -117
data/CHANGELOG
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
= 2.1
|
2
|
+
=== 19th Aug, 2010 (whyday)
|
3
|
+
* Helpers#R now calls to_param on any object it passes in
|
4
|
+
* Fix route generation issue with routes including "." (#22)
|
5
|
+
* Improved tests
|
6
|
+
* Improved 1.9 support
|
7
|
+
* Camping::Server is now built upon Rack::Server
|
8
|
+
* Add support for ERB, Haml etc through Tilt
|
9
|
+
* Introducing Camping.options and Camping#set
|
10
|
+
* Camping::Server only loads ActiveRecord when needed
|
11
|
+
|
1
12
|
= 2.0
|
2
13
|
=== 9th Apr, 2010
|
3
14
|
* Speed-up of Camping::Mab (thanks zimbatm!)
|
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ task :default => :check
|
|
10
10
|
|
11
11
|
## Constants
|
12
12
|
NAME = "camping"
|
13
|
-
BRANCH = "2.
|
13
|
+
BRANCH = "2.1"
|
14
14
|
GIT = ENV['GIT'] || "git"
|
15
15
|
REV = `#{GIT} rev-list HEAD`.strip.split.length
|
16
16
|
VERS = ENV['VERSION'] || (REV.zero? ? BRANCH : [BRANCH, REV] * '.')
|
@@ -60,6 +60,7 @@ omni =
|
|
60
60
|
s.add_dependency('sqlite3-ruby', '>=1.1.0.1')
|
61
61
|
s.add_dependency('mongrel')
|
62
62
|
s.add_dependency('RedCloth')
|
63
|
+
s.add_dependency('markaby')
|
63
64
|
end
|
64
65
|
|
65
66
|
## RDoc
|
@@ -123,7 +124,8 @@ end
|
|
123
124
|
|
124
125
|
## Tests
|
125
126
|
Rake::TestTask.new(:test) do |t|
|
126
|
-
t.
|
127
|
+
t.libs << "test"
|
128
|
+
t.test_files = FileList['test/app_*.rb']
|
127
129
|
# t.warning = true
|
128
130
|
# t.verbose = true
|
129
131
|
end
|
@@ -139,14 +141,19 @@ task :diff do
|
|
139
141
|
u << Ruby2Ruby.new.process(RubyParser.new.parse(File.read("lib/camping.rb")))
|
140
142
|
m << Ruby2Ruby.new.process(RubyParser.new.parse(File.read("lib/camping-unabridged.rb")))
|
141
143
|
|
144
|
+
u.flush
|
145
|
+
m.flush
|
146
|
+
|
142
147
|
sh "diff -u #{u.path} #{m.path} | less"
|
143
148
|
|
144
149
|
u.delete
|
145
150
|
m.delete
|
146
151
|
end
|
147
152
|
|
153
|
+
error = false
|
154
|
+
|
148
155
|
## Check
|
149
|
-
task :check => ["check:valid", "check:size", "check:lines"]
|
156
|
+
task :check => ["test", "check:valid", "check:size", "check:lines", "check:exit"]
|
150
157
|
namespace :check do
|
151
158
|
|
152
159
|
desc "Check source code validity"
|
@@ -155,8 +162,13 @@ namespace :check do
|
|
155
162
|
u = RubyParser.new.parse(File.read("lib/camping-unabridged.rb"))
|
156
163
|
m = RubyParser.new.parse(File.read("lib/camping.rb"))
|
157
164
|
|
165
|
+
u.reject! do |sexp|
|
166
|
+
sexp.is_a?(Sexp) and sexp[1] == s(:gvar, :$LOADED_FEATURES)
|
167
|
+
end
|
168
|
+
|
158
169
|
unless u == m
|
159
170
|
STDERR.puts "camping.rb and camping-unabridged.rb are not synchronized."
|
171
|
+
error = true
|
160
172
|
end
|
161
173
|
end
|
162
174
|
|
@@ -169,6 +181,7 @@ namespace :check do
|
|
169
181
|
end
|
170
182
|
if File.size("lib/camping.rb") > SIZE_LIMIT
|
171
183
|
STDERR.puts "lib/camping.rb: file is too big (> #{SIZE_LIMIT})"
|
184
|
+
error = true
|
172
185
|
end
|
173
186
|
end
|
174
187
|
|
@@ -177,10 +190,15 @@ namespace :check do
|
|
177
190
|
i = 1
|
178
191
|
File.open("lib/camping.rb").each_line do |line|
|
179
192
|
if line.size > 81 # 1 added for \n
|
193
|
+
error = true
|
180
194
|
STDERR.puts "lib/camping.rb:#{i}: line too long (#{line[-10..-1].inspect})"
|
181
195
|
end
|
182
196
|
i += 1
|
183
197
|
end
|
184
198
|
end
|
199
|
+
|
200
|
+
task :exit do
|
201
|
+
exit 1 if error
|
202
|
+
end
|
185
203
|
|
186
204
|
end
|
data/bin/camping
CHANGED
@@ -1,97 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
trap("INT") { exit }
|
4
|
-
require 'optparse'
|
5
|
-
require 'ostruct'
|
6
|
-
require 'stringio'
|
7
|
-
require 'yaml'
|
8
|
-
|
9
3
|
$:.unshift File.dirname(__FILE__) + "/../lib"
|
4
|
+
|
10
5
|
require 'camping'
|
11
6
|
require 'camping/server'
|
12
7
|
|
13
|
-
conf = OpenStruct.new(:host => '0.0.0.0', :port => 3301)
|
14
|
-
|
15
|
-
# Setup paths
|
16
|
-
if home = ENV['HOME'] # POSIX
|
17
|
-
db_path = File.join(home, '.camping.db')
|
18
|
-
rc_path = File.join(home, '.campingrc')
|
19
|
-
elsif home = ENV['APPDATA'] # MSWIN
|
20
|
-
db_path = File.join(home, 'Camping.db')
|
21
|
-
rc_path = File.join(home, 'Campingrc')
|
22
|
-
end
|
23
|
-
|
24
|
-
# Parse options
|
25
|
-
opts = OptionParser.new do |opts|
|
26
|
-
opts.banner = "Usage: camping app1.rb, app2.rb..."
|
27
|
-
opts.define_head "#{File.basename($0)}, the microframework ON-button for ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
28
|
-
opts.separator ""
|
29
|
-
opts.separator "Specific options:"
|
30
|
-
|
31
|
-
opts.on("-h", "--host HOSTNAME", "Host for web server to bind to (default is all IPs)") { |val| conf.host = val }
|
32
|
-
opts.on("-p", "--port NUM", "Port for web server (defaults to #{conf.port})") { |val| conf.port = val }
|
33
|
-
opts.on("-d", "--database FILE", "SQLite3 database path (defaults to #{db_path ? db_path : '<none>'})") { |db_path| conf.database = {:adapter => 'sqlite3', :database => db_path} }
|
34
|
-
opts.on("-C", "--console", "Run in console mode with IRB") { conf.server = "console" }
|
35
|
-
server_list = ["mongrel", "webrick", "console"]
|
36
|
-
opts.on("-s", "--server NAME", server_list, "Server to force (#{server_list.join(', ')})") { |val| conf.server = val }
|
37
|
-
|
38
|
-
opts.separator ""
|
39
|
-
opts.separator "Common options:"
|
40
|
-
|
41
|
-
# No argument, shows at tail. This will print an options summary.
|
42
|
-
# Try it and see!
|
43
|
-
opts.on_tail("-?", "--help", "Show this message") do
|
44
|
-
puts opts
|
45
|
-
exit
|
46
|
-
end
|
47
|
-
|
48
|
-
# Another typical switch to print the version.
|
49
|
-
opts.on_tail("-v", "--version", "Show version") do
|
50
|
-
puts Gem.loaded_specs['camping'].version
|
51
|
-
exit
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
8
|
begin
|
56
|
-
|
9
|
+
Camping::Server.start
|
57
10
|
rescue OptionParser::ParseError => ex
|
58
11
|
STDERR.puts "!! #{ex.message}"
|
59
12
|
puts "** use `#{File.basename($0)} --help` for more details..."
|
60
13
|
exit 1
|
61
14
|
end
|
62
|
-
|
63
|
-
if ARGV.length < 1
|
64
|
-
puts opts
|
65
|
-
exit 1
|
66
|
-
end
|
67
|
-
|
68
|
-
# Load configuration if any
|
69
|
-
if rc_path and File.exists?(rc_path)
|
70
|
-
YAML.load_file(rc_path).each do |k,v|
|
71
|
-
conf.send("#{k}=", v) unless conf.send(k)
|
72
|
-
end
|
73
|
-
puts "** conf file #{rc_path} loaded"
|
74
|
-
end
|
75
|
-
|
76
|
-
# Default db
|
77
|
-
if conf.database.nil? and db_path
|
78
|
-
conf.database = { :adapter => 'sqlite3', :database => db_path }
|
79
|
-
end
|
80
|
-
|
81
|
-
|
82
|
-
# get a copy of the paths to pass to the server
|
83
|
-
paths = ARGV.dup
|
84
|
-
|
85
|
-
# Check that mongrel exists
|
86
|
-
if conf.server.nil? || conf.server == "mongrel"
|
87
|
-
begin
|
88
|
-
require 'mongrel'
|
89
|
-
conf.server = "mongrel"
|
90
|
-
rescue LoadError
|
91
|
-
puts "!! Could not load mongrel. Falling back to webrick."
|
92
|
-
conf.server = "webrick"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
server = Camping::Server.new(conf, paths)
|
97
|
-
server.start
|
data/book/51_upgrading
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
= Appendix I: Upgrade Notes
|
2
2
|
|
3
|
+
This document includes everything needed in order to *upgrade* your
|
4
|
+
applications. If you're looking for all the new features in a version, please
|
5
|
+
have a look at the CHANGELOG in the Camping source.
|
6
|
+
|
7
|
+
|
8
|
+
== From 2.0 to 2.1
|
9
|
+
=== Options
|
10
|
+
|
11
|
+
In Camping 2.1 there is now a built-in way to store options and settings. If
|
12
|
+
you use cookie session, it means that you'll now have to change to:
|
13
|
+
|
14
|
+
module Nuts
|
15
|
+
set :secret, "Very secret text, which no-one else should know!"
|
16
|
+
include Camping::Session
|
17
|
+
end
|
18
|
+
|
19
|
+
|
3
20
|
== From 1.5 to 2.0
|
4
21
|
=== Rack
|
5
22
|
|
data/lib/camping-unabridged.rb
CHANGED
@@ -12,6 +12,8 @@
|
|
12
12
|
require "uri"
|
13
13
|
require "rack"
|
14
14
|
|
15
|
+
$LOADED_FEATURES << "camping.rb"
|
16
|
+
|
15
17
|
class Object #:nodoc:
|
16
18
|
def meta_def(m,&b) #:nodoc:
|
17
19
|
(class<<self;self end).send(:define_method,m,&b)
|
@@ -46,6 +48,7 @@ module Camping
|
|
46
48
|
S = IO.read(__FILE__) rescue nil
|
47
49
|
P = "<h1>Cam\ping Problem!</h1><h2>%s</h2>"
|
48
50
|
U = Rack::Utils
|
51
|
+
O = {}
|
49
52
|
Apps = []
|
50
53
|
# An object-like Hash.
|
51
54
|
# All Camping query string and cookie variables are loaded as this.
|
@@ -183,7 +186,7 @@ module Camping
|
|
183
186
|
raise "bad route" unless u = c.urls.find{|x|
|
184
187
|
break x if x.scan(p).size == g.size &&
|
185
188
|
/^#{x}\/?$/ =~ (x=g.inject(x){|x,a|
|
186
|
-
x.sub p,U.escape((a
|
189
|
+
x.sub p,U.escape((a.to_param rescue a))}.gsub(/\\(.)/){$1})
|
187
190
|
}
|
188
191
|
h.any?? u+"?"+U.build_query(h[0]) : u
|
189
192
|
end
|
@@ -195,7 +198,7 @@ module Camping
|
|
195
198
|
# self / "styles.css" #=> "styles.css"
|
196
199
|
# self / R(Edit, 1) #=> "/blog/edit/1"
|
197
200
|
#
|
198
|
-
def /(p); p[0]
|
201
|
+
def /(p); p[0] == ?/ ? @root + p : p end
|
199
202
|
|
200
203
|
# Builds a URL route to a controller or a path, returning a URI object.
|
201
204
|
# This way you'll get the hostname and the port number, a complete URL.
|
@@ -235,7 +238,25 @@ module Camping
|
|
235
238
|
module Base
|
236
239
|
attr_accessor :env, :request, :root, :input, :cookies, :state,
|
237
240
|
:status, :headers, :body
|
238
|
-
|
241
|
+
|
242
|
+
T = {}
|
243
|
+
L = :layout
|
244
|
+
|
245
|
+
# Finds a template, returning either:
|
246
|
+
#
|
247
|
+
# false # => Could not find template
|
248
|
+
# true # => Found template in Views
|
249
|
+
# instance of Tilt # => Found template in a file
|
250
|
+
def lookup(n)
|
251
|
+
T.fetch(n.to_sym) do |k|
|
252
|
+
t = Views.method_defined?(k) ||
|
253
|
+
(f = Dir[[O[:views] || "views", "#{n}.*"]*'/'][0]) &&
|
254
|
+
Template.new(f, O[f[/\.(\w+)$/, 1].to_sym] || {})
|
255
|
+
|
256
|
+
O[:dynamic_templates] ? t : T[k] = t
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
239
260
|
# Display a view, calling it by its method name +v+. If a <tt>layout</tt>
|
240
261
|
# method is found in Camping::Views, it will be used to wrap the HTML.
|
241
262
|
#
|
@@ -248,8 +269,15 @@ module Camping
|
|
248
269
|
# end
|
249
270
|
# end
|
250
271
|
#
|
251
|
-
def render(v
|
252
|
-
|
272
|
+
def render(v, *a, &b)
|
273
|
+
if t = lookup(v)
|
274
|
+
o = Hash === a[-1] ? a.pop : {}
|
275
|
+
s = (t == true) ? mab{ send(v, *a, &b) } : t.render(self, o[:locals] || {}, &b)
|
276
|
+
s = render(L, o.merge(L => false)) { s } if v.to_s[0] != ?_ && o[L] != false && lookup(L)
|
277
|
+
s
|
278
|
+
else
|
279
|
+
raise "Can't find template #{v}"
|
280
|
+
end
|
253
281
|
end
|
254
282
|
|
255
283
|
# You can directly return HTML form your controller for quick debugging
|
@@ -262,11 +290,8 @@ module Camping
|
|
262
290
|
# end
|
263
291
|
#
|
264
292
|
# You can also pass true to use the :layout HTML wrapping method
|
265
|
-
def mab(
|
266
|
-
|
267
|
-
s=m.capture(&b)
|
268
|
-
s=m.capture{layout{s}} if l && m.respond_to?(:layout)
|
269
|
-
s
|
293
|
+
def mab(&b)
|
294
|
+
(@mab ||= Mab.new({},self)).capture(&b)
|
270
295
|
end
|
271
296
|
|
272
297
|
# A quick means of setting this controller's status, body and headers
|
@@ -355,7 +380,7 @@ module Camping
|
|
355
380
|
# end
|
356
381
|
# end
|
357
382
|
def to_a
|
358
|
-
@env['rack.session'] = @state
|
383
|
+
@env['rack.session'] = Hash[@state]
|
359
384
|
r = Rack::Response.new(@body, @status, @headers)
|
360
385
|
@cookies.each do |k, v|
|
361
386
|
next if @old_cookies[k] == v
|
@@ -517,11 +542,11 @@ module Camping
|
|
517
542
|
# * Classes with routes are searched in order of their creation.
|
518
543
|
#
|
519
544
|
# So, define your catch-all controllers last.
|
520
|
-
def D(p, m)
|
545
|
+
def D(p, m, e)
|
521
546
|
p = '/' if !p || !p[0]
|
522
547
|
r.map { |k|
|
523
548
|
k.urls.map { |x|
|
524
|
-
return (k.
|
549
|
+
return (k.method_defined?(m)) ?
|
525
550
|
[k, m, *$~[1..-1]] : [I, 'r501', m] if p =~ /^#{x}\/?$/
|
526
551
|
}
|
527
552
|
}
|
@@ -547,9 +572,9 @@ module Camping
|
|
547
572
|
end
|
548
573
|
constants.map { |c|
|
549
574
|
k = const_get(c)
|
550
|
-
k.send :include,C,Base,Helpers,Models
|
575
|
+
k.send :include,C,X,Base,Helpers,Models
|
551
576
|
@r=[k]+r if r-[k]==r
|
552
|
-
k.meta_def(:urls){["/#{c.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.respond_to?:urls
|
577
|
+
k.meta_def(:urls){["/#{c.to_s.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.respond_to?:urls
|
553
578
|
}
|
554
579
|
end
|
555
580
|
end
|
@@ -584,7 +609,7 @@ module Camping
|
|
584
609
|
def call(e)
|
585
610
|
X.M
|
586
611
|
p = e['PATH_INFO'] = U.unescape(e['PATH_INFO'])
|
587
|
-
k,m,*a=X.D p,e['REQUEST_METHOD'].downcase
|
612
|
+
k,m,*a=X.D p,e['REQUEST_METHOD'].downcase,e
|
588
613
|
k.new(e,m).service(*a).to_a
|
589
614
|
rescue
|
590
615
|
r500(:I, k, m, $!, :env => e).to_a
|
@@ -627,6 +652,20 @@ module Camping
|
|
627
652
|
m = a.shift.new(method(:call), *a, &b)
|
628
653
|
meta_def(:call) { |e| m.call(e) }
|
629
654
|
end
|
655
|
+
|
656
|
+
# A hash where you can set different settings.
|
657
|
+
def options
|
658
|
+
O
|
659
|
+
end
|
660
|
+
|
661
|
+
# Shortcut for setting options:
|
662
|
+
#
|
663
|
+
# module Blog
|
664
|
+
# set :secret, "Hello!"
|
665
|
+
# end
|
666
|
+
def set(k, v)
|
667
|
+
O[k] = v
|
668
|
+
end
|
630
669
|
end
|
631
670
|
|
632
671
|
# Views is an empty module for storing methods which create HTML. The HTML
|
@@ -696,6 +735,7 @@ module Camping
|
|
696
735
|
end
|
697
736
|
|
698
737
|
autoload :Mab, 'camping/mab'
|
738
|
+
autoload :Template, 'camping/template'
|
699
739
|
C
|
700
740
|
end
|
701
741
|
|
data/lib/camping.rb
CHANGED
@@ -1,40 +1,45 @@
|
|
1
1
|
require "uri";require "rack";class Object;def meta_def m,&b;(class<<self;self
|
2
2
|
end).send:define_method,m,&b end end;module Camping;C=self;S=IO.read(__FILE__
|
3
|
-
)rescue nil;P="<h1>Cam\ping Problem!</h1><h2>%s</h2>";U=Rack::Utils;Apps=[]
|
3
|
+
)rescue nil;P="<h1>Cam\ping Problem!</h1><h2>%s</h2>";U=Rack::Utils;O={};Apps=[]
|
4
4
|
class H<Hash;def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.
|
5
5
|
to_s]:super end;undef id,type if ??==63;end;module Helpers;def R c,*g;p,h=
|
6
6
|
/\(.+?\)/,g.grep(Hash);g-=h;raise"bad route"unless u=c.urls.find{|x|break x if
|
7
|
-
x.scan(p).size==g.size&&/^#{x}\/?$/=~(x=g.inject(x){|x,a|x.sub p,U.escape((a
|
8
|
-
|
7
|
+
x.scan(p).size==g.size&&/^#{x}\/?$/=~(x=g.inject(x){|x,a|x.sub p,U.escape((a.
|
8
|
+
to_param rescue a))}.gsub(/\\(.)/){$1})};h.any?? u+"?"+U.build_query(h[0]):u end;def
|
9
9
|
/ p;p[0]==?/?@root + p : p end;def URL c='/',*a;c=R(c, *a) if c.respond_to?(
|
10
10
|
:urls);c=self/c;c=@request.url[/.{8,}?(?=\/)/]+c if c[0]==?/;URI c end end
|
11
11
|
module Base;attr_accessor:env,:request,:root,:input,:cookies,:state,:status,
|
12
|
-
:headers,:body;def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end;
|
33
|
-
|
34
|
-
k,
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
12
|
+
:headers,:body;T={};L=:layout;def lookup n;T.fetch(n.to_sym){|k|t=Views.
|
13
|
+
method_defined?(k)||(f=Dir[[O[:views]||"views","#{n}.*"]*'/'][0])&&Template.
|
14
|
+
new(f,O[f[/\.(\w+)$/,1].to_sym]||{});O[:dynamic_templates]?t:T[k]=t} end
|
15
|
+
def render(v,*a,&b)if t=lookup(v);o=Hash===a[-1]?a.pop: {};s=(t==true)?mab{
|
16
|
+
send v,*a,&b}: t.render(self,o[:locals]||{},&b);s=render(L,o.merge(L=>false)){s
|
17
|
+
}if v.to_s[0]!=?_&&o[L]!=false&&lookup(L);s;else;raise"Can't find template #{v}"end
|
18
|
+
end;def mab &b;(@mab||=Mab.new({},self)).capture(&b) end;def r s,b,h={};b,h=h,
|
19
|
+
b if Hash===b;@status=s;@headers.merge!(h);@body=b;end;def redirect *a;r 302,'',
|
20
|
+
'Location'=>URL(*a).to_s;end;def r404 p;P%"#{p} not found"end;def r500 k,m,e
|
21
|
+
raise e;end;def r501 m;P%"#{m.upcase} not implemented"end;def to_a;@env[
|
22
|
+
'rack.session']=Hash[@state];r=Rack::Response.new(@body,@status,@headers)
|
23
|
+
@cookies.each{|k,v|next if @old_cookies[k]==v;v={:value=>v,:path=>self/"/"} if
|
24
|
+
String===v;r.set_cookie(k,v)};r.to_a;end;def initialize(env,m) r=@request=Rack::
|
25
|
+
Request.new(@env=env);@root,@input,@cookies,@state,@headers,@status,@method=r.
|
26
|
+
script_name.sub(/\/$/,''),n(r.params),H[@old_cookies = r.cookies],H[r.session],
|
27
|
+
{},m=~/r(\d+)/?$1.to_i: 200,m end;def n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]=
|
28
|
+
n(v);m}: h end;def service *a;r=catch(:halt){send(@method,*a)};@body||=r;self
|
29
|
+
end;end;module Controllers;@r=[];class<<self;def r;@r end;def R *u;r=@r;Class.
|
30
|
+
new{meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def D p,m,e;p='/'if !p||
|
31
|
+
!p[0];r.map{|k|k.urls.map{|x|return(k.method_defined? m)?[k,m,*$~[1..-1]]:[I,
|
32
|
+
'r501',m]if p=~/^#{x}\/?$/}};[I,'r404',p] end;N=H.new{|_,x|x.downcase}.merge!(
|
33
|
+
"N"=>'(\d+)',"X"=>'([^/]+)',"Index"=>'');def M;def M;end;constants.map{|c|k=
|
34
|
+
const_get(c);k.send:include,C,X,Base,Helpers,Models;@r=[k]+r if r-[k]==r
|
35
|
+
k.meta_def(:urls){ [ "/#{c.to_s.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.
|
36
|
+
respond_to?:urls}end end;I=R();end;X=Controllers;class<<self;def goes m;Apps<<
|
37
|
+
eval(S.gsub(/Camping/,m.to_s),TOPLEVEL_BINDING) end;def call e;X.M
|
38
|
+
p=e['PATH_INFO']=U.unescape(e['PATH_INFO']);k,m,*a=X.D p,e['REQUEST_METHOD'].
|
39
|
+
downcase,e;k.new(e,m).service(*a).to_a;rescue;r500(:I,k,m,$!,:env=>e).to_a;end
|
40
|
+
def method_missing m,c,*a;X.M;h=Hash===a[-1]?a.pop: {};e=H[Rack::MockRequest.
|
41
|
+
env_for('',h.delete(:env)||{})];k=X.const_get(c).new(e,m.to_s);h.each{|i,v|k.
|
42
|
+
send"#{i}=",v};k.service(*a);end;def use*a,&b;m=a.shift.new(method(:call),*a,&b)
|
43
|
+
meta_def(:call){|e|m.call(e)}end;def options;O end;def set k,v;O[k]=v end end
|
44
|
+
module Views;include X,Helpers end;module Models;autoload:Base,'camping/ar';end
|
45
|
+
autoload:Mab,'camping/mab';autoload:Template,'camping/template';C end
|