waves 0.8.2 → 0.9.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/bin/waves +4 -3
- data/doc/VERSION +1 -1
- data/lib/waves.rb +52 -40
- data/lib/{caches → waves/caches}/file.rb +3 -1
- data/lib/waves/caches/memcached.rb +56 -0
- data/lib/{caches → waves/caches}/simple.rb +6 -7
- data/lib/{caches → waves/caches}/synchronized.rb +15 -1
- data/lib/{commands → waves/commands}/console.rb +4 -4
- data/lib/{commands → waves/commands}/generate.rb +6 -5
- data/lib/{commands → waves/commands}/help.rb +0 -0
- data/lib/{commands → waves/commands}/server.rb +1 -1
- data/lib/{dispatchers → waves/dispatchers}/base.rb +17 -31
- data/lib/waves/dispatchers/default.rb +19 -0
- data/lib/{ext → waves/ext}/float.rb +0 -0
- data/lib/{ext → waves/ext}/hash.rb +0 -0
- data/lib/{ext → waves/ext}/integer.rb +16 -1
- data/lib/{ext → waves/ext}/kernel.rb +3 -7
- data/lib/{ext → waves/ext}/module.rb +3 -3
- data/lib/{ext → waves/ext}/object.rb +2 -0
- data/lib/waves/ext/string.rb +73 -0
- data/lib/{ext → waves/ext}/symbol.rb +0 -1
- data/lib/{ext → waves/ext}/tempfile.rb +0 -0
- data/lib/waves/ext/time.rb +5 -0
- data/lib/{foundations → waves/foundations}/classic.rb +9 -21
- data/lib/{foundations → waves/foundations}/compact.rb +15 -20
- data/lib/waves/foundations/rest.rb +311 -0
- data/lib/waves/helpers/basic.rb +13 -0
- data/lib/{helpers → waves/helpers}/doc_type.rb +3 -0
- data/lib/waves/helpers/form.rb +94 -0
- data/lib/waves/helpers/formatting.rb +14 -0
- data/lib/waves/layers/mvc.rb +65 -0
- data/lib/{layers → waves/layers}/mvc/controllers.rb +0 -0
- data/lib/{layers → waves/layers}/mvc/extensions.rb +23 -11
- data/lib/{layers → waves/layers}/orm/migration.rb +0 -0
- data/lib/{layers → waves/layers}/orm/providers/active_record.rb +2 -5
- data/lib/{layers → waves/layers}/orm/providers/active_record/migrations/empty.rb.erb +0 -0
- data/lib/{layers → waves/layers}/orm/providers/active_record/tasks/generate.rb +1 -1
- data/lib/{layers → waves/layers}/orm/providers/active_record/tasks/schema.rb +1 -1
- data/lib/{layers → waves/layers}/orm/providers/data_mapper.rb +0 -0
- data/lib/{layers → waves/layers}/orm/providers/filebase.rb +0 -0
- data/lib/{layers → waves/layers}/orm/providers/sequel.rb +28 -29
- data/lib/{layers → waves/layers}/orm/providers/sequel/migrations/empty.rb.erb +0 -0
- data/lib/{layers → waves/layers}/orm/providers/sequel/tasks/generate.rb +1 -1
- data/lib/{layers → waves/layers}/orm/providers/sequel/tasks/schema.rb +2 -0
- data/lib/waves/layers/rack/rack_cache.rb +32 -0
- data/lib/waves/layers/renderers/erubis.rb +52 -0
- data/lib/waves/layers/renderers/haml.rb +67 -0
- data/lib/waves/layers/renderers/markaby.rb +41 -0
- data/lib/waves/layers/text/inflect/english.rb +42 -0
- data/lib/waves/matchers/accept.rb +47 -0
- data/lib/waves/matchers/ext.rb +27 -0
- data/lib/waves/matchers/path.rb +72 -0
- data/lib/waves/matchers/query.rb +43 -0
- data/lib/waves/matchers/request.rb +86 -0
- data/lib/waves/matchers/requested.rb +31 -0
- data/lib/{matchers → waves/matchers}/resource.rb +8 -1
- data/lib/waves/matchers/traits.rb +30 -0
- data/lib/waves/matchers/uri.rb +69 -0
- data/lib/waves/media/mime_types.rb +542 -0
- data/lib/waves/renderers/mixin.rb +9 -0
- data/lib/waves/request/accept.rb +92 -0
- data/lib/{runtime → waves/request}/request.rb +77 -61
- data/lib/waves/resources/file_mixin.rb +11 -0
- data/lib/{resources → waves/resources}/mixin.rb +42 -44
- data/lib/waves/resources/paths.rb +132 -0
- data/lib/waves/response/client_errors.rb +10 -0
- data/lib/waves/response/packaged.rb +19 -0
- data/lib/waves/response/redirects.rb +35 -0
- data/lib/{runtime → waves/response}/response.rb +29 -11
- data/lib/{runtime → waves/response}/response_mixin.rb +30 -17
- data/lib/waves/runtime/applications.rb +18 -0
- data/lib/{runtime → waves/runtime}/configuration.rb +31 -25
- data/lib/waves/runtime/console.rb +24 -0
- data/lib/{runtime → waves/runtime}/logger.rb +3 -3
- data/lib/{runtime → waves/runtime}/mocks.rb +2 -2
- data/lib/waves/runtime/rackup.rb +37 -0
- data/lib/waves/runtime/runtime.rb +48 -0
- data/lib/waves/runtime/server.rb +33 -0
- data/lib/{servers → waves/servers}/base.rb +0 -0
- data/lib/{servers → waves/servers}/mongrel.rb +0 -0
- data/lib/{servers → waves/servers}/webrick.rb +0 -0
- data/lib/{tasks → waves/tasks}/gem.rb +0 -0
- data/lib/{tasks → waves/tasks}/generate.rb +0 -0
- data/lib/waves/views/cassy.rb +173 -0
- data/lib/{views → waves/views}/errors.rb +8 -7
- data/lib/waves/views/mixin.rb +23 -0
- data/lib/waves/views/templated.rb +40 -0
- data/samples/basic/basic_startup.rb +70 -0
- data/samples/basic/config.ru +9 -0
- data/samples/blog/configurations/development.rb +17 -16
- data/samples/blog/configurations/production.rb +0 -11
- data/samples/blog/resources/entry.rb +3 -3
- data/samples/blog/resources/map.rb +10 -3
- data/samples/blog/startup.rb +4 -3
- data/templates/classic/Rakefile +28 -29
- data/templates/classic/configurations/default.rb.erb +8 -3
- data/templates/classic/configurations/development.rb.erb +1 -20
- data/templates/classic/configurations/production.rb.erb +2 -16
- data/templates/classic/public/images/favicon.ico +0 -0
- data/templates/classic/resources/server.rb.erb +9 -0
- data/templates/classic/startup.rb.erb +3 -3
- data/templates/classic/views/css.rb.erb +14 -0
- data/templates/classic/views/default.rb.erb +17 -0
- data/templates/classic/views/errors.rb.erb +10 -0
- data/templates/classic/views/pages.rb.erb +14 -0
- data/templates/compact/startup.rb.erb +8 -3
- data/test/ext/object.rb +55 -0
- data/test/ext/shortcuts.rb +73 -0
- data/test/helpers.rb +17 -0
- data/test/match/accept.rb +78 -0
- data/test/match/ext.rb +156 -0
- data/test/match/methods.rb +22 -0
- data/test/match/params.rb +33 -0
- data/test/match/path.rb +106 -0
- data/test/match/query.rb +60 -0
- data/test/match/request.rb +91 -0
- data/test/match/requested.rb +149 -0
- data/test/match/uri.rb +136 -0
- data/test/process/request.rb +75 -0
- data/test/process/resource.rb +53 -0
- data/test/resources/path.rb +166 -0
- data/test/runtime/configurations.rb +19 -0
- data/test/runtime/request.rb +63 -0
- data/test/runtime/response.rb +85 -0
- data/test/views/views.rb +40 -0
- metadata +243 -157
- data/lib/caches/memcached.rb +0 -40
- data/lib/dispatchers/default.rb +0 -25
- data/lib/ext/string.rb +0 -20
- data/lib/helpers/basic.rb +0 -11
- data/lib/helpers/extended.rb +0 -21
- data/lib/helpers/form.rb +0 -42
- data/lib/helpers/formatting.rb +0 -30
- data/lib/helpers/layouts.rb +0 -37
- data/lib/helpers/model.rb +0 -37
- data/lib/helpers/view.rb +0 -22
- data/lib/layers/inflect/english.rb +0 -67
- data/lib/layers/mvc.rb +0 -54
- data/lib/layers/renderers/erubis.rb +0 -60
- data/lib/layers/renderers/haml.rb +0 -47
- data/lib/layers/renderers/markaby.rb +0 -29
- data/lib/matchers/accept.rb +0 -21
- data/lib/matchers/base.rb +0 -30
- data/lib/matchers/content_type.rb +0 -17
- data/lib/matchers/path.rb +0 -67
- data/lib/matchers/query.rb +0 -21
- data/lib/matchers/request.rb +0 -27
- data/lib/matchers/traits.rb +0 -19
- data/lib/matchers/uri.rb +0 -20
- data/lib/renderers/mixin.rb +0 -36
- data/lib/resources/paths.rb +0 -34
- data/lib/runtime/console.rb +0 -23
- data/lib/runtime/mime_types.rb +0 -536
- data/lib/runtime/monitor.rb +0 -32
- data/lib/runtime/runtime.rb +0 -67
- data/lib/runtime/server.rb +0 -20
- data/lib/runtime/session.rb +0 -27
- data/lib/runtime/worker.rb +0 -86
- data/lib/views/mixin.rb +0 -62
- data/samples/blog/blog.db +0 -0
- data/samples/blog/log/waves.production +0 -3
- data/templates/classic/resources/map.rb.erb +0 -8
- data/templates/classic/templates/errors/not_found_404.mab +0 -7
- data/templates/classic/templates/errors/server_error_500.mab +0 -7
- data/templates/classic/templates/layouts/default.mab +0 -14
- data/templates/classic/tmp/sessions/.gitignore +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'rack/cache'
|
|
2
|
+
|
|
3
|
+
module Waves
|
|
4
|
+
|
|
5
|
+
module Cache
|
|
6
|
+
|
|
7
|
+
module RackCache
|
|
8
|
+
|
|
9
|
+
def self.included(app)
|
|
10
|
+
|
|
11
|
+
#registering the default configuration for rack-cache
|
|
12
|
+
app.application.use Rack::Cache,
|
|
13
|
+
#set cache related options
|
|
14
|
+
:verbose => true,
|
|
15
|
+
# default_ttl will be add to any cacheable response without explicit indication of max-age.
|
|
16
|
+
# set :default_ttl, 60 * 60 * 24
|
|
17
|
+
# store can be heap, memcache or disk. Default option is heap.
|
|
18
|
+
#set :metastore, 'file:/var/cache/rack/meta'
|
|
19
|
+
:entitystore => 'file:./cache/rack/body',
|
|
20
|
+
# request containing 'Authorization' and 'Cookie' headers are defined 'private' and thus not cacheable.
|
|
21
|
+
# overriding the private_headers will define which headers make the request not cacheable.
|
|
22
|
+
# instead of overriding this config, you may choose to use the header 'Vary' in your application.
|
|
23
|
+
:private_headers => ['Authorization']
|
|
24
|
+
#end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'erubis'
|
|
2
|
+
|
|
3
|
+
module Waves
|
|
4
|
+
|
|
5
|
+
module Renderers
|
|
6
|
+
|
|
7
|
+
module Erubis
|
|
8
|
+
|
|
9
|
+
Extension = :erb
|
|
10
|
+
|
|
11
|
+
# extend Waves::Renderers::Mixin
|
|
12
|
+
|
|
13
|
+
def self.included( app )
|
|
14
|
+
Waves::Views.renderers << self
|
|
15
|
+
app.auto_eval :Views do
|
|
16
|
+
auto_eval true do
|
|
17
|
+
include ViewMethods
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# def self.render( path, assigns={} )
|
|
23
|
+
# eruby = ::Erubis::Eruby.new( template( path ) )
|
|
24
|
+
# helper = helper( path )
|
|
25
|
+
# context = ::Erubis::Context.new( assigns )
|
|
26
|
+
# ( class << context ; self ; end ).module_eval do
|
|
27
|
+
# include( helper )
|
|
28
|
+
# def << (s) ; s ; end
|
|
29
|
+
# end
|
|
30
|
+
# eruby.evaluate( context )
|
|
31
|
+
# end
|
|
32
|
+
|
|
33
|
+
module ViewMethods
|
|
34
|
+
|
|
35
|
+
def erb(string, assigns={})
|
|
36
|
+
eruby = ::Erubis::Eruby.new( string )
|
|
37
|
+
helper = Waves.main::Helpers[self.class.basename]
|
|
38
|
+
context = ::Erubis::Context.new( assigns )
|
|
39
|
+
( class << context ; self ; end ).module_eval do
|
|
40
|
+
include( helper )
|
|
41
|
+
def << (s) ; s ; end
|
|
42
|
+
end
|
|
43
|
+
eruby.evaluate( context )
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'haml'
|
|
2
|
+
|
|
3
|
+
module Waves
|
|
4
|
+
|
|
5
|
+
module Renderers
|
|
6
|
+
|
|
7
|
+
module Haml
|
|
8
|
+
|
|
9
|
+
Extension = :haml
|
|
10
|
+
|
|
11
|
+
# extend Waves::Renderers::Mixin
|
|
12
|
+
|
|
13
|
+
def self.included(app)
|
|
14
|
+
Waves::Views.renderers << self
|
|
15
|
+
Waves::Views::Base.send(:include, self::ViewMethods)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module ViewMethods
|
|
19
|
+
|
|
20
|
+
def haml(string, assigns={})
|
|
21
|
+
engine = ::Haml::Engine.new( string )
|
|
22
|
+
scope = Scope.new
|
|
23
|
+
helper = Waves.main::Helpers[self.class.basename]
|
|
24
|
+
scope.meta_eval { include( helper ) }
|
|
25
|
+
scope.instance_eval do
|
|
26
|
+
assigns.each { |key,val| instance_variable_set("@#{key}",val) unless key == :request }
|
|
27
|
+
end
|
|
28
|
+
engine.render(scope, assigns)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# def self.render( path, assigns )
|
|
34
|
+
# engine = ::Haml::Engine.new( template( path ) )
|
|
35
|
+
# scope = Scope.new
|
|
36
|
+
# helper = helper( path )
|
|
37
|
+
# scope.meta_eval { include( helper ) }
|
|
38
|
+
# scope.instance_eval do
|
|
39
|
+
# assigns.each { |key,val| instance_variable_set("@#{key}",val) unless key == :request }
|
|
40
|
+
# end
|
|
41
|
+
# engine.render(scope, assigns)
|
|
42
|
+
# end
|
|
43
|
+
|
|
44
|
+
class Scope
|
|
45
|
+
include Waves::Helpers::DocType
|
|
46
|
+
include Waves::Helpers::Layouts
|
|
47
|
+
include Waves::Helpers::Model
|
|
48
|
+
include Waves::Helpers::View
|
|
49
|
+
|
|
50
|
+
def <<(s)
|
|
51
|
+
eval("@haml_buffer", @binding).push_text s # add to rendered output
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def capture(&block)
|
|
55
|
+
capture_haml(nil, &block)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Waves
|
|
2
|
+
|
|
3
|
+
module Renderers
|
|
4
|
+
|
|
5
|
+
module Markaby
|
|
6
|
+
|
|
7
|
+
Extension = :mab
|
|
8
|
+
|
|
9
|
+
# extend Waves::Renderers::Mixin
|
|
10
|
+
|
|
11
|
+
def self.included( app )
|
|
12
|
+
require 'markaby'
|
|
13
|
+
::Markaby::Builder.set( :indent, 2 )
|
|
14
|
+
Waves::Views.renderers << self
|
|
15
|
+
# Waves::Views::Base.send(:include, self::ViewMethods)
|
|
16
|
+
app.auto_eval :Views do
|
|
17
|
+
auto_eval :Default do
|
|
18
|
+
include ViewMethods
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module ViewMethods
|
|
24
|
+
|
|
25
|
+
def mab(string, assigns={})
|
|
26
|
+
builder = ::Markaby::Builder.new( assigns )
|
|
27
|
+
helper = Waves.main::Helpers[self.class.basename]
|
|
28
|
+
builder.meta_eval { include( helper ) }
|
|
29
|
+
builder.instance_eval( string )
|
|
30
|
+
builder.to_s
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Waves
|
|
2
|
+
module Layers
|
|
3
|
+
module Text
|
|
4
|
+
module Inflect
|
|
5
|
+
|
|
6
|
+
# Adds plural/singular methods for English to String
|
|
7
|
+
module English
|
|
8
|
+
|
|
9
|
+
def self.included(app)
|
|
10
|
+
|
|
11
|
+
require 'english/inflect'
|
|
12
|
+
|
|
13
|
+
Waves::Resources::Mixin::ClassMethods.module_eval do
|
|
14
|
+
def singular ; basename.snake_case.singular ; end
|
|
15
|
+
def plural ; basename.snake_case.plural ; end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Waves::ResponseMixin.module_eval do
|
|
19
|
+
def singular ; self.class.basename.snake_case.singular ; end
|
|
20
|
+
def plural ; self.class.basename.snake_case.plural ; end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Waves::Resources::Mixin.module_eval do
|
|
24
|
+
def singular ; self.class.singular ; end
|
|
25
|
+
def plural ; self.class.plural ; end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Waves::Resources::Paths.module_eval do
|
|
29
|
+
def resource ; self.class.resource.singular ; end
|
|
30
|
+
def resources ; self.class.resource.plural ; end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Waves
|
|
2
|
+
module Matchers
|
|
3
|
+
|
|
4
|
+
# @todo Rename to Negotiation? --rue
|
|
5
|
+
#
|
|
6
|
+
class Accept
|
|
7
|
+
|
|
8
|
+
# Set up Accept parsing.
|
|
9
|
+
#
|
|
10
|
+
# Only the defined constraints are included.
|
|
11
|
+
#
|
|
12
|
+
def initialize(options)
|
|
13
|
+
|
|
14
|
+
@constraints = {}
|
|
15
|
+
|
|
16
|
+
{ :accept => :accept, :charset => :accept_charset, :lang => :accept_lang }.each { |key,method|
|
|
17
|
+
if options[key]
|
|
18
|
+
if options[key].is_a? Array
|
|
19
|
+
@constraints[method] = options[key] unless options[key].empty?
|
|
20
|
+
else
|
|
21
|
+
@constraints[method] = [ options[key] ]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Verify that any and all Accept constraints match.
|
|
29
|
+
#
|
|
30
|
+
# Request handles these.
|
|
31
|
+
#
|
|
32
|
+
def call(request)
|
|
33
|
+
@constraints.all? { |key, val| request.send(key).include? val }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Proc-like interface
|
|
37
|
+
#
|
|
38
|
+
def [](request)
|
|
39
|
+
call request
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Waves
|
|
2
|
+
module Matchers
|
|
3
|
+
|
|
4
|
+
class Ext
|
|
5
|
+
|
|
6
|
+
def initialize( ext )
|
|
7
|
+
@ext = ext
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def call(request)
|
|
11
|
+
test( request.extension, @ext )
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test( val, pat )
|
|
15
|
+
case pat
|
|
16
|
+
when false then val.nil?
|
|
17
|
+
when true, '.*', val then true
|
|
18
|
+
when Symbol, Symbol then val == ".#{pat}"
|
|
19
|
+
when Array then pat.any? { |e| test( val, e ) }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module Waves
|
|
2
|
+
|
|
3
|
+
module Matchers
|
|
4
|
+
|
|
5
|
+
class Path
|
|
6
|
+
|
|
7
|
+
# Takes an array of pattern elements ... coming soon, support for formatted strings!
|
|
8
|
+
#
|
|
9
|
+
# Empty Array means no path, but nil is not processed.
|
|
10
|
+
#
|
|
11
|
+
def initialize(pattern)
|
|
12
|
+
@pattern = pattern
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# returns a hash of captured values
|
|
16
|
+
def call( request )
|
|
17
|
+
if @pattern.is_a? Array
|
|
18
|
+
path = extract_path( request ).reverse
|
|
19
|
+
return {} if @pattern.empty? && path.empty?
|
|
20
|
+
capture = {}
|
|
21
|
+
match = @pattern.all? do | want |
|
|
22
|
+
case want
|
|
23
|
+
when true # same as a Range of 1..-1
|
|
24
|
+
path = [] unless path.empty?
|
|
25
|
+
when Range
|
|
26
|
+
if want.end == -1
|
|
27
|
+
path = [] if path.length >= want.begin
|
|
28
|
+
else
|
|
29
|
+
path = [] if want.include? path.length
|
|
30
|
+
end
|
|
31
|
+
when String then want == path.pop
|
|
32
|
+
when Symbol then capture[ want ] = path.pop
|
|
33
|
+
when Regexp then want === path.pop
|
|
34
|
+
when Hash
|
|
35
|
+
key, value = want.to_a.first
|
|
36
|
+
case value
|
|
37
|
+
when true
|
|
38
|
+
( capture[ key ], path = path.reverse, [] ) unless path.empty?
|
|
39
|
+
when Range
|
|
40
|
+
if value.end == -1
|
|
41
|
+
( capture[ key ], path = path.reverse, [] ) if path.length >= value.begin
|
|
42
|
+
else
|
|
43
|
+
( capture[ key ], path = path.reverse, [] ) if value.include? path.length
|
|
44
|
+
end
|
|
45
|
+
when String, Symbol
|
|
46
|
+
got = path.pop
|
|
47
|
+
capture[ key ] = got ? got : value.to_s
|
|
48
|
+
when Regexp then
|
|
49
|
+
got = path.pop
|
|
50
|
+
capture[ key ] = got if value === got
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
capture if match && path.empty?
|
|
55
|
+
elsif @pattern == true or @pattern == false or @pattern == nil
|
|
56
|
+
{}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# private
|
|
61
|
+
|
|
62
|
+
# just a little helper method
|
|
63
|
+
def extract_path( request )
|
|
64
|
+
request.traits.waves.path ||= request.path.chomp(request.ext).scan(/[^\/]+/).map { |e| Rack::Utils.unescape(e) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Waves
|
|
2
|
+
|
|
3
|
+
module Matchers
|
|
4
|
+
|
|
5
|
+
# Query parameter matching.
|
|
6
|
+
#
|
|
7
|
+
class Query
|
|
8
|
+
|
|
9
|
+
# Create query matcher or fail.
|
|
10
|
+
#
|
|
11
|
+
# @todo Should map Symbols to Strings here. --rue
|
|
12
|
+
#
|
|
13
|
+
def initialize(pattern)
|
|
14
|
+
raise ArgumentError, "No Query constraints!" unless pattern
|
|
15
|
+
@pattern = pattern
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Match query parameters.
|
|
19
|
+
#
|
|
20
|
+
def call(request)
|
|
21
|
+
@pattern.all? {|key, val|
|
|
22
|
+
# @todo Is this right? I do not see how even a
|
|
23
|
+
# Proc would be useful just given nil from
|
|
24
|
+
# a nonexisting key. We just fail in those
|
|
25
|
+
# cases for now. --rue
|
|
26
|
+
if given = request.query[key.to_s]
|
|
27
|
+
val == true or val === given or (val.call(given) rescue false)
|
|
28
|
+
end
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Proc-like interface
|
|
33
|
+
#
|
|
34
|
+
def [](request)
|
|
35
|
+
call request
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
module Waves
|
|
2
|
+
module Matchers
|
|
3
|
+
|
|
4
|
+
class Request
|
|
5
|
+
|
|
6
|
+
attr_accessor :constraints
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# @todo Further optimise the cases where there are no
|
|
11
|
+
# constraints. --rue
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
def initialize(options)
|
|
15
|
+
|
|
16
|
+
@uri = Matchers::URI.new( options )
|
|
17
|
+
|
|
18
|
+
@constraints = {}
|
|
19
|
+
|
|
20
|
+
if options[ :requested ]
|
|
21
|
+
@constraints[ :requested ] = Matchers::Requested.new( options[ :requested ] )
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if options.key?( :accept ) || options.key?( :lang ) || options.key?( :charset )
|
|
25
|
+
@constraints[:accept] = Matchers::Accept.new( options )
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if options.key?( :ext )
|
|
29
|
+
@constraints[ :ext ] = Matchers::Ext.new( options[ :ext ] )
|
|
30
|
+
elsif options.key?( :extension )
|
|
31
|
+
@constraints[ :ext ] = Matchers::Ext.new( options[ :extension ] )
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if options.key?( :query )
|
|
35
|
+
@constraints[:query] = Matchers::Query.new( options[:query] )
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if options[ :traits ]
|
|
39
|
+
@constraints[ :traits ] = Matchers::Traits.new( options[ :traits ] )
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if options[ :when ]
|
|
43
|
+
@constraints[ :when ] = options[ :when ]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Process all matchers for request.
|
|
49
|
+
#
|
|
50
|
+
def call(request)
|
|
51
|
+
if captured = @uri.call(request) and test(request)
|
|
52
|
+
request.traits.waves.captured = captured
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
#
|
|
57
|
+
# @todo This could maybe be optimised by detecting
|
|
58
|
+
# empty constraints before calling. Not high
|
|
59
|
+
# importance. --rue
|
|
60
|
+
#
|
|
61
|
+
def test(request)
|
|
62
|
+
constraints.all? {|key, val|
|
|
63
|
+
if val.nil? or val == true
|
|
64
|
+
true
|
|
65
|
+
else
|
|
66
|
+
if val.respond_to? :call
|
|
67
|
+
val.call( request )
|
|
68
|
+
else
|
|
69
|
+
val == request.send( key ) or val === request.send( key ) or request.send( key ) === val
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# Proc-like interface
|
|
77
|
+
#
|
|
78
|
+
def [](request)
|
|
79
|
+
call request
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|