GitHub Sale: sign up for any paid plan this week and pay nothing until January 1, 2009!  [ hide ]

public
Rubygem
Description: Resource-oriented open source Ruby framework for Web apps.
Homepage: http://rubywaves.com/
Clone URL: git://github.com/dyoder/waves.git
Working version of new mappings, albeit somewhat buggy.
dyoder (author)
Sun Jun 22 02:20:14 -0700 2008
commit  b49df4bc69f20fbf4fe7e14e3c639e6a0c89d3e6
tree    4ff9cddc8f4918425fc42af3c833f63deb070277
parent  03d2de42ed9924e3a9f4c52163c0482d55e4409a
...
49
50
51
52
 
53
54
55
...
61
62
63
 
 
 
 
 
 
 
 
 
 
 
64
65
66
...
49
50
51
 
52
53
54
55
...
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
0
@@ -49,7 +49,7 @@ module Waves
0
 
0
             end
0
 
0
- auto_create_class true, Default
0
+ auto_create_class true, self::Default
0
             auto_load true, :directories => [ :controllers ]
0
             
0
           end
0
@@ -61,6 +61,17 @@ module Waves
0
             auto_eval( true ){ include Waves::Helpers::Default }
0
           end
0
 
0
+ auto_eval :Resources do
0
+ const_set( :Default, Class.new( Waves::Resources::Base ) ).module_eval do
0
+ def __c ; @controller ||= controllers[ resource ].process( @request ) { self } ; end
0
+ def __v ; @view ||= views[ resource ].process( @request ) { self } ; end
0
+ def action( method, *args ) ; @data = __c.send( method, *args ) ; end
0
+ def render( method ) ; puts "RENDER: #{resource}"; __v.send( method, ( @data.kind_of?( Enumerable ) ? resources : resource ) => @data ) ; end
0
+ def method_missing( name, *args, &block) ; params[ name ] ; end
0
+ end
0
+ auto_create_class true, self::Default
0
+ end
0
+
0
         end
0
       end
0
     end
...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
...
25
26
27
 
 
 
 
 
 
 
 
 
 
 
 
28
29
30
0
@@ -25,18 +25,6 @@ module Waves
0
           auto_create_module( :Resources ) do
0
             include AutoCode
0
             auto_create_class true, Waves::Resources::Base
0
- # this should probably be refactored into a separate layer
0
- auto_eval do
0
- def resource ; self.class.name ; end
0
- def resources ; resource.plural ; end
0
- def controller ; @controller ||= controllers[ resource ].process( @request ) { self } ; end
0
- def view ; @view ||= views[ resource ].process( @request ) { self } ; end
0
- def render( method ) ; view.send( method, ( @data.kind_of? Enumerable ? resources : resource ) => @data ) ; end
0
- def redirect( path ) ; request.redirect( path ) ; end
0
- def method_missing( name, *args, &block) ; @data = controller.send( name, *args, &block ) ; end
0
- # have to define this explicitly for now because for some reason sequel defines it on Object ...
0
- def all ; method_missing( :all ) ; end
0
- end
0
           end
0
 
0
         end
...
4
5
6
7
 
8
9
10
11
12
13
14
15
 
 
 
 
 
 
 
 
 
 
 
 
16
17
18
19
20
21
22
23
 
 
 
24
25
26
27
28
29
30
31
 
 
32
33
34
...
41
42
43
44
 
45
46
 
 
 
47
48
49
 
50
...
4
5
6
 
7
8
9
 
 
 
 
 
 
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
 
 
 
 
 
24
25
26
27
28
 
 
 
 
 
 
29
30
31
32
33
...
40
41
42
 
43
44
 
45
46
47
48
49
 
50
51
0
@@ -4,31 +4,30 @@ module Waves
0
     
0
     class Action
0
       
0
- attr_accessor :name, :resource, :pattern, :constraints, :descriptors
0
+ attr_reader :name, :resource, :pattern, :constraints, :descriptors
0
       
