equipment 0.1.0 → 1.4.84
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +9 -0
- data/LICENSE +340 -0
- data/README +29 -12
- data/Rakefile +157 -0
- data/TODO +14 -0
- data/doc/structure.dia +0 -0
- data/doc/structure.png +0 -0
- data/lib/camping_ext.rb +72 -0
- data/lib/equipment.rb +39 -116
- data/lib/ext.rb +33 -0
- data/lib/ext/active_record.rb +146 -0
- data/lib/ext/basic_auth.rb +15 -15
- data/lib/ext/controls.rb +16 -14
- data/lib/ext/flash.rb +35 -17
- data/lib/ext/form_helpers.rb +46 -0
- data/lib/ext/forward.rb +44 -15
- data/lib/ext/js_helpers.rb +66 -19
- data/lib/ext/logging.rb +61 -0
- data/lib/ext/mount.rb +33 -27
- data/lib/ext/negociate_content.rb +90 -0
- data/lib/ext/og.rb +18 -10
- data/lib/ext/og_scaffold.rb +5 -8
- data/lib/ext/resource.rb +127 -0
- data/lib/ext/security.rb +66 -31
- data/lib/ext/sendfile.rb +3 -4
- data/lib/ext/settings.rb +243 -0
- data/lib/ext/template_view.rb +9 -37
- data/lib/ext/use_helper.rb +6 -10
- data/lib/ext/view.rb +98 -0
- data/lib/ext/view_slot.rb +60 -0
- data/lib/mimetype_ext.rb +12 -0
- data/lib/more/typecast.rb +288 -0
- data/lib/ruby_ext.rb +126 -0
- data/share/js/date_ext.js +234 -0
- data/share/js/es-confirm.js +23 -0
- data/share/js/event-selector.js +145 -0
- data/share/js/jquery.js +1793 -0
- data/share/js/prototype.js +2012 -0
- metadata +50 -35
- data/ProjectInfo +0 -55
- data/examples/basicauthtest.rb +0 -59
- data/examples/erubytest.rb +0 -36
- data/examples/flashtest.rb +0 -46
- data/examples/index.erb +0 -9
- data/examples/mounttest.rb +0 -34
- data/examples/ogtest.rb +0 -41
- data/examples/patchestest.rb +0 -40
- data/examples/sendfiletest.rb +0 -29
- data/lib/ext/forms.rb +0 -22
- data/lib/ext/patches.rb +0 -130
- data/lib/ext/ressource.rb +0 -88
data/lib/ext/basic_auth.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'base64'
|
1
2
|
require 'equipment'
|
2
3
|
require 'ext/security'
|
3
4
|
|
@@ -7,8 +8,11 @@ module Ext
|
|
7
8
|
#
|
8
9
|
# Inspired by Manfred Stienstra (http://www.fngtps.com/2006/05/basic-authentication-for-camping).
|
9
10
|
#
|
11
|
+
# See Security for more informations.
|
12
|
+
#
|
10
13
|
# == Dependencies
|
11
14
|
#
|
15
|
+
# * Base64
|
12
16
|
# * Equipment
|
13
17
|
# * Security
|
14
18
|
#
|
@@ -19,28 +23,24 @@ module Ext
|
|
19
23
|
extend Equipment
|
20
24
|
depends_on Security
|
21
25
|
|
22
|
-
def self.equip(app)
|
23
|
-
super
|
24
|
-
app::Controllers::Unauthenticated.send :include, app::Base
|
25
|
-
end
|
26
|
-
|
27
26
|
module Base
|
28
27
|
|
29
28
|
# Gets HTTP_Basic credendials from a request. It consists in an array
|
30
29
|
# of user and password.
|
31
30
|
def basic_credentials
|
32
|
-
puts "Authenticate"
|
33
31
|
if d = %w{X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION}.inject([]) \
|
34
32
|
{ |d,h| env.has_key?(h) ? env[h].to_s.split : [] }
|
35
33
|
return Base64.decode64(d[1]).split(':')[0..1] if d[0] == 'Basic'
|
36
|
-
end
|
34
|
+
end
|
35
|
+
[nil, nil]
|
37
36
|
end
|
38
|
-
alias :authenticate :basic_credentials
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
# This method won't be accessible if this module is on the roof of other
|
39
|
+
# all.
|
40
|
+
def authenticate
|
41
|
+
creds = basic_credentials
|
42
|
+
return super unless creds[0]
|
43
|
+
return *creds
|
44
44
|
end
|
45
45
|
|
46
46
|
end
|
@@ -52,7 +52,7 @@ module Ext
|
|
52
52
|
class << self
|
53
53
|
attr_accessor :realm
|
54
54
|
end
|
55
|
-
|
55
|
+
@realm = 'Camping'
|
56
56
|
|
57
57
|
def get
|
58
58
|
@status = 401
|
@@ -62,8 +62,8 @@ module Ext
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
class Unauthorized < Unauthenticated
|
66
|
-
end
|
65
|
+
# class Unauthorized < Unauthenticated
|
66
|
+
# end
|
67
67
|
|
68
68
|
end
|
69
69
|
end
|
data/lib/ext/controls.rb
CHANGED
@@ -1,26 +1,28 @@
|
|
1
1
|
require 'equipment'
|
2
2
|
|
3
3
|
module Ext
|
4
|
-
#
|
4
|
+
# A generic html control generation mechanism.
|
5
|
+
#
|
6
|
+
# TODO : Finish this
|
5
7
|
module Controls
|
6
8
|
extend Equipment
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
module Views
|
11
|
+
def _control_for(thing, opts={})
|
12
|
+
thing.class.ancestors.each do |a|
|
13
|
+
m = '_' + a.name.gsub('::', '__').downcase + '_control'
|
14
|
+
if respond_to? m
|
15
|
+
return send(m, name, thing)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
return "No control for #{thing}"
|
12
19
|
end
|
13
20
|
|
14
|
-
def
|
15
|
-
|
16
|
-
alias :to_s :render
|
17
|
-
end
|
18
|
-
|
19
|
-
module Helpers
|
20
|
-
def control(*args)
|
21
|
-
Control.new(*args)
|
21
|
+
def _text_control(str, opts={})
|
22
|
+
input {:type=>'text', :value=>str}.merge(opts)
|
22
23
|
end
|
24
|
+
alias :_string_control :_text_control
|
25
|
+
alias :_numeric_control :_text_control
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
26
|
-
|
data/lib/ext/flash.rb
CHANGED
@@ -4,7 +4,13 @@ module Ext
|
|
4
4
|
# Hilight some things for a short time. It's very convenient to have some
|
5
5
|
# look over things in the night. See Helpers#flash for more options.
|
6
6
|
#
|
7
|
-
# ==
|
7
|
+
# == How it works
|
8
|
+
#
|
9
|
+
# For example, you set flash.info to "hey!". Next time it is accessed,
|
10
|
+
# it will be available until the end of the controller's execution. So
|
11
|
+
# on the next page, flash.info will be back to nil.
|
12
|
+
#
|
13
|
+
# == Example
|
8
14
|
#
|
9
15
|
# in your controller :
|
10
16
|
#
|
@@ -36,44 +42,56 @@ module Ext
|
|
36
42
|
module Flash
|
37
43
|
extend Equipment
|
38
44
|
|
45
|
+
module Base
|
46
|
+
def initialize(r,e,m)
|
47
|
+
super
|
48
|
+
@flash = Flasher.new(@k, @cookies)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
39
52
|
module Helpers
|
40
53
|
# The flash helper. Use in your controller or view. Retuns
|
41
54
|
# a Flasher.
|
42
|
-
|
43
|
-
@__flash ||= Flasher.new(cookies)
|
44
|
-
end
|
55
|
+
attr_reader :flash
|
45
56
|
end
|
46
57
|
|
47
58
|
# The flash class. Stores the data temporarily in the cookies.
|
48
59
|
# Only store Strings.
|
49
60
|
class Flasher
|
50
|
-
def initialize(
|
51
|
-
@
|
52
|
-
@data = cookies.dup
|
61
|
+
def initialize(cookies_in, cookies_out)
|
62
|
+
@in, @out = cookies_in, cookies_out
|
53
63
|
end
|
54
64
|
|
55
65
|
def [](key)
|
56
|
-
key =
|
57
|
-
@
|
58
|
-
|
66
|
+
key = convert_key(key)
|
67
|
+
if @in[key] and not @in[key].empty?
|
68
|
+
@out[key] = '' if @out.has_key? key
|
69
|
+
return @in[key]
|
70
|
+
else
|
71
|
+
return nil
|
72
|
+
end
|
59
73
|
end
|
60
74
|
|
61
75
|
def []=(key, value)
|
62
76
|
unless value.nil? or value.empty?
|
63
|
-
key =
|
64
|
-
@
|
65
|
-
return @data[key] = value
|
77
|
+
key = convert_key(key)
|
78
|
+
@in[key] = @out[key] = value
|
66
79
|
end
|
67
80
|
end
|
68
81
|
|
69
82
|
# Allows fancy flash.xy or flash.xy = 'sdsd'
|
70
|
-
def method_missing(m,
|
71
|
-
/=$/ =~ m.to_s
|
83
|
+
def method_missing(m, *args)
|
84
|
+
if /=$/ =~ m.to_s
|
85
|
+
send(:[]=, m.to_s.sub(/=$/,''), *args)
|
86
|
+
else
|
87
|
+
raise NoMethodError, "Cannot pass arguments to #{m}, use = to assign data" unless args.empty?
|
88
|
+
send(:[], m)
|
89
|
+
end
|
72
90
|
end
|
73
91
|
|
74
92
|
private
|
75
|
-
def
|
76
|
-
"__flash__#{key}"
|
93
|
+
def convert_key(key)
|
94
|
+
"__flash__#{key}"
|
77
95
|
end
|
78
96
|
end
|
79
97
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
require 'ext/active_record'
|
3
|
+
|
4
|
+
module Ext
|
5
|
+
# Hey a FormHelper.
|
6
|
+
#
|
7
|
+
# This extension is quite simple for now and only provides on method
|
8
|
+
# used to generate forms form active record models. That method is
|
9
|
+
# also not capable of generating something else than text fields.
|
10
|
+
#
|
11
|
+
# When complete, this module will be used by Ext::Scaffold.
|
12
|
+
#
|
13
|
+
# == Dependencies
|
14
|
+
#
|
15
|
+
# * Equipment
|
16
|
+
# * Ext::ActiveRecord
|
17
|
+
#
|
18
|
+
# == TODO
|
19
|
+
#
|
20
|
+
# * Implement and use Ext::Controls
|
21
|
+
#
|
22
|
+
module FormHelpers
|
23
|
+
extend Equipment
|
24
|
+
depends_on ActiveRecord
|
25
|
+
|
26
|
+
module Helpers
|
27
|
+
# No relations yet
|
28
|
+
def form_for(entity, opts)
|
29
|
+
entity = entity.new if entity.kind_of? Class
|
30
|
+
form({:method=>:post}.merge(opts)) do
|
31
|
+
entity.attributes.each do |prop|
|
32
|
+
unless /^id$|_id$/.match prop[0].to_s
|
33
|
+
input_name = prop[0]
|
34
|
+
label prop[0].to_s, :for=>input_name; br
|
35
|
+
input :type=>'text', :name=>input_name, :value=>entity.send(prop[0]); br
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
input :type=>:hidden, :name=>'id', :value=>entity.id if entity.id
|
40
|
+
input :type=>:submit
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
data/lib/ext/forward.rb
CHANGED
@@ -5,9 +5,16 @@ module Ext
|
|
5
5
|
# Forwarding is like redirecting but internally. This won't send another
|
6
6
|
# request to the browser. See Base#forward for options.
|
7
7
|
#
|
8
|
-
# *HINT* : forwarding should be used rarely
|
8
|
+
# *HINT* : forwarding should be used rarely in apps. Use redirect on
|
9
9
|
# POST.
|
10
10
|
#
|
11
|
+
# == Added features
|
12
|
+
#
|
13
|
+
# If $DBG is enabled :
|
14
|
+
#
|
15
|
+
# * Print errors in the console
|
16
|
+
# * Show the requested URI with the dispatched controller.
|
17
|
+
#
|
11
18
|
# == Workflows
|
12
19
|
#
|
13
20
|
# these are simplified workflows that illustrate the difference between
|
@@ -28,7 +35,7 @@ module Ext
|
|
28
35
|
#
|
29
36
|
# == TODO
|
30
37
|
#
|
31
|
-
# *
|
38
|
+
# * Limit forwarding to X requests
|
32
39
|
module Forward
|
33
40
|
extend Equipment
|
34
41
|
|
@@ -36,22 +43,36 @@ module Ext
|
|
36
43
|
super
|
37
44
|
app.module_eval do
|
38
45
|
def self.run(r=$stdin,e=ENV)
|
46
|
+
puts "REQUEST: `#{e['PATH_INFO']}`" if $DBG
|
47
|
+
self::Controllers.M
|
39
48
|
k, a = self::Controllers.D un("/#{e['PATH_INFO']}".gsub(%r!/+!,'/'))
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
fw
|
44
|
-
|
45
|
-
|
49
|
+
begin
|
50
|
+
puts " --> #{k}" if $DBG
|
51
|
+
k.new(r,e,(m=m||e['REQUEST_METHOD']||'GET')).service(*a)
|
52
|
+
rescue Forwarder => fw
|
53
|
+
k, m, a = fw.controller, fw.method, fw.args
|
54
|
+
|
55
|
+
if /NotFound$/ =~ k.name # facility for NotFound controller
|
56
|
+
a = [e['PATH_INFO']] if a.empty? or not a.first
|
57
|
+
m = 'get'
|
58
|
+
end
|
59
|
+
|
60
|
+
retry
|
61
|
+
rescue Exception => x
|
62
|
+
pp x if $DBG
|
63
|
+
pp x.backtrace if $DBG
|
64
|
+
k, a, m = self::Controllers::ServerError, [k,m,x], 'GET'
|
65
|
+
retry
|
66
|
+
end
|
46
67
|
end
|
47
68
|
end
|
48
69
|
end
|
49
70
|
|
50
71
|
class Forwarder < Exception # :nodoc:
|
51
|
-
attr_accessor :controller, :args
|
72
|
+
attr_accessor :controller, :method, :args
|
52
73
|
|
53
|
-
def initialize(controller, *args)
|
54
|
-
@controller, @args = controller, args
|
74
|
+
def initialize(controller, method, *args)
|
75
|
+
@controller, @method, @args = controller, method, args
|
55
76
|
end
|
56
77
|
end
|
57
78
|
|
@@ -59,12 +80,20 @@ module Ext
|
|
59
80
|
# Forwards to another controller
|
60
81
|
#
|
61
82
|
# * controller : the other controller
|
62
|
-
# *
|
83
|
+
# * method : the designed method, actual method if not specified
|
84
|
+
# * *args : method arguments
|
63
85
|
#
|
64
|
-
|
65
|
-
|
66
|
-
|
86
|
+
def forward(controller, method=@method, *a)
|
87
|
+
# method selector, :method=>'get' or 'post'
|
88
|
+
|
89
|
+
if /NotFound$/ =~ controller.name # facility for NotFound controller
|
90
|
+
a = [e['PATH_INFO']] if a.empty? or not a.first
|
91
|
+
method = 'get'
|
92
|
+
end
|
93
|
+
|
94
|
+
raise Forwarder.new(controller, method, *a)
|
67
95
|
end
|
68
96
|
end
|
69
97
|
end
|
70
98
|
end
|
99
|
+
|
data/lib/ext/js_helpers.rb
CHANGED
@@ -2,7 +2,6 @@ require 'equipment'
|
|
2
2
|
require 'ext/app_util'
|
3
3
|
require 'ext/use_helper'
|
4
4
|
|
5
|
-
|
6
5
|
module Ext
|
7
6
|
module JsHelpers
|
8
7
|
extend Equipment
|
@@ -10,38 +9,86 @@ module Ext
|
|
10
9
|
depends_on UseHelper
|
11
10
|
|
12
11
|
module Helpers
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
|
13
|
+
# Returns a link to the JoinJavascripts controller with the desired
|
14
|
+
# scripts. If no script is passed, it will use the UseHelper specified
|
15
|
+
# javascripts.
|
16
|
+
#
|
17
|
+
# This is useful to avoid IE bugs. IE does not guarantee the javascript
|
18
|
+
# loading order. That way, you are sure they're always as you want ;-)
|
19
|
+
#
|
20
|
+
# raises ArgumentError if the produced url is longer than 512 chars.
|
21
|
+
#
|
22
|
+
# == Example
|
23
|
+
#
|
24
|
+
# joined_js('prototype.js', 'event-selector.js')
|
25
|
+
# #=> "/join_js/prototype-and-event-selector.js"
|
26
|
+
#
|
27
|
+
# == Usage in the Views
|
28
|
+
#
|
29
|
+
# def layout
|
30
|
+
# html do
|
31
|
+
# head do
|
32
|
+
# script :type=>'text/css', :src=>joined_js
|
33
|
+
# end
|
34
|
+
# body { yield }
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# def index
|
39
|
+
# use 'prototype.js', 'event-selector.js', 'my-script.js'
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
def joined_js(*scripts)
|
43
|
+
scripts = javascripts if scripts.empty?
|
44
|
+
script_name = scripts.map{|js| File.basename(js, '.js')}.join('-and-')
|
45
|
+
url = R(app::Controllers::JoinJavascripts, script_name)
|
46
|
+
raise ArgumentError, "Script name '#{script_name}' is too long" unless url.to_s.size < 512
|
47
|
+
url
|
20
48
|
end
|
21
49
|
end
|
22
50
|
|
23
51
|
module Controllers
|
24
|
-
|
52
|
+
# Returns a big script with all the requested scripts.
|
53
|
+
# -and- is the separator.
|
54
|
+
#
|
55
|
+
# It will look in it's JoinJavascripts.lookup_paths accessor for
|
56
|
+
# paths where the scripts exist. ['.'] is the default.
|
57
|
+
#
|
58
|
+
# If a script is not found, it will throw a javascript error.
|
59
|
+
class JoinJavascripts
|
25
60
|
class << self
|
26
|
-
attr_accessor :
|
27
|
-
def urls; ['/
|
61
|
+
attr_accessor :lookup_paths
|
62
|
+
def urls; ['/join_js/([^\/\.]*).js'] end
|
28
63
|
end
|
29
64
|
|
30
|
-
|
65
|
+
@lookup_paths = [File.join(Equipment::DATA_PATH, 'js')]
|
31
66
|
|
32
67
|
def get(scripts)
|
33
|
-
|
68
|
+
@headers['Content-Type'] = 'text/javascript'
|
69
|
+
scripts = scripts.split('-and-').map{|s|s+'.js'}
|
70
|
+
|
71
|
+
return "throw 'no files passed to JoinJavascript controller'" if scripts.empty?
|
72
|
+
|
34
73
|
data = ""
|
35
74
|
scripts.each do |script|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
75
|
+
message = "#{script} not found"
|
76
|
+
self.class.lookup_paths.each do |path|
|
77
|
+
path = File.join(path, script)
|
78
|
+
if File.exists?(path)
|
79
|
+
begin
|
80
|
+
data << File.read(path)
|
81
|
+
message = nil
|
82
|
+
break
|
83
|
+
rescue => ex
|
84
|
+
message = ex.message
|
85
|
+
end
|
86
|
+
end
|
41
87
|
end
|
88
|
+
data << "throw '#{message.gsub("'", "\\\\'")}'\n" if message
|
42
89
|
end
|
43
90
|
|
44
|
-
data
|
91
|
+
return data
|
45
92
|
end
|
46
93
|
end
|
47
94
|
end
|