strelka 0.0.1pre4 → 0.0.1.pre129

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/History.rdoc +1 -1
  2. data/IDEAS.rdoc +62 -0
  3. data/Manifest.txt +38 -7
  4. data/README.rdoc +124 -5
  5. data/Rakefile +22 -6
  6. data/bin/leash +102 -157
  7. data/contrib/hoetemplate/.autotest.erb +23 -0
  8. data/contrib/hoetemplate/History.rdoc.erb +4 -0
  9. data/contrib/hoetemplate/Manifest.txt.erb +8 -0
  10. data/contrib/hoetemplate/README.rdoc.erb +17 -0
  11. data/contrib/hoetemplate/Rakefile.erb +24 -0
  12. data/contrib/hoetemplate/data/file_name/apps/file_name_app +36 -0
  13. data/contrib/hoetemplate/data/file_name/templates/layout.tmpl.erb +13 -0
  14. data/contrib/hoetemplate/data/file_name/templates/top.tmpl.erb +8 -0
  15. data/contrib/hoetemplate/lib/file_name.rb.erb +18 -0
  16. data/contrib/hoetemplate/spec/file_name_spec.rb.erb +21 -0
  17. data/data/strelka/apps/hello-world +30 -0
  18. data/lib/strelka/app/defaultrouter.rb +49 -30
  19. data/lib/strelka/app/errors.rb +121 -0
  20. data/lib/strelka/app/exclusiverouter.rb +40 -0
  21. data/lib/strelka/app/filters.rb +18 -7
  22. data/lib/strelka/app/negotiation.rb +122 -0
  23. data/lib/strelka/app/parameters.rb +171 -14
  24. data/lib/strelka/app/paramvalidator.rb +751 -0
  25. data/lib/strelka/app/plugins.rb +66 -46
  26. data/lib/strelka/app/restresources.rb +499 -0
  27. data/lib/strelka/app/router.rb +73 -0
  28. data/lib/strelka/app/routing.rb +140 -18
  29. data/lib/strelka/app/templating.rb +12 -3
  30. data/lib/strelka/app.rb +174 -24
  31. data/lib/strelka/constants.rb +0 -20
  32. data/lib/strelka/exceptions.rb +29 -0
  33. data/lib/strelka/httprequest/acceptparams.rb +377 -0
  34. data/lib/strelka/httprequest/negotiation.rb +257 -0
  35. data/lib/strelka/httprequest.rb +155 -7
  36. data/lib/strelka/httpresponse/negotiation.rb +579 -0
  37. data/lib/strelka/httpresponse.rb +140 -0
  38. data/lib/strelka/logging.rb +4 -1
  39. data/lib/strelka/mixins.rb +53 -0
  40. data/lib/strelka.rb +22 -1
  41. data/spec/data/error.tmpl +1 -0
  42. data/spec/lib/constants.rb +0 -1
  43. data/spec/lib/helpers.rb +21 -0
  44. data/spec/strelka/app/defaultrouter_spec.rb +41 -35
  45. data/spec/strelka/app/errors_spec.rb +212 -0
  46. data/spec/strelka/app/exclusiverouter_spec.rb +220 -0
  47. data/spec/strelka/app/filters_spec.rb +196 -0
  48. data/spec/strelka/app/negotiation_spec.rb +73 -0
  49. data/spec/strelka/app/parameters_spec.rb +149 -0
  50. data/spec/strelka/app/paramvalidator_spec.rb +1059 -0
  51. data/spec/strelka/app/plugins_spec.rb +26 -19
  52. data/spec/strelka/app/restresources_spec.rb +393 -0
  53. data/spec/strelka/app/router_spec.rb +63 -0
  54. data/spec/strelka/app/routing_spec.rb +183 -9
  55. data/spec/strelka/app/templating_spec.rb +1 -2
  56. data/spec/strelka/app_spec.rb +265 -32
  57. data/spec/strelka/exceptions_spec.rb +53 -0
  58. data/spec/strelka/httprequest/acceptparams_spec.rb +282 -0
  59. data/spec/strelka/httprequest/negotiation_spec.rb +246 -0
  60. data/spec/strelka/httprequest_spec.rb +204 -14
  61. data/spec/strelka/httpresponse/negotiation_spec.rb +464 -0
  62. data/spec/strelka/httpresponse_spec.rb +114 -0
  63. data/spec/strelka/mixins_spec.rb +99 -0
  64. data.tar.gz.sig +1 -0
  65. metadata +175 -79
  66. metadata.gz.sig +2 -0
  67. data/IDEAS.textile +0 -174
  68. data/data/strelka/apps/strelka-admin +0 -65
  69. data/data/strelka/apps/strelka-setup +0 -26
  70. data/data/strelka/bootstrap-config.rb +0 -34
  71. data/data/strelka/templates/admin/console.tmpl +0 -21
  72. data/data/strelka/templates/layout.tmpl +0 -30
  73. data/lib/strelka/process.rb +0 -19