0
       def initialize( options, &block )
0
- name = options[:name]
0
- pattern = Pattern.new( options )
0
- matcher = Constraints.new( options )
0
- descriptors = Descriptors.new( options )
0
- resource = Waves.application[:resources][ options[:resource] ]
0
- resource.instance_eval{ define_method n, &block } if block_given?
0
+ @name = name = options[:name]
0
+ @pattern = pattern = Pattern.new( options )
0
+ @constraints = Constraints.new( options )
0
+ @descriptors = Descriptors.new( options )
0
+ if rname = options[ :resource ]
0
+ @resource = resource = Waves.application[:resources][ rname ]
0
+ else
0
+ resource = Waves.application[:resources][ :default ]
0
+ @resource = Waves::Resources::Proxy
0
+ end
0
+ resource.instance_eval { define_method name, &block } if name and block_given?
0
+ resource.paths.instance_eval { meta_def name, &pattern.generator }
0
       end
0
       
0
- # how / when can i take the results of the pattern match
0
- # and merge them with the request params ... can't do it here
0
- # because a number of actions may be run, but I can't store
0
- # it as state because actions are shared between requests
0
- def call?( request )
0
- constraints.satisfy?( request ) and pattern.match( request )
0
+ def bind( request )
0
+ ( constraints.satisfy?( request ) and
0
+ ( params = pattern.match( request ) ) and Binding.new( self, params ) )
0
       end
0
       
0
- def call( request )
0
- resource.new( request ).send( name )
0
- end
0
-
0
- def method_missing( name, *args )
0
- descriptors.send( name, *args )
0
+ def threaded?
0
+ descriptors.threaded?
0
       end
0
       
0
     end
0
@@ -41,9 +40,11 @@ module Waves
0
       
0
       def call( request )
0
         request.params.merge!( @params )
0
- @action.call( request )
0
+ @action.resource.new( request ).send( @action.name )
0
       end
0
-
0
+
0
+ end
0
+
0
   end
0
 
0
-end
0
+end
0
\ No newline at end of file
...
6
7
8
9
 
10
11
12
13
14
15
 
 
 
16
17
18
19
20
21
22
23
 
 
 
 
24
25
26
...
6
7
8
 
9
10
11
12
13
 
 
14
15
16
17
18
19
20
 
 
 
 
21
22
23
24
25
26
27
0
@@ -6,21 +6,22 @@ module Waves
0
       
0
       # TODO: Add other header methods here ...
0
       # may include some shortcuts for accessing Rack vars also
0
- METHODS = %w( method accepts ).map( &:intern )
0
+ METHODS = %w( method accept ).map( &:intern )
0
       
0
       attr_accessor *METHODS
0
       
0
       def initialize( options )
0
- METHODS.each do |method|
0
- send( "#{method}=", options[method] ) if options[method]
0
+ METHODS.each do | method |
0
+ instance_variable_set( "@#{method}", options[ method ] ) if options[ method ]
0
+ send( "#{method}=", options[ method ] ) if options[ method ]
0
         end
0
       end
0
       
0
       def satisfy?( request )
0
- METHODS.all? do |method|
0
- wanted = send( method )
0
- got = request.send( method )
0
- wanted == got if wanted == got
0
+ METHODS.all? do | method |
0
+ wanted = self.send( method )
0
+ got = request.send( method ) if wanted
0
+ wanted == got
0
         end
0
       end
0
             
...
3
4
5
6
 
7
8
9
...
3
4
5
 
6
7
8
9
0
@@ -3,7 +3,7 @@ module Waves
0
   module Mapping
0
     
0
     class Descriptors
0
-
0
+
0
       def initialize( options )
0
         @threaded = options[ :threaded ]
0
       end
...
5
6
7
8
9
 
 
 
 
 
10
11
12
13
14
 
 
 
 
 
 
 
 
 
 
15
16
17
18
19
20
21
 
