camping 1.5 → 1.5.180

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -2,13 +2,14 @@ require 'rake'
2
2
  require 'rake/clean'
3
3
  require 'rake/gempackagetask'
4
4
  require 'rake/rdoctask'
5
+ require 'rake/testtask'
5
6
  require 'fileutils'
6
7
  include FileUtils
7
8
 
8
9
  NAME = "camping"
9
10
  REV = File.read(".svn/entries")[/committed-rev="(\d+)"/, 1] rescue nil
10
11
  VERS = ENV['VERSION'] || ("1.5" + (REV ? ".#{REV}" : ""))
11
- CLEAN.include ['**/.*.sw?', '*.gem', '.config']
12
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config', 'test/test.log']
12
13
  RDOC_OPTS = ['--quiet', '--title', "Camping, the Documentation",
13
14
  "--opname", "index.html",
14
15
  "--line-numbers",
@@ -74,11 +75,32 @@ spec =
74
75
  s.bindir = "bin"
75
76
  end
76
77
 
78
+ omni =
79
+ Gem::Specification.new do |s|
80
+ s.name = "camping-omnibus"
81
+ s.version = VERS
82
+ s.platform = Gem::Platform::RUBY
83
+ s.summary = "the camping meta-package for updating ActiveRecord, Mongrel and SQLite3 bindings"
84
+ s.description = s.summary
85
+ %w[author email homepage].each { |x| s.__send__("#{x}=", spec.__send__(x)) }
86
+
87
+ s.add_dependency('camping', "=#{VERS}")
88
+ s.add_dependency('activerecord')
89
+ s.add_dependency('sqlite3-ruby', '>=1.1.0.1')
90
+ s.add_dependency('mongrel')
91
+ s.add_dependency('acts_as_versioned')
92
+ s.add_dependency('RedCloth')
93
+ end
94
+
77
95
  Rake::GemPackageTask.new(spec) do |p|
78
96
  p.need_tar = true
79
97
  p.gem_spec = spec
80
98
  end
81
99
 
100
+ Rake::GemPackageTask.new(omni) do |p|
101
+ p.gem_spec = omni
102
+ end
103
+
82
104
  task :install do
83
105
  sh %{rake package}
84
106
  sh %{sudo gem install pkg/#{NAME}-#{VERS}}
@@ -87,3 +109,9 @@ end
87
109
  task :uninstall => [:clean] do
88
110
  sh %{sudo gem uninstall #{NAME}}
89
111
  end
112
+
113
+ Rake::TestTask.new(:test) do |t|
114
+ t.test_files = FileList['test/test_*.rb']
115
+ # t.warning = true
116
+ # t.verbose = true
117
+ end
@@ -203,10 +203,10 @@ module Camping
203
203
  # </div>
204
204
  #
205
205
  def R(c,*g)
206
- p=/\(.+?\)/
207
- g.inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|
206
+ p,h=/\(.+?\)/,g.grep(Hash)
207
+ (g-=h).inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|
208
208
  s.sub p,C.escape((a[a.class.primary_key]rescue a))
209
- }
209
+ }+(h.any?? "?"+h[0].map{|x|x.map{|z|C.escape z}*"="}*"&": "")
210
210
  end
211
211
 
212
212
  # Shows AR validation errors for the object passed.
@@ -337,7 +337,7 @@ module Camping
337
337
  a.shift if a[0]==:render
338
338
  m=Mab.new({},self)
339
339
  s=m.capture{send(*a,&b)}
340
- s=m.layout{s} if /^_/!~a[0].to_s and m.respond_to?:layout
340
+ s=m.capture{send(:layout){s}} if /^_/!~a[0].to_s and m.respond_to?:layout
341
341
  s
342
342
  end
343
343
 
@@ -368,12 +368,26 @@ module Camping
368
368
  #
369
369
  def r(s, b, h = {}); @status = s; @headers.merge!(h); @body = b; end
370
370
 
371
+ # Turn a controller into an array. This is designed to be used to pipe
372
+ # controllers into the <tt>r</tt> method. A great way to forward your
373
+ # requests!
374
+ #
375
+ # class Read < '/(\d+)'
376
+ # def get(id)
377
+ # Post.find(id)
378
+ # rescue
379
+ # r *Blog.get(:NotFound, @env.REQUEST_URI)
380
+ # end
381
+ # end
382
+ #
383
+ def to_a;[@status, @body, @headers] end
384
+
371
385
  def initialize(r, e, m) #:nodoc:
372
386
  e = H[e.to_hash]
373
387
  @status, @method, @env, @headers, @root = 200, m.downcase, e,
374
388
  {'Content-Type'=>'text/html'}, e.SCRIPT_NAME.sub(/\/$/,'')
375
389
  @k = C.kp(e.HTTP_COOKIE)
376
- qs = C.qs_parse(e.QUERY_STRING)
390
+ qs = C.qsp(e.QUERY_STRING)
377
391
  @in = r
378
392
  if %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)|n.match(e.CONTENT_TYPE)