@@ -1,9 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'yajl'
4
+ require 'yaml'
3
5
  require 'uri'
4
6
 
5
7
  require 'mongrel2/httprequest'
6
8
  require 'strelka' unless defined?( Strelka )
9
+ require 'strelka/httpresponse'
7
10
 
8
11
  # An HTTP request class.
9
12
  class Strelka::HTTPRequest < Mongrel2::HTTPRequest
@@ -14,11 +17,23 @@ class Strelka::HTTPRequest < Mongrel2::HTTPRequest
14
17
  register_request_type( self, *HTTP::RFC2616_VERBS )
15
18
 
16
19
 
20
+ ### Override the type of response returned by this request type.
21
+ def self::response_class
22
+ return Strelka::HTTPResponse
23
+ end
24
+
25
+
26
+ #################################################################
27
+ ### I N S T A N C E M E T H O D S
28
+ #################################################################
29
+
17
30
  ### Initialize some additional stuff for Strelka requests.
18
31
  def initialize( * ) # :notnew:
19
32
  super
20
- @uri = nil
21
- @verb = self.headers[:method].to_sym
33
+ @uri = nil
34
+ @verb = self.headers[:method].to_sym
35
+ @params = nil
36
+ @notes = Hash.new( &method(:autovivify) )
22
37
  end
23
38
 
24
39
 
@@ -29,24 +44,157 @@ class Strelka::HTTPRequest < Mongrel2::HTTPRequest
29
44
  # The HTTP verb of the request (as a Symbol)
30
45
  attr_accessor :verb
31
46
 
47
+ # The parameters hash parsed from the request
48
+ attr_writer :params
49
+
50
+ # A Hash that plugins can use to pass data amongst themselves. The missing-key
51
+ # callback is set to auto-create nested sub-hashes.
52
+ attr_reader :notes
53
+
32
54
 
33
55
  ### Return a URI object parsed from the URI of the request.
56
+ ###
57
+ ### # "GET /user/1/profile HTTP/1.1"
58
+ ### request.uri
59
+ ### # => #<URI::HTTP:0x007fe34d16b2e0 URL:http://localhost:8080/user/1/profile>
34
60
  def uri
35
- return @uri ||= URI( self.headers.uri )
61
+ unless @uri
62
+ # :TODO: Make this detect https scheme once I figure out how to
63
+ # detect it.
64
+ uri = "http://%s%s" % [
65
+ self.headers.host,
66
+ self.headers.uri
67
+ ]
68
+ @uri = URI( uri )
69
+ end
70
+
71
+ return @uri
72
+ end
73
+
74
+
75
+ ### Return a URI object for the base of the app being run. This is the #uri with the
76
+ ### #app_path and any query string removed.
77
+ ###
78
+ ### # For a handler with a route of '/user', for the request:
79
+ ### # "GET /user/1/profile HTTP/1.1"
80
+ ### request.base_uri
81
+ ### # => #<URI::HTTP:0x007fe34d16b2e0 URL:http://localhost:8080/user>
82
+ def base_uri
83
+ rval = self.uri
84
+ rval.path = self.route
85
+ rval.query = nil
86
+ return rval
36
87
  end
37
88
 
38
89
 
39
90
  ### Return the portion of the Request's path that was routed by Mongrel2. This and the
40
91
  ### #app_path make up the #path.
