strelka 0.0.1pre4 → 0.0.1.pre129

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.
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