Implement Blob, Tree and Lazy, add tests for Tree.
[phpgit.git] / tests / fixtures / diff_mode_only
blob6fc18f69e9b74eafb4a58a6fcbd218adc0d80c36
1 diff --git a/bin/merb b/bin/merb
2 old mode 100644
3 new mode 100755
4 diff --git a/lib/merb.rb b/lib/merb.rb
5 index 76cb3e269e46fdf9b63cda7cb563c6cf40fdcb15..a2ab4ed47f9cb2ab942da5c46a2b561758a0d704 100644
6 --- a/lib/merb.rb
7 +++ b/lib/merb.rb
8 @@ -15,7 +15,7 @@ require 'merb_core/core_ext'
9  require 'merb_core/gem_ext/erubis'
10  require 'merb_core/logger'
11  require 'merb_core/version'
13 +require 'merb_core/controller/mime'
15  module Merb
16    class << self
17 @@ -23,6 +23,7 @@ module Merb
18      def start(argv=ARGV)
19        Merb::Config.parse_args(argv)
20        BootLoader.run
21 +      
22        case Merb::Config[:adapter]
23        when "mongrel"
24          adapter = Merb::Rack::Mongrel
25 diff --git a/lib/merb_core/boot/bootloader.rb b/lib/merb_core/boot/bootloader.rb
26 index d873924860bf4da06ac93db5c6a188f63dd1c3cc..57da75f05e28e8a256922bf345ccd3902e0a0b02 100644
27 --- a/lib/merb_core/boot/bootloader.rb
28 +++ b/lib/merb_core/boot/bootloader.rb
29 @@ -20,7 +20,7 @@ module Merb
30        end
31        
32        def run
33 -        subclasses.each {|klass| Object.full_const_get(klass).new.run }
34 +        subclasses.each {|klass| Object.full_const_get(klass).run }
35        end
36        
37        def after(klass)
38 @@ -37,95 +37,128 @@ module Merb
39    
40  end
42 -class Merb::BootLoader::BuildFramework < Merb::BootLoader
43 -  def run
44 -    build_framework
45 +class Merb::BootLoader::LoadInit < Merb::BootLoader
46 +  def self.run
47 +    if Merb::Config[:init_file]
48 +      require Merb.root / Merb::Config[:init_file]
49 +    elsif File.exists?(Merb.root / "config" / "merb_init.rb")
50 +      require Merb.root / "config" / "merb_init"
51 +    elsif File.exists?(Merb.root / "merb_init.rb")
52 +      require Merb.root / "merb_init"
53 +    elsif File.exists?(Merb.root / "application.rb")
54 +      require Merb.root / "application"
55 +    end
56 +  end
57 +end
59 +class Merb::BootLoader::Environment < Merb::BootLoader
60 +  def self.run
61 +    Merb.environment = Merb::Config[:environment]
62 +  end
63 +end
65 +class Merb::BootLoader::Logger < Merb::BootLoader
66 +  def self.run
67 +    Merb.logger = Merb::Logger.new(Merb.dir_for(:log) / "test_log")
68 +    Merb.logger.level = Merb::Logger.const_get(Merb::Config[:log_level].upcase) rescue Merb::Logger::INFO    
69    end
70 +end
72 +class Merb::BootLoader::BuildFramework < Merb::BootLoader
73 +  class << self
74 +    def run
75 +      build_framework
76 +    end
77    
78 -  # This method should be overridden in merb_init.rb before Merb.start to set up a different
79 -  # framework structure
80 -  def build_framework
81 -    %[view model controller helper mailer part].each do |component|
82 -      Merb.push_path(component.to_sym, Merb.root_path("app/#{component}s"))
83 +    # This method should be overridden in merb_init.rb before Merb.start to set up a different
84 +    # framework structure
85 +    def build_framework
86 +      %w[view model controller helper mailer part].each do |component|
87 +        Merb.push_path(component.to_sym, Merb.root_path("app/#{component}s"))
88 +      end
89 +      Merb.push_path(:application,    Merb.root_path("app/controllers/application.rb"))
90 +      Merb.push_path(:config,         Merb.root_path("config/router.rb"))
91 +      Merb.push_path(:lib,            Merb.root_path("lib"))    
92      end
93 -    Merb.push_path(:application,    Merb.root_path("app/controllers/application.rb"))
94 -    Merb.push_path(:config,         Merb.root_path("config/router.rb"))
95 -    Merb.push_path(:lib,            Merb.root_path("lib"))    
96    end
97  end
99  class Merb::BootLoader::LoadPaths < Merb::BootLoader
100    LOADED_CLASSES = {}
101    
102 -  def run
103 -    # Add models, controllers, and lib to the load path
104 -    $LOAD_PATH.unshift Merb.load_paths[:model].first      if Merb.load_paths[:model]
105 -    $LOAD_PATH.unshift Merb.load_paths[:controller].first if Merb.load_paths[:controller]
106 -    $LOAD_PATH.unshift Merb.load_paths[:lib].first        if Merb.load_paths[:lib]
107 +  class << self
108 +    def run
109 +      # Add models, controllers, and lib to the load path
110 +      $LOAD_PATH.unshift Merb.load_paths[:model].first      if Merb.load_paths[:model]
111 +      $LOAD_PATH.unshift Merb.load_paths[:controller].first if Merb.load_paths[:controller]
112 +      $LOAD_PATH.unshift Merb.load_paths[:lib].first        if Merb.load_paths[:lib]
113      
114 -    # Require all the files in the registered load paths
115 -    puts Merb.load_paths.inspect
116 -    Merb.load_paths.each do |name, path|
117 -      Dir[path.first / path.last].each do |file| 
118 -        klasses = ObjectSpace.classes.dup
119 -        require f
120 -        LOADED_CLASSES[file] = ObjectSpace.classes - klasses
121 +      # Require all the files in the registered load paths
122 +      puts Merb.load_paths.inspect
123 +      Merb.load_paths.each do |name, path|
124 +        Dir[path.first / path.last].each do |file| 
125 +          klasses = ObjectSpace.classes.dup
126 +          require file
127 +          LOADED_CLASSES[file] = ObjectSpace.classes - klasses
128 +        end
129        end
130      end
131 -  end
133 -  def reload(file)
134 -    if klasses = LOADED_CLASSES[file]
135 -      klasses.each do |klass|
136 -        remove_constant(klass)
137 +    def reload(file)
138 +      if klasses = LOADED_CLASSES[file]
139 +        klasses.each do |klass|
140 +          remove_constant(klass)
141 +        end
142        end
143 +      load file
144      end
145 -    load file
146 -  end
147    
148 -  def remove_constant(const)
149 -    # This is to support superclasses (like AbstractController) that track
150 -    # their subclasses in a class variable. Classes that wish to use this
151 -    # functionality are required to alias it to _subclasses_list. Plugins
152 -    # for ORMs and other libraries should keep this in mind.
153 -    if klass.superclass.respond_to?(:_subclasses_list)
154 -      klass.superclass.send(:_subclasses_list).delete(klass)
155 -      klass.superclass.send(:_subclasses_list).delete(klass.to_s)          
156 -    end
157 +    def remove_constant(const)
158 +      # This is to support superclasses (like AbstractController) that track
159 +      # their subclasses in a class variable. Classes that wish to use this
160 +      # functionality are required to alias it to _subclasses_list. Plugins
161 +      # for ORMs and other libraries should keep this in mind.
162 +      if klass.superclass.respond_to?(:_subclasses_list)
163 +        klass.superclass.send(:_subclasses_list).delete(klass)
164 +        klass.superclass.send(:_subclasses_list).delete(klass.to_s)          
165 +      end
166    
167 -    parts = const.to_s.split("::")
168 -    base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
169 -    object = parts[-1].intern
170 -    Merb.logger.debugger("Removing constant #{object} from #{base}")
171 -    base.send(:remove_const, object) if object
172 +      parts = const.to_s.split("::")
173 +      base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
174 +      object = parts[-1].intern
175 +      Merb.logger.debugger("Removing constant #{object} from #{base}")
176 +      base.send(:remove_const, object) if object
177 +    end
178    end
179    
180  end
182  class Merb::BootLoader::Templates < Merb::BootLoader
183 -  def run
184 -    template_paths.each do |path|
185 -      Merb::Template.inline_template(path)
186 +  class << self
187 +    def run
188 +      template_paths.each do |path|
189 +        Merb::Template.inline_template(path)
190 +      end
191      end
192 -  end
193    
194 -  def template_paths
195 -    extension_glob = "{#{Merb::Template::EXTENSIONS.keys.join(',')}}"
196 +    def template_paths
197 +      extension_glob = "{#{Merb::Template::EXTENSIONS.keys.join(',')}}"
199 -    # This gets all templates set in the controllers template roots        
200 -    # We separate the two maps because most of controllers will have
201 -    # the same _template_root, so it's silly to be globbing the same
202 -    # path over and over.
203 -    template_paths = Merb::AbstractController._abstract_subclasses.map do |klass| 
204 -      Object.full_const_get(klass)._template_root
205 -    end.uniq.map {|path| Dir["#{path}/**/*.#{extension_glob}"] }
206 +      # This gets all templates set in the controllers template roots        
207 +      # We separate the two maps because most of controllers will have
208 +      # the same _template_root, so it's silly to be globbing the same
209 +      # path over and over.
210 +      template_paths = Merb::AbstractController._abstract_subclasses.map do |klass| 
211 +        Object.full_const_get(klass)._template_root
212 +      end.uniq.compact.map {|path| Dir["#{path}/**/*.#{extension_glob}"] }
213      
214 -    # This gets the templates that might be created outside controllers
215 -    # template roots.  eg app/views/shared/*
216 -    template_paths << Dir["#{Merb.dir_for(:view)}/**/*.#{extension_glob}"] if Merb.dir_for(:view)
217 +      # This gets the templates that might be created outside controllers
218 +      # template roots.  eg app/views/shared/*
219 +      template_paths << Dir["#{Merb.dir_for(:view)}/**/*.#{extension_glob}"] if Merb.dir_for(:view)
220      
221 -    template_paths.flatten.compact.uniq
222 -  end  
223 +      template_paths.flatten.compact.uniq
224 +    end
225 +  end
226  end
228  class Merb::BootLoader::Libraries < Merb::BootLoader
229 @@ -145,18 +178,41 @@ class Merb::BootLoader::Libraries < Merb::BootLoader
230    def self.add_libraries(hsh)
231      @@libraries.merge!(hsh)
232    end
233 -  
234 -  def run
236 +  def self.run
237      @@libraries.each do |exclude, choices|
238        require_first_working(*choices) unless Merb::Config[exclude]
239      end
240    end
241 -  
242 -  def require_first_working(first, *rest)
244 +  def self.require_first_working(first, *rest)
245      p first, rest
246      require first
247    rescue LoadError
248      raise LoadError if rest.empty?
249      require_first_working rest.unshift, *rest
250    end
251 +end
253 +class Merb::BootLoader::MimeTypes < Merb::BootLoader
254 +  def self.run
255 +    # Sets the default mime-types
256 +    # 
257 +    # By default, the mime-types include:
258 +    # :all:: no transform, */*
259 +    # :yaml:: to_yaml, application/x-yaml or text/yaml
260 +    # :text:: to_text, text/plain
261 +    # :html:: to_html, text/html or application/xhtml+xml or application/html
262 +    # :xml:: to_xml, application/xml or text/xml or application/x-xml, adds "Encoding: UTF-8" response header
263 +    # :js:: to_json, text/javascript ot application/javascript or application/x-javascript
264 +    # :json:: to_json, application/json or text/x-json
265 +    Merb.available_mime_types.clear
266 +    Merb.add_mime_type(:all,  nil,      %w[*/*])
267 +    Merb.add_mime_type(:yaml, :to_yaml, %w[application/x-yaml text/yaml])
268 +    Merb.add_mime_type(:text, :to_text, %w[text/plain])
269 +    Merb.add_mime_type(:html, :to_html, %w[text/html application/xhtml+xml application/html])
270 +    Merb.add_mime_type(:xml,  :to_xml,  %w[application/xml text/xml application/x-xml], :Encoding => "UTF-8")
271 +    Merb.add_mime_type(:js,   :to_json, %w[text/javascript application/javascript application/x-javascript])
272 +    Merb.add_mime_type(:json, :to_json, %w[application/json text/x-json])      
273 +  end
274  end
275 \ No newline at end of file
276 diff --git a/lib/merb_core/config.rb b/lib/merb_core/config.rb
277 index c92f2e6f071c234551ecb16a4716d47fa92f6c7b..ab0864e0174b54833c758f9f22a840d3b53c7653 100644
278 --- a/lib/merb_core/config.rb
279 +++ b/lib/merb_core/config.rb
280 @@ -92,6 +92,10 @@ module Merb
281               options[:cluster] = nodes
282             end
284 +           opts.on("-I", "--init-file FILE", "Name of the file to load first") do |init_file|
285 +             options[:init_file] = init_file
286 +           end
288             opts.on("-p", "--port PORTNUM", "Port to run merb on, defaults to 4000.") do |port|
289               options[:port] = port
290             end
291 @@ -261,29 +265,29 @@ module Merb
293           @configuration = Merb::Config.apply_configuration_from_file options, environment_merb_yml
294           
295 -         case Merb::Config[:environment].to_s
296 -         when 'production'
297 -           Merb::Config[:reloader] = Merb::Config.fetch(:reloader, false)
298 -           Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, false)
299 -           Merb::Config[:cache_templates] = true
300 -         else
301 -           Merb::Config[:reloader] = Merb::Config.fetch(:reloader, true)
302 -           Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, true)
303 -         end
305 -         Merb::Config[:reloader_time] ||= 0.5 if Merb::Config[:reloader] == true
308 -         if Merb::Config[:reloader]
309 -           Thread.abort_on_exception = true
310 -           Thread.new do
311 -             loop do
312 -               sleep( Merb::Config[:reloader_time] )
313 -               ::Merb::BootLoader.reload if ::Merb::BootLoader.app_loaded?
314 -             end
315 -             Thread.exit
316 -           end
317 -         end
318 +         # case Merb::Config[:environment].to_s
319 +         # when 'production'
320 +         #   Merb::Config[:reloader] = Merb::Config.fetch(:reloader, false)
321 +         #   Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, false)
322 +         #   Merb::Config[:cache_templates] = true
323 +         # else
324 +         #   Merb::Config[:reloader] = Merb::Config.fetch(:reloader, true)
325 +         #   Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, true)
326 +         # end
327 +         # 
328 +         # Merb::Config[:reloader_time] ||= 0.5 if Merb::Config[:reloader] == true
329 +         # 
330 +         # 
331 +         # if Merb::Config[:reloader]
332 +         #   Thread.abort_on_exception = true
333 +         #   Thread.new do
334 +         #     loop do
335 +         #       sleep( Merb::Config[:reloader_time] )
336 +         #       ::Merb::BootLoader.reload if ::Merb::BootLoader.app_loaded?
337 +         #     end
338 +         #     Thread.exit
339 +         #   end
340 +         # end
341           @configuration
342         end
343         
344 diff --git a/lib/merb_core/controller/abstract_controller.rb b/lib/merb_core/controller/abstract_controller.rb
345 index fbf83372793da6da4b803b799994f0e341fddf88..f5e9a59057d67a6d56377a516a726cf51aa03d6f 100644
346 --- a/lib/merb_core/controller/abstract_controller.rb
347 +++ b/lib/merb_core/controller/abstract_controller.rb
348 @@ -96,7 +96,7 @@ class Merb::AbstractController
349    # the superclass.
350    #---
351    # @public
352 -  def _template_location(action, controller = controller_name, type = nil)
353 +  def _template_location(action, type = nil, controller = controller_name)
354      "#{controller}/#{action}"
355    end
356    
357 @@ -106,6 +106,8 @@ class Merb::AbstractController
358    # own subclasses. We're using a Set so we don't have to worry about
359    # uniqueness.
360    self._abstract_subclasses = Set.new
361 +  self._template_root = Merb.dir_for(:view)
362 +  
363    def self.subclasses_list() _abstract_subclasses end
364    
365    class << self
366 @@ -114,7 +116,6 @@ class Merb::AbstractController
367      #   The controller that is being inherited from Merb::AbstractController
368      def inherited(klass)
369        _abstract_subclasses << klass.to_s
370 -      klass._template_root ||= Merb.dir_for(:view)
371        super
372      end
373      
374 diff --git a/lib/merb_core/controller/merb_controller.rb b/lib/merb_core/controller/merb_controller.rb
375 index 7283f006bb0501b29f825da129600cf045264b62..98af6ef3330a6b3f46d7bb1f8643261e28155ae5 100644
376 --- a/lib/merb_core/controller/merb_controller.rb
377 +++ b/lib/merb_core/controller/merb_controller.rb
378 @@ -71,6 +71,10 @@ class Merb::Controller < Merb::AbstractController
379      end
380    end
381    
382 +  def _template_location(action, type = nil, controller = controller_name)
383 +    "#{controller}/#{action}.#{type}"
384 +  end  
385 +  
386    # Sets the variables that came in through the dispatch as available to
387    # the controller. This is called by .build, so see it for more
388    # information.
389 @@ -107,9 +111,7 @@ class Merb::Controller < Merb::AbstractController
390          request.cookies[_session_id_key] = request.params[_session_id_key]
391        end
392      end
393 -    @_request, @_response, @_status, @_headers = 
394 -      request, response, status, headers
396 +    @request, @response, @status, @headers = request, response, status, headers
397      nil
398    end
399    
400 @@ -135,7 +137,8 @@ class Merb::Controller < Merb::AbstractController
401      @_benchmarks[:action_time] = Time.now - start
402    end
403    
404 -  _attr_reader :request, :response, :status, :headers
405 +  attr_reader :request, :response, :headers
406 +  attr_accessor :status
407    def params()  request.params  end
408    def cookies() request.cookies end
409    def session() request.session end
410 diff --git a/lib/merb_core/controller/mime.rb b/lib/merb_core/controller/mime.rb
411 index d17570786ca318cff7201c4b1e947ae229b01de8..ff9abe4d1c452aeabfcf5f7dc7a2c7cdd3f67035 100644
412 --- a/lib/merb_core/controller/mime.rb
413 +++ b/lib/merb_core/controller/mime.rb
414 @@ -8,7 +8,7 @@ module Merb
416      # Any specific outgoing headers should be included here.  These are not
417      # the content-type header but anything in addition to it.
418 -    # +tranform_method+ should be set to a symbol of the method used to
419 +    # +transform_method+ should be set to a symbol of the method used to
420      # transform a resource into this mime type.
421      # For example for the :xml mime type an object might be transformed by
422      # calling :to_xml, or for the :js mime type, :to_json.
423 @@ -71,27 +71,6 @@ module Merb
424      def mime_by_request_header(header)
425        available_mime_types.find {|key,info| info[request_headers].include?(header)}.first
426      end
428 -    # Resets the default mime-types
429 -    # 
430 -    # By default, the mime-types include:
431 -    # :all:: no transform, */*
432 -    # :yaml:: to_yaml, application/x-yaml or text/yaml
433 -    # :text:: to_text, text/plain
434 -    # :html:: to_html, text/html or application/xhtml+xml or application/html
435 -    # :xml:: to_xml, application/xml or text/xml or application/x-xml, adds "Encoding: UTF-8" response header
436 -    # :js:: to_json, text/javascript ot application/javascript or application/x-javascript
437 -    # :json:: to_json, application/json or text/x-json
438 -    def reset_default_mime_types!
439 -      available_mime_types.clear
440 -      Merb.add_mime_type(:all,  nil,      %w[*/*])
441 -      Merb.add_mime_type(:yaml, :to_yaml, %w[application/x-yaml text/yaml])
442 -      Merb.add_mime_type(:text, :to_text, %w[text/plain])
443 -      Merb.add_mime_type(:html, :to_html, %w[text/html application/xhtml+xml application/html])
444 -      Merb.add_mime_type(:xml,  :to_xml,  %w[application/xml text/xml application/x-xml], :Encoding => "UTF-8")
445 -      Merb.add_mime_type(:js,   :to_json, %w[text/javascript application/javascript application/x-javascript])
446 -      Merb.add_mime_type(:json, :to_json, %w[application/json text/x-json])      
447 -    end
448      
449    end
450  end
451 \ No newline at end of file
452 diff --git a/lib/merb_core/controller/mixins/render.rb b/lib/merb_core/controller/mixins/render.rb
453 index 8e096546d4647bb597ab2e00a4b15d09db35e9c9..a298263af7d655d9ce43007554f3827046831287 100644
454 --- a/lib/merb_core/controller/mixins/render.rb
455 +++ b/lib/merb_core/controller/mixins/render.rb
456 @@ -51,21 +51,22 @@ module Merb::RenderMixin
457      
458      # If you don't specify a thing to render, assume they want to render the current action
459      thing ||= action_name.to_sym
460 -    
462      # Content negotiation
463      opts[:format] ? (self.content_type = opts[:format]) : content_type 
464      
465      # Do we have a template to try to render?
466      if thing.is_a?(Symbol) || opts[:template]
467 -      
469        # Find a template path to look up (_template_location adds flexibility here)
470 -      template_location = _template_root / (opts[:template] || _template_location(thing))
471 +      template_location = _template_root / (opts[:template] || _template_location(thing, content_type))
472 +      
473        # Get the method name from the previously inlined list
474        template_method = Merb::Template.template_for(template_location)
476        # Raise an error if there's no template
477        raise TemplateNotFound, "No template found at #{template_location}" unless 
478 -        self.respond_to?(template_method)
479 +        template_method && self.respond_to?(template_method)
481        # Call the method in question and throw the content for later consumption by the layout
482        throw_content(:for_layout, self.send(template_method))
483 diff --git a/lib/merb_core/controller/mixins/responder.rb b/lib/merb_core/controller/mixins/responder.rb
484 index e910b2b32c844ab51cf2a10d0ad26c314dbb3631..5ac67fb907aaf9f95effc7eb3cbb07b8963ce022 100644
485 --- a/lib/merb_core/controller/mixins/responder.rb
486 +++ b/lib/merb_core/controller/mixins/responder.rb
487 @@ -97,6 +97,8 @@ module Merb
488    # and none of the provides methods can be used.
489    module ResponderMixin
490      
491 +    TYPES = {}
492 +    
493      class ContentTypeAlreadySet < StandardError; end
494      
495      # ==== Parameters
496 @@ -105,6 +107,7 @@ module Merb
497        base.extend(ClassMethods)
498        base.class_eval do
499          class_inheritable_accessor :class_provided_formats
500 +        self.class_provided_formats = []
501        end
502        base.reset_provides
503      end
504 @@ -178,171 +181,253 @@ module Merb
505        def reset_provides
506          only_provides(:html)
507        end
508 -      
509 -      # ==== Returns
510 -      # The current list of formats provided for this instance of the controller. 
511 -      # It starts with what has been set in the controller (or :html by default) 
512 -      # but can be modifed on a per-action basis.      
513 -      def _provided_formats
514 -        @_provided_formats ||= class_provided_formats.dup
515 +    end
517 +    # ==== Returns
518 +    # The current list of formats provided for this instance of the controller. 
519 +    # It starts with what has been set in the controller (or :html by default) 
520 +    # but can be modifed on a per-action basis.      
521 +    def _provided_formats
522 +      @_provided_formats ||= class_provided_formats.dup
523 +    end
524 +    
525 +    # Sets the provided formats for this action.  Usually, you would
526 +    # use a combination of +provides+, +only_provides+ and +does_not_provide+
527 +    # to manage this, but you can set it directly.
528 +    # 
529 +    # ==== Parameters
530 +    # *formats<Symbol>:: A list of formats to be passed to provides
531 +    #
532 +    # ==== Raises
533 +    # Merb::ResponderMixin::ContentTypeAlreadySet::
534 +    #   Content negotiation already occured, and the content_type is set.
535 +    #
536 +    # ==== Returns
537 +    # Array:: List of formats passed in
538 +    def _set_provided_formats(*formats)
539 +      if @_content_type
540 +        raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
541        end
542 -      
543 -      # Sets the provided formats for this action.  Usually, you would
544 -      # use a combination of +provides+, +only_provides+ and +does_not_provide+
545 -      # to manage this, but you can set it directly.
546 -      # 
547 -      # ==== Parameters
548 -      # *formats<Symbol>:: A list of formats to be passed to provides
549 -      #
550 -      # ==== Raises
551 -      # Merb::ResponderMixin::ContentTypeAlreadySet::
552 -      #   Content negotiation already occured, and the content_type is set.
553 -      #
554 -      # ==== Returns
555 -      # Array:: List of formats passed in
556 -      def _set_provided_formats(*formats)
557 -        if @_content_type
558 -          raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
559 -        end
560 -        @_provided_formats = []
561 -        provides(*formats)
562 +      @_provided_formats = []
563 +      provides(*formats)
564 +    end
565 +    alias :_provided_formats= :_set_provided_formats   
566 +    
567 +    # Adds formats to the list of provided formats for this particular 
568 +    # request. Usually used to add formats to a single action. See also
569 +    # the controller-level provides that affects all actions in a controller.
570 +    #
571 +    # ==== Parameters
572 +    # *formats<Symbol>:: A list of formats to add to the per-action list
573 +    #                    of provided formats
574 +    #
575 +    # ==== Raises
576 +    # Merb::ResponderMixin::ContentTypeAlreadySet::
577 +    #   Content negotiation already occured, and the content_type is set.
578 +    #
579 +    # ==== Returns
580 +    # Array:: List of formats passed in
581 +    #
582 +    #---
583 +    # @public
584 +    def provides(*formats)
585 +      if @_content_type
586 +        raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
587        end
588 -      alias :_provided_formats= :_set_provided_formats   
589 -      
590 -      # Adds formats to the list of provided formats for this particular 
591 -      # request. Usually used to add formats to a single action. See also
592 -      # the controller-level provides that affects all actions in a controller.
593 -      #
594 -      # ==== Parameters
595 -      # *formats<Symbol>:: A list of formats to add to the per-action list
596 -      #                    of provided formats
597 -      #
598 -      # ==== Raises
599 -      # Merb::ResponderMixin::ContentTypeAlreadySet::
600 -      #   Content negotiation already occured, and the content_type is set.
601 -      #
602 -      # ==== Returns
603 -      # Array:: List of formats passed in
604 -      #
605 -      #---
606 -      # @public
607 -      def provides(*formats)
608 -        if @_content_type
609 -          raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
610 -        end
611 -        formats.each do |fmt|
612 -          _provided_formats << fmt unless _provided_formats.include?(fmt)
613 -        end
614 +      formats.each do |fmt|
615 +        _provided_formats << fmt unless _provided_formats.include?(fmt)
616        end
617 +    end
619 -      # Sets list of provided formats for this particular 
620 -      # request. Usually used to limit formats to a single action. See also
621 -      # the controller-level only_provides that affects all actions
622 -      # in a controller.      
623 -      # 
624 -      # ==== Parameters
625 -      # *formats<Symbol>:: A list of formats to use as the per-action list
626 -      #                    of provided formats
627 -      #
628 -      # ==== Returns
629 -      # Array:: List of formats passed in
630 -      #
631 -      #---
632 -      # @public
633 -      def only_provides(*formats)
634 -        self._provided_formats = *formats
635 -      end
636 -      
637 -      # Removes formats from the list of provided formats for this particular 
638 -      # request. Usually used to remove formats from a single action.  See
639 -      # also the controller-level does_not_provide that affects all actions in a
640 -      # controller.
641 -      #
642 -      # ==== Parameters
643 -      # *formats<Symbol>:: Registered mime-type
644 -      # 
645 -      # ==== Returns
646 -      # Array:: List of formats that remain after removing the ones not to provide
647 -      #
648 -      #---
649 -      # @public      
650 -      def does_not_provide(*formats)
651 -        formats.flatten!
652 -        self._provided_formats -= formats
653 -      end
654 -      
655 -      # Do the content negotiation:
656 -      # 1. if params[:format] is there, and provided, use it
657 -      # 2. Parse the Accept header
658 -      # 3. If it's */*, use the first provided format
659 -      # 4. Look for one that is provided, in order of request
660 -      # 5. Raise 406 if none found
661 -      def _perform_content_negotiation # :nodoc:
662 -        raise Merb::ControllerExceptions::NotAcceptable if provided_formats.empty?
663 -        if fmt = params[:format]
664 -          return fmt.to_sym if provided_formats.include?(fmt.to_sym)
665 -        else
666 -          accepts = Responder.parse(request.accept).map {|t| t.to_sym}
667 -          return provided_formats.first if accepts.include?(:all)
668 -          return accepts.each { |type| break type if provided_formats.include?(type) }
669 -        end
670 -        raise Merb::ControllerExceptions::NotAcceptable          
671 +    # Sets list of provided formats for this particular 
672 +    # request. Usually used to limit formats to a single action. See also
673 +    # the controller-level only_provides that affects all actions
674 +    # in a controller.      
675 +    # 
676 +    # ==== Parameters
677 +    # *formats<Symbol>:: A list of formats to use as the per-action list
678 +    #                    of provided formats
679 +    #
680 +    # ==== Returns
681 +    # Array:: List of formats passed in
682 +    #
683 +    #---
684 +    # @public
685 +    def only_provides(*formats)
686 +      self._provided_formats = *formats
687 +    end
688 +    
689 +    # Removes formats from the list of provided formats for this particular 
690 +    # request. Usually used to remove formats from a single action.  See
691 +    # also the controller-level does_not_provide that affects all actions in a
692 +    # controller.
693 +    #
694 +    # ==== Parameters
695 +    # *formats<Symbol>:: Registered mime-type
696 +    # 
697 +    # ==== Returns
698 +    # Array:: List of formats that remain after removing the ones not to provide
699 +    #
700 +    #---
701 +    # @public      
702 +    def does_not_provide(*formats)
703 +      formats.flatten!
704 +      self._provided_formats -= formats
705 +    end
706 +    
707 +    # Do the content negotiation:
708 +    # 1. if params[:format] is there, and provided, use it
709 +    # 2. Parse the Accept header
710 +    # 3. If it's */*, use the first provided format
711 +    # 4. Look for one that is provided, in order of request
712 +    # 5. Raise 406 if none found
713 +    def _perform_content_negotiation # :nodoc:
714 +      raise Merb::ControllerExceptions::NotAcceptable if _provided_formats.empty?
715 +      if fmt = params[:format] && _provided_formats.include?(fmt.to_sym)
716 +        return fmt.to_sym
717        end
718 +      accepts = Responder.parse(request.accept).map {|t| t.to_sym}
719 +      return _provided_formats.first if accepts.include?(:all)
720 +      (accepts & _provided_formats).first || (raise Merb::ControllerExceptions::NotAcceptable)
721 +    end
723 -      # Returns the output format for this request, based on the 
724 -      # provided formats, <tt>params[:format]</tt> and the client's HTTP
725 -      # Accept header.
726 -      #
727 -      # The first time this is called, it triggers content negotiation
728 -      # and caches the value.  Once you call +content_type+ you can
729 -      # not set or change the list of provided formats.
730 -      #
731 -      # Called automatically by +render+, so you should only call it if
732 -      # you need the value, not to trigger content negotiation. 
733 -      # 
734 -      # ==== Parameters
735 -      # fmt<String?>:: 
736 -      #   An optional format to use instead of performing content negotiation.
737 -      #   This can be used to pass in the values of opts[:format] from the 
738 -      #   render function to short-circuit content-negotiation when it's not
739 -      #   necessary. This optional parameter should not be considered part
740 -      #   of the public API.
741 -      #
742 -      # ==== Returns
743 -      # Symbol:: The content-type that will be used for this controller.
744 -      #
745 -      #---
746 -      # @public
747 -      def content_type(fmt = nil)
748 -        self.content_type = (fmt || _perform_content_negotiation) unless @_content_type
749 -        @_content_type
750 +    # Returns the output format for this request, based on the 
751 +    # provided formats, <tt>params[:format]</tt> and the client's HTTP
752 +    # Accept header.
753 +    #
754 +    # The first time this is called, it triggers content negotiation
755 +    # and caches the value.  Once you call +content_type+ you can
756 +    # not set or change the list of provided formats.
757 +    #
758 +    # Called automatically by +render+, so you should only call it if
759 +    # you need the value, not to trigger content negotiation. 
760 +    # 
761 +    # ==== Parameters
762 +    # fmt<String?>:: 
763 +    #   An optional format to use instead of performing content negotiation.
764 +    #   This can be used to pass in the values of opts[:format] from the 
765 +    #   render function to short-circuit content-negotiation when it's not
766 +    #   necessary. This optional parameter should not be considered part
767 +    #   of the public API.
768 +    #
769 +    # ==== Returns
770 +    # Symbol:: The content-type that will be used for this controller.
771 +    #
772 +    #---
773 +    # @public
774 +    def content_type(fmt = nil)
775 +      @_content_type = (fmt || _perform_content_negotiation) unless @_content_type
776 +      @_content_type
777 +    end
778 +    
779 +    # Sets the content type of the current response to a value based on 
780 +    # a passed in key. The Content-Type header will be set to the first
781 +    # registered header for the mime-type.
782 +    #
783 +    # ==== Parameters
784 +    # type<Symbol>:: A type that is in the list of registered mime-types.
785 +    #
786 +    # ==== Raises
787 +    # ArgumentError:: "type" is not in the list of registered mime-types.
788 +    #
789 +    # ==== Returns
790 +    # Symbol:: The content-type that was passed in.
791 +    #
792 +    #---
793 +    # @semipublic
794 +    def content_type=(type)
795 +      unless Merb.available_mime_types.has_key?(type)
796 +        raise Merb::ControllerExceptions::NotAcceptable.new("Unknown content_type for response: #{type}") 
797 +      end        
798 +      headers['Content-Type'] = Merb.available_mime_types[type].first        
799 +      @_content_type = type
800 +    end
801 +    
802 +  end
804 +  class Responder
805 +  
806 +    protected
807 +    def self.parse(accept_header)
808 +      # parse the raw accept header into a unique, sorted array of AcceptType objects
809 +      list = accept_header.to_s.split(/,/).enum_for(:each_with_index).map do |entry,index|
810 +        AcceptType.new(entry,index += 1)
811 +      end.sort.uniq
812 +      # firefox (and possibly other browsers) send broken default accept headers.
813 +      # fix them up by sorting alternate xml forms (namely application/xhtml+xml)
814 +      # ahead of pure xml types (application/xml,text/xml).
815 +      if app_xml = list.detect{|e| e.super_range == 'application/xml'}
816 +        list.select{|e| e.to_s =~ /\+xml/}.each { |acc_type|
817 +          list[list.index(acc_type)],list[list.index(app_xml)] = 
818 +            list[list.index(app_xml)],list[list.index(acc_type)] }
819        end
820 -      
821 -      # Sets the content type of the current response to a value based on 
822 -      # a passed in key. The Content-Type header will be set to the first
823 -      # registered header for the mime-type.
824 -      #
825 -      # ==== Parameters
826 -      # type<Symbol>:: A type that is in the list of registered mime-types.
827 -      #
828 -      # ==== Raises
829 -      # ArgumentError:: "type" is not in the list of registered mime-types.
830 -      #
831 -      # ==== Returns
832 -      # Symbol:: The content-type that was passed in.
833 -      #
834 -      #---
835 -      # @semipublic
836 -      def content_type=(type)
837 -        unless Merb.available_mime_types.has_key?(type)
838 -          raise Merb::ControllerExceptions::NotAcceptable.new("Unknown content_type for response: #{type}") 
839 -        end        
840 -        headers['Content-Type'] = Merb.available_mime_types[type].first        
841 -        @_content_type = type
842 +      list
843 +    end
844 +    
845 +    public
846 +    def self.params_to_query_string(value, prefix = nil)
847 +      case value
848 +      when Array
849 +        value.map { |v|
850 +          params_to_query_string(v, "#{prefix}[]")
851 +        } * "&"
852 +      when Hash
853 +        value.map { |k, v|
854 +          params_to_query_string(v, prefix ? "#{prefix}[#{Merb::Request.escape(k)}]" : Merb::Request.escape(k))
855 +        } * "&"
856 +      else
857 +        "#{prefix}=#{Merb::Request.escape(value)}"
858        end
859 +    end      
860        
861 -    end
862 +  end
864 +  class AcceptType
866 +    attr_reader :media_range, :quality, :index, :type, :sub_type
867      
868 +    def initialize(entry,index)
869 +      @index = index
870 +      @media_range, quality = entry.split(/;\s*q=/).map{|a| a.strip }
871 +      @type, @sub_type = @media_range.split(/\//)
872 +      quality ||= 0.0 if @media_range == '*/*'
873 +      @quality = ((quality || 1.0).to_f * 100).to_i
874 +    end
875 +  
876 +    def <=>(entry)
877 +      c = entry.quality <=> quality
878 +      c = index <=> entry.index if c == 0
879 +      c
880 +    end
881 +  
882 +    def eql?(entry)
883 +      synonyms.include?(entry.media_range)
884 +    end
885 +  
886 +    def ==(entry); eql?(entry); end
887 +  
888 +    def hash; super_range.hash; end
889 +  
890 +    def synonyms
891 +      @syns ||= Merb.available_mime_types.values.map do |e| 
892 +        e[:request_headers] if e[:request_headers].include?(@media_range)
893 +      end.compact.flatten
894 +    end
895 +  
896 +    def super_range
897 +      synonyms.first || @media_range
898 +    end
899 +  
900 +    def to_sym
901 +      Merb.available_mime_types.select{|k,v| 
902 +        v[:request_headers] == synonyms || v[:request_headers][0] == synonyms[0]}.flatten.first
903 +    end
904 +  
905 +    def to_s
906 +      @media_range
907 +    end
908 +  
909    end
911      
912  end
913 \ No newline at end of file
914 diff --git a/lib/merb_core/dispatch/dispatcher.rb b/lib/merb_core/dispatch/dispatcher.rb
915 index c458c9f9ad454d3b0c3055d6b2a8e88b17712b44..f7fed0f539a20f9cce08b72c551725ad0563bf37 100644
916 --- a/lib/merb_core/dispatch/dispatcher.rb
917 +++ b/lib/merb_core/dispatch/dispatcher.rb
918 @@ -33,10 +33,10 @@ class Merb::Dispatcher
920      # this is the custom dispatch_exception; it allows failures to still be dispatched
921      # to the error controller
922 -    rescue => exception
923 -      Merb.logger.error(Merb.exception(exception))
924 -      exception = controller_exception(exception)
925 -      dispatch_exception(request, response, exception)
926 +    # rescue => exception
927 +    #   Merb.logger.error(Merb.exception(exception))
928 +    #   exception = controller_exception(exception)
929 +    #   dispatch_exception(request, response, exception)
930      end
931      
932      private
933 @@ -49,10 +49,10 @@ class Merb::Dispatcher
934      def dispatch_action(klass, action, request, response, status=200)
935        # build controller
936        controller = klass.build(request, response, status)
937 -      if @@use_mutex
938 -        @@mutex.synchronize { controller.dispatch(action) }
939 +      if use_mutex
940 +        @@mutex.synchronize { controller._dispatch(action) }
941        else
942 -        controller.dispatch(action)
943 +        controller._dispatch(action)
944        end
945        [controller, action]
946      end
947 diff --git a/lib/merb_core/rack/adapter.rb b/lib/merb_core/rack/adapter.rb
948 index ffc7117e9733e83b0567bbe4a43fac7663800b7d..217399a5382d0b3878aaea3d3e302173c5b5f119 100644
949 --- a/lib/merb_core/rack/adapter.rb
950 +++ b/lib/merb_core/rack/adapter.rb
951 @@ -40,7 +40,7 @@ module Merb
952          begin
953            controller, action = ::Merb::Dispatcher.handle(request, response)
954          rescue Object => e
955 -          return [500, {"Content-Type"=>"text/html"}, "Internal Server Error"]
956 +          return [500, {"Content-Type"=>"text/html"}, e.message + "<br/>" + e.backtrace.join("<br/>")]
957          end
958          [controller.status, controller.headers, controller.body]
959        end
960 diff --git a/lib/merb_core/test/request_helper.rb b/lib/merb_core/test/request_helper.rb
961 index 10a9fb3ace56eaf1db0fa300df3fb2ab88a7118a..f302a3b71539182ba142cd208fe6d6aae171b1a1 100644
962 --- a/lib/merb_core/test/request_helper.rb
963 +++ b/lib/merb_core/test/request_helper.rb
964 @@ -26,8 +26,10 @@ module Merb::Test::RequestHelper
965      Merb::Test::FakeRequest.new(env, StringIO.new(req))
966    end
967    
968 -  def dispatch_to(controller_klass, action, env = {}, opt = {}, &blk)
969 -    request = fake_request(env, opt)
970 +  def dispatch_to(controller_klass, action, params = {}, env = {}, &blk)
971 +    request = fake_request(env, 
972 +      :query_string => Merb::Responder.params_to_query_string(params))
974      controller = controller_klass.build(request)
975      controller.instance_eval(&blk) if block_given?
976      controller._dispatch(action)
977 diff --git a/spec/public/abstract_controller/spec_helper.rb b/spec/public/abstract_controller/spec_helper.rb
978 index df759008d14e7572b5c44de24f77f828f83f1682..694cee2592a210a5c1fa40ca7846beeaa09725fe 100644
979 --- a/spec/public/abstract_controller/spec_helper.rb
980 +++ b/spec/public/abstract_controller/spec_helper.rb
981 @@ -1,12 +1,10 @@
982  __DIR__ = File.dirname(__FILE__)
983  require File.join(__DIR__, "..", "..", "spec_helper")
985 -# The framework structure *must* be set up before loading in framework
986 -# files.
987  require File.join(__DIR__, "controllers", "filters")
988  require File.join(__DIR__, "controllers", "render")
990 -Merb::BootLoader::Templates.new.run
991 +Merb::BootLoader::Templates.run
993  module Merb::Test::Behaviors
994    def dispatch_should_make_body(klass, body, action = :index)
995 diff --git a/spec/public/controller/base_spec.rb b/spec/public/controller/base_spec.rb
996 index 1709e612629ed2c2b6af4579a8b89684aca9aa3c..5bcdb59948cc22592639b1aee9bd233ff2c306fa 100644
997 --- a/spec/public/controller/base_spec.rb
998 +++ b/spec/public/controller/base_spec.rb
999 @@ -10,11 +10,11 @@ describe Merb::Controller, " callable actions" do
1000    end
1001    
1002    it "should dispatch to callable actions" do
1003 -    dispatch_to(Merb::Test::Fixtures::TestFoo, :index).body.should == "index"
1004 +    dispatch_to(Merb::Test::Fixtures::TestBase, :index).body.should == "index"
1005    end
1007    it "should not dispatch to hidden actions" do
1008 -    calling { dispatch_to(Merb::Test::Fixtures::TestFoo, :hidden) }.
1009 +    calling { dispatch_to(Merb::Test::Fixtures::TestBase, :hidden) }.
1010        should raise_error(Merb::ControllerExceptions::ActionNotFound)
1011    end
1012      
1013 diff --git a/spec/public/controller/controllers/base.rb b/spec/public/controller/controllers/base.rb
1014 index a1b3beb27899df781d943427d9b23945f02e14de..c4b69a440a9da3c3486208d2cb95ccb8bdb974b9 100644
1015 --- a/spec/public/controller/controllers/base.rb
1016 +++ b/spec/public/controller/controllers/base.rb
1017 @@ -3,7 +3,7 @@ module Merb::Test::Fixtures
1018      self._template_root = File.dirname(__FILE__) / "views"
1019    end
1020    
1021 -  class TestFoo < ControllerTesting
1022 +  class TestBase < ControllerTesting
1023      def index
1024        "index"
1025      end
1026 diff --git a/spec/public/controller/controllers/responder.rb b/spec/public/controller/controllers/responder.rb
1027 new file mode 100644
1028 index 0000000000000000000000000000000000000000..867192e8f6e995a43fd5cd3daffa0ec11b3d31e5
1029 --- /dev/null
1030 +++ b/spec/public/controller/controllers/responder.rb
1031 @@ -0,0 +1,25 @@
1032 +module Merb::Test::Fixtures
1033 +  class ControllerTesting < Merb::Controller
1034 +    self._template_root = File.dirname(__FILE__) / "views"
1035 +  end
1036 +  
1037 +  class TestResponder < ControllerTesting
1038 +    def index
1039 +      render
1040 +    end
1041 +  end
1042 +  
1043 +  class TestHtmlDefault < TestResponder; end
1044 +  
1045 +  class TestClassProvides < TestResponder; 
1046 +    provides :xml
1047 +  end
1048 +  
1049 +  class TestLocalProvides < TestResponder; 
1050 +    def index
1051 +      provides :xml
1052 +      render
1053 +    end
1054 +  end
1055 +  
1056 +end
1057 \ No newline at end of file
1058 diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.html.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.html.erb
1059 new file mode 100644
1060 index 0000000000000000000000000000000000000000..1bfb77d4a44c444bba6888ae7740f7df4b074c58
1061 --- /dev/null
1062 +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.html.erb
1063 @@ -0,0 +1 @@
1064 +This should not be rendered
1065 \ No newline at end of file
1066 diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.xml.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.xml.erb
1067 new file mode 100644
1068 index 0000000000000000000000000000000000000000..7c91f633987348e87e5e34e1d9e87d9dd0e5100c
1069 --- /dev/null
1070 +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.xml.erb
1071 @@ -0,0 +1 @@
1072 +<XML:Class provides='true' />
1073 \ No newline at end of file
1074 diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_html_default/index.html.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_html_default/index.html.erb
1075 new file mode 100644
1076 index 0000000000000000000000000000000000000000..eb4b52bf5a7aaba8f1706de419f42789c05684a2
1077 --- /dev/null
1078 +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_html_default/index.html.erb
1079 @@ -0,0 +1 @@
1080 +HTML: Default
1081 \ No newline at end of file
1082 diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.html.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.html.erb
1083 new file mode 100644
1084 index 0000000000000000000000000000000000000000..a3a841a89c62e6174038935a42da9cd24ff54413
1085 --- /dev/null
1086 +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.html.erb
1087 @@ -0,0 +1 @@
1088 +This should not render
1089 \ No newline at end of file
1090 diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.xml.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.xml.erb
1091 new file mode 100644
1092 index 0000000000000000000000000000000000000000..c1384ec6af0357b585cc367035d1bc3a30347ade
1093 --- /dev/null
1094 +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.xml.erb
1095 @@ -0,0 +1 @@
1096 +<XML:Local provides='true' />
1097 \ No newline at end of file
1098 diff --git a/spec/public/controller/responder_spec.rb b/spec/public/controller/responder_spec.rb
1099 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bcf18532442e5965cf6ca8501770d7b7a1eb2429 100644
1100 --- a/spec/public/controller/responder_spec.rb
1101 +++ b/spec/public/controller/responder_spec.rb
1102 @@ -0,0 +1,31 @@
1103 +require File.join(File.dirname(__FILE__), "spec_helper")
1105 +describe Merb::Controller, " responds" do
1106 +  
1107 +  before do
1108 +    Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")    
1109 +    Merb::Router.prepare do |r|
1110 +      r.default_routes
1111 +    end
1112 +  end
1113 +  
1114 +  it "should default the mime-type to HTML" do
1115 +    dispatch_to(Merb::Test::Fixtures::TestHtmlDefault, :index).body.should == "HTML: Default"
1116 +  end
1118 +  it "should use other mime-types if they are provided on the class level" do
1119 +    controller = dispatch_to(Merb::Test::Fixtures::TestClassProvides, :index, {}, :http_accept => "application/xml")
1120 +    controller.body.should == "<XML:Class provides='true' />"
1121 +  end
1123 +  it "should fail if none of the acceptable mime-types are available" do
1124 +    calling { dispatch_to(Merb::Test::Fixtures::TestClassProvides, :index, {}, :http_accept => "application/json") }.
1125 +      should raise_error(Merb::ControllerExceptions::NotAcceptable)
1126 +  end
1127 +  
1128 +  it "should use mime-types that are provided at the local level" do
1129 +    controller = dispatch_to(Merb::Test::Fixtures::TestLocalProvides, :index, {}, :http_accept => "application/xml")
1130 +    controller.body.should == "<XML:Local provides='true' />"    
1131 +  end
1132 +    
1133 +end
1134 \ No newline at end of file
1135 diff --git a/spec/public/controller/spec_helper.rb b/spec/public/controller/spec_helper.rb
1136 index f68628a63740f4ce0235a15d71c5889e55ecaf78..e360194c1fbaf72c3298c61543c2d3a19b512b41 100644
1137 --- a/spec/public/controller/spec_helper.rb
1138 +++ b/spec/public/controller/spec_helper.rb
1139 @@ -1,4 +1,10 @@
1140  __DIR__ = File.dirname(__FILE__)
1141 +require 'ruby-debug'
1143  require File.join(__DIR__, "..", "..", "spec_helper")
1145 -require File.join(__DIR__, "controllers", "base")
1146 \ No newline at end of file
1147 +require File.join(__DIR__, "controllers", "base")
1148 +require File.join(__DIR__, "controllers", "responder")
1150 +Merb::BootLoader::Templates.run
1151 +Merb::BootLoader::MimeTypes.run
1152 \ No newline at end of file