41
- def pattern
92
+ ###
93
+ ### # For a handler with a route of '/user', for the request:
94
+ ### # "GET /user/1/profile HTTP/1.1"
95
+ ### request.route
96
+ ### # => "/user"
97
+ def route
42
98
  return self.headers.pattern
43
99
  end
100
+ alias_method :pattern, :route
44
101
 
45
102
 
46
- ### Return the portion of the Request's path relative to the application's
47
- ### Mongrel2 route.
103
+ ### Return the portion of the Request's path relative to the request's #route.
104
+ ###
105
+ ### # For a handler with a route of '/user', for the request:
106
+ ### # "GET /user/1/profile HTTP/1.1"
107
+ ### request.app_path
108
+ ### # => "/1/profile"
48
109
  def app_path
49
- return self.path[ self.pattern.length .. -1 ]
110
+ rval = self.uri.path.dup
111
+ rval.slice!( 0, self.route.length )
112
+ return rval
113
+ end
114
+
115
+
116
+ ### Parse the request parameters and return them as a Hash. For GET requests, these are
117
+ ### take from the query arguments, and for POST requests, from the
118
+ ###
119
+ ### # For a handler with a route of '/user', for the request:
120
+ ### # "GET /user/1/profile?checkbox=1&checkbox=2&text=foo HTTP/1.1"
121
+ ### # r.params
122
+ ### # => {"checkbox"=>["1", "2"], "text"=>"foo"}
123
+ def params
124
+ unless @params
125
+ case self.verb
126
+ when :GET, :HEAD
127
+ @params = self.parse_query_args
128
+ when :POST, :PUT
129
+ @params = self.parse_form_data
130
+ else
131
+ self.log.debug "No parameters for a %s request." % [ self.verb ]
132
+ end
133
+ end
134
+
135
+ return @params
136
+ end
137
+
138
+
139
+ #########
140
+ protected
141
+ #########
142
+
143
+ ### Return a Hash of request query arguments.
144
+ ### ?arg1=yes&arg2=no&arg3 #=> {'arg1' => 'yes', 'arg2' => 'no', 'arg3' => nil}
145
+ def parse_query_args
146
+ return {} if self.uri.query.nil?
147
+ return merge_query_args( URI.decode_www_form(self.uri.query) )
148
+ end
149
+
150
+
151
+ ### Return a Hash of request form data.
152
+ def parse_form_data
153
+ case self.headers.content_type
154
+ when 'application/x-www-form-urlencoded'
155
+ return merge_query_args( URI.decode_www_form(self.body) )
156
+ when 'application/json', 'text/javascript'
157
+ return Yajl.load( self.body )
158
+ when 'text/x-yaml', 'application/x-yaml'
159
+ return YAML.load( self.body )
160
+ when 'multipart/form-data'
161
+ raise NotImplementedError, "%p doesn't handle multipart form data yet" %
162
+ [ self.class ]
163
+ else
164
+ raise Strelka::Error, "don't know how to handle %p form data" %
165
+ [ self.headers.content_type ]
166
+ end
167
+ end
168
+
169
+
170
+ #######
171
+ private
172
+ #######
173
+
174
+ ### Return the given +enum+ containing query arguments (such as those returned from
175
+ ### URI.decode_www_form) as a Hash, combining multiple values for the same key
176
+ ### into an Array.
177
+ def merge_query_args( enum )
178
+ return enum.inject({}) do |hash,(key,val)|
179
+
180
+ # If there's already a value in the Hash, turn it into an array if
181
+ # it's not already, and append the new value
182
+ if hash.key?( key )
183
+ hash[ key ] = [ hash[key] ] unless hash[ key ].is_a?( Array )
184
+ hash[ key ] << val
185
+ else
186
+ hash[ key ] = val
187
+ end
188
+
189
+ hash
190
+ end
191
+ end
192
+
193
+
194
+ ### Create and return a Hash that will auto-vivify any values it is missing with
195
+ ### another auto-vivifying Hash.
196
+ def autovivify( hash, key )
197
+ hash[ key ] = Hash.new( &method(:autovivify) )
50
198
  end
51
199
 
52
200
  end # class Strelka::HTTPRequest