22
23
24
25
 
26
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
53
54
 
55
56
57
58
...
5
6
7
 
 
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
53
54
 
55
 
 
 
 
 
 
 
 
 
 
 
56
57
58
59
60
0
@@ -5,53 +5,55 @@ module Waves
0
     METHODS = %w( get put post delete ).map( &:intern )
0
     RULES = %w( before action after always ).map( &:intern )
0
     
0
- def method_missing( name, *args, &block )
0
- mappings[ name ].push( map( *args, &block ) )
0
+ def mappings
0
+ @mappings ||= Hash.new { |h,k| h[k] = [] }
0
+ end
0
+
0
+ def before( options, &block )
0
     end
0
     
0
     def wrap( name, *args, &block )
0
       before( name, *args, &block ) ; after( name, *args, &block )
0
     end
0
+
0
+ def after( options, &block )
0
+ end
0
+
0
+ def always( options, &block )
0
+ end
0
+
0
+ def handle( exception )
0
+ end
0
+
0
     
0
     def with( options, &block )
0
       @options = options; yield if block_given? ; @options = nil
0
     end
0
 
0
     def path( name, options = {}, &block )
0
- mappings[ :action ] = map( options.merge!( :name => name, :target => :path ), &block )
0
+ map( options.merge!( :name => name, :target => :path ), &block )
0
     end
0
     
0
     def url( name, options = {}, &block )
0
- mappings[ :action ] = map( options.merge!( :name => name, :target => :url ), &block )
0
+ map( options.merge!( :name => name, :target => :url ), &block )
0
     end
0
     
0
- def map( *args, &block )
0
- options = ( @options || {} ).merge( normalize( *args ) )
0
+ def map( options, &block )
0
+ options = ( @options || {} ).merge( options )
0
       options[ :target ] ||= :path
0
       options[ :method ] = method = METHODS.find { |method| options[ method ] }
0
       options[ :pattern ] = options[ method ]
0
- Action.new( options, &block )
0
+ mappings[ :action ].push( Action.new( options, &block ) )
0
     end
0
     
0
     def []( request )
0
- results = {} ; RULES.each do | rule |
0
- results[ rule ] = mappings[ rule ].select do | action |
0
- ( params = action.call?( request ) ) and Action::Binding.new( action, params )
0
+ returning Hash.new { |h,k| h[k] = [] } do | results |
0
+ RULES.each do | rule |
0
+ mappings[ rule ].each { | action | binding = action.bind( request ) and results[ rule ].push( binding ) }
0
         end
0
       end
0
- return results
0
     end
0
-
0
- private
0
-
0
- include Functor::Method
0
-
0
- functor( :normalize, Symbol, Hash ) { | name, options | options.merge!( :name => name ) }
0
- functor( :normalize, String, Hash ) { | pattern, options | options.merge!( :pattern => pattern ) }
0
- functor( :normalize, Regexp, Hash ) { | regexp, options | options.merge!( :pattern => regexp ) }
0
- functor( :normalize, Exception ) { | exception | { :exception => exception } }
0
- functor( :normalize, Hash ) { | options | options }
0
-
0
+
0
   end
0
 
0
 end
0
\ No newline at end of file
...
 
 
1
2
3
4
5
6
7
 
 
 
 
8
9
10
 
11
12
13
14
15
 
 
16
17
18
19
20
21
22
23
24
 
 
 
25
26
27
 
 
 
 
 
 
 
 
 
 
 
28
29
30
...
1
2
3
4
5
6
7
8
 
9
10
11
12
13
14
 
15
16
17
18
 
 
19
20
21
22
23
24
 
 
 
 
 
25
26
27
28
29
 
30
31
32
33
34
35
36
37
38
39
40
41
42
43
0
@@ -1,30 +1,43 @@
0
+require 'generator'
0
+
0
 module Waves
0
 
0
   module Mapping
0
     