379
393
  b = /(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/
@@ -404,11 +418,11 @@ module Camping
404
418
  end
405
419
  o<<l
406
420
  end
407
- qs[fn]=fh if fn
421
+ C.qsp(fn,'&;',fh,qs) if fn
408
422
  fh[:tempfile].rewind if fh.is_a?H
409
423
  end
410
424
  elsif @method == "post"
411
- qs.merge!(C.qs_parse(@in.read))
425
+ qs.merge!(C.qsp(@in.read))
412
426
  end
413
427
  @cookies, @input = @k.dup, qs.dup
414
428
  end
@@ -427,7 +441,9 @@ module Camping
427
441
  # Used by the web server to convert the current request to a string. If you need to
428
442
  # alter the way Camping builds HTTP headers, consider overriding this method.
429
443
  def to_s
430
- "Status: #{@status}#{Z+@headers.map{|k,v|[*v].map{|x|"#{k}: #{x}"}}*Z+Z*2+@body}"
444
+ a=[]
445
+ @headers.map{|k,v|[*v].map{|x|a<<"#{k}: #{x}"}}
446
+ "Status: #{@status}#{Z+a*Z+Z*2+@body}"
431
447
  end
432
448
 
433
449
  end
@@ -518,7 +534,7 @@ module Camping
518
534
  end
519
535
  constants.map { |c|
520
536
  k=const_get(c)
521
- k.send:include,C,Base,Models
537
+ k.send :include,C,Base,Models
522
538
  r[0,0]=k if !r.include?k
523
539
  k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls
524
540
  }
@@ -614,28 +630,28 @@ module Camping
614
630
 
615
631
  # Parses a query string into an Camping::H object.
616
632
  #
617
- # input = Camping.qs_parse("name=Philarp+Tremain&hair=sandy+blonde")
633
+ # input = Camping.qsp("name=Philarp+Tremain&hair=sandy+blonde")
618
634
  # input.name
619
635
  # #=> "Philarp Tremaine"
620
636
  #
621
637
  # Also parses out the Hash-like syntax used in PHP and Rails and builds
622
638
  # nested hashes from it.
623
639
  #
624
- # input = Camping.qs_parse("post[id]=1&post[user]=_why")
640
+ # input = Camping.qsp("post[id]=1&post[user]=_why")
625
641
  # #=> {'post' => {'id' => '1', 'user' => '_why'}}
626
642
  #
627
- def qs_parse(qs, d = '&;')
643
+ def qsp(qs, d='&;', y=nil, z=H[])
628
644
  m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)}
629
645
  (qs||'').
