equipment 0.1.0 → 1.4.84

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/CHANGES +9 -0
  2. data/LICENSE +340 -0
  3. data/README +29 -12
  4. data/Rakefile +157 -0
  5. data/TODO +14 -0
  6. data/doc/structure.dia +0 -0
  7. data/doc/structure.png +0 -0
  8. data/lib/camping_ext.rb +72 -0
  9. data/lib/equipment.rb +39 -116
  10. data/lib/ext.rb +33 -0
  11. data/lib/ext/active_record.rb +146 -0
  12. data/lib/ext/basic_auth.rb +15 -15
  13. data/lib/ext/controls.rb +16 -14
  14. data/lib/ext/flash.rb +35 -17
  15. data/lib/ext/form_helpers.rb +46 -0
  16. data/lib/ext/forward.rb +44 -15
  17. data/lib/ext/js_helpers.rb +66 -19
  18. data/lib/ext/logging.rb +61 -0
  19. data/lib/ext/mount.rb +33 -27
  20. data/lib/ext/negociate_content.rb +90 -0
  21. data/lib/ext/og.rb +18 -10
  22. data/lib/ext/og_scaffold.rb +5 -8
  23. data/lib/ext/resource.rb +127 -0
  24. data/lib/ext/security.rb +66 -31
  25. data/lib/ext/sendfile.rb +3 -4
  26. data/lib/ext/settings.rb +243 -0
  27. data/lib/ext/template_view.rb +9 -37
  28. data/lib/ext/use_helper.rb +6 -10
  29. data/lib/ext/view.rb +98 -0
  30. data/lib/ext/view_slot.rb +60 -0
  31. data/lib/mimetype_ext.rb +12 -0
  32. data/lib/more/typecast.rb +288 -0
  33. data/lib/ruby_ext.rb +126 -0
  34. data/share/js/date_ext.js +234 -0
  35. data/share/js/es-confirm.js +23 -0
  36. data/share/js/event-selector.js +145 -0
  37. data/share/js/jquery.js +1793 -0
  38. data/share/js/prototype.js +2012 -0
  39. metadata +50 -35
  40. data/ProjectInfo +0 -55
  41. data/examples/basicauthtest.rb +0 -59
  42. data/examples/erubytest.rb +0 -36
  43. data/examples/flashtest.rb +0 -46
  44. data/examples/index.erb +0 -9
  45. data/examples/mounttest.rb +0 -34
  46. data/examples/ogtest.rb +0 -41
  47. data/examples/patchestest.rb +0 -40
  48. data/examples/sendfiletest.rb +0 -29
  49. data/lib/ext/forms.rb +0 -22
  50. data/lib/ext/patches.rb +0 -130
  51. data/lib/ext/ressource.rb +0 -88
@@ -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; [nil, nil]
34
+ end
35
+ [nil, nil]
37
36
  end
38
- alias :authenticate :basic_credentials
39
37
 
40
- def authorize(user, pass, force=false)
41
- puts "Authorize"
42
- return super unless force
43
- forward(app::Controller::BasicAuth)
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
- self.realm = 'Camping'
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
@@ -1,26 +1,28 @@
1
1
  require 'equipment'
2
2
 
3
3
  module Ext
4
- # Not implemented yet
4
+ # A generic html control generation mechanism.
5
+ #
6
+ # TODO : Finish this
5
7
  module Controls
6
8
  extend Equipment
7
9
 
8
- class Control
9
- attr_reader :opts
10
- def initialize(opts={})
11
- @opts = opts
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 render
15
- end
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
-
@@ -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
- # == Look :
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
- def flash
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(cookies)
51
- @cookies = cookies
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 = 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
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 = to_key(key)
64
- @cookies[key] = value
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, val='')
71
- /=$/ =~ m.to_s ? send(:[]=, m.to_s.sub(/=$/,''), val) : send(:[], m)
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 to_key(key)
76
- "__flash__#{key}".to_sym
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
+
@@ -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 and only on GET. Use redirect on
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
- # * Allow more options in forwarding
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
- 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)
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
- # * *a : only for ruby hackers ;-)
83
+ # * method : the designed method, actual method if not specified
84
+ # * *args : method arguments
63
85
  #
64
- # TODO : make *a accessible for non hackers
65
- def forward(controller, *a)
66
- raise Forwarder.new(controller, *a)
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
+
@@ -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
- 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
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
- class JoinScripts
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 :root
27
- def urls; ['/scripts/(.*).js'] end
61
+ attr_accessor :lookup_paths
62
+ def urls; ['/join_js/([^\/\.]*).js'] end
28
63
  end
29
64
 
30
- self.root = '.'
65
+ @lookup_paths = [File.join(Equipment::DATA_PATH, 'js')]
31
66
 
32
67
  def get(scripts)
33
- scripts = scripts.split(';').uniq
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
- 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"
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