0
     class Pattern
0
       
0
- attr_accessor :target, :pattern
0
+ include Functor::Method
0
+
0
+ attr_accessor :target, :pattern, :generator
0
+
0
       def initialize( options )
0
         @keys = [] ; @target = options[ :target ]
0
- @pattern = compile( option[ :pattern ] )
0
+ compile( options[ :pattern ] )
0
       end
0
       
0
       def match( request )
0
- return false unless m = pattern.match( request.send( target ) )
0
- params = [] ; @keys.zip( m ) { | key, val | r[ key ] = val } ; params
0
+ return false unless m = @pattern.match( request.send( target ) )
0
+ returning( Hash.new ) { | r | @keys.zip( m[1..-1] ) { | k, v | r[ k ] = v } }
0
       end
0
       
0
       private
0
       
0
- functor( :compile, Regexp ) { |pattern| pattern }
0
-
0
- functor( :compile, String ) do | pattern |
0
- pattern = Regexp.escape( pattern ).gsub!( /<([\w\_\-\\]+)>/ ) { |match| @keys << match ; "(#{ match })" }
0
- "^#{pattern}/?$"
0
+ functor( :compile, Array ) do | path |
0
+ @generator = lambda { |*args| self.instance_eval { generate( path, args ) } }
0
+ @pattern = Regexp.new( path.map { |component| compile( component ) }.join('/') )
0
       end
0
       
0
-
0
+ functor( :compile, String ) { |s| Regexp.escape( s ) }
0
+ functor( :compile, Regexp ) { |re| s }
0
+ functor( :compile, Symbol ) { |sy| @keys << sy.to_s ; '([\w\_\-\#]+)' }
0
+
0
+ functor( :generate, Array, Array ) { | keys, vals | keys.map { |key| generate( key, vals ) }.join('/') }
0
+ functor( :generate, :resource, Array ) { | key, vals | resource }
0
+ functor( :generate, :resources, Array ) { | key, vals | resources }
0
+ functor( :generate, Symbol, Array ) { | key, vals | generate( key, vals.shift ) }
0
+ functor( :generate, Symbol, Symbol ) { | key, val | val }
0
+ functor( :generate, Regexp, Array ) { | key, vals | raise ArgumentError.new( "Can't generate a path from Regexp." ) }
0
+
0
     end
0
 
0
   end
...
7
8
9
10
11
 
 
 
 
 
 
 
 
 
 
12
13
14
15
16
 
17
18
19
...
7
8
9
 
 
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
24
25
26
27
0
@@ -7,13 +7,21 @@ module Waves
0
       attr_reader :request
0
 
0
       include ResponseMixin
0
-
0
- def initialize(request); @request = request; end
0
+
0
+ def self.included( target )
0
+ def target.paths ; @paths ||= Object.new ; end
0
+ end
0
+
0
+ def initialize(request); @request = request ; end
0
+ def resource ; self.class.basename.downcase ; end
0
+ def resources ; resource.plural ; end
0
+ def redirect( path ) ; request.redirect( path ) ; end
0
+ def paths ; self.class.paths ; end
0
       
0
     end
0
       
0
     # :)
0
- const_set( :Base, Class.new ).module_eval { include Mixin }
0
+ const_set( :Base, Class.new ).module_eval { include Mixin }
0
 
0
   end
0
 
...
21
22
23
24
25
 
 
 
 
26
27
28
...
40
41
42
43
 
44
45
46
47
48
49
 
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
 
 
66
67
68
...
21
22
23
 
 
24
25
26
27
28
29
30
...
42
43
44
 
45
46
 
 
 
 
 
47
48
49
50
51
52
53
 
 
 
 
 
 
 
 
 
 
54
55
56
57
58
0
@@ -21,8 +21,10 @@ module Waves
0
 
0
     # Accessor not explicitly defined by Waves::Request are delegated to Rack::Request.
0
     # Check the Rack documentation for more information.
