wycats-merb-core 0.9.8

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 (98) hide show
  1. data/CHANGELOG +992 -0
  2. data/CONTRIBUTORS +94 -0
  3. data/LICENSE +20 -0
  4. data/PUBLIC_CHANGELOG +142 -0
  5. data/README +21 -0
  6. data/Rakefile +458 -0
  7. data/TODO +0 -0
  8. data/bin/merb +11 -0
  9. data/bin/merb-specs +5 -0
  10. data/lib/merb-core.rb +598 -0
  11. data/lib/merb-core/autoload.rb +31 -0
  12. data/lib/merb-core/bootloader.rb +717 -0
  13. data/lib/merb-core/config.rb +305 -0
  14. data/lib/merb-core/constants.rb +45 -0
  15. data/lib/merb-core/controller/abstract_controller.rb +568 -0
  16. data/lib/merb-core/controller/exceptions.rb +315 -0
  17. data/lib/merb-core/controller/merb_controller.rb +256 -0
  18. data/lib/merb-core/controller/mime.rb +107 -0
  19. data/lib/merb-core/controller/mixins/authentication.rb +123 -0
  20. data/lib/merb-core/controller/mixins/conditional_get.rb +83 -0
  21. data/lib/merb-core/controller/mixins/controller.rb +319 -0
  22. data/lib/merb-core/controller/mixins/render.rb +513 -0
  23. data/lib/merb-core/controller/mixins/responder.rb +469 -0
  24. data/lib/merb-core/controller/template.rb +254 -0
  25. data/lib/merb-core/core_ext.rb +9 -0
  26. data/lib/merb-core/core_ext/hash.rb +7 -0
  27. data/lib/merb-core/core_ext/kernel.rb +340 -0
  28. data/lib/merb-core/dispatch/cookies.rb +130 -0
  29. data/lib/merb-core/dispatch/default_exception/default_exception.rb +93 -0
  30. data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +198 -0
  31. data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +73 -0
  32. data/lib/merb-core/dispatch/default_exception/views/index.html.erb +94 -0
  33. data/lib/merb-core/dispatch/dispatcher.rb +176 -0
  34. data/lib/merb-core/dispatch/request.rb +729 -0
  35. data/lib/merb-core/dispatch/router.rb +151 -0
  36. data/lib/merb-core/dispatch/router/behavior.rb +566 -0
  37. data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
  38. data/lib/merb-core/dispatch/router/resources.rb +191 -0
  39. data/lib/merb-core/dispatch/router/route.rb +511 -0
  40. data/lib/merb-core/dispatch/session.rb +222 -0
  41. data/lib/merb-core/dispatch/session/container.rb +74 -0
  42. data/lib/merb-core/dispatch/session/cookie.rb +173 -0
  43. data/lib/merb-core/dispatch/session/memcached.rb +68 -0
  44. data/lib/merb-core/dispatch/session/memory.rb +99 -0
  45. data/lib/merb-core/dispatch/session/store_container.rb +150 -0
  46. data/lib/merb-core/dispatch/worker.rb +28 -0
  47. data/lib/merb-core/gem_ext/erubis.rb +77 -0
  48. data/lib/merb-core/logger.rb +203 -0
  49. data/lib/merb-core/plugins.rb +67 -0
  50. data/lib/merb-core/rack.rb +25 -0
  51. data/lib/merb-core/rack/adapter.rb +44 -0
  52. data/lib/merb-core/rack/adapter/ebb.rb +25 -0
  53. data/lib/merb-core/rack/adapter/evented_mongrel.rb +26 -0
  54. data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
  55. data/lib/merb-core/rack/adapter/irb.rb +118 -0
  56. data/lib/merb-core/rack/adapter/mongrel.rb +26 -0
  57. data/lib/merb-core/rack/adapter/runner.rb +28 -0
  58. data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
  59. data/lib/merb-core/rack/adapter/thin.rb +39 -0
  60. data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
  61. data/lib/merb-core/rack/adapter/webrick.rb +36 -0
  62. data/lib/merb-core/rack/application.rb +32 -0
  63. data/lib/merb-core/rack/handler/mongrel.rb +97 -0
  64. data/lib/merb-core/rack/middleware.rb +20 -0
  65. data/lib/merb-core/rack/middleware/conditional_get.rb +29 -0
  66. data/lib/merb-core/rack/middleware/content_length.rb +18 -0
  67. data/lib/merb-core/rack/middleware/csrf.rb +73 -0
  68. data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
  69. data/lib/merb-core/rack/middleware/profiler.rb +19 -0
  70. data/lib/merb-core/rack/middleware/static.rb +45 -0
  71. data/lib/merb-core/rack/middleware/tracer.rb +20 -0
  72. data/lib/merb-core/server.rb +284 -0
  73. data/lib/merb-core/tasks/audit.rake +68 -0
  74. data/lib/merb-core/tasks/gem_management.rb +229 -0
  75. data/lib/merb-core/tasks/merb.rb +1 -0
  76. data/lib/merb-core/tasks/merb_rake_helper.rb +80 -0
  77. data/lib/merb-core/tasks/stats.rake +71 -0
  78. data/lib/merb-core/test.rb +11 -0
  79. data/lib/merb-core/test/helpers.rb +9 -0
  80. data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
  81. data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
  82. data/lib/merb-core/test/helpers/request_helper.rb +393 -0
  83. data/lib/merb-core/test/helpers/route_helper.rb +39 -0
  84. data/lib/merb-core/test/helpers/view_helper.rb +121 -0
  85. data/lib/merb-core/test/matchers.rb +9 -0
  86. data/lib/merb-core/test/matchers/controller_matchers.rb +351 -0
  87. data/lib/merb-core/test/matchers/route_matchers.rb +137 -0
  88. data/lib/merb-core/test/matchers/view_matchers.rb +375 -0
  89. data/lib/merb-core/test/run_specs.rb +49 -0
  90. data/lib/merb-core/test/tasks/spectasks.rb +68 -0
  91. data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
  92. data/lib/merb-core/test/test_ext/object.rb +14 -0
  93. data/lib/merb-core/test/test_ext/string.rb +14 -0
  94. data/lib/merb-core/vendor/facets.rb +2 -0
  95. data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
  96. data/lib/merb-core/vendor/facets/inflect.rb +342 -0
  97. data/lib/merb-core/version.rb +3 -0
  98. metadata +253 -0
