camping 1.5.180 → 2.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|