0
- def method_missing(name,*args)
0
- @request.send(name,*args)
0
+ def method_missing( name, *args )
0
+ ( ( @request.respond_to?( name ) and @request.send( name,*args ) ) or
0
+ ( args.empty? and ( @request.env[ "HTTP_#{name.to_s.upcase}" ] or
0
+ @request.env[ "rack.#{name.to_s.downcase}" ] ) ) or super )
0
     end
0
 
0
     # The request path (PATH_INFO). Ex: +/entry/2008-01-17+
0
@@ -40,29 +42,17 @@ module Waves
0
       @request.env['CONTENT_TYPE']
0
     end
0
 
0
- # Supported request methods
0
+ # Request method predicates, defined in terms of #method.
0
     METHODS = %w{get post put delete head options trace}
0
-
0
- # Override the Rack methods for querying the request method.
0
- METHODS.each do |method|
0
- class_eval "def #{method}?; method == :#{method} end"
0
- end
0
+ METHODS.each { |m| define_method( m ) { method == m } }
0
 
0
     # The request method. Because browsers can't send PUT or DELETE
0
     # requests this can be simulated by sending a POST with a hidden
0
     # field named '_method' and a value with 'PUT' or 'DELETE'. Also
0
     # accepted is when a query parameter named '_method' is provided.
0
     def method
0
- @method ||= begin
0
- request_method = @request.request_method.downcase
0
- if request_method == 'post'
0
- _method = @request['_method']
0
- _method.downcase! if _method
0
- METHODS.include?(_method) ? _method.intern : :post
0
- else
0
- request_method.intern
0
- end
0
- end
0
+ @method ||= ( ( ( m = @request.request_method.downcase ) == 'post' and
0
+ ( n = @request['_method'] ) ) ? n.downcase : m ).intern
0
     end
0
 
0
     # Raise a not found exception.
...
1
 
 
 
 
2
3
 
4
5
6
7
 
 
 
 
8
9
10
...
23
24
25
26
 
27
28
29
30
31
32
33
34
35
 
 
36
37
38
...
41
42
43
 
 
 
 
44
45
46
47
...
1
2
3
4
5
6
 
7
8
9
10
11
12
13
14
15
16
17
18
...
31
32
33
 
34
35
36
37
 
 
 
 
 
 
38
39
40
41
42
...
45
46
47
48
49
50
51
52
53
54
55
0
@@ -1,10 +1,18 @@
0
 module Attributes
0
+
0
+ def initialize(hash = {} )
0
+ attributes = hash
0
+ end
0
   
0
- def initialize(hash={})
0
+ def attributes=( hash )
0
    # copy the hash, converting all keys to strings
0
     @attrs = hash.inject({}) { |h,p| k,v = p; h[k.to_s] = v; h }
0
   end
0
   
0
+ def attributes
0
+ @attrs ||= {}
0
+ end
0
+
0
   def method_missing(name,*args)
0
    name = name.to_s
0
     if name =~/=$/ and args.length == 1
0
@@ -23,16 +31,12 @@ module Attributes
0
   end
0
   
0
   def set(name, val)
0
- @attrs[name.to_s] = val
0
+ attributes[name.to_s] = val
0
   end
0
   
0
   def get(name)
0
- rval = ( @attrs[name.to_s] )
0
- if Hash === rval
0
- Attributes.new(rval)
0
- else
0
- rval
0
- end
0
+ rval = attributes[name.to_s]
0
+ rval.is_a?( Hash ) ? Attributes.new( rval ) : rval
0
   end
0
   
0
   def to_h
0
@@ -41,6 +45,10 @@ module Attributes
0
   
0
   alias_method :to_hash, :to_h
0
   
0
+ class Object
0
+ include Attributes
0
+ end
0
+
0
 end
0
   
0
   
0
\ No newline at end of file
...
5
6
7
8
 