630
646
  split(/[#{d}] */n).
631
- inject(H[]) { |h,p| k, v=un(p).split('=',2)
647
+ inject((b,z=z,H[])[0]) { |h,p| k, v=un(p).split('=',2)
632
648
  h.u(k.split(/[\]\[]+/).reverse.
633
- inject(v) { |x,i| H[i,x] },&m)
649
+ inject(y||v) { |x,i| H[i,x] },&m)
634
650
  }
635
651
  end
636
652
 
637
653
  # Parses a string of cookies from the <tt>Cookie</tt> header.
638
- def kp(s); c = qs_parse(s, ';,'); end
654
+ def kp(s); c = qsp(s, ';,'); end
639
655
 
640
656
  # Fields a request through Camping. For traditional CGI applications, the method can be
641
657
  # executed without arguments.
@@ -661,7 +677,7 @@ module Camping
661
677
  X.M
662
678
  k,a=X.D un("/#{e['PATH_INFO']}".gsub(/\/+/,'/'))
663
679
  k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.service *a
664
- rescue Exception=>x
680
+ rescue Object=>x
665
681
  X::ServerError.new(r,e,'get').service(k,m,x)
666
682
  end
667
683
 
@@ -718,7 +734,7 @@ module Camping
718
734
  #
719
735
  # Models cannot be referred to in Views at this time.
720
736
  module Models
721
- autoload:Base,'camping/db'
737
+ autoload :Base,'camping/db'
722
738
  def Y;self;end
723
739
  end
724
740
 
data/lib/camping.rb CHANGED
@@ -1,30 +1,33 @@
1
1
  %w[active_support markaby tempfile uri].map{|l|require l}
2
2
  module Camping;Apps=[];C=self;S=IO.read(__FILE__).sub(/S=I.+$/,'')
3
- P="Cam\ping Problem!";module Helpers;def R c,*g;p=/\(.+?\)/;g.inject(c.
4
- urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|s.sub p,C.escape((a[
5
- a.class.primary_key]rescue a))}end;def URL c='/',*a;c=R(c,*a)if c.
3
+ P="Cam\ping Problem!";module Helpers;def R(c,*g);p,h=/\(.+?\)/,g.grep(Hash)
4
+ (g-=h).inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|s.sub p,C.
5
+ escape((a[a.class.primary_key]rescue a))}+(h.any?? "?"+h[0].map{|x|x.map{|z|C.
6
+ escape z}*"="}*"&": "")end;def URL c='/',*a;c=R(c,*a)if c.
6
7
  respond_to?:urls;c=self/c;c="//"+@env.HTTP_HOST+c if c[/^\//];URI(c)end;def/p
7
8
  p[/^\//]?@root+p : p end;def errors_for o;ul.errors{o.errors.each_full{|x|li x}
8
9
  }if o.errors.any?end end;module Base;include Helpers;attr_accessor:input,
9
10
  :cookies,:env,:headers,:body,:status,:root;def method_missing*a,&b
10
- a.shift if a[0]==:render;m=Mab.new({},self);s=m.capture{send(*a,&b)};s=m.layout{s}if
11
- /^_/!~a[0].to_s and m.respond_to?:layout;s end;def r s,b,h={};@status=s;@headers.
12
- merge!h;@body=b end;def redirect*a;r 302,'','Location'=>URL(*a)end;Z="\r\n"
11
+ a.shift if a[0]==:render;m=Mab.new({},self);s=m.capture{send(*a,&b)}
12
+ s=m.capture{send(:layout){s}} if /^_/!~a[0].to_s and m.respond_to?:layout
13
+ s end;def r s,b,h={};@status=s;@headers.merge!h;@body=b end
14
+ def redirect*a;r 302,'','Location'=>URL(*a)end;Z="\r\n"
15
+ def to_a;[@status,@body,@headers]end
13
16
  def initialize r,e,m;e=H[e.to_hash];@status,@method,@env,@headers,@root=200,m.
14
17
  downcase,e,{'Content-Type'=>"text/html"},e.SCRIPT_NAME.sub(/\/$/,'')
15
- @k=C.kp e.HTTP_COOKIE;q=C.qs_parse e.QUERY_STRING;@in=r
18
+ @k=C.kp e.HTTP_COOKIE;q=C.qsp e.QUERY_STRING;@in=r
16
19
  if%r|\Amultipart/form-.*boundary=\"?([^\";,]+)|n.match e.CONTENT_TYPE
17
20
  b=/(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/;until@in.eof?;fh=H[];for l in@in
18
21
  case l;when Z;break;when/^Content-D.+?: form-data;/;fh.u H[*$'.
19
22
  scan(/(?:\s(\w+)="([^"]+)")/).flatten];when/^Content-Type: (.+?)(\r$|\Z)/m;fh[
20
23
  :type]=$1;end;end;fn=fh[:name];o=if fh[:filename];o=fh[:tempfile]=Tempfile.new(:C)
21
24
  o.binmode;else;fh=""end;while l=@in.read(16384);if l=~b;o<<$`.chomp;@in.seek(-$'.
22
- size,IO::SEEK_CUR);break;end;o<<l;end;q[fn]=fh if fn;fh[:tempfile].rewind if
23
- fh.is_a?H;end;elsif@method=="post";q.u C.qs_parse(@in.read)end;@cookies,@input=
25
+ size,IO::SEEK_CUR);break;end;o<<l;end;C.qsp(fn,'&;',fh,q) if fn;fh[:tempfile].rewind if
26
+ fh.is_a?H;end;elsif@method=="post";q.u C.qsp(@in.read)end;@cookies,@input=
24
27
  @k.dup,q.dup end;def service*a;@body=send(@method,*a)if respond_to?@method
25
28
  @headers["Set-Cookie"]=@cookies.map{|k,v|"#{k}=#{C.escape(v)}; path=#{self/'/'
26
- }"if v!=@k[k]}-[nil];self end;def to_s;"Status: #{@status}#{Z+@headers.map{|k,v|
27
- [*v].map{|x|"#{k}: #{x}"}}*Z+Z*2+@body}"end;end
29
+ }"if v!=@k[k]}-[nil];self end;def to_s;a=[];@headers.map{|k,v|[*v].map{|x|a<<
30
+ "#{k}: #{x}"}};"Status: #{@status}#{Z+a*Z+Z*2+@body}"end;end
28
31
  X=module Controllers;@r=[];class<<self;def r;@r;end;def R*u;r=@r;Class.new{
29
32
  meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def M;def M;end;constants.map{|c|
30
33
  k=const_get(c);k.send:include,C,Base,Models;r[0,0]=k if !r.include?k;k.meta_def(
@@ -36,12 +39,12 @@ ServerError<R();def get k,m,e;r(500,Mab.new{h1 P;h2"#{k}.#{m}";h3"#{e.class
36
39
  self;def goes m;eval S.gsub(/Camping/,m.to_s).gsub("A\pps=[]","Cam\ping::Apps<<\
37
40
  self"),TOPLEVEL_BINDING;end;def escape s;s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.
38
41
  unpack('H2'*$&.size)*'%').upcase}.tr(' ','+')end;def un s;s.tr('+',' ').gsub(
39
- /%([\da-f]{2})/in){[$1].pack('H*')}end;def qs_parse q,d='&;';m=proc{|_,o,n|o.u(
40
- n,&m)rescue([*o]<<n)};q.to_s.split(/[#{d}] */n).inject(H[]){|h,p|k,v=un(p).
41
- split('=',2);h.u k.split(/[\]\[]+/).reverse.inject(v){|x,i|H[i,x]},&m}end;def
42
- kp s;c=qs_parse(s,';,')end;def run r=$stdin,e=ENV;X.M;k,a=X.D un("/#{e[
42
+ /%([\da-f]{2})/in){[$1].pack('H*')}end;def qsp q,d='&;',y=nil,z=H[];m=proc{|_,o,n|o.u(
43
+ n,&m)rescue([*o]<<n)};q.to_s.split(/[#{d}] */n).inject((b,z=z,H[])[0]){|h,p|k,v=un(p).
44
+ split('=',2);h.u k.split(/[\]\[]+/).reverse.inject(y||v){|x,i|H[i,x]},&m}end;def
45
+ kp s;c=qsp(s,';,')end;def run r=$stdin,e=ENV;X.M;k,a=X.D un("/#{e[
43
46
  'PATH_INFO']}".gsub(/\/+/,'/'));k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.
44
- service *a;rescue Exception=>x;X::ServerError.new(r,e,'get').service(k,m,x)end
47
+ service *a;rescue Object=>x;X::ServerError.new(r,e,'get').service(k,m,x)end
45
48
  def method_missing m,c,*a;X.M;k=X.const_get(c).new(StringIO.new,H['HTTP_HOST',
46
49
  '','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s);H.new(a.pop).each{|e,f|k.send(
47
50
  "#{e}=",f)}if Hash===a[-1];k.service *a;end;end;module Views;include X,Helpers
@@ -58,6 +58,8 @@ module Camping
58
58
  class FastCGI
59
59
  CHUNK_SIZE=(4 * 1024)
60
60
 
61
+ attr_reader :mounts
62
+
61
63
  # Creates a Camping::FastCGI class with empty mounts.
62
64
  def initialize
63
65
  @mounts = {}
@@ -69,71 +71,12 @@ class FastCGI
69
71
  dir.gsub!(/\/+$/, '')
70
72
  @mounts[dir] = app
71
73
  end
74
+
72
75
  #
73
76
  # Starts the FastCGI main loop.
74
- def start
77
+ def start(&blk)
75
78
  FCGI.each do |req|
76
- dir, app = nil
77
- begin
78
- root, path = "/"
79
- if ENV['FORCE_ROOT'] and ENV['FORCE_ROOT'].to_i == 1
80
- path = req.env['REQUEST_URI']
81
- else
82
- root = req.env['SCRIPT_NAME']
83
- path = req.env['PATH_INFO']
84
- end
85
-
86
- dir, app = @mounts.max { |a,b| match(path, a[0]) <=> match(path, b[0]) }
87
- unless dir and app
88
- dir, app = '/', Camping
89
- end
90
- yield dir, app if block_given?
91
-
92
- req.env['SERVER_SCRIPT_NAME'] = req.env['SCRIPT_NAME']
93
- req.env['SERVER_PATH_INFO'] = req.env['PATH_INFO']
94
- req.env['SCRIPT_NAME'] = File.join(root, dir)
95
- req.env['PATH_INFO'] = path.gsub(/^#{dir}/, '')
96
-
97
- controller = app.run(req.in, req.env)
98
- sendfile = nil
99
- headers = {}
100
- controller.headers.each do |k, v|
101
- if k =~ /^X-SENDFILE$/i and !ENV['SERVER_X_SENDFILE']
102
- sendfile = v
103
- else
104
- headers[k] = v
105
- end
106
- end
107
-
108
- body = controller.body
109
- controller.body = ""
110
- controller.headers = headers
111
-
112
- req.out << controller.to_s
113
- if sendfile
114
- File.open(sendfile, "rb") do |f|
115
- while chunk = f.read(CHUNK_SIZE) and chunk.length > 0
116
- req.out << chunk
117
- end
118
- end
119
- elsif body.respond_to? :read
120
- while chunk = body.read(CHUNK_SIZE) and chunk.length > 0
121
- req.out << chunk
122
- end
123
- body.close if body.respond_to? :close
124
- else
125
- req.out << body.to_s
126
- end
127
- rescue Exception => e
128
- req.out << "Content-Type: text/html\r\n\r\n" +
129
- "<h1>Camping Problem!</h1>" +
130
- "<h2><strong>#{root}</strong>#{path}</h2>" +
131
- "<h3>#{e.class} #{esc e.message}</h3>" +
132
- "<ul>" + e.backtrace.map { |bt| "<li>#{esc bt}</li>" }.join + "</ul>" +
133
- "<hr /><p>#{req.env.inspect}</p>"
134
- ensure
135
- req.finish
136
- end
79
+ camp_do(req, &blk)
137
80
  end
138
81
  end
139
82
 
@@ -173,7 +116,7 @@ class FastCGI
173
116
  fast.start do |dir, app|
174
117
  Dir[File.join(path, dir, '*.rb')].each do |script|
175
118
  smount = "/" + File.basename(script, '.rb')
176
- script_load[script] unless @mounts.has_key? smount
119
+ script_load[script] unless fast.mounts.has_key? smount
177
120
  end
178
121
  end
179
122
  else
@@ -183,6 +126,71 @@ class FastCGI
183
126
 
184
127
  private
185
128
 
129
+ def camp_do(req)
130
+ root, path, dir, app = "/"
131
+ if ENV['FORCE_ROOT'] and ENV['FORCE_ROOT'].to_i == 1
132
+ path = req.env['SCRIPT_NAME']
133
+ else
134
+ root = req.env['SCRIPT_NAME']
135
+ path = req.env['PATH_INFO']
136
+ end
137
+
138
+ dir, app = @mounts.max { |a,b| match(path, a[0]) <=> match(path, b[0]) }
139
+ unless dir and app
140
+ dir, app = '/', Camping
141
+ end
142
+ yield dir, app if block_given?
143
+
144
+ req.env['SERVER_SCRIPT_NAME'] = req.env['SCRIPT_NAME']
145
+ req.env['SERVER_PATH_INFO'] = req.env['PATH_INFO']
146
+ req.env['SCRIPT_NAME'] = File.join(root, dir)
147
+ req.env['PATH_INFO'] = path.gsub(/^#{dir}/, '')
148
+
149
+ controller = app.run(SeekStream.new(req.in), req.env)
150
+ sendfile = nil
151
+ headers = {}
152
+ controller.headers.each do |k, v|
153
+ if k =~ /^X-SENDFILE$/i and !ENV['SERVER_X_SENDFILE']
154
+ sendfile = v
155
+ else
156
+ headers[k] = v
157
+ end
158
+ end
159
+
160
+ body = controller.body
161
+ controller.body = ""
162
+ controller.headers = headers
163
+
164
+ req.out << controller.to_s
165
+ if sendfile
166
+ File.open(sendfile, "rb") do |f|
167
+ while chunk = f.read(CHUNK_SIZE) and chunk.length > 0
168
+ req.out << chunk
169
+ end
170
+ end
171
+ elsif body.respond_to? :read
172
+ while chunk = body.read(CHUNK_SIZE) and chunk.length > 0
173
+ req.out << chunk
174
+ end
175
+ body.close if body.respond_to? :close
176
+ else
177
+ req.out << body.to_s
178
+ end
179
+ rescue Exception => e
180
+ req.out << server_error(root, path, exc, req)
181
+ ensure
182
+ req.finish
183
+ end
184
+
185
+ def server_error(root, path, exc, req)
186
+ "Content-Type: text/html\r\n\r\n" +
187
+ "<h1>Camping Problem!</h1>" +
188
+ "<h2><strong>#{root}</strong>#{path}</h2>" +
189
+ "<h3>#{exc.class} #{esc exc.message}</h3>" +
190
+ "<ul>" + exc.backtrace.map { |bt| "<li>#{esc bt}</li>" }.join + "</ul>" +
191
+ "<hr /><p>#{req.env.inspect}</p>"
192
+ end
193
+
186
194
  def match(path, mount)
187
195
  m = path.match(/^#{Regexp::quote mount}(\/|$)/)
188
196
  if m; m.end(0)
@@ -194,5 +202,43 @@ class FastCGI
194
202
  str.gsub(/&/n, '&amp;').gsub(/\"/n, '&quot;').gsub(/>/n, '&gt;').gsub(/</n, '&lt;')
195
203
  end
196
204
 
205
+ class SeekStream
206
+ def initialize(stream)
207
+ @last_read = ""
208
+ @stream = stream
209
+ @buffer = ""
210
+ end
211
+ def eof?
212
+ @buffer.empty? && @stream.eof?
213
+ end
214
+ def each
215
+ while true
216
+ pull(1024) until eof? or @buffer.index("\n")
217
+ return nil if eof?
218
+ yield @buffer.slice!(0..(@buffer.index("\n") || -1))
219
+ end
220
+ end
221
+ def pull(len)
222
+ @buffer += @stream.read(len).to_s
223
+ end
224
+ def read(len = 16384)
225
+ pull(len)
226
+ @last_read =
227
+ if eof?
228
+ nil
229
+ else
230
+ @buffer.slice!(0...len)
231
+ end
232
+ end
233
+ def seek(len, typ)
234
+ raise NotImplementedError, "only IO::SEEK_CUR is supported with SeekStream" if typ != IO::SEEK_CUR
235
+ raise NotImplementedError, "only rewinding is supported with SeekStream" if len > 0
236
+ raise NotImplementedError, "rewinding #{-len} past the buffer #{@last_read.size} start not supported with SeekStream" if -len > @last_read.size
237
+ @buffer = @last_read[len..-1] + @buffer
238
+ @last_read = ""
239
+ self
240
+ end
241
+ end
242
+
197
243
  end
198
244
  end
@@ -146,13 +146,7 @@ class Reloader
146
146
  Camping::Models::Base.logger = Logger.new(@log == "-" ? STDOUT : @log)
147
147
  end
148
148
 
149
- begin
150
- Camping::Models::Session.create_schema
151
- rescue MissingSourceFile
152
- puts "** #$0 stopped: SQLite3 not found, please install."
153
- puts "** See http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for instructions."
154
- exit
155
- end
149
+ Camping::Models::Session.create_schema
156
150
 
157
151
  if @database and @database[:adapter] == 'sqlite3'
158
152
  begin
@@ -56,7 +56,7 @@ class CampingHandler < WEBrick::HTTPServlet::DefaultFileHandler
56
56
  end
57
57
 
58
58
  if @local_path
59
- do_GET(req, res)
59
+ do_GET(req, resp)
60
60
  else
61
61
  resp.body = controller.body.to_s
62
62
  end
@@ -0,0 +1,55 @@
1
+ require 'mosquito'
2
+
3
+ Camping.goes :XhtmlTrans
4
+
5
+ module XhtmlTrans
6
+ module Controllers
7
+ class WithLayout < R '/with_layout'
8
+ def get
9
+ render :with_layout
10
+ end
11
+ end
12
+
13
+ class WithoutLayout < R '/without_layout'
14
+ def get
15
+ render :_without_layout
16
+ end
17
+ end
18
+ end
19
+
20
+ module Views
21
+ def layout
22
+ xhtml_transitional do
23
+ head do title "title" end
24
+ body do capture { yield } end
25
+ end
26
+ end
27
+
28
+ def with_layout
29
+ h1 "With layout"
30
+ end
31
+
32
+ def _without_layout
33
+ xhtml_transitional do
34
+ head do title "title" end
35
+ body do h1 "Without layout" end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ class XhtmlTransTest < Camping::FunctionalTest
42
+ def test_with_layout
43
+ get '/with_layout'
44
+
45
+ assert(@response.body =~ /DOCTYPE/, "No doctype defined")
46
+ end
47
+
48
+ def test_without_layout
49
+ get '/without_layout'
50
+
51
+ assert(@response.body =~ /DOCTYPE/, "No doctype defined")
52
+ end
53
+
54
+ end
55
+
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0.1
2
+ rubygems_version: 0.9.0.8
3
3
  specification_version: 1
4
4
  name: camping
5
5
  version: !ruby/object:Gem::Version
6
- version: "1.5"
7
- date: 2006-10-03 00:00:00 -06:00
6
+ version: 1.5.180
7
+ date: 2007-01-06 00:00:00 -07:00
8
8
  summary: minature rails for stay-at-home moms
9
9
  require_paths:
10
10
  - lib
@@ -34,6 +34,7 @@ files:
34
34
  - Rakefile
35
35
  - bin/camping
36
36
  - doc/camping.1.gz
37
+ - test/test_xhtml_trans.rb
37
38
  - lib/camping
38
39
  - lib/camping.rb
39
40
  - lib/camping-unabridged.rb
@@ -45,9 +46,9 @@ files:
45
46
  - extras/permalink.gif
46
47
  - extras/Camping.gif
47
48
  - extras/flipbook_rdoc.rb
49
+ - examples/campsh.rb
48
50
  - examples/tepee.rb
49
51
  - examples/blog.rb
50
- - examples/campsh.rb
51
52
  - CHANGELOG
52
53
  test_files: []
53
54