camping 1.5.180 → 2.0.rc0
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/CHANGELOG +35 -0
- data/README +43 -68
- data/Rakefile +155 -86
- data/bin/camping +64 -246
- data/book/01_introduction +19 -0
- data/book/02_getting_started +443 -0
- data/book/51_upgrading +93 -0
- data/doc/api.html +1953 -0
- data/doc/book.html +73 -0
- data/doc/book/01_introduction.html +57 -0
- data/doc/book/02_getting_started.html +573 -0
- data/doc/book/51_upgrading.html +146 -0
- data/doc/created.rid +1 -0
- data/{extras → doc/images}/Camping.gif +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/{extras → doc/images}/permalink.gif +0 -0
- data/doc/index.html +148 -0
- data/doc/js/camping.js +79 -0
- data/doc/js/jquery.js +32 -0
- data/doc/rdoc.css +117 -0
- data/examples/blog.rb +280 -181
- data/extras/images/badge.gif +0 -0
- data/extras/images/boys-life.png +0 -0
- data/extras/images/deerputer.png +0 -0
- data/extras/images/diagram.png +0 -0
- data/extras/images/hill.png +0 -0
- data/extras/images/i-wish.png +0 -0
- data/extras/images/latl.png +0 -0
- data/extras/images/little-wheels.png +0 -0
- data/extras/images/square-badge.png +0 -0
- data/extras/images/uniform.png +0 -0
- data/extras/images/whale-bounce.png +0 -0
- data/extras/rdoc/generator/singledarkfish.rb +205 -0
- data/extras/rdoc/generator/template/flipbook/images/Camping.gif +0 -0
- data/extras/rdoc/generator/template/flipbook/images/loadingAnimation.gif +0 -0
- data/extras/rdoc/generator/template/flipbook/images/permalink.gif +0 -0
- data/extras/rdoc/generator/template/flipbook/js/camping.js +79 -0
- data/extras/rdoc/generator/template/flipbook/js/jquery.js +32 -0
- data/extras/rdoc/generator/template/flipbook/page.rhtml +30 -0
- data/extras/rdoc/generator/template/flipbook/rdoc.css +117 -0
- data/extras/rdoc/generator/template/flipbook/readme.rhtml +31 -0
- data/extras/rdoc/generator/template/flipbook/reference.rhtml +71 -0
- data/extras/rdoc/generator/template/flipbook/toc.rhtml +43 -0
- data/lib/camping-unabridged.rb +420 -481
- data/lib/camping.rb +40 -55
- data/lib/camping/{db.rb → ar.rb} +5 -8
- data/lib/camping/mab.rb +26 -0
- data/lib/camping/reloader.rb +175 -147
- data/lib/camping/server.rb +178 -0
- data/lib/camping/session.rb +34 -121
- data/test/apps/env_debug.rb +65 -0
- data/test/apps/forms.rb +95 -0
- data/test/apps/forward_to_other_controller.rb +60 -0
- data/test/apps/migrations.rb +97 -0
- data/test/apps/misc.rb +86 -0
- data/test/apps/sessions.rb +38 -0
- metadata +120 -80
- data/doc/camping.1.gz +0 -0
- data/examples/campsh.rb +0 -630
- data/examples/tepee.rb +0 -242
- data/extras/flipbook_rdoc.rb +0 -491
- data/lib/camping/fastcgi.rb +0 -244
- data/lib/camping/webrick.rb +0 -65
- data/test/test_xhtml_trans.rb +0 -55
data/lib/camping.rb
CHANGED
@@ -1,55 +1,40 @@
|
|
1
|
-
|
2
|
-
module Camping;
|
3
|
-
P="Cam\ping Problem
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def
|
15
|
-
def
|
16
|
-
def
|
17
|
-
|
18
|
-
@k
|
19
|
-
if
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
unpack('H2'*$&.size)*'%').upcase}.tr(' ','+')end;def un s;s.tr('+',' ').gsub(
|
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[
|
46
|
-
'PATH_INFO']}".gsub(/\/+/,'/'));k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.
|
47
|
-
service *a;rescue Object=>x;X::ServerError.new(r,e,'get').service(k,m,x)end
|
48
|
-
def method_missing m,c,*a;X.M;k=X.const_get(c).new(StringIO.new,H['HTTP_HOST',
|
49
|
-
'','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s);H.new(a.pop).each{|e,f|k.send(
|
50
|
-
"#{e}=",f)}if Hash===a[-1];k.service *a;end;end;module Views;include X,Helpers
|
51
|
-
end;module Models;autoload:Base,'camping/db';def Y;self;end;end;class Mab<Markaby::Builder
|
52
|
-
include Views;def tag!*g,&b;h=g[-1];[:href,:action,:src].map{|a|(h[a]=self/h[a])rescue
|
53
|
-
0};super end end;H=HashWithIndifferentAccess;class H;def method_missing m,*a
|
54
|
-
m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m]:raise(NoMethodError,"#{m}")end
|
55
|
-
alias_method:u,:regular_update;end end
|
1
|
+
require "uri";require "rack";class Object;def meta_def m,&b;(class<<self;self
|
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=[]
|
4
|
+
class H<Hash;def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.
|
5
|
+
to_s]:super end;undef id,type if ??==63;end;module Helpers;def R c,*g;p,h=
|
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
|
+
a.class.primary_key]rescue a))})};h.any?? u+"?"+U.build_query(h[0]):u end;def
|
9
|
+
/ p;p[0]==?/?@root + p : p end;def URL c='/',*a;c=R(c, *a) if c.respond_to?(
|
10
|
+
:urls);c=self/c;c=@request.url[/.{8,}?(?=\/)/]+c if c[0]==?/;URI c end end
|
11
|
+
module Base;attr_accessor:env,:request,:root,:input,:cookies,:state,:status,
|
12
|
+
:headers,:body;def render v,*a,&b;mab(/^_/!~v.to_s){send(v,*a,&b)} end;def
|
13
|
+
mab l=nil,&b;m=Mab.new({},self);s=m.capture(&b);s=m.capture{layout{s}} if l &&
|
14
|
+
m.respond_to?(:layout);s end;def r s,b,h={};b,h=h,b if Hash===b;@status=s;
|
15
|
+
@headers.merge!(h);@body=b;end;def redirect *a;r 302,'','Location'=>URL(*a).
|
16
|
+
to_s;end;def r404 p;P%"#{p} not found"end;def r500 k,m,e;raise e;end;def r501 m
|
17
|
+
P%"#{m.upcase} not implemented"end;def to_a;@env['rack.session']=@state;r=Rack::
|
18
|
+
Response.new(@body,@status,@headers);@cookies.each{|k,v|next if @old_cookies[
|
19
|
+
k]==v;v={:value=>v,:path=>self/"/"} if String===v;r.set_cookie(k,v)};r.to_a;end
|
20
|
+
def initialize(env,m) r=@request=Rack::Request.new(@env=env);@root,@input,
|
21
|
+
@cookies,@state,@headers,@status,@method=r.script_name.sub(/\/$/,''),n(r.params
|
22
|
+
),H[@old_cookies = r.cookies],H[r.session],{},m=~/r(\d+)/?$1.to_i: 200,m end;def
|
23
|
+
n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]=n(v);m}: h end;def service *a;r=catch(
|
24
|
+
:halt){send(@method,*a)};@body||=r;self;end;end;module Controllers;@r=[];class<<
|
25
|
+
self;def r;@r end;def R *u;r=@r;Class.new{meta_def(:urls){u};meta_def(:inherited
|
26
|
+
){|x|r<<x}}end;def D p,m;p='/'if !p||!p[0];r.map{|k|k.urls.map{|x|return(k.
|
27
|
+
instance_method(m)rescue nil)?[k,m,*$~[1..-1]]:[I,'r501',m]if p=~/^#{x}\/?$/}}
|
28
|
+
[I,'r404',p] end;N=H.new{|_,x|x.downcase}.merge! "N"=>'(\d+)',"X"=>'([^/]+)',
|
29
|
+
"Index"=>'';def M;def M;end;constants.map{|c|k=const_get(c);k.send:include,C,
|
30
|
+
Base,Helpers,Models;@r=[k]+r if r-[k]==r;k.meta_def(:urls){ [ "/#{c.scan(
|
31
|
+
/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.respond_to?:urls}end end;I=R()
|
32
|
+
end;X=Controllers;class<<self;def goes m;Apps<<eval(S.gsub(/Camping/,m.to_s),
|
33
|
+
TOPLEVEL_BINDING) end;def call e;X.M;p=e['PATH_INFO']=U.unescape(e['PATH_INFO'])
|
34
|
+
k,m,*a=X.D p,e['REQUEST_METHOD'].downcase;k.new(e,m).service(*a).to_a;rescue
|
35
|
+
r500(:I,k,m,$!,:env=>e).to_a;end;def method_missing m,c,*a;X.M;h=Hash===a[-1]?
|
36
|
+
a.pop: {};e=H[Rack::MockRequest.env_for('',h.delete(:env)||{})];k=X.const_get(c
|
37
|
+
).new(e,m.to_s);h.each{|i,v|k.send"#{i}=",v};k.service(*a);end;def use*a,&b;m=a.
|
38
|
+
shift.new(method(:call),*a,&b);meta_def(:call){|e|m.call(e)}end end;module Views
|
39
|
+
include X,Helpers end;module Models;autoload:Base,
|
40
|
+
'camping/ar';end;autoload:Mab,'camping/mab';C end
|
data/lib/camping/{db.rb → ar.rb}
RENAMED
@@ -9,13 +9,11 @@ end
|
|
9
9
|
$AR_EXTRAS = %{
|
10
10
|
Base = ActiveRecord::Base unless const_defined? :Base
|
11
11
|
|
12
|
-
def Y; ActiveRecord::Base.verify_active_connections!; self; end
|
13
|
-
|
14
12
|
class SchemaInfo < Base
|
15
13
|
end
|
16
14
|
|
17
15
|
def self.V(n)
|
18
|
-
@final = [n, @final.
|
16
|
+
@final = [n, @final.to_f].max
|
19
17
|
m = (@migrations ||= [])
|
20
18
|
Class.new(ActiveRecord::Migration) do
|
21
19
|
meta_def(:version) { n }
|
@@ -37,7 +35,7 @@ $AR_EXTRAS = %{
|
|
37
35
|
|
38
36
|
si = SchemaInfo.find(:first) || SchemaInfo.new(:version => opts[:assume])
|
39
37
|
if si.version < opts[:version]
|
40
|
-
@migrations.each do |k|
|
38
|
+
@migrations.sort_by { |m| m.version }.each do |k|
|
41
39
|
k.migrate(:up) if si.version < k.version and k.version <= opts[:version]
|
42
40
|
k.migrate(:down) if si.version > k.version and k.version > opts[:version]
|
43
41
|
end
|
@@ -71,8 +69,7 @@ module Camping
|
|
71
69
|
module_eval $AR_EXTRAS
|
72
70
|
end
|
73
71
|
end
|
74
|
-
Camping::S.sub!
|
75
|
-
Camping::
|
76
|
-
|
77
|
-
app::Models.module_eval $AR_EXTRAS
|
72
|
+
Camping::S.sub! /autoload\s*:Base\s*,\s*['"]camping\/ar['"]/, $AR_EXTRAS
|
73
|
+
Camping::Apps.each do |c|
|
74
|
+
c::Models.module_eval $AR_EXTRAS
|
78
75
|
end
|
data/lib/camping/mab.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class MissingLibrary < Exception #:nodoc: all
|
2
|
+
end
|
3
|
+
begin
|
4
|
+
require 'markaby'
|
5
|
+
rescue LoadError => e
|
6
|
+
raise MissingLibrary, "Markaby could not be loaded (is it installed?): #{e.message}"
|
7
|
+
end
|
8
|
+
|
9
|
+
$MAB_CODE = %{
|
10
|
+
# The Mab class wraps Markaby, allowing it to run methods from Camping::Views
|
11
|
+
# and also to replace :href, :action and :src attributes in tags by prefixing the root
|
12
|
+
# path.
|
13
|
+
class Mab < Markaby::Builder
|
14
|
+
include Views
|
15
|
+
def tag!(*g,&b)
|
16
|
+
h=g[-1]
|
17
|
+
[:href,:action,:src].map{|a|(h[a]&&=self/h[a])rescue 0}
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
}
|
22
|
+
|
23
|
+
Camping::S.sub! /autoload\s*:Mab\s*,\s*['"]camping\/mab['"]/, $MAB_CODE
|
24
|
+
Camping::Apps.each do |c|
|
25
|
+
c.module_eval $MAB_CODE
|
26
|
+
end
|
data/lib/camping/reloader.rb
CHANGED
@@ -1,163 +1,191 @@
|
|
1
1
|
module Camping
|
2
|
-
# == The Camping Reloader
|
3
|
-
#
|
4
|
-
# Camping apps are generally small and predictable. Many Camping apps are
|
5
|
-
# contained within a single file. Larger apps are split into a handful of
|
6
|
-
# other Ruby libraries within the same directory.
|
7
|
-
#
|
8
|
-
# Since Camping apps (and their dependencies) are loaded with Ruby's require
|
9
|
-
# method, there is a record of them in $LOADED_FEATURES. Which leaves a
|
10
|
-
# perfect space for this class to manage auto-reloading an app if any of its
|
11
|
-
# immediate dependencies changes.
|
12
|
-
#
|
13
|
-
# == Wrapping Your Apps
|
14
|
-
#
|
15
|
-
# Since bin/camping and the Camping::
|
16
|
-
# you probably don't need to hack it on your own. But, if you're rolling your
|
17
|
-
# own situation, here's how.
|
18
|
-
#
|
19
|
-
# Rather than this:
|
20
|
-
#
|
21
|
-
# require 'yourapp'
|
22
|
-
#
|
23
|
-
# Use this:
|
24
|
-
#
|
25
|
-
# require 'camping/reloader'
|
26
|
-
# Camping::Reloader.new('/path/to/yourapp.rb')
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
2
|
+
# == The Camping Reloader
|
3
|
+
#
|
4
|
+
# Camping apps are generally small and predictable. Many Camping apps are
|
5
|
+
# contained within a single file. Larger apps are split into a handful of
|
6
|
+
# other Ruby libraries within the same directory.
|
7
|
+
#
|
8
|
+
# Since Camping apps (and their dependencies) are loaded with Ruby's require
|
9
|
+
# method, there is a record of them in $LOADED_FEATURES. Which leaves a
|
10
|
+
# perfect space for this class to manage auto-reloading an app if any of its
|
11
|
+
# immediate dependencies changes.
|
12
|
+
#
|
13
|
+
# == Wrapping Your Apps
|
14
|
+
#
|
15
|
+
# Since bin/camping and the Camping::Server class already use the Reloader,
|
16
|
+
# you probably don't need to hack it on your own. But, if you're rolling your
|
17
|
+
# own situation, here's how.
|
18
|
+
#
|
19
|
+
# Rather than this:
|
20
|
+
#
|
21
|
+
# require 'yourapp'
|
22
|
+
#
|
23
|
+
# Use this:
|
24
|
+
#
|
25
|
+
# require 'camping/reloader'
|
26
|
+
# reloader = Camping::Reloader.new('/path/to/yourapp.rb')
|
27
|
+
# blog = reloader.apps[:Blog]
|
28
|
+
# wiki = reloader.apps[:Wiki]
|
29
|
+
#
|
30
|
+
# The <tt>blog</tt> and <tt>wiki</tt> objects will behave exactly like your
|
31
|
+
# Blog and Wiki, but they will update themselves if yourapp.rb changes.
|
32
|
+
#
|
33
|
+
# You can also give Reloader more than one script.
|
34
|
+
class Reloader
|
35
|
+
attr_reader :scripts
|
36
|
+
|
37
|
+
# This is a simple wrapper which causes the script to reload (if needed)
|
38
|
+
# on any method call. Then the method call will be forwarded to the
|
39
|
+
# app.
|
40
|
+
class App < (defined?(BasicObject) ? BasicObject : Object) # :nodoc:
|
41
|
+
if superclass == ::Object
|
42
|
+
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_accessor :app, :script
|
46
|
+
|
47
|
+
def initialize(script)
|
48
|
+
@script = script
|
49
|
+
end
|
50
|
+
|
51
|
+
# Reloads if needed, before calling the method on the app.
|
52
|
+
def method_missing(meth, *args, &blk)
|
53
|
+
@script.reload!
|
54
|
+
@app.send(meth, *args, &blk)
|
55
|
+
end
|
53
56
|
end
|
54
|
-
|
55
|
-
#
|
56
|
-
#
|
57
|
-
|
58
|
-
|
57
|
+
|
58
|
+
# This class is doing all the hard work; however, it only works on
|
59
|
+
# single files. Reloader just wraps up support for multiple scripts
|
60
|
+
# and hides away some methods you normally won't need.
|
61
|
+
class Script # :nodoc:
|
62
|
+
attr_reader :apps, :file, :dir, :extras
|
63
|
+
|
64
|
+
def initialize(file)
|
65
|
+
@file = File.expand_path(file)
|
66
|
+
@dir = File.dirname(@file)
|
67
|
+
@extras = File.join(@dir, File.basename(@file, ".rb"))
|
68
|
+
@mtime = Time.at(0)
|
69
|
+
@requires = []
|
70
|
+
@apps = {}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Loads the apps availble in this script. Use <tt>apps</tt> to get
|
74
|
+
# the loaded apps.
|
75
|
+
def load_apps
|
76
|
+
all_requires = $LOADED_FEATURES.dup
|
77
|
+
all_apps = Camping::Apps.dup
|
78
|
+
|
59
79
|
begin
|
60
|
-
|
61
|
-
load @script
|
62
|
-
@requires = ($LOADED_FEATURES - all_requires).select do |req|
|
63
|
-
req.index(File.basename(@script) + "/") == 0 || req.index(title + "/") == 0
|
64
|
-
end
|
80
|
+
load(@file)
|
65
81
|
rescue Exception => e
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
return
|
82
|
+
puts "!! Error loading #{@file}:"
|
83
|
+
puts "#{e.class}: #{e.message}"
|
84
|
+
puts e.backtrace
|
85
|
+
puts "!! Error loading #{@file}, see backtrace above"
|
71
86
|
end
|
72
|
-
|
73
|
-
@
|
74
|
-
|
75
|
-
|
76
|
-
puts "!! trouble loading #{title}: not a Camping app, no #{title.capitalize} module found"
|
77
|
-
remove_app
|
78
|
-
return
|
87
|
+
|
88
|
+
@requires = ($LOADED_FEATURES - all_requires).map do |req|
|
89
|
+
full = full_path(req)
|
90
|
+
full if full == @file or full.index(@extras) == 0
|
79
91
|
end
|
80
92
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
File.mtime(File.join(File.dirname(@script), fname))
|
92
|
-
rescue Errno::ENOENT
|
93
|
-
remove_app
|
94
|
-
@mtime
|
95
|
-
end
|
96
|
-
end.max
|
97
|
-
end
|
98
|
-
|
99
|
-
# Conditional reloading of the app. This gets called on each request and
|
100
|
-
# only reloads if the modification times on any of the files is updated.
|
101
|
-
def reload_app
|
102
|
-
return if @klass and @mtime and mtime <= @mtime
|
103
|
-
|
104
|
-
if @requires
|
105
|
-
@requires.each { |req| $LOADED_FEATURES.delete(req) }
|
93
|
+
@mtime = mtime
|
94
|
+
|
95
|
+
new_apps = (Camping::Apps - all_apps)
|
96
|
+
old_apps = @apps.dup
|
97
|
+
@apps = new_apps.inject({}) do |hash, app|
|
98
|
+
key = app.name.to_sym
|
99
|
+
hash[key] = (old = old_apps[key]) || App.new(self)
|
100
|
+
hash[key].app = app
|
101
|
+
app.create if app.respond_to?(:create) && !old
|
102
|
+
hash
|
106
103
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
# Removes all the apps defined in this script.
|
108
|
+
def remove_apps
|
109
|
+
@apps.each do |name, app|
|
110
|
+
Camping::Apps.delete(app.app)
|
111
|
+
Object.send :remove_const, name
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Reloads the file if needed. No harm is done by calling this multiple
|
116
|
+
# times, so feel free call just to be sure.
|
117
|
+
def reload!
|
118
|
+
return if @mtime >= mtime
|
119
|
+
remove_apps
|
120
|
+
load_apps
|
121
|
+
end
|
122
|
+
|
123
|
+
# Checks if both scripts watches the same file.
|
124
|
+
def ==(other)
|
125
|
+
@file == other.file
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def mtime
|
131
|
+
(@requires + [@file]).compact.map do |fname|
|
132
|
+
File.mtime(fname)
|
133
|
+
end.reject{|t| t > Time.now }.max
|
134
|
+
end
|
135
|
+
|
136
|
+
# Figures out the full path of a required file.
|
137
|
+
def full_path(req)
|
138
|
+
dir = $LOAD_PATH.detect { |l| File.exists?(File.join(l, req)) }
|
139
|
+
if dir
|
140
|
+
File.join(File.expand_path(dir), req)
|
118
141
|
else
|
119
|
-
|
142
|
+
req
|
120
143
|
end
|
144
|
+
end
|
121
145
|
end
|
122
146
|
|
123
|
-
#
|
124
|
-
|
125
|
-
|
147
|
+
# Creates the reloader, assigns a +script+ to it and initially loads the
|
148
|
+
# application. Pass in the full path to the script, otherwise the script
|
149
|
+
# will be loaded relative to the current working directory.
|
150
|
+
def initialize(*scripts)
|
151
|
+
@scripts = []
|
152
|
+
update(*scripts)
|
126
153
|
end
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
case @log
|
143
|
-
when Logger
|
144
|
-
Camping::Models::Base.logger = @log
|
145
|
-
when String
|
146
|
-
Camping::Models::Base.logger = Logger.new(@log == "-" ? STDOUT : @log)
|
147
|
-
end
|
148
|
-
|
149
|
-
Camping::Models::Session.create_schema
|
150
|
-
|
151
|
-
if @database and @database[:adapter] == 'sqlite3'
|
152
|
-
begin
|
153
|
-
require 'sqlite3_api'
|
154
|
-
rescue LoadError
|
155
|
-
puts "!! Your SQLite3 adapter isn't a compiled extension."
|
156
|
-
abort "!! Please check out http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for tips."
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
154
|
+
|
155
|
+
# Updates the reloader to only use the scripts provided:
|
156
|
+
#
|
157
|
+
# reloader.update("examples/blog.rb", "examples/wiki.rb")
|
158
|
+
def update(*scripts)
|
159
|
+
old = @scripts.dup
|
160
|
+
clear
|
161
|
+
@scripts = scripts.map do |script|
|
162
|
+
s = Script.new(script)
|
163
|
+
if pos = old.index(s)
|
164
|
+
# We already got a script, so we use the old (which might got a mtime)
|
165
|
+
old[pos]
|
166
|
+
else
|
167
|
+
s.load_apps
|
160
168
|
end
|
169
|
+
end
|
161
170
|
end
|
162
|
-
|
171
|
+
|
172
|
+
# Removes all the scripts from the reloader.
|
173
|
+
def clear
|
174
|
+
@scrips = []
|
175
|
+
end
|
176
|
+
|
177
|
+
# Simply calls reload! on all the Script objects.
|
178
|
+
def reload!
|
179
|
+
@scripts.each { |script| script.reload! }
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns a Hash of all the apps available in the scripts, where the key
|
183
|
+
# would be the name of the app (the one you gave to Camping.goes) and the
|
184
|
+
# value would be the app (wrapped inside App).
|
185
|
+
def apps
|
186
|
+
@scripts.inject({}) do |hash, script|
|
187
|
+
hash.merge(script.apps)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
163
191
|
end
|