@@ -0,0 +1,137 @@
1
+ module Merb::Test::Rspec::RouteMatchers
2
+
3
+ class RouteToMatcher
4
+
5
+ # ==== Parameters
6
+ # klass_or_name<Class, String>::
7
+ # The controller class or class name to match routes for.
8
+ # action<~to_s>:: The name of the action to match routes for.
9
+ def initialize(klass_or_name, action)
10
+ @expected_controller = Class === klass_or_name ? klass_or_name.name : klass_or_name
11
+ @expected_action = action.to_s
12
+ end
13
+
14
+ # ==== Parameters
15
+ # target<Hash>:: The route parameters to match.
16
+ #
17
+ # ==== Returns
18
+ # Boolean:: True if the controller action and parameters match.
19
+ def matches?(target)
20
+ @target_env = target.dup
21
+ @target_controller, @target_action = @target_env.delete(:controller).to_s, @target_env.delete(:action).to_s
22
+
23
+ @target_controller = "#{target.delete(:namespace)}::#{@target_controller}" if target.has_key?(:namespace)
24
+
25
+ @expected_controller.snake_case == @target_controller.snake_case && @expected_action == @target_action && match_parameters(@target_env)
26
+ end
27
+
28
+ # ==== Parameters
29
+ # target<Hash>:: The route parameters to match.
30
+ #
31
+ # ==== Returns
32
+ # Boolean::
33
+ # True if the parameter matcher created with #with matches or if no
34
+ # parameter matcher exists.
35
+ def match_parameters(target)
36
+ @parameter_matcher.nil? ? true : @parameter_matcher.matches?(target)
37
+ end
38
+
39
+ # Creates a new paramter matcher.
40
+ #
41
+ # ==== Parameters
42
+ # parameters<Hash, ~to_param>:: The parameters to match.
43
+ #
44
+ # ==== Returns
45
+ # RouteToMatcher:: This matcher.
46
+ #
47
+ # ==== Alternatives
48
+ # If parameters is an object, then a new expected hash will be constructed
49
+ # with the key :id set to parameters.to_param.
50
+ def with(parameters)
51
+ @parameter_matcher = ParameterMatcher.new(parameters)
52
+
53
+ self
54
+ end
55
+
56
+ # ==== Returns
57
+ # String:: The failure message.
58
+ def failure_message
59
+ "expected the request to route to #{@expected_controller.camel_case}##{@expected_action}#{expected_parameters_message}, but was #{@target_controller.camel_case}##{@target_action}#{actual_parameters_message}"
60
+ end
61
+
62
+ # ==== Returns
63
+ # String:: The failure message to be displayed in negative matches.
64
+ def negative_failure_message
65
+ "expected the request not to route to #{@expected_controller.camel_case}##{@expected_action}#{expected_parameters_message}, but it did"
66
+ end
67
+
68
+ def expected_parameters_message
69
+ " with #{@parameter_matcher.expected.inspect}" if @parameter_matcher
70
+ end
71
+
72
+ def actual_parameters_message
73
+ " with #{(@parameter_matcher.actual || {}).inspect}" if @parameter_matcher
74
+ end
75
+ end
76
+
77
+ class ParameterMatcher
78
+ attr_accessor :expected, :actual
79
+
80
+ # ==== Parameters
81
+ # hash_or_object<Hash, ~to_param>:: The parameters to match.
82
+ #
83
+ # ==== Alternatives
84
+ # If hash_or_object is an object, then a new expected hash will be
85
+ # constructed with the key :id set to hash_or_object.to_param.
86
+ def initialize(hash_or_object)
87
+ @expected = {}
88
+ case hash_or_object
89
+ when Hash then @expected = hash_or_object
90
+ else @expected[:id] = hash_or_object.to_param
91
+ end
92
+ end
93
+
94
+ # ==== Parameters
95
+ # parameter_hash<Hash>:: The route parameters to match.
96
+ #
97
+ # ==== Returns
98
+ # Boolean:: True if the route parameters match the expected ones.
99
+ def matches?(parameter_hash)
100
+ @actual = parameter_hash.dup.except(:controller, :action)
101
+
102
+ return @actual.empty? if @expected.empty?
103
+ @expected.all? {|(k, v)| @actual.has_key?(k) && @actual[k] == v}
104
+ end
105
+
106
+ # ==== Returns
107
+ # String:: The failure message.
108
+ def failure_message
109
+ "expected the route to contain parameters #{@expected.inspect}, but instead contained #{@actual.inspect}"
110
+ end
111
+
112
+ # ==== Returns
113
+ # String:: The failure message to be displayed in negative matches.
114
+ def negative_failure_message
115
+ "expected the route not to contain parameters #{@expected.inspect}, but it did"
116
+ end
117
+ end
118
+
119
+ # Passes when the actual route parameters match the expected controller class
120
+ # and controller action. Exposes a +with+ method for specifying parameters.
121
+ #
122
+ # ==== Parameters
123
+ # klass_or_name<Class, String>::
124
+ # The controller class or class name to match routes for.
125
+ # action<~to_s>:: The name of the action to match routes for.
126
+ #
127
+ # ==== Example
128
+ # # Passes if a GET request to "/" is routed to the Widgets controller's
129
+ # # index action.
130
+ # request_to("/", :get).should route_to(Widgets, :index)
131
+ #
132
+ # # Use the 'with' method for parameter checks
133
+ # request_to("/123").should route_to(widgets, :show).with(:id => "123")
134
+ def route_to(klass_or_name, action)
135
+ RouteToMatcher.new(klass_or_name, action)
136
+ end
137
+ end
@@ -0,0 +1,375 @@
1
+ module Merb::Test::Rspec::ViewMatchers
2
+ class HaveXpath
3
+ def initialize(expected)
4
+ @expected = expected
5
+ end
6
+
7
+ def matches?(stringlike)
8
+ @document = case stringlike
9
+ when LibXML::XML::Document, LibXML::XML::Node
10
+ stringlike
11
+ when StringIO
12
+ LibXML::XML::HTMLParser.string(stringlike.string).parse
13
+ else
14
+ LibXML::XML::HTMLParser.string(stringlike).parse
15
+ end
16
+ !@document.find(@expected).empty?
17
+ end
18
+
19
+ # ==== Returns
20
+ # String:: The failure message.
21
+ def failure_message
22
+ "expected following text to match xpath #{@expected}:\n#{@document}"
23
+ end
24
+
25
+ # ==== Returns
26
+ # String:: The failure message to be displayed in negative matches.
27
+ def negative_failure_message
28
+ "expected following text to not match xpath #{@expected}:\n#{@document}"
29
+ end
30
+ end
31
+
32
+ class HaveSelector
33
+
34
+ # ==== Parameters
35
+ # expected<String>:: The string to look for.
36
+ def initialize(expected)
37
+ @expected = expected
38
+ end
39
+
40
+ # ==== Parameters
41
+ # stringlike<Hpricot::Elem, StringIO, String>:: The thing to search in.
42
+ #
43
+ # ==== Returns
44
+ # Boolean:: True if there was at least one match.
45
+ def matches?(stringlike)
46
+ @document = case stringlike
47
+ when Hpricot::Elem
48
+ stringlike
49
+ when StringIO
50
+ Hpricot.parse(stringlike.string)
51
+ else
52
+ Hpricot.parse(stringlike)
53
+ end
54
+ !@document.search(@expected).empty?
55
+ end
56
+
57
+ # ==== Returns
58
+ # String:: The failure message.
59
+ def failure_message
60
+ "expected following text to match selector #{@expected}:\n#{@document}"
61
+ end
62
+
63
+ # ==== Returns
64
+ # String:: The failure message to be displayed in negative matches.
65
+ def negative_failure_message
66
+ "expected following text to not match selector #{@expected}:\n#{@document}"
67
+ end
68
+ end
69
+
70
+ class MatchTag
71
+
72
+ # ==== Parameters
73
+ # name<~to_s>:: The name of the tag to look for.
74
+ # attrs<Hash>:: Attributes to look for in the tag (see below).
75
+ #
76
+ # ==== Options (attrs)
77
+ # :content<String>:: Optional content to match.
78
+ def initialize(name, attrs)
79
+ @name, @attrs = name, attrs
80
+ @content = @attrs.delete(:content)
81
+ end
82
+
83
+ # ==== Parameters
84
+ # target<String>:: The string to look for the tag in.
85
+ #
86
+ # ==== Returns
87
+ # Boolean:: True if the tag matched.
88
+ def matches?(target)
89
+ @errors = []
90
+ unless target.include?("<#{@name}")
91
+ @errors << "Expected a <#{@name}>, but was #{target}"
92
+ end
93
+ @attrs.each do |attr, val|
94
+ unless target.include?("#{attr}=\"#{val}\"")
95
+ @errors << "Expected #{attr}=\"#{val}\", but was #{target}"
96
+ end
97
+ end
98
+ if @content
99
+ unless target.include?(">#{@content}<")
100
+ @errors << "Expected #{target} to include #{@content}"
101
+ end
102
+ end
103
+ @errors.size == 0
104
+ end
105
+
106
+ # ==== Returns
107
+ # String:: The failure message.
108
+ def failure_message
109
+ @errors[0]
110
+ end
111
+
112
+ # ==== Returns
113
+ # String:: The failure message to be displayed in negative matches.
114
+ def negative_failure_message
115
+ "Expected not to match against <#{@name} #{@attrs.map{ |a,v| "#{a}=\"#{v}\"" }.join(" ")}> tag, but it matched"
116
+ end
117
+ end
118
+
119
+ class NotMatchTag
120
+
121
+ # === Parameters
122
+ # attrs<Hash>:: A set of attributes that must not be matched.
123
+ def initialize(attrs)
124
+ @attrs = attrs
125
+ end
126
+
127
+ # ==== Parameters
128
+ # target<String>:: The target to look for the match in.
129
+ #
130
+ # ==== Returns
131
+ # Boolean:: True if none of the attributes were matched.
132
+ def matches?(target)
133
+ @errors = []
134
+ @attrs.each do |attr, val|
135
+ if target.include?("#{attr}=\"#{val}\"")
136
+ @errors << "Should not include #{attr}=\"#{val}\", but was #{target}"
137
+ end
138
+ end
139
+ @errors.size == 0
140
+ end
141
+
142
+ # ==== Returns
143
+ # String:: The failure message.
144
+ def failure_message
145
+ @errors[0]
146
+ end
147
+ end
148
+
149
+ class HasTag
150
+
151
+ # ==== Parameters
152
+ # tag<~to_s>:: The tag to look for.
153
+ # attributes<Hash>:: Attributes for the tag (see below).
154
+ def initialize(tag, attributes = {}, &blk)
155
+ @tag, @attributes = tag, attributes
156
+ @id, @class = @attributes.delete(:id), @attributes.delete(:class)
157
+ @blk = blk
158
+ end
159
+
160
+ # ==== Parameters
161
+ # stringlike<Hpricot::Elem, StringIO, String>:: The thing to search in.
162
+ # &blk:: An optional block for searching in child elements using with_tag.
163
+ #
164
+ # ==== Returns
165
+ # Boolean:: True if there was at least one match.
166
+ def matches?(stringlike, &blk)
167
+ @document = case stringlike
168
+ when Hpricot::Elem
169
+ stringlike
170
+ when StringIO
171
+ Hpricot.parse(stringlike.string)
172
+ else
173
+ Hpricot.parse(stringlike)
174
+ end
175
+
176
+ @blk = blk unless blk.nil?
177
+
178
+ unless @blk.nil?
179
+ !@document.search(selector).select do |ele|
180
+ @blk.call ele
181
+ true
182
+ end.empty?
183
+ else
184
+ !@document.search(selector).empty?
185
+ end
186
+ end
187
+
188
+ # ==== Returns
189
+ # String:: The complete selector for element queries.
190
+ def selector
191
+ @selector = "//#{@tag}#{id_selector}#{class_selector}"
192
+ @selector << @attributes.map{|a, v| "[@#{a}=\"#{v}\"]"}.join
193
+
194
+ @selector << @inner_has_tag.selector unless @inner_has_tag.nil?
195
+
196
+ @selector
197
+ end
198
+
199
+ # ==== Returns
200
+ # String:: ID selector for use in element queries.
201
+ def id_selector
202
+ "##{@id}" if @id
203
+ end
204
+
205
+ # ==== Returns
206
+ # String:: Class selector for use in element queries.
207
+ def class_selector
208
+ ".#{@class}" if @class
209
+ end
210
+
211
+ # ==== Returns
212
+ # String:: The failure message.
213
+ def failure_message
214
+ "expected following output to contain a #{tag_for_error} tag:\n#{@document}"
215
+ end
216
+
217
+ # ==== Returns
218
+ # String:: The failure message to be displayed in negative matches.
219
+ def negative_failure_message
220
+ "expected following output to omit a #{tag_for_error} tag:\n#{@document}"
221
+ end
222
+
223
+ # ==== Returns
224
+ # String:: The tag used in failure messages.
225
+ def tag_for_error
226
+ "#{inner_failure_message}<#{@tag}#{id_for_error}#{class_for_error}#{attributes_for_error}>"
227
+ end
228
+
229
+ # ==== Returns
230
+ # String::
231
+ # The failure message to be displayed in negative matches within the
232
+ # have_tag block.
233
+ def inner_failure_message
234
+ "#{@inner_has_tag.tag_for_error} tag within a " unless @inner_has_tag.nil?
235
+ end
236
+
237
+ # ==== Returns
238
+ # String:: ID for the error tag.
239
+ def id_for_error
240
+ " id=\"#{@id}\"" unless @id.nil?
241
+ end
242
+
243
+ # ==== Returns
244
+ # String:: Class for the error tag.
245
+ def class_for_error
246
+ " class=\"#{@class}\"" unless @class.nil?
247
+ end
248
+
249
+ # ==== Returns
250
+ # String:: Class for the error tag.
251
+ def attributes_for_error
252
+ @attributes.map{|a,v| " #{a}=\"#{v}\""}.join
253
+ end
254
+
255
+ # Search for a child tag within a have_tag block.
256
+ #
257
+ # ==== Parameters
258
+ # tag<~to_s>:: The tag to look for.
259
+ # attributes<Hash>:: Attributes for the tag (see below).
260
+ def with_tag(name, attrs={})
261
+ @inner_has_tag = HasTag.new(name, attrs)
262
+ end
263
+ end
264
+
265
+ class HasContent
266
+ def initialize(content)
267
+ @content = content
268
+ end
269
+
270
+ def matches?(element)
271
+ @element = element
272
+
273
+ case @content
274
+ when String
275
+ @element.contains?(@content)
276
+ when Regexp
277
+ @element.matches?(@content)
278
+ end
279
+ end
280
+
281
+ # ==== Returns
282
+ # String:: The failure message.
283
+ def failure_message
284
+ "expected the following element's content to #{content_message}:\n#{@element.inner_text}"
285
+ end
286
+
287
+ # ==== Returns
288
+ # String:: The failure message to be displayed in negative matches.
289
+ def negative_failure_message
290
+ "expected the following element's content to not #{content_message}:\n#{@element.inner_text}"
291
+ end
292
+
293
+ def content_message
294
+ case @content
295
+ when String
296
+ "include \"#{@content}\""
297
+ when Regexp
298
+ "match #{@content.inspect}"
299
+ end
300
+ end
301
+ end
302
+
303
+ # ==== Parameters
304
+ # name<~to_s>:: The name of the tag to look for.
305
+ # attrs<Hash>:: Attributes to look for in the tag (see below).
306
+ #
307
+ # ==== Options (attrs)
308
+ # :content<String>:: Optional content to match.
309
+ #
310
+ # ==== Returns
311
+ # MatchTag:: A new match tag matcher.
312
+ def match_tag(name, attrs={})
313
+ MatchTag.new(name, attrs)
314
+ end
315
+
316
+ # ==== Parameters
317
+ # attrs<Hash>:: A set of attributes that must not be matched.
318
+ #
319
+ # ==== Returns
320
+ # NotMatchTag:: A new not match tag matcher.
321
+ def not_match_tag(attrs)
322
+ NotMatchTag.new(attrs)
323
+ end
324
+
325
+ # ==== Parameters
326
+ # expected<String>:: The string to look for.
327
+ #
328
+ # ==== Returns
329
+ # HaveSelector:: A new have selector matcher.
330
+ def have_selector(expected)
331
+ HaveSelector.new(expected)
332
+ end
333
+ alias_method :match_selector, :have_selector
334
+
335
+ def have_xpath(expected)
336
+ begin
337
+ require "libxml"
338
+ rescue LoadError => e
339
+ puts "To use have_xpath helper you need to install libxml-ruby gem"
340
+ end
341
+ HaveXpath.new(expected)
342
+ end
343
+ alias_method :match_xpath, :have_xpath
344
+
345
+ # RSpec matcher to test for the presence of tags.
346
+ #
347
+ # ==== Parameters
348
+ # tag<~to_s>:: The name of the tag.
349
+ # attributes<Hash>:: Tag attributes.
350
+ #
351
+ # ==== Returns
352
+ # HasTag:: A new has tag matcher.
353
+ #
354
+ # ==== Examples
355
+ # # Check for <div>
356
+ # body.should have_tag("div")
357
+ #
358
+ # # Check for <span id="notice">
359
+ # body.should have_tag("span", :id => :notice)
360
+ #
361
+ # # Check for <h1 id="foo" class="bar">
362
+ # body.should have_tag(:h2, :class => "bar", :id => "foo")
363
+ #
364
+ # # Check for <div attr="val">
365
+ # body.should have_tag(:div, :attr => :val)
366
+ def have_tag(tag, attributes = {}, &blk)
367
+ HasTag.new(tag, attributes, &blk)
368
+ end
369
+
370
+ alias_method :with_tag, :have_tag
371
+
372
+ def contain(content)
373
+ HasContent.new(content)
374
+ end
375
+ end