strelka 0.0.1.pre129 → 0.0.1.pre148
Sign up to get free protection for your applications and to get access to all the features.
- data/IDEAS.rdoc +26 -32
- data/Manifest.txt +27 -12
- data/README.rdoc +29 -33
- data/Rakefile +2 -1
- data/bin/leash +2 -1
- data/contrib/hoetemplate/README.rdoc.erb +18 -0
- data/contrib/hoetemplate/data/{file_name → project}/apps/file_name_app +0 -0
- data/contrib/hoetemplate/data/{file_name → project}/templates/layout.tmpl.erb +0 -0
- data/contrib/hoetemplate/data/{file_name → project}/templates/top.tmpl.erb +0 -0
- data/examples/config.yml +3 -0
- data/examples/gen-config.rb +48 -0
- data/examples/sessions-demo.rb +43 -0
- data/lib/strelka/app/errors.rb +59 -17
- data/lib/strelka/app/filters.rb +3 -1
- data/lib/strelka/app/negotiation.rb +5 -3
- data/lib/strelka/app/parameters.rb +33 -31
- data/lib/strelka/app/plugins.rb +14 -8
- data/lib/strelka/app/restresources.rb +3 -1
- data/lib/strelka/app/routing.rb +9 -7
- data/lib/strelka/app/sessions.rb +175 -0
- data/lib/strelka/app/templating.rb +6 -3
- data/lib/strelka/app.rb +19 -11
- data/lib/strelka/behavior/plugin.rb +4 -2
- data/lib/strelka/constants.rb +9 -0
- data/lib/strelka/cookie.rb +357 -0
- data/lib/strelka/cookieset.rb +117 -0
- data/lib/strelka/httprequest/acceptparams.rb +12 -10
- data/lib/strelka/httprequest/negotiation.rb +4 -2
- data/lib/strelka/httprequest/session.rb +71 -0
- data/lib/strelka/httprequest.rb +19 -7
- data/lib/strelka/httpresponse/negotiation.rb +17 -15
- data/lib/strelka/httpresponse/session.rb +101 -0
- data/lib/strelka/httpresponse.rb +26 -4
- data/lib/strelka/logging.rb +3 -1
- data/lib/strelka/mixins.rb +174 -2
- data/lib/strelka/{app/paramvalidator.rb → paramvalidator.rb} +25 -22
- data/lib/strelka/{app/defaultrouter.rb → router/default.rb} +6 -4
- data/lib/strelka/{app/exclusiverouter.rb → router/exclusive.rb} +6 -4
- data/lib/strelka/{app/router.rb → router.rb} +9 -7
- data/lib/strelka/session/default.rb +209 -0
- data/lib/strelka/session.rb +178 -0
- data/lib/strelka.rb +6 -4
- data/spec/lib/constants.rb +3 -1
- data/spec/lib/helpers.rb +7 -0
- data/spec/strelka/app/errors_spec.rb +32 -52
- data/spec/strelka/app/filters_spec.rb +3 -1
- data/spec/strelka/app/negotiation_spec.rb +3 -1
- data/spec/strelka/app/parameters_spec.rb +5 -3
- data/spec/strelka/app/plugins_spec.rb +5 -3
- data/spec/strelka/app/restresources_spec.rb +3 -1
- data/spec/strelka/app/routing_spec.rb +6 -4
- data/spec/strelka/app/sessions_spec.rb +109 -0
- data/spec/strelka/app/templating_spec.rb +3 -1
- data/spec/strelka/app_spec.rb +11 -2
- data/spec/strelka/cookie_spec.rb +194 -0
- data/spec/strelka/cookieset_spec.rb +159 -0
- data/spec/strelka/exceptions_spec.rb +3 -1
- data/spec/strelka/httprequest/acceptparams_spec.rb +3 -1
- data/spec/strelka/httprequest/negotiation_spec.rb +3 -1
- data/spec/strelka/httprequest/session_spec.rb +43 -0
- data/spec/strelka/httprequest_spec.rb +28 -1
- data/spec/strelka/httpresponse/negotiation_spec.rb +3 -3
- data/spec/strelka/httpresponse_spec.rb +13 -0
- data/spec/strelka/logging_spec.rb +3 -1
- data/spec/strelka/mixins_spec.rb +125 -1
- data/spec/strelka/{app/paramvalidator_spec.rb → paramvalidator_spec.rb} +4 -4
- data/spec/strelka/{app/defaultrouter_spec.rb → router/default_spec.rb} +6 -4
- data/spec/strelka/{app/exclusiverouter_spec.rb → router/exclusive_spec.rb} +6 -4
- data/spec/strelka/{app/router_spec.rb → router_spec.rb} +9 -7
- data/spec/strelka/session/default_spec.rb +210 -0
- data/spec/strelka/session_spec.rb +101 -0
- data.tar.gz.sig +1 -1
- metadata +64 -47
- metadata.gz.sig +0 -0
- data/contrib/hoetemplate/.autotest.erb +0 -23
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
require 'pluginfactory'
|
4
6
|
|
@@ -14,20 +16,20 @@ require 'strelka/mixins'
|
|
14
16
|
#
|
15
17
|
# # Create an instance of the default router strategy with the given
|
16
18
|
# # routes and options.
|
17
|
-
# Strelka::
|
19
|
+
# Strelka::Router.create( 'default', routes, options )
|
18
20
|
#
|
19
21
|
# To define your own strategy, you'll need to inherit this class, name it
|
20
|
-
# <tt>Strelka::
|
21
|
-
# <tt>strelka/
|
22
|
+
# <tt>Strelka::Router::{Something}</tt>, save it in a file named
|
23
|
+
# <tt>strelka/router/{something}.rb</tt>, and be sure to override the
|
22
24
|
# #add_route and #route_request methods.
|
23
|
-
class Strelka::
|
25
|
+
class Strelka::Router
|
24
26
|
include PluginFactory,
|
25
27
|
Strelka::Loggable,
|
26
28
|
Strelka::AbstractClass
|
27
29
|
|
28
30
|
### PluginFactory API -- return the Array of directories to search for plugins.
|
29
31
|
def self::derivative_dirs
|
30
|
-
return ['strelka/
|
32
|
+
return ['strelka/router']
|
31
33
|
end
|
32
34
|
|
33
35
|
|
@@ -70,4 +72,4 @@ class Strelka::App::Router
|
|
70
72
|
# the routing info Hash.
|
71
73
|
pure_virtual :route_request
|
72
74
|
|
73
|
-
end # class Strelka::
|
75
|
+
end # class Strelka::Router
|
@@ -0,0 +1,209 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
require 'securerandom'
|
5
|
+
require 'forwardable'
|
6
|
+
|
7
|
+
require 'strelka' unless defined?( Strelka )
|
8
|
+
require 'strelka/app' unless defined?( Strelka::App )
|
9
|
+
require 'strelka/session'
|
10
|
+
require 'strelka/mixins'
|
11
|
+
|
12
|
+
# Default session class -- simple in-memory, cookie-based base-bones session.
|
13
|
+
#
|
14
|
+
# == Hash Interface
|
15
|
+
#
|
16
|
+
# The following methods are delegated to the inner Hash via the #namespaced_hash method:
|
17
|
+
# #&, #==, #[], #[]=, #assoc, #case, #clear, #compare_by_identity,
|
18
|
+
# #compare_by_identity?, #default, # #default=, #default_proc, #default_proc=,
|
19
|
+
# #delete, #delete_if, #each, #each_key, #each_pair, #each_value,
|
20
|
+
# #empty?, #eql?, #fetch, #flatten, #has_key?, #has_value?, #hash, #include?,
|
21
|
+
# #index, #inspect, #invert, #keep_if, #key, #key?, #keys, #length, #member?,
|
22
|
+
# #merge, #merge!, #pretty_print, #pretty_print_cycle, #rassoc, #rehash, #reject,
|
23
|
+
# #reject!, #replace, #select, #select!, #shift, #size, #sql_expr, #sql_negate,
|
24
|
+
# #sql_or, #store, #to_a, #to_hash, #to_s, #update, #value?, #values, #values_at,
|
25
|
+
# #|, #~
|
26
|
+
class Strelka::Session::Default < Strelka::Session
|
27
|
+
extend Forwardable,
|
28
|
+
Strelka::Delegation
|
29
|
+
include Enumerable,
|
30
|
+
Strelka::Loggable,
|
31
|
+
Strelka::DataUtilities
|
32
|
+
|
33
|
+
|
34
|
+
# The default name of the cookie that stores the session ID
|
35
|
+
DEFAULT_COOKIE_NAME = 'strelka-sessionid'
|
36
|
+
|
37
|
+
# Class-instance variables
|
38
|
+
@sessions = {}
|
39
|
+
@cookie_name = DEFAULT_COOKIE_NAME
|
40
|
+
|
41
|
+
class << self
|
42
|
+
# Persist sessions in memory
|
43
|
+
attr_reader :sessions
|
44
|
+
|
45
|
+
# The name of the cookie that stores the session ID
|
46
|
+
attr_accessor :cookie_name
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
### Configure the session class with the given +options+, which should be a
|
51
|
+
### Hash or an object that has a Hash-like interface. Sets the cookie name
|
52
|
+
### the session ID is stored in in responses if the +:cookie_name+ key
|
53
|
+
### is set.
|
54
|
+
def self::configure( options )
|
55
|
+
if options
|
56
|
+
self.cookie_name = options[:cookie_name] if options[:cookie_name]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
### Load a session instance from storage using the given +session_id+ and return
|
62
|
+
### it. Returns +nil+ if no session could be loaded. You should probably override
|
63
|
+
### this, as the default just returns +nil+.
|
64
|
+
def self::load_session_data( session_id )
|
65
|
+
return Strelka::DataUtilities.deep_copy( self.sessions[session_id] )
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
### Save the given +data+ to memory associated with the given +session_id+.
|
70
|
+
def self::save_session_data( session_id, data )
|
71
|
+
self.sessions[ session_id ] = Strelka::DataUtilities.deep_copy( data )
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
### Delete the data associated with the given +session_id+ from memory.
|
76
|
+
def self::delete_session_data( session_id )
|
77
|
+
self.sessions.delete( session_id )
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
### Fetch the session ID from the given +request+, or create a new one if the
|
82
|
+
### request doesn't have the necessary attributes. You should override this,
|
83
|
+
### as the default implementation just returns +nil+.
|
84
|
+
def self::get_session_id( request=nil )
|
85
|
+
id = nil
|
86
|
+
|
87
|
+
# Fetch and untaint the existing ID if it exists and looks valid
|
88
|
+
if request && (cookie = request.cookies[ self.cookie_name ])
|
89
|
+
Strelka.log.debug "Cookie value: %p" % [ cookie.value ]
|
90
|
+
id = $1.untaint if cookie.value =~ /^([[:xdigit:]]+)$/i
|
91
|
+
Strelka.log.debug "Hmm? %p" % [ $1 ]
|
92
|
+
end
|
93
|
+
|
94
|
+
return id || SecureRandom.random_bytes.unpack( 'H*' ).join
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
#################################################################
|
99
|
+
### I N S T A N C E M E T H O D S
|
100
|
+
#################################################################
|
101
|
+
|
102
|
+
### Create a new Mongrel2::Table using the given +hash+ for initial
|
103
|
+
### values.
|
104
|
+
def initialize( session_id=nil, initial_values={} )
|
105
|
+
session_id ||= self.class.get_session_id
|
106
|
+
|
107
|
+
@hash = Hash.new {|h,k| h[k] = {} }
|
108
|
+
@hash.merge!( initial_values )
|
109
|
+
|
110
|
+
@namespace = nil
|
111
|
+
|
112
|
+
super
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
### Make sure the inner Hash is unique on duplications.
|
117
|
+
def initialize_dup( * ) # :nodoc:
|
118
|
+
@hash = deep_copy( @hash )
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
### Make sure the inner Hash is unique on clones.
|
123
|
+
def initialize_clone( * ) # :nodoc:
|
124
|
+
@hash = deep_copy( @hash )
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
######
|
129
|
+
public
|
130
|
+
######
|
131
|
+
|
132
|
+
# The namespace that determines which subhash of the session is exposed
|
133
|
+
# to the application.
|
134
|
+
attr_reader :namespace
|
135
|
+
|
136
|
+
# Delegate Hash methods to whichever Hash is the current namespace
|
137
|
+
def_method_delegators :namespaced_hash, *Hash.instance_methods( false )
|
138
|
+
|
139
|
+
|
140
|
+
### Set the current namespace for session values to +namespace+. Setting
|
141
|
+
### +namespace+ to +nil+ exposes the toplevel namespace (keys are named
|
142
|
+
### namespaces)
|
143
|
+
def namespace=( namespace )
|
144
|
+
@namespace = namespace.nil? ? nil : namespace.to_sym
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
### Save the session to storage and add the session cookie to the given +response+.
|
149
|
+
def save( response )
|
150
|
+
self.log.debug "Saving session %s" % [ self.session_id ]
|
151
|
+
self.class.save_session_data( self.session_id, @hash )
|
152
|
+
self.log.debug "Adding session cookie to the request."
|
153
|
+
response.cookies[ self.class.cookie_name ] = self.session_id
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
#########
|
158
|
+
protected
|
159
|
+
#########
|
160
|
+
|
161
|
+
### Proxy method: handle getting/setting headers via methods instead of the
|
162
|
+
### index operator.
|
163
|
+
def method_missing( sym, *args )
|
164
|
+
# work magic
|
165
|
+
return super unless sym.to_s =~ /^([a-z]\w+)(=)?$/
|
166
|
+
|
167
|
+
# If it's an assignment, the (=)? will have matched
|
168
|
+
key, assignment = $1, $2
|
169
|
+
|
170
|
+
method_body = nil
|
171
|
+
if assignment
|
172
|
+
self.log.debug "Makin' a setter for %p" % [ key ]
|
173
|
+
method_body = self.make_setter( key )
|
174
|
+
else
|
175
|
+
self.log.debug "Makin' a getter for %p" % [ key ]
|
176
|
+
method_body = self.make_getter( key )
|
177
|
+
end
|
178
|
+
|
179
|
+
self.class.send( :define_method, sym, &method_body )
|
180
|
+
return self.method( sym ).call( *args )
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
### Create a Proc that will act as a setter for the given key
|
185
|
+
def make_setter( key )
|
186
|
+
return Proc.new {|new_value| self.namespaced_hash[ key.to_sym ] = new_value }
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
### Create a Proc that will act as a getter for the given key
|
191
|
+
def make_getter( key )
|
192
|
+
return Proc.new { self.namespaced_hash[key.to_sym] }
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
### Return the Hash that corresponds with the current namespace's storage. If no
|
197
|
+
### namespace is currently set, returns the entire session store as a Hash of Hashes
|
198
|
+
### keyed by namespaces as Symbols.
|
199
|
+
def namespaced_hash
|
200
|
+
if @namespace
|
201
|
+
self.log.debug "Returning namespaced hash: %p" % [ @namespace ]
|
202
|
+
return @hash[ @namespace ]
|
203
|
+
else
|
204
|
+
self.log.debug "Returning toplevel namespace"
|
205
|
+
return @hash
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
end # class Strelka::Session::Default
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#! -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
require 'digest/sha1'
|
5
|
+
require 'pluginfactory'
|
6
|
+
|
7
|
+
require 'strelka' unless defined?( Strelka )
|
8
|
+
require 'strelka/mixins'
|
9
|
+
|
10
|
+
# Abstract base class for pluggable session strategies for the Sessions
|
11
|
+
# plugin.
|
12
|
+
#
|
13
|
+
# To define your own session type, you'll need to inherit this class (either
|
14
|
+
# directly or via a subclass), name it <tt>Strelka::Session::{Something}</tt>,
|
15
|
+
# save it in a file named <tt>strelka/session/{something}.rb</tt>, and
|
16
|
+
# override the required methods.
|
17
|
+
#
|
18
|
+
# The class methods you'll need to provide implementations for are:
|
19
|
+
#
|
20
|
+
# * self.configure
|
21
|
+
# * self.get_session_id
|
22
|
+
# * self.load_session_data
|
23
|
+
# * self.save_session_data
|
24
|
+
# * self.delete_session_data
|
25
|
+
#
|
26
|
+
# The instance methods fetch and set values in the session itself, and manipulate
|
27
|
+
# the namespace that's used to partition session data between applications:
|
28
|
+
#
|
29
|
+
# * #[]
|
30
|
+
# * #[]=
|
31
|
+
# * #save
|
32
|
+
# * #delete
|
33
|
+
# * #key?
|
34
|
+
# * #namespace=
|
35
|
+
# * #namespace
|
36
|
+
#
|
37
|
+
# These methods provide basic functionality, but you might find it more efficient
|
38
|
+
# to override them:
|
39
|
+
#
|
40
|
+
# * self.load_or_create
|
41
|
+
# * self.load
|
42
|
+
#
|
43
|
+
#
|
44
|
+
class Strelka::Session
|
45
|
+
include PluginFactory,
|
46
|
+
Strelka::Loggable,
|
47
|
+
Strelka::AbstractClass
|
48
|
+
|
49
|
+
|
50
|
+
### PluginFactory API -- return the Array of directories to search for concrete
|
51
|
+
### Session classes.
|
52
|
+
def self::derivative_dirs
|
53
|
+
return ['strelka/session']
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
### Configure the session class with the given +options+, which should be a
|
58
|
+
### Hash or an object that has a Hash-like interface. This is a no-op by
|
59
|
+
### default.
|
60
|
+
def self::configure( options )
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
### Fetch the session ID from the given +request+, or create a new one if the
|
65
|
+
### request is +nil+ or doesn't have the necessary attributes. You should
|
66
|
+
### override this, as the default implementation just returns +nil+.
|
67
|
+
def self::get_session_id( request=nil )
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
### Load session data for the specified +session_id+. This should return a data
|
73
|
+
### structure that can #merge!, or +nil+ if there was no existing session data
|
74
|
+
### associated with +session_id+.
|
75
|
+
def self::load_session_data( session_id )
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
### Save the session data for the specified +session_id+.
|
81
|
+
def self::save_session_data( session_id, data )
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
### Delete the session data for the specified +session_id+.
|
86
|
+
def self::delete_session_data( session_id )
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
### Load a session instance from storage using the given +session_id+ and return
|
91
|
+
### it. Returns +nil+ if no session could be loaded. You can either overload
|
92
|
+
### ::load_session_data if you are loading a data structure, or override ::load
|
93
|
+
### if you're serializing the session object directly.
|
94
|
+
def self::load( session_id )
|
95
|
+
values = self.load_session_data( session_id ) or return nil
|
96
|
+
return new( session_id, values )
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
### Return an instance of the session class that's associated with the specified
|
101
|
+
### request, either loading one from the persistant store, or creating a new one
|
102
|
+
### if it can't be loaded or +request+ is nil.
|
103
|
+
def self::load_or_create( request=nil )
|
104
|
+
session_id = self.get_session_id( request )
|
105
|
+
return self.load( session_id ) || new( session_id )
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
#################################################################
|
110
|
+
### I N S T A N C E M E T H O D S
|
111
|
+
#################################################################
|
112
|
+
|
113
|
+
### Set up a new instance with the given +session_id+ and +initial_values+.
|
114
|
+
def initialize( session_id, initial_values={} ) # :notnew:
|
115
|
+
@session_id = session_id
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
######
|
120
|
+
public
|
121
|
+
######
|
122
|
+
|
123
|
+
# The key of the session in the session store
|
124
|
+
attr_reader :session_id
|
125
|
+
|
126
|
+
|
127
|
+
# :call-seq:
|
128
|
+
# session[ key ] -> object
|
129
|
+
#
|
130
|
+
# Index operator -- fetch the value associated with +key+ in the current namespace
|
131
|
+
pure_virtual :[]
|
132
|
+
|
133
|
+
|
134
|
+
# :call-seq:
|
135
|
+
# session[ key ] = object
|
136
|
+
#
|
137
|
+
# Index set operator -- set the value associated with +key+ in the current
|
138
|
+
# namespace to +object+.
|
139
|
+
pure_virtual :[]=
|
140
|
+
|
141
|
+
|
142
|
+
# :call-seq:
|
143
|
+
# save( response )
|
144
|
+
#
|
145
|
+
# Save the session and set up the specified +response+ to persist the
|
146
|
+
# session ID.
|
147
|
+
pure_virtual :save
|
148
|
+
|
149
|
+
|
150
|
+
# :call-seq:
|
151
|
+
# key?( key ) -> boolean
|
152
|
+
#
|
153
|
+
# Returns +true+ if the specified +key+ exists in the current namespace.
|
154
|
+
pure_virtual :key?
|
155
|
+
|
156
|
+
|
157
|
+
# :call-seq:
|
158
|
+
# namespace = new_namespace
|
159
|
+
#
|
160
|
+
# Set the namespace of the session that will be used for future access.
|
161
|
+
pure_virtual :namespace=
|
162
|
+
|
163
|
+
|
164
|
+
# :call-seq:
|
165
|
+
# namespace -> symbol
|
166
|
+
#
|
167
|
+
# Return the current namespace of the session.
|
168
|
+
pure_virtual :namespace
|
169
|
+
|
170
|
+
|
171
|
+
# :call-seq:
|
172
|
+
# delete( key ) -> object
|
173
|
+
#
|
174
|
+
# Remove the value associated with the specified +key+ from the current namespace
|
175
|
+
# and return it, if it exists.
|
176
|
+
pure_virtual :delete
|
177
|
+
|
178
|
+
end # class Strelka::Session
|
data/lib/strelka.rb
CHANGED
@@ -1,22 +1,24 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
require 'mongrel2'
|
4
6
|
require 'configurability'
|
5
7
|
require 'configurability/config'
|
6
8
|
|
7
9
|
# An application framework for Ruby-mongrel2
|
8
|
-
#
|
10
|
+
#
|
9
11
|
# == Author/s
|
10
12
|
#
|
11
13
|
# * Michael Granger <ged@FaerieMUD.org>
|
12
|
-
#
|
14
|
+
#
|
13
15
|
module Strelka
|
14
16
|
|
15
17
|
# Library version constant
|
16
18
|
VERSION = '0.0.1'
|
17
19
|
|
18
20
|
# Version-control revision constant
|
19
|
-
REVISION = %q$Revision:
|
21
|
+
REVISION = %q$Revision: fa6133ac407d $
|
20
22
|
|
21
23
|
|
22
24
|
require 'strelka/logging'
|
data/spec/lib/constants.rb
CHANGED
data/spec/lib/helpers.rb
CHANGED
@@ -133,6 +133,13 @@ module Strelka::SpecHelpers
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
+
# Collection .all? matcher
|
137
|
+
RSpec::Matchers.define( :all_be_a ) do |expected|
|
138
|
+
match do |collection|
|
139
|
+
collection.all? {|obj| obj.is_a?(expected) }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
136
143
|
end
|
137
144
|
|
138
145
|
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
BEGIN {
|
4
6
|
require 'pathname'
|
@@ -99,79 +101,57 @@ describe Strelka::App::Errors do
|
|
99
101
|
res.body.should =~ /internal server error/i
|
100
102
|
end
|
101
103
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
return res
|
109
|
-
end
|
104
|
+
it "calls a callback-style handler for any status when finished with BAD_REQUEST" do
|
105
|
+
@app.class_eval do
|
106
|
+
on_status do |res, info|
|
107
|
+
res.body = '(%d) Filthy banana' % [ info[:status] ]
|
108
|
+
return res
|
109
|
+
end
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
end
|
111
|
+
get do |req|
|
112
|
+
finish_with HTTP::BAD_REQUEST, "Your sandwich is missing something."
|
114
113
|
end
|
115
114
|
end
|
116
115
|
|
116
|
+
req = @request_factory.get( '/foom' )
|
117
|
+
res = @app.new.handle( req )
|
117
118
|
|
118
|
-
|
119
|
-
|
120
|
-
res = @app.new.handle( req )
|
121
|
-
|
122
|
-
res.status.should == HTTP::BAD_REQUEST
|
123
|
-
res.body.should == 'Filthy banana'
|
124
|
-
end
|
125
|
-
|
119
|
+
res.status.should == HTTP::BAD_REQUEST
|
120
|
+
res.body.should == '(400) Filthy banana'
|
126
121
|
end
|
127
122
|
|
128
123
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
res.body = 'NOPE!'
|
135
|
-
return res
|
136
|
-
end
|
124
|
+
it "calls a callback-style handler for NOT_FOUND when the response is NOT_FOUND" do
|
125
|
+
@app.class_eval do
|
126
|
+
on_status HTTP::NOT_FOUND do |res, _|
|
127
|
+
res.body = 'NOPE!'
|
128
|
+
return res
|
137
129
|
end
|
138
130
|
end
|
139
131
|
|
132
|
+
req = @request_factory.get( '/foom' )
|
133
|
+
res = @app.new.handle( req )
|
140
134
|
|
141
|
-
|
142
|
-
req = @request_factory.get( '/foom' )
|
143
|
-
res = @app.new.handle( req )
|
144
|
-
|
145
|
-
res.body.should == 'NOPE!'
|
146
|
-
end
|
147
|
-
|
135
|
+
res.body.should == 'NOPE!'
|
148
136
|
end
|
149
137
|
|
150
138
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
res.body = 'Error: JAMBA'
|
157
|
-
return res
|
158
|
-
end
|
139
|
+
it "calls a callback-style handler for all 400-level statuses when the response is NOT_FOUND" do
|
140
|
+
@app.class_eval do
|
141
|
+
on_status 400..499 do |res, _|
|
142
|
+
res.body = 'Error: JAMBA'
|
143
|
+
return res
|
159
144
|
end
|
160
145
|
end
|
161
146
|
|
147
|
+
req = @request_factory.get( '/foom' )
|
148
|
+
res = @app.new.handle( req )
|
162
149
|
|
163
|
-
|
164
|
-
req = @request_factory.get( '/foom' )
|
165
|
-
res = @app.new.handle( req )
|
166
|
-
|
167
|
-
res.body.should == 'Error: JAMBA'
|
168
|
-
end
|
169
|
-
|
150
|
+
res.body.should == 'Error: JAMBA'
|
170
151
|
end
|
171
152
|
|
172
153
|
|
173
|
-
context "
|
174
|
-
|
154
|
+
context "template-style handlers" do
|
175
155
|
|
176
156
|
before( :all ) do
|
177
157
|
basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
BEGIN {
|
4
6
|
require 'pathname'
|
@@ -173,7 +175,7 @@ describe Strelka::App::Parameters do
|
|
173
175
|
req = @request_factory.get( '/user/search' )
|
174
176
|
@app.new.handle( req )
|
175
177
|
|
176
|
-
req.params.should be_a( Strelka::
|
178
|
+
req.params.should be_a( Strelka::ParamValidator )
|
177
179
|
req.params.should have_errors()
|
178
180
|
req.params.error_messages.should == ["Missing value for 'Username'"]
|
179
181
|
end
|
@@ -182,7 +184,7 @@ describe Strelka::App::Parameters do
|
|
182
184
|
req = @request_factory.get( '/user/search?username=anheptoh'.taint )
|
183
185
|
@app.new.handle( req )
|
184
186
|
|
185
|
-
req.params.should be_a( Strelka::
|
187
|
+
req.params.should be_a( Strelka::ParamValidator )
|
186
188
|
req.params.should be_okay()
|
187
189
|
req.params.should_not have_errors()
|
188
190
|
req.params[:username].should == 'anheptoh'
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
BEGIN {
|
4
6
|
require 'pathname'
|
@@ -34,9 +36,9 @@ describe Strelka::App::Plugins do
|
|
34
36
|
RSpec::Matchers.define( :order ) do |item|
|
35
37
|
match do |enumerable|
|
36
38
|
if defined?( @before )
|
37
|
-
enumerable.index( @before ) < enumerable.index( item )
|
39
|
+
enumerable.index( @before ) < enumerable.index( item )
|
38
40
|
elsif defined?( @after )
|
39
|
-
enumerable.index( @after ) > enumerable.index( item )
|
41
|
+
enumerable.index( @after ) > enumerable.index( item )
|
40
42
|
else
|
41
43
|
raise "No .before or .after to compare against!"
|
42
44
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
2
4
|
|
3
5
|
BEGIN {
|
4
6
|
require 'pathname'
|
@@ -184,13 +186,13 @@ describe Strelka::App::Routing do
|
|
184
186
|
end
|
185
187
|
|
186
188
|
|
187
|
-
it "uses the Strelka::
|
189
|
+
it "uses the Strelka::Router::Default as it's router by default" do
|
188
190
|
@app.routerclass.should == :default
|
189
|
-
@app.new.router.should be_a( Strelka::
|
191
|
+
@app.new.router.should be_a( Strelka::Router::Default )
|
190
192
|
end
|
191
193
|
|
192
194
|
it "can specify a different Router class than the default" do
|
193
|
-
class MyRouter < Strelka::
|
195
|
+
class MyRouter < Strelka::Router; end
|
194
196
|
@app.class_eval do
|
195
197
|
router MyRouter
|
196
198
|
end
|