9
10
11
...
21
22
23
 
 
24
25
26
...
32
33
34
35
36
37
38
...
51
52
53
 
 
 
 
54
 
55
56
57
...
5
6
7
 
8
9
10
11
...
21
22
23
24
25
26
27
28
...
34
35
36
 
37
38
39
...
52
53
54
55
56
57
58
59
60
61
62
63
0
@@ -5,7 +5,7 @@ require 'rack'
0
 require 'daemons'
0
 require 'live_console'
0
 
0
-# gem 'dyoder-autocode'
0
+gem 'dyoder-autocode'
0
 require 'autocode'
0
 
0
 # for mimetypes only or when using as default handler
0
@@ -21,6 +21,8 @@ require 'benchmark'
0
 # require 'memcache'
0
 require 'base64'
0
 
0
+require 'functor'
0
+
0
 # selected project-specific extensions
0
 require 'utilities/module'
0
 require 'utilities/string'
0
@@ -32,7 +34,6 @@ require 'utilities/inflect'
0
 require 'utilities/proc'
0
 require 'utilities/hash'
0
 require 'utilities/attributes'
0
-require 'utilities/functor'
0
 # waves Runtime
0
 require 'dispatchers/base'
0
 require 'dispatchers/default'
0
@@ -51,7 +52,12 @@ require 'runtime/configuration'
0
 
0
 # waves URI mapping
0
 require 'mapping/mapping'
0
+require 'mapping/action'
0
+require 'mapping/constraints'
0
+require 'mapping/descriptors'
0
+require 'mapping/pattern'
0
 require 'resources/mixin'
0
+require 'resources/proxy'
0
 
0
 # waves mvc support
0
 require 'controllers/mixin'
...
7
8
9
10
11
 
 
12
13
14
15
16
17
18
19
20
 
 
 
 
 
 
21
22
23
24
25
26
 
27
...
7
8
9
 
 
10
11
12
13
14
 
 
 
 
 
 
15
16
17
18
19
20
21
22
23
24
25
 
26
27
0
@@ -7,20 +7,20 @@ module Blog
0
       extend Waves::Mapping
0
       
0
       # specific to comments - on create redirect to the entry, not the comment itself
0
- path :create, :resource => :comment, :post => '/comments' do
0
- instance = create and redirect( Blog::Resources::Entries.path.show( instance.entry.name ) )
0
+ path :create, :resource => :comment, :post => [ :comments ] do
0
+ redirect( Blog::Resources::Entries.paths.show( action( :create ).entry.name ) )
0
       end
0
       
0
       # defaults for generic resources
0
- path :list, :get => '/<resources>' { all and render( :list ) }
0
- path :show, :get => '/<resource>/<name>' { find( params[:name] ) and render( :show ) }
0
- path :edit, :get => '/<resource>/<name>/editor' { find( params[:name] ) and render( :editor ) }
0
- path :create, :post => '/<resources>' { instance = create and redirect( path.editor( instance.name ) ) }
0
- path :update, :post => '/<resource>/<name>' { update( params[:name] ) and redirect( path.show( params[:name] ) ) }
0
- path :delete, :delete => '/<resource><name>' { delete( params[:name] ) }
0
+ path( :list, :get => [ :resources ] ) { action( :all ) and render( :list ) }
0
+ path( :show, :get => [ :resource, :name ] ) { action( :find, name ) and render( :show ) }
0
+ path( :edit, :get => [ :resource, :name, :view ] ) { action( :find, name ) and render( view ) }
0
+ path( :create, :post => [ :resources ] ) { redirect( paths.edit( action( :create ).name ) ) }
0
+ path( :update, :post => [ :resource, :name ] ) { action( :update, name ) and redirect( paths.show( name ) ) }
0
+ path( :delete, :delete => [ :resource, :name ] ) { action( :delete, name ) }
0
       
0
     end
0
 
0
   end
0
 
0
-end
0
+end
0
\ No newline at end of file

Comments

    No one has commented yet.