equipment 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.
- data/ProjectInfo +55 -0
- data/README +67 -0
- data/examples/basicauthtest.rb +59 -0
- data/examples/erubytest.rb +36 -0
- data/examples/flashtest.rb +46 -0
- data/examples/index.erb +9 -0
- data/examples/mounttest.rb +34 -0
- data/examples/ogtest.rb +41 -0
- data/examples/patchestest.rb +40 -0
- data/examples/sendfiletest.rb +29 -0
- data/lib/equipment.rb +195 -0
- data/lib/ext/app_util.rb +28 -0
- data/lib/ext/basic_auth.rb +71 -0
- data/lib/ext/controls.rb +26 -0
- data/lib/ext/eruby_view.rb +83 -0
- data/lib/ext/flash.rb +81 -0
- data/lib/ext/forms.rb +22 -0
- data/lib/ext/forward.rb +70 -0
- data/lib/ext/js_helpers.rb +50 -0
- data/lib/ext/mount.rb +152 -0
- data/lib/ext/og.rb +95 -0
- data/lib/ext/og_scaffold.rb +119 -0
- data/lib/ext/og_session.rb +76 -0
- data/lib/ext/patches.rb +130 -0
- data/lib/ext/ressource.rb +88 -0
- data/lib/ext/security.rb +83 -0
- data/lib/ext/sendfile.rb +84 -0
- data/lib/ext/template_view.rb +72 -0
- data/lib/ext/use_helper.rb +83 -0
- data/lib/ext/xml_view.rb +47 -0
- metadata +78 -0
data/lib/ext/app_util.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
|
3
|
+
module Ext
|
4
|
+
|
5
|
+
# Provides the Base#app method. It's used in extensions to get the
|
6
|
+
# application's module.
|
7
|
+
#
|
8
|
+
# == Dependency
|
9
|
+
#
|
10
|
+
# * Equipment
|
11
|
+
#
|
12
|
+
module AppUtil
|
13
|
+
extend Equipment
|
14
|
+
|
15
|
+
module Helpers
|
16
|
+
# this is a curious method that's needed because I can't access MyApp::C
|
17
|
+
# in extensions. I think this is because of how constants are resolved in ruby.
|
18
|
+
# I've seen that Rite will change that. Mabye it will be not needed then.
|
19
|
+
#
|
20
|
+
# In the meanwhile, you can use app::Controllers, app::Views, ...
|
21
|
+
def app
|
22
|
+
@__app ||= Kernel.const_get(/^\w+/.match(self.class.name).to_a.first)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
require 'ext/security'
|
3
|
+
|
4
|
+
module Ext
|
5
|
+
|
6
|
+
# Basic Http Authentication.
|
7
|
+
#
|
8
|
+
# Inspired by Manfred Stienstra (http://www.fngtps.com/2006/05/basic-authentication-for-camping).
|
9
|
+
#
|
10
|
+
# == Dependencies
|
11
|
+
#
|
12
|
+
# * Equipment
|
13
|
+
# * Security
|
14
|
+
#
|
15
|
+
# == TODO
|
16
|
+
# * More docs
|
17
|
+
#
|
18
|
+
module BasicAuth
|
19
|
+
extend Equipment
|
20
|
+
depends_on Security
|
21
|
+
|
22
|
+
def self.equip(app)
|
23
|
+
super
|
24
|
+
app::Controllers::Unauthenticated.send :include, app::Base
|
25
|
+
end
|
26
|
+
|
27
|
+
module Base
|
28
|
+
|
29
|
+
# Gets HTTP_Basic credendials from a request. It consists in an array
|
30
|
+
# of user and password.
|
31
|
+
def basic_credentials
|
32
|
+
puts "Authenticate"
|
33
|
+
if d = %w{X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION}.inject([]) \
|
34
|
+
{ |d,h| env.has_key?(h) ? env[h].to_s.split : [] }
|
35
|
+
return Base64.decode64(d[1]).split(':')[0..1] if d[0] == 'Basic'
|
36
|
+
end; [nil, nil]
|
37
|
+
end
|
38
|
+
alias :authenticate :basic_credentials
|
39
|
+
|
40
|
+
def authorize(user, pass, force=false)
|
41
|
+
puts "Authorize"
|
42
|
+
return super unless force
|
43
|
+
forward(app::Controller::BasicAuth)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
module Controllers
|
49
|
+
|
50
|
+
# Called when an url is not authorized. You can override this is your app.
|
51
|
+
class Unauthenticated < Security::Controllers::Unauthenticated
|
52
|
+
class << self
|
53
|
+
attr_accessor :realm
|
54
|
+
end
|
55
|
+
self.realm = 'Camping'
|
56
|
+
|
57
|
+
def get
|
58
|
+
@status = 401
|
59
|
+
@headers['Status'] = 'Unauthorized'
|
60
|
+
@headers['WWW-Authenticate'] = "Basic realm=\"#{self.class.realm}\""
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Unauthorized < Unauthenticated
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
data/lib/ext/controls.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
|
3
|
+
module Ext
|
4
|
+
# Not implemented yet
|
5
|
+
module Controls
|
6
|
+
extend Equipment
|
7
|
+
|
8
|
+
class Control
|
9
|
+
attr_reader :opts
|
10
|
+
def initialize(opts={})
|
11
|
+
@opts = opts
|
12
|
+
end
|
13
|
+
|
14
|
+
def render
|
15
|
+
end
|
16
|
+
alias :to_s :render
|
17
|
+
end
|
18
|
+
|
19
|
+
module Helpers
|
20
|
+
def control(*args)
|
21
|
+
Control.new(*args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
require 'ext/template_view'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'erubis' # faster eruby parser
|
6
|
+
ERB = Erubis::Eruby
|
7
|
+
rescue LoadError
|
8
|
+
require 'erb'
|
9
|
+
end
|
10
|
+
|
11
|
+
module Ext
|
12
|
+
|
13
|
+
# Gives eruby templating capabilities to your app.
|
14
|
+
#
|
15
|
+
# == Dependencies
|
16
|
+
#
|
17
|
+
# * Equipment
|
18
|
+
# * TemplateView
|
19
|
+
# * `erubis` package. Available as a gem. If not available, it will use `erb`
|
20
|
+
#
|
21
|
+
# == Usage
|
22
|
+
#
|
23
|
+
# define the template_root to your views :
|
24
|
+
#
|
25
|
+
# YourApp::Views.template_root = 'tpl/'
|
26
|
+
#
|
27
|
+
# Then put your templates as tpl/xy.erb
|
28
|
+
#
|
29
|
+
# rendering occurs as usual.
|
30
|
+
#
|
31
|
+
# == Issues
|
32
|
+
#
|
33
|
+
# Rendering only occurs on regular views. Vars and blocks are not really
|
34
|
+
# integrated. You can still use them. Vars as *a and blocks as &b. Like
|
35
|
+
# <%= v[1] %> in your template.
|
36
|
+
#
|
37
|
+
module ErubyView
|
38
|
+
extend Equipment
|
39
|
+
depends_on TemplateView
|
40
|
+
|
41
|
+
module Base
|
42
|
+
|
43
|
+
# Generic wrapper. Forwards to #eruby_view? or ask parent.
|
44
|
+
def has_view?(view)
|
45
|
+
return true if eruby_view?(view)
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
49
|
+
# Checks if the view exists as an eruby template
|
50
|
+
def eruby_view?(view)
|
51
|
+
if /text\/html|\*\/\*/ =~ (env.HTTP_ACCEPT || '*/*')
|
52
|
+
return true if eruby_template(view)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the path or nil from a view name. Template extensions are .erb.
|
57
|
+
def eruby_template(view)
|
58
|
+
file = File.join(template_root, "#{view}.erb")
|
59
|
+
File.exists?(file) ? file : nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# Generic wrapper. Forwards to #eruby_view or ask parent.
|
63
|
+
def view(m, *a, &b)
|
64
|
+
if eruby_view?(m)
|
65
|
+
return eruby_view(m, *a, &b)
|
66
|
+
end
|
67
|
+
super
|
68
|
+
end
|
69
|
+
|
70
|
+
# Compiles an eruby template from current instance variables, helpers
|
71
|
+
# and the template
|
72
|
+
#
|
73
|
+
# TODO : Support splat and block
|
74
|
+
# TODO : Implement parse caching here
|
75
|
+
# NOTE : Override @headers['Content-Type'] if necessary here
|
76
|
+
def eruby_view(m, *a, &b)
|
77
|
+
e = ::ERB.new(File.read(eruby_template(m)))
|
78
|
+
e.result(ivs_send(app::V.new).bind(m,*a,&b)) # instance variables are wrapped in V
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
data/lib/ext/flash.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
|
3
|
+
module Ext
|
4
|
+
# Hilight some things for a short time. It's very convenient to have some
|
5
|
+
# look over things in the night. See Helpers#flash for more options.
|
6
|
+
#
|
7
|
+
# == Look :
|
8
|
+
#
|
9
|
+
# in your controller :
|
10
|
+
#
|
11
|
+
# def get
|
12
|
+
# flash.error = 'hey !'
|
13
|
+
# redirect R(Index)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# in your view :
|
17
|
+
#
|
18
|
+
# def index
|
19
|
+
# div.error(flash.error) if flash.error
|
20
|
+
# # ...
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# or in your layout.. like you want. The flashed data will then disappear
|
24
|
+
# on the next request.
|
25
|
+
#
|
26
|
+
# == Dependency
|
27
|
+
#
|
28
|
+
# * Equipment
|
29
|
+
#
|
30
|
+
# == Issues
|
31
|
+
#
|
32
|
+
# The cookies are not deleted until the end of the session. This is because
|
33
|
+
# Camping does not provide this facility and I didn't implement it. I think
|
34
|
+
# it is okay altrough.
|
35
|
+
#
|
36
|
+
module Flash
|
37
|
+
extend Equipment
|
38
|
+
|
39
|
+
module Helpers
|
40
|
+
# The flash helper. Use in your controller or view. Retuns
|
41
|
+
# a Flasher.
|
42
|
+
def flash
|
43
|
+
@__flash ||= Flasher.new(cookies)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# The flash class. Stores the data temporarily in the cookies.
|
48
|
+
# Only store Strings.
|
49
|
+
class Flasher
|
50
|
+
def initialize(cookies)
|
51
|
+
@cookies = cookies
|
52
|
+
@data = cookies.dup
|
53
|
+
end
|
54
|
+
|
55
|
+
def [](key)
|
56
|
+
key = to_key(key)
|
57
|
+
@cookies[key] = '' if @cookies.has_key? key
|
58
|
+
return (not @data[key].nil? and not @data[key].empty?) ? @data[key] : nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def []=(key, value)
|
62
|
+
unless value.nil? or value.empty?
|
63
|
+
key = to_key(key)
|
64
|
+
@cookies[key] = value
|
65
|
+
return @data[key] = value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Allows fancy flash.xy or flash.xy = 'sdsd'
|
70
|
+
def method_missing(m, val='')
|
71
|
+
/=$/ =~ m.to_s ? send(:[]=, m.to_s.sub(/=$/,''), val) : send(:[], m)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def to_key(key)
|
76
|
+
"__flash__#{key}".to_sym
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/lib/ext/forms.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
require 'ext/controls'
|
3
|
+
|
4
|
+
module Ext
|
5
|
+
# Not implemented yet
|
6
|
+
module Forms
|
7
|
+
extend Equipment
|
8
|
+
depends_on Controls
|
9
|
+
|
10
|
+
module Helpers
|
11
|
+
def form_for(xy)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Mab
|
16
|
+
def form(*a, &b)
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/ext/forward.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
|
3
|
+
module Ext
|
4
|
+
|
5
|
+
# Forwarding is like redirecting but internally. This won't send another
|
6
|
+
# request to the browser. See Base#forward for options.
|
7
|
+
#
|
8
|
+
# *HINT* : forwarding should be used rarely and only on GET. Use redirect on
|
9
|
+
# POST.
|
10
|
+
#
|
11
|
+
# == Workflows
|
12
|
+
#
|
13
|
+
# these are simplified workflows that illustrate the difference between
|
14
|
+
# redirecting and forwarding.
|
15
|
+
#
|
16
|
+
# === Workflow with redirect
|
17
|
+
#
|
18
|
+
# Http client -> YourApp::Controller1 -> Http client -> YourApp::Controller2
|
19
|
+
# -> Http client
|
20
|
+
#
|
21
|
+
# === Workflow with forwarding
|
22
|
+
#
|
23
|
+
# Http client -> YourApp::Controller1 -> YourApp::Controller2 -> Http client
|
24
|
+
#
|
25
|
+
# == Dependency
|
26
|
+
#
|
27
|
+
# * Equipment
|
28
|
+
#
|
29
|
+
# == TODO
|
30
|
+
#
|
31
|
+
# * Allow more options in forwarding
|
32
|
+
module Forward
|
33
|
+
extend Equipment
|
34
|
+
|
35
|
+
def self.equip(app) # :nodoc:
|
36
|
+
super
|
37
|
+
app.module_eval do
|
38
|
+
def self.run(r=$stdin,e=ENV)
|
39
|
+
k, a = self::Controllers.D un("/#{e['PATH_INFO']}".gsub(%r!/+!,'/'))
|
40
|
+
k.send :include, self, self::Base, self::Models
|
41
|
+
k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).service(*a)
|
42
|
+
rescue Forwarder => fw
|
43
|
+
fw.controller.new(nil,H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s).service(*fw.args)
|
44
|
+
rescue Exception => x
|
45
|
+
self::Controllers::ServerError.new(r,e,'get').service(k,m,x)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Forwarder < Exception # :nodoc:
|
51
|
+
attr_accessor :controller, :args
|
52
|
+
|
53
|
+
def initialize(controller, *args)
|
54
|
+
@controller, @args = controller, args
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module Base
|
59
|
+
# Forwards to another controller
|
60
|
+
#
|
61
|
+
# * controller : the other controller
|
62
|
+
# * *a : only for ruby hackers ;-)
|
63
|
+
#
|
64
|
+
# TODO : make *a accessible for non hackers
|
65
|
+
def forward(controller, *a)
|
66
|
+
raise Forwarder.new(controller, *a)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
require 'ext/app_util'
|
3
|
+
require 'ext/use_helper'
|
4
|
+
|
5
|
+
|
6
|
+
module Ext
|
7
|
+
module JsHelpers
|
8
|
+
extend Equipment
|
9
|
+
depends_on AppUtil
|
10
|
+
depends_on UseHelper
|
11
|
+
|
12
|
+
module Helpers
|
13
|
+
def join_scripts
|
14
|
+
if javascripts.size > 0
|
15
|
+
link = R(app::Controllers::JoinScripts, javascripts.map{|js| File.basename(js, '.js')}.join(';'))
|
16
|
+
app::Mab.new do
|
17
|
+
script :type=>'text/javascript', :src=>link
|
18
|
+
end.to_s
|
19
|
+
else "" end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Controllers
|
24
|
+
class JoinScripts
|
25
|
+
class << self
|
26
|
+
attr_accessor :root
|
27
|
+
def urls; ['/scripts/(.*).js'] end
|
28
|
+
end
|
29
|
+
|
30
|
+
self.root = '.'
|
31
|
+
|
32
|
+
def get(scripts)
|
33
|
+
scripts = scripts.split(';').uniq
|
34
|
+
data = ""
|
35
|
+
scripts.each do |script|
|
36
|
+
path = File.join(self.class.root, "#{script}.js")
|
37
|
+
begin
|
38
|
+
data << File.open(path).read
|
39
|
+
rescue Errno::ENOENT => ex
|
40
|
+
data << "// ERROR : #{ex}\n"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
data
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/ext/mount.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
require 'ext/sendfile'
|
3
|
+
require 'ext/patches'
|
4
|
+
|
5
|
+
module Ext
|
6
|
+
# That equipment allows you to mount whole directories as a camping
|
7
|
+
# controller. See ControllersClassMethods#mount for options.
|
8
|
+
#
|
9
|
+
# == Features
|
10
|
+
#
|
11
|
+
# * Easy to use
|
12
|
+
# * Directory listing (skinnable)
|
13
|
+
# * Resolving Content-Type on file extensions
|
14
|
+
#
|
15
|
+
# == Dependencies
|
16
|
+
#
|
17
|
+
# * Equipment
|
18
|
+
# * Sendfile
|
19
|
+
# * Patches
|
20
|
+
# * `mime-types` package
|
21
|
+
#
|
22
|
+
# == Example
|
23
|
+
#
|
24
|
+
# Camping.goes :YourApp
|
25
|
+
#
|
26
|
+
# module YourApp::Controllers
|
27
|
+
# mount File.dirname(File.expand_path(__FILE__)) #=> YourApp::Controllers::Somefolder
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# that will be available under the url : "/your_app/somefolder"
|
31
|
+
#
|
32
|
+
# Check the mount method in ControllersClassMethod for more informations.
|
33
|
+
# You can also redefine the dir listing template by redefining `mount_listing`
|
34
|
+
# or `yourcontroller_listing`
|
35
|
+
#
|
36
|
+
# eg.
|
37
|
+
#
|
38
|
+
# module YourApp::Views
|
39
|
+
#
|
40
|
+
# def mount_listing
|
41
|
+
# ul do
|
42
|
+
# @files.each { |f| li f }
|
43
|
+
# nil # array bug in markaby
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# def somefolder_listing # default
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# Controller assignation by hand :
|
53
|
+
#
|
54
|
+
# module YourApp::Controllers
|
55
|
+
# class Stylesheets < M File.dirname('../public/css'), :name => false, :listing => false
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# == Known bug
|
60
|
+
#
|
61
|
+
# There is a known bug where issued controllers appears as NilClass in the
|
62
|
+
# view. I really don't know why...
|
63
|
+
#
|
64
|
+
module Mount
|
65
|
+
extend Equipment
|
66
|
+
depends_on Patches
|
67
|
+
depends_on Sendfile
|
68
|
+
|
69
|
+
module ControllersClassMethods
|
70
|
+
# Mounts the path given by 'path'
|
71
|
+
#
|
72
|
+
# Options :
|
73
|
+
# * urls : list of accessible
|
74
|
+
# * name : name of the controller, false sets no controller
|
75
|
+
# * listing : set to false if you don't want directory listing.
|
76
|
+
#
|
77
|
+
# Option defaults for '/var/my_path' :
|
78
|
+
# * urls : /my_path(|/.*)
|
79
|
+
# * name : MyPath
|
80
|
+
#
|
81
|
+
# Renders the view Views#mount_listing if dir listing is enabled.
|
82
|
+
|
83
|
+
def mount(path, opts={})
|
84
|
+
defaults = {
|
85
|
+
:name => File.basename(path).gsub(/(^|_)(.)/){ $2.upcase },
|
86
|
+
:url => "/#{File.basename(path)}",
|
87
|
+
:listing => true
|
88
|
+
}
|
89
|
+
opts = defaults.merge(opts)
|
90
|
+
|
91
|
+
urls = ["#{opts[:url]}(|/.*)"]
|
92
|
+
|
93
|
+
klass = Class.new() do
|
94
|
+
meta_def(:urls) { urls }
|
95
|
+
meta_def(:path) { path }
|
96
|
+
meta_def(:listing?) { opts[:listing] }
|
97
|
+
end
|
98
|
+
klass.class_eval do
|
99
|
+
def get(file='') # :nodoc:
|
100
|
+
@path = File.join(self.class.path, file)
|
101
|
+
if File.directory?(@path) and self.class.listing?
|
102
|
+
@files = Dir[File.join(@path, '*')].map{|f| File.basename(f)}
|
103
|
+
if has_view?("#{self.class.name.downcase}_listing")
|
104
|
+
render("#{self.class.name.downcase}_listing")
|
105
|
+
else
|
106
|
+
render(:mount_listing)
|
107
|
+
end
|
108
|
+
else
|
109
|
+
sendfile(@path)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
const_set(opts[:name], klass) if opts[:name]
|
114
|
+
|
115
|
+
if $DBG
|
116
|
+
puts "** mounted #{path}"
|
117
|
+
puts "Controller : #{klass}"
|
118
|
+
puts "Options : #{opts.inspect}"
|
119
|
+
end
|
120
|
+
|
121
|
+
klass
|
122
|
+
end
|
123
|
+
alias :M :mount
|
124
|
+
end
|
125
|
+
|
126
|
+
module Views
|
127
|
+
# Default dir listing. @files contains all the files.
|
128
|
+
def mount_listing
|
129
|
+
path_info = @env.PATH_INFO.sub /\/$/, ''
|
130
|
+
h1 "Dir listing of #{path_info}"
|
131
|
+
ul do
|
132
|
+
li { a '..', :href => path_info.sub(/\w*$/,'') }
|
133
|
+
@files.each do |file|
|
134
|
+
li { a file, :href => "#{path_info}/#{file}" }
|
135
|
+
end
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
### Mime-types extensions
|
145
|
+
|
146
|
+
js_type = MIME::Type.from_hash(
|
147
|
+
'Content-Type' => 'text/javascript',
|
148
|
+
'Extensions' => ['js']
|
149
|
+
)
|
150
|
+
|
151
|
+
MIME::Types.add(js_type)
|
152
|
+
|