roda 1.3.0 → 2.0.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -4
- data/doc/release_notes/2.0.0.txt +75 -0
- data/lib/roda/plugins/assets.rb +2 -2
- data/lib/roda/plugins/backtracking_array.rb +2 -11
- data/lib/roda/plugins/caching.rb +4 -2
- data/lib/roda/plugins/chunked.rb +4 -9
- data/lib/roda/plugins/class_level_routing.rb +1 -3
- data/lib/roda/plugins/default_headers.rb +1 -2
- data/lib/roda/plugins/error_email.rb +4 -14
- data/lib/roda/plugins/error_handler.rb +4 -4
- data/lib/roda/plugins/flash.rb +1 -3
- data/lib/roda/plugins/halt.rb +24 -5
- data/lib/roda/plugins/header_matchers.rb +2 -7
- data/lib/roda/plugins/hooks.rb +1 -3
- data/lib/roda/plugins/json.rb +4 -2
- data/lib/roda/plugins/mailer.rb +8 -7
- data/lib/roda/plugins/middleware.rb +21 -9
- data/lib/roda/plugins/not_found.rb +3 -3
- data/lib/roda/plugins/padrino_render.rb +60 -0
- data/lib/roda/plugins/param_matchers.rb +3 -3
- data/lib/roda/plugins/path.rb +2 -1
- data/lib/roda/plugins/render.rb +55 -37
- data/lib/roda/plugins/render_each.rb +4 -2
- data/lib/roda/plugins/static_path_info.rb +2 -63
- data/lib/roda/plugins/streaming.rb +4 -2
- data/lib/roda/version.rb +2 -2
- data/lib/roda.rb +71 -172
- data/spec/matchers_spec.rb +31 -82
- data/spec/plugin/assets_spec.rb +6 -6
- data/spec/plugin/error_handler_spec.rb +23 -0
- data/spec/plugin/halt_spec.rb +39 -0
- data/spec/plugin/middleware_spec.rb +7 -0
- data/spec/plugin/padrino_render_spec.rb +57 -0
- data/spec/plugin/render_each_spec.rb +1 -1
- data/spec/plugin/render_spec.rb +59 -5
- data/spec/request_spec.rb +0 -12
- data/spec/response_spec.rb +0 -24
- data/spec/views/_test.erb +1 -0
- metadata +7 -4
- data/lib/roda/plugins/delete_nil_headers.rb +0 -34
- data/spec/module_spec.rb +0 -29
    
        data/lib/roda.rb
    CHANGED
    
    | @@ -59,18 +59,6 @@ class Roda | |
| 59 59 | 
             
              @opts = {}
         | 
| 60 60 | 
             
              @route_block = nil
         | 
| 61 61 |  | 
| 62 | 
            -
              module RodaDeprecateMutation
         | 
| 63 | 
            -
                [:[]=, :clear, :compare_by_identity, :default=, :default_proc=, :delete, :delete_if,
         | 
| 64 | 
            -
                 :keep_if, :merge!, :reject!, :replace, :select!, :shift, :store, :update].each do |m|
         | 
| 65 | 
            -
                  class_eval(<<-END, __FILE__, __LINE__+1)
         | 
| 66 | 
            -
                    def #{m}(*)
         | 
| 67 | 
            -
                      RodaPlugins.deprecate("Mutating this hash (\#{inspect}) via the #{m} method is deprecated, this hash will be frozen in Roda 2.")
         | 
| 68 | 
            -
                      super
         | 
| 69 | 
            -
                    end
         | 
| 70 | 
            -
                  END
         | 
| 71 | 
            -
                end
         | 
| 72 | 
            -
              end
         | 
| 73 | 
            -
             | 
| 74 62 | 
             
              # Module in which all Roda plugins should be stored. Also contains logic for
         | 
| 75 63 | 
             
              # registering and loading plugins.
         | 
| 76 64 | 
             
              module RodaPlugins
         | 
| @@ -98,12 +86,6 @@ class Roda | |
| 98 86 | 
             
                  @plugins[name] = mod
         | 
| 99 87 | 
             
                end
         | 
| 100 88 |  | 
| 101 | 
            -
                # Emit a deprecation message.  By default this just calls warn.  You can override this
         | 
| 102 | 
            -
                # method to log deprecation messages to a file or include backtraces (or something else).
         | 
| 103 | 
            -
                def self.deprecate(msg)
         | 
| 104 | 
            -
                  warn(msg)
         | 
| 105 | 
            -
                end
         | 
| 106 | 
            -
             | 
| 107 89 | 
             
                # The base plugin for Roda, implementing all default functionality.
         | 
| 108 90 | 
             
                # Methods are put into a plugin so future plugins can easily override
         | 
| 109 91 | 
             
                # them and call super to get the default behavior.
         | 
| @@ -151,11 +133,6 @@ class Roda | |
| 151 133 | 
             
                      super
         | 
| 152 134 | 
             
                    end
         | 
| 153 135 |  | 
| 154 | 
            -
                    def hash_matcher(key, &block)
         | 
| 155 | 
            -
                      RodaPlugins.deprecate("Roda.hash_matcher is deprecated and will be removed in Roda 2.  It has been moved to the hash_matcher plugin.")
         | 
| 156 | 
            -
                      self::RodaRequest.send(:define_method, :"match_#{key}", &block)
         | 
| 157 | 
            -
                    end
         | 
| 158 | 
            -
             | 
| 159 136 | 
             
                    # When inheriting Roda, copy the shared data into the subclass,
         | 
| 160 137 | 
             
                    # and setup the request and response subclasses.
         | 
| 161 138 | 
             
                    def inherited(subclass)
         | 
| @@ -167,9 +144,6 @@ class Roda | |
| 167 144 | 
             
                      subclass.opts.to_a.each do |k,v|
         | 
| 168 145 | 
             
                        if (v.is_a?(Array) || v.is_a?(Hash)) && !v.frozen?
         | 
| 169 146 | 
             
                          subclass.opts[k] = v.dup
         | 
| 170 | 
            -
                          if v.is_a?(RodaDeprecateMutation)
         | 
| 171 | 
            -
                            subclass.opts[k].extend(RodaDeprecateMutation)
         | 
| 172 | 
            -
                          end
         | 
| 173 147 | 
             
                        end
         | 
| 174 148 | 
             
                      end
         | 
| 175 149 | 
             
                      subclass.instance_variable_set(:@route_block, @route_block)
         | 
| @@ -204,16 +178,6 @@ class Roda | |
| 204 178 | 
             
                      plugin.configure(self, *args, &block) if plugin.respond_to?(:configure)
         | 
| 205 179 | 
             
                    end
         | 
| 206 180 |  | 
| 207 | 
            -
                    def request_module(mod = nil, &block)
         | 
| 208 | 
            -
                      RodaPlugins.deprecate("Roda.request_module is deprecated and will be removed in Roda 2.  It has been moved to the module_include plugin.")
         | 
| 209 | 
            -
                      module_include(:request, mod, &block)
         | 
| 210 | 
            -
                    end
         | 
| 211 | 
            -
                
         | 
| 212 | 
            -
                    def response_module(mod = nil, &block)
         | 
| 213 | 
            -
                      RodaPlugins.deprecate("Roda.response_module is deprecated and will be removed in Roda 2.  It has been moved to the module_include plugin.")
         | 
| 214 | 
            -
                      module_include(:response, mod, &block)
         | 
| 215 | 
            -
                    end
         | 
| 216 | 
            -
             | 
| 217 181 | 
             
                    # Setup routing tree for the current Roda application, and build the
         | 
| 218 182 | 
             
                    # underlying rack application using the stored middleware. Requires
         | 
| 219 183 | 
             
                    # a block, which is yielded the request.  By convention, the block
         | 
| @@ -254,49 +218,37 @@ class Roda | |
| 254 218 | 
             
                      if block = @route_block
         | 
| 255 219 | 
             
                        builder = Rack::Builder.new
         | 
| 256 220 | 
             
                        @middleware.each{|a, b| builder.use(*a, &b)}
         | 
| 257 | 
            -
                        builder.run lambda{|env|  | 
| 221 | 
            +
                        builder.run lambda{|env| new(env).call(&block)}
         | 
| 258 222 | 
             
                        @app = builder.to_app
         | 
| 259 223 | 
             
                      end
         | 
| 260 224 | 
             
                    end
         | 
| 261 | 
            -
             | 
| 262 | 
            -
                    # REMOVE20
         | 
| 263 | 
            -
                    def module_include(type, mod)
         | 
| 264 | 
            -
                      if type == :response
         | 
| 265 | 
            -
                        klass = self::RodaResponse
         | 
| 266 | 
            -
                        iv = :@response_module
         | 
| 267 | 
            -
                      else
         | 
| 268 | 
            -
                        klass = self::RodaRequest
         | 
| 269 | 
            -
                        iv = :@request_module
         | 
| 270 | 
            -
                      end
         | 
| 271 | 
            -
             | 
| 272 | 
            -
                      if mod
         | 
| 273 | 
            -
                        raise RodaError, "can't provide both argument and block to response_module" if block_given?
         | 
| 274 | 
            -
                        klass.send(:include, mod)
         | 
| 275 | 
            -
                      else
         | 
| 276 | 
            -
                        if instance_variable_defined?(iv)
         | 
| 277 | 
            -
                          mod = instance_variable_get(iv)
         | 
| 278 | 
            -
                        else
         | 
| 279 | 
            -
                          mod = instance_variable_set(iv, Module.new)
         | 
| 280 | 
            -
                          klass.send(:include, mod)
         | 
| 281 | 
            -
                        end
         | 
| 282 | 
            -
             | 
| 283 | 
            -
                        mod.module_eval(&Proc.new) if block_given?
         | 
| 284 | 
            -
                      end
         | 
| 285 | 
            -
             | 
| 286 | 
            -
                      mod
         | 
| 287 | 
            -
                    end
         | 
| 288 225 | 
             
                  end
         | 
| 289 226 |  | 
| 290 227 | 
             
                  # Instance methods for the Roda class.
         | 
| 228 | 
            +
                  #
         | 
| 229 | 
            +
                  # In addition to the listed methods, the following two methods are available:
         | 
| 230 | 
            +
                  #
         | 
| 231 | 
            +
                  # request :: The instance of the request class related to this request.
         | 
| 232 | 
            +
                  #            This is the same object yielded by Roda.route.
         | 
| 233 | 
            +
                  # response :: The instance of the response class related to this request.
         | 
| 291 234 | 
             
                  module InstanceMethods
         | 
| 292 | 
            -
                    # Create a request and response of the appopriate
         | 
| 293 | 
            -
                     | 
| 294 | 
            -
             | 
| 295 | 
            -
             | 
| 296 | 
            -
             | 
| 297 | 
            -
             | 
| 298 | 
            -
             | 
| 299 | 
            -
             | 
| 235 | 
            +
                    # Create a request and response of the appopriate class
         | 
| 236 | 
            +
                    def initialize(env)
         | 
| 237 | 
            +
                      klass = self.class
         | 
| 238 | 
            +
                      @_request = klass::RodaRequest.new(self, env)
         | 
| 239 | 
            +
                      @_response = klass::RodaResponse.new
         | 
| 240 | 
            +
                    end
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                    # instance_exec the route block in the scope of the
         | 
| 243 | 
            +
                    # receiver, with the related request.  Catch :halt so that
         | 
| 244 | 
            +
                    # the route block can throw :halt at any point with the
         | 
| 245 | 
            +
                    # rack response to use.
         | 
| 246 | 
            +
                    def call(&block)
         | 
| 247 | 
            +
                      catch(:halt) do
         | 
| 248 | 
            +
                        r = @_request
         | 
| 249 | 
            +
                        r.block_result(instance_exec(r, &block))
         | 
| 250 | 
            +
                        @_response.finish
         | 
| 251 | 
            +
                      end
         | 
| 300 252 | 
             
                    end
         | 
| 301 253 |  | 
| 302 254 | 
             
                    # The environment hash for the current request. Example:
         | 
| @@ -317,16 +269,13 @@ class Roda | |
| 317 269 | 
             
                      self.class.opts
         | 
| 318 270 | 
             
                    end
         | 
| 319 271 |  | 
| 320 | 
            -
                     | 
| 321 | 
            -
                     | 
| 322 | 
            -
                     | 
| 323 | 
            -
                      @_request
         | 
| 324 | 
            -
                    end
         | 
| 272 | 
            +
                    attr_reader :_request # :nodoc:
         | 
| 273 | 
            +
                    alias request _request
         | 
| 274 | 
            +
                    remove_method :_request
         | 
| 325 275 |  | 
| 326 | 
            -
                     | 
| 327 | 
            -
                     | 
| 328 | 
            -
             | 
| 329 | 
            -
                    end
         | 
| 276 | 
            +
                    attr_reader :_response # :nodoc:
         | 
| 277 | 
            +
                    alias response _response
         | 
| 278 | 
            +
                    remove_method :_response
         | 
| 330 279 |  | 
| 331 280 | 
             
                    # The session hash for the current request. Raises RodaError
         | 
| 332 281 | 
             
                    # if no session exists. Example:
         | 
| @@ -335,18 +284,6 @@ class Roda | |
| 335 284 | 
             
                    def session
         | 
| 336 285 | 
             
                      @_request.session
         | 
| 337 286 | 
             
                    end
         | 
| 338 | 
            -
             | 
| 339 | 
            -
                    private
         | 
| 340 | 
            -
             | 
| 341 | 
            -
                    # Internals of #call, extracted so that plugins can override
         | 
| 342 | 
            -
                    # behavior after the request and response have been setup.
         | 
| 343 | 
            -
                    def _route(&block)
         | 
| 344 | 
            -
                      catch(:halt) do
         | 
| 345 | 
            -
                        r = @_request
         | 
| 346 | 
            -
                        r.block_result(instance_exec(r, &block))
         | 
| 347 | 
            -
                        @_response.finish
         | 
| 348 | 
            -
                      end
         | 
| 349 | 
            -
                    end
         | 
| 350 287 | 
             
                  end
         | 
| 351 288 |  | 
| 352 289 | 
             
                  # Class methods for RodaRequest
         | 
| @@ -418,6 +355,7 @@ class Roda | |
| 418 355 | 
             
                    def initialize(scope, env)
         | 
| 419 356 | 
             
                      @scope = scope
         | 
| 420 357 | 
             
                      @captures = []
         | 
| 358 | 
            +
                      @remaining_path = env[PATH_INFO]
         | 
| 421 359 | 
             
                      super(env)
         | 
| 422 360 | 
             
                    end
         | 
| 423 361 |  | 
| @@ -465,7 +403,7 @@ class Roda | |
| 465 403 | 
             
                    # executed, and when the match block returns, the rack response is
         | 
| 466 404 | 
             
                    # returned.
         | 
| 467 405 | 
             
                    # 
         | 
| 468 | 
            -
                    #   r. | 
| 406 | 
            +
                    #   r.remaining_path
         | 
| 469 407 | 
             
                    #   # => "/foo/bar"
         | 
| 470 408 | 
             
                    #
         | 
| 471 409 | 
             
                    #   r.is 'foo' do
         | 
| @@ -487,7 +425,7 @@ class Roda | |
| 487 425 | 
             
                    # Note that this matches only if the path after matching the arguments
         | 
| 488 426 | 
             
                    # is empty, not if it still contains a trailing slash:
         | 
| 489 427 | 
             
                    #
         | 
| 490 | 
            -
                    #   r. | 
| 428 | 
            +
                    #   r.remaining_path
         | 
| 491 429 | 
             
                    #   # =>  "/foo/bar/"
         | 
| 492 430 | 
             
                    #
         | 
| 493 431 | 
             
                    #   r.is 'foo/bar' do
         | 
| @@ -526,7 +464,7 @@ class Roda | |
| 526 464 | 
             
                    # path, this is usually used to setup branches of the routing tree,
         | 
| 527 465 | 
             
                    # not for final handling of the request.
         | 
| 528 466 | 
             
                    # 
         | 
| 529 | 
            -
                    #   r. | 
| 467 | 
            +
                    #   r.remaining_path
         | 
| 530 468 | 
             
                    #   # => "/foo/bar"
         | 
| 531 469 | 
             
                    #
         | 
| 532 470 | 
             
                    #   r.on 'foo' do
         | 
| @@ -558,7 +496,8 @@ class Roda | |
| 558 496 |  | 
| 559 497 | 
             
                    # The already matched part of the path, including the original SCRIPT_NAME.
         | 
| 560 498 | 
             
                    def matched_path
         | 
| 561 | 
            -
                      @env | 
| 499 | 
            +
                      e = @env
         | 
| 500 | 
            +
                      e[SCRIPT_NAME] + e[PATH_INFO].chomp(@remaining_path)
         | 
| 562 501 | 
             
                    end
         | 
| 563 502 |  | 
| 564 503 | 
             
                    # This an an optimized version of Rack::Request#path.
         | 
| @@ -572,16 +511,8 @@ class Roda | |
| 572 511 | 
             
                      "#{e[SCRIPT_NAME]}#{e[PATH_INFO]}"
         | 
| 573 512 | 
             
                    end
         | 
| 574 513 |  | 
| 575 | 
            -
                     | 
| 576 | 
            -
             | 
| 577 | 
            -
                      path
         | 
| 578 | 
            -
                    end
         | 
| 579 | 
            -
             | 
| 580 | 
            -
                    # The current path to match requests against.  This is the same as PATH_INFO
         | 
| 581 | 
            -
                    # in the environment, which gets updated as the request is being routed.
         | 
| 582 | 
            -
                    def remaining_path
         | 
| 583 | 
            -
                      @env[PATH_INFO]
         | 
| 584 | 
            -
                    end
         | 
| 514 | 
            +
                    # The current path to match requests against.
         | 
| 515 | 
            +
                    attr_reader :remaining_path
         | 
| 585 516 |  | 
| 586 517 | 
             
                    # Match POST requests.  If no arguments are provided, matches all POST
         | 
| 587 518 | 
             
                    # requests, otherwise, matches only POST requests where the arguments
         | 
| @@ -637,7 +568,7 @@ class Roda | |
| 637 568 | 
             
                    # path is +/+.  If it matches, the match block is executed, and when
         | 
| 638 569 | 
             
                    # the match block returns, the rack response is returned.
         | 
| 639 570 | 
             
                    #
         | 
| 640 | 
            -
                    #   [r.request_method, r. | 
| 571 | 
            +
                    #   [r.request_method, r.remaining_path]
         | 
| 641 572 | 
             
                    #   # => ['GET', '/']
         | 
| 642 573 | 
             
                    #
         | 
| 643 574 | 
             
                    #   r.root do
         | 
| @@ -646,7 +577,7 @@ class Roda | |
| 646 577 | 
             
                    #
         | 
| 647 578 | 
             
                    # This is usuable inside other match blocks:
         | 
| 648 579 | 
             
                    #
         | 
| 649 | 
            -
                    #   [r.request_method, r. | 
| 580 | 
            +
                    #   [r.request_method, r.remaining_path]
         | 
| 650 581 | 
             
                    #   # => ['GET', '/foo/']
         | 
| 651 582 | 
             
                    #
         | 
| 652 583 | 
             
                    #   r.on 'foo' do
         | 
| @@ -657,7 +588,7 @@ class Roda | |
| 657 588 | 
             
                    #
         | 
| 658 589 | 
             
                    # Note that this does not match non-+GET+ requests:
         | 
| 659 590 | 
             
                    #
         | 
| 660 | 
            -
                    #   [r.request_method, r. | 
| 591 | 
            +
                    #   [r.request_method, r.remaining_path]
         | 
| 661 592 | 
             
                    #   # => ['POST', '/']
         | 
| 662 593 | 
             
                    #
         | 
| 663 594 | 
             
                    #   r.root do
         | 
| @@ -669,7 +600,7 @@ class Roda | |
| 669 600 | 
             
                    # 
         | 
| 670 601 | 
             
                    # Nor does it match empty paths:
         | 
| 671 602 | 
             
                    #
         | 
| 672 | 
            -
                    #   [r.request_method, r. | 
| 603 | 
            +
                    #   [r.request_method, r.remaining_path]
         | 
| 673 604 | 
             
                    #   # => ['GET', '/foo']
         | 
| 674 605 | 
             
                    #
         | 
| 675 606 | 
             
                    #   r.on 'foo' do
         | 
| @@ -693,8 +624,25 @@ class Roda | |
| 693 624 | 
             
                    #   r.run(proc{[403, {}, []]}) unless r['letmein'] == '1'
         | 
| 694 625 | 
             
                    #   r.run(proc{[404, {}, []]})
         | 
| 695 626 | 
             
                    #   response.status = 404 # not reached
         | 
| 627 | 
            +
                    #
         | 
| 628 | 
            +
                    # This updates SCRIPT_NAME/PATH_INFO based on the current remaining_path
         | 
| 629 | 
            +
                    # before dispatching to another rack app, so the app still works as
         | 
| 630 | 
            +
                    # a URL mapper.
         | 
| 696 631 | 
             
                    def run(app)
         | 
| 697 | 
            -
                       | 
| 632 | 
            +
                      e = @env
         | 
| 633 | 
            +
                      path = @remaining_path
         | 
| 634 | 
            +
                      sn = SCRIPT_NAME
         | 
| 635 | 
            +
                      pi = PATH_INFO
         | 
| 636 | 
            +
                      script_name = e[sn]
         | 
| 637 | 
            +
                      path_info = e[pi]
         | 
| 638 | 
            +
                      begin
         | 
| 639 | 
            +
                        e[sn] += path_info.chomp(path)
         | 
| 640 | 
            +
                        e[pi] = path
         | 
| 641 | 
            +
                        throw :halt, app.call(e)
         | 
| 642 | 
            +
                      ensure
         | 
| 643 | 
            +
                        e[sn] = script_name
         | 
| 644 | 
            +
                        e[pi] = path_info
         | 
| 645 | 
            +
                      end
         | 
| 698 646 | 
             
                    end
         | 
| 699 647 |  | 
| 700 648 | 
             
                    # The session for the current request.  Raises a RodaError if
         | 
| @@ -780,7 +728,7 @@ class Roda | |
| 780 728 | 
             
                    # path from PATH_INFO, and updates captures with any regex captures.
         | 
| 781 729 | 
             
                    def consume(pattern)
         | 
| 782 730 | 
             
                      if matchdata = remaining_path.match(pattern)
         | 
| 783 | 
            -
                         | 
| 731 | 
            +
                        @remaining_path = matchdata.post_match
         | 
| 784 732 | 
             
                        @captures.concat(matchdata.captures)
         | 
| 785 733 | 
             
                      end
         | 
| 786 734 | 
             
                    end
         | 
| @@ -813,29 +761,18 @@ class Roda | |
| 813 761 | 
             
                    # returns the rack response when the block returns.  If any of
         | 
| 814 762 | 
             
                    # the match arguments doesn't match, does nothing.
         | 
| 815 763 | 
             
                    def if_match(args)
         | 
| 816 | 
            -
                       | 
| 817 | 
            -
             | 
| 818 | 
            -
             | 
| 819 | 
            -
             | 
| 820 | 
            -
             | 
| 821 | 
            -
             | 
| 822 | 
            -
             | 
| 823 | 
            -
             | 
| 824 | 
            -
                      end
         | 
| 825 | 
            -
                    end
         | 
| 826 | 
            -
                    
         | 
| 827 | 
            -
                    # Yield to the block, restoring SCRIPT_NAME and PATH_INFO to
         | 
| 828 | 
            -
                    # their initial values before returning from the block.
         | 
| 829 | 
            -
                    def keep_remaining_path
         | 
| 830 | 
            -
                      env = @env
         | 
| 831 | 
            -
                      script = env[sn = SCRIPT_NAME]
         | 
| 832 | 
            -
                      path = env[pi = PATH_INFO]
         | 
| 833 | 
            -
                      yield
         | 
| 764 | 
            +
                      path = @remaining_path
         | 
| 765 | 
            +
                      # For every block, we make sure to reset captures so that
         | 
| 766 | 
            +
                      # nesting matchers won't mess with each other's captures.
         | 
| 767 | 
            +
                      @captures.clear
         | 
| 768 | 
            +
             | 
| 769 | 
            +
                      return unless match_all(args)
         | 
| 770 | 
            +
                      block_result(yield(*captures))
         | 
| 771 | 
            +
                      throw :halt, response.finish
         | 
| 834 772 | 
             
                    ensure
         | 
| 835 | 
            -
                       | 
| 836 | 
            -
                      env[pi] = path
         | 
| 773 | 
            +
                      @remaining_path = path
         | 
| 837 774 | 
             
                    end
         | 
| 838 | 
            -
             | 
| 775 | 
            +
                    
         | 
| 839 776 | 
             
                    # Attempt to match the argument to the given request, handling
         | 
| 840 777 | 
             
                    # common ruby types.
         | 
| 841 778 | 
             
                    def match(matcher)
         | 
| @@ -864,11 +801,6 @@ class Roda | |
| 864 801 | 
             
                      args.all?{|arg| match(arg)}
         | 
| 865 802 | 
             
                    end
         | 
| 866 803 |  | 
| 867 | 
            -
                    def match_extension(ext)
         | 
| 868 | 
            -
                      RodaPlugins.deprecate("The :extension matcher is deprecated and will be removed in Roda 2.  It has been moved to the path_matchers plugin.")
         | 
| 869 | 
            -
                      consume(self.class.cached_matcher([:extension, ext]){/([^\\\/]+)\.#{ext}/})
         | 
| 870 | 
            -
                    end
         | 
| 871 | 
            -
             | 
| 872 804 | 
             
                    # Match by request method.  This can be an array if you want
         | 
| 873 805 | 
             
                    # to match on multiple methods.
         | 
| 874 806 | 
             
                    def match_method(type)
         | 
| @@ -878,29 +810,6 @@ class Roda | |
| 878 810 | 
             
                        type.to_s.upcase == @env[REQUEST_METHOD]
         | 
| 879 811 | 
             
                      end
         | 
| 880 812 | 
             
                    end
         | 
| 881 | 
            -
             | 
| 882 | 
            -
                    def match_param(key)
         | 
| 883 | 
            -
                      RodaPlugins.deprecate("The :param matcher is deprecated and will be removed in Roda 2.  It has been moved to the param_matchers plugin.")
         | 
| 884 | 
            -
                      if v = self[key]
         | 
| 885 | 
            -
                        @captures << v
         | 
| 886 | 
            -
                      end
         | 
| 887 | 
            -
                    end
         | 
| 888 | 
            -
             | 
| 889 | 
            -
                    def match_param!(key)
         | 
| 890 | 
            -
                      RodaPlugins.deprecate("The :param! matcher is deprecated and will be removed in Roda 2.  It has been moved to the param_matchers plugin.")
         | 
| 891 | 
            -
                      if (v = self[key]) && !v.empty?
         | 
| 892 | 
            -
                        @captures << v
         | 
| 893 | 
            -
                      end
         | 
| 894 | 
            -
                    end
         | 
| 895 | 
            -
             | 
| 896 | 
            -
                    # Update PATH_INFO and SCRIPT_NAME based on the matchend and remaining variables.
         | 
| 897 | 
            -
                    def update_remaining_path(remaining)
         | 
| 898 | 
            -
                      e = @env
         | 
| 899 | 
            -
             | 
| 900 | 
            -
                      # Don't mutate SCRIPT_NAME, breaks try
         | 
| 901 | 
            -
                      e[SCRIPT_NAME] += e[pi = PATH_INFO].chomp(remaining)
         | 
| 902 | 
            -
                      e[pi] = remaining
         | 
| 903 | 
            -
                    end
         | 
| 904 813 | 
             
                  end
         | 
| 905 814 |  | 
| 906 815 | 
             
                  # Class methods for RodaResponse
         | 
| @@ -959,11 +868,6 @@ class Roda | |
| 959 868 | 
             
                      DEFAULT_HEADERS
         | 
| 960 869 | 
             
                    end
         | 
| 961 870 |  | 
| 962 | 
            -
                    def delete_cookie(key, value = {})
         | 
| 963 | 
            -
                      RodaPlugins.deprecate("RodaResponse#delete_cookie is deprecated and will be removed in Roda 2.  It has been moved to the cookies plugin.")
         | 
| 964 | 
            -
                      ::Rack::Utils.delete_cookie_header!(@headers, key, value)
         | 
| 965 | 
            -
                    end
         | 
| 966 | 
            -
             | 
| 967 871 | 
             
                    # Whether the response body has been written to yet.  Note
         | 
| 968 872 | 
             
                    # that writing an empty string to the response body marks
         | 
| 969 873 | 
             
                    # the response as not empty. Example:
         | 
| @@ -1025,11 +929,6 @@ class Roda | |
| 1025 929 | 
             
                      self.class.roda_class
         | 
| 1026 930 | 
             
                    end
         | 
| 1027 931 |  | 
| 1028 | 
            -
                    def set_cookie(key, value)
         | 
| 1029 | 
            -
                      RodaPlugins.deprecate("RodaResponse#set_cookie is deprecated and will be removed in Roda 2.  It has been moved to the cookies plugin.")
         | 
| 1030 | 
            -
                      ::Rack::Utils.set_cookie_header!(@headers, key, value)
         | 
| 1031 | 
            -
                    end
         | 
| 1032 | 
            -
             | 
| 1033 932 | 
             
                    # Write to the response body.  Returns nil.
         | 
| 1034 933 | 
             
                    #
         | 
| 1035 934 | 
             
                    #   response.write('foo')
         | 
    
        data/spec/matchers_spec.rb
    CHANGED
    
    | @@ -291,20 +291,48 @@ describe "r.on" do | |
| 291 291 | 
             
                body("/123").should == '+1'
         | 
| 292 292 | 
             
              end
         | 
| 293 293 |  | 
| 294 | 
            -
              it "ensures  | 
| 294 | 
            +
              it "ensures remaining_path is reverted if modified in failing matcher" do
         | 
| 295 295 | 
             
                app do |r|
         | 
| 296 | 
            -
                  r.on lambda {  | 
| 296 | 
            +
                  r.on lambda { @remaining_path = "/blah"; false } do
         | 
| 297 297 | 
             
                    "Unreachable"
         | 
| 298 298 | 
             
                  end
         | 
| 299 299 |  | 
| 300 300 | 
             
                  r.on do
         | 
| 301 | 
            -
                    r. | 
| 301 | 
            +
                    r.matched_path + ':' + r.remaining_path
         | 
| 302 302 | 
             
                  end
         | 
| 303 303 | 
             
                end
         | 
| 304 304 |  | 
| 305 305 | 
             
                body("/hello").should == ':/hello'
         | 
| 306 306 | 
             
              end
         | 
| 307 307 |  | 
| 308 | 
            +
              it "modifies matched_path/remaining_path during routing" do
         | 
| 309 | 
            +
                app do |r|
         | 
| 310 | 
            +
                  r.on 'login', 'foo' do 
         | 
| 311 | 
            +
                    "Unreachable"
         | 
| 312 | 
            +
                  end
         | 
| 313 | 
            +
                  
         | 
| 314 | 
            +
                  r.on 'hello' do
         | 
| 315 | 
            +
                    r.matched_path + ':' + r.remaining_path
         | 
| 316 | 
            +
                  end
         | 
| 317 | 
            +
                end
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                body("/hello/you").should == '/hello:/you'
         | 
| 320 | 
            +
              end
         | 
| 321 | 
            +
             | 
| 322 | 
            +
              it "doesn't modify SCRIPT_NAME/PATH_INFO during routing" do
         | 
| 323 | 
            +
                app do |r|
         | 
| 324 | 
            +
                  r.on 'login', 'foo' do 
         | 
| 325 | 
            +
                    "Unreachable"
         | 
| 326 | 
            +
                  end
         | 
| 327 | 
            +
                  
         | 
| 328 | 
            +
                  r.on 'hello' do
         | 
| 329 | 
            +
                    r.env["SCRIPT_NAME"] + ':' + r.env["PATH_INFO"]
         | 
| 330 | 
            +
                  end
         | 
| 331 | 
            +
                end
         | 
| 332 | 
            +
             | 
| 333 | 
            +
                body("/hello/you").should == ':/hello/you'
         | 
| 334 | 
            +
              end
         | 
| 335 | 
            +
             | 
| 308 336 | 
             
              it "doesn't mutate SCRIPT_NAME or PATH_INFO after request is returned" do
         | 
| 309 337 | 
             
                app do |r|
         | 
| 310 338 | 
             
                  r.on 'login', 'foo' do 
         | 
| @@ -377,44 +405,6 @@ describe "r.on" do | |
| 377 405 | 
             
              end
         | 
| 378 406 | 
             
            end
         | 
| 379 407 |  | 
| 380 | 
            -
            describe "param! matcher" do
         | 
| 381 | 
            -
              it "should yield a param only if given and not empty" do
         | 
| 382 | 
            -
                app do |r|
         | 
| 383 | 
            -
                  r.get "signup", :param! => "email" do |email|
         | 
| 384 | 
            -
                    email
         | 
| 385 | 
            -
                  end
         | 
| 386 | 
            -
             | 
| 387 | 
            -
                  r.on do
         | 
| 388 | 
            -
                    "No email"
         | 
| 389 | 
            -
                  end
         | 
| 390 | 
            -
                end
         | 
| 391 | 
            -
             | 
| 392 | 
            -
                io = StringIO.new
         | 
| 393 | 
            -
                body("/signup", "rack.input" => io, "QUERY_STRING" => "email=john@doe.com").should == 'john@doe.com'
         | 
| 394 | 
            -
                body("/signup", "rack.input" => io, "QUERY_STRING" => "").should == 'No email'
         | 
| 395 | 
            -
                body("/signup", "rack.input" => io, "QUERY_STRING" => "email=").should == 'No email'
         | 
| 396 | 
            -
              end
         | 
| 397 | 
            -
            end
         | 
| 398 | 
            -
             | 
| 399 | 
            -
            describe "param matcher" do
         | 
| 400 | 
            -
              it "should yield a param only if given" do
         | 
| 401 | 
            -
                app do |r|
         | 
| 402 | 
            -
                  r.get "signup", :param=>"email" do |email|
         | 
| 403 | 
            -
                    email
         | 
| 404 | 
            -
                  end
         | 
| 405 | 
            -
             | 
| 406 | 
            -
                  r.on do
         | 
| 407 | 
            -
                    "No email"
         | 
| 408 | 
            -
                  end
         | 
| 409 | 
            -
                end
         | 
| 410 | 
            -
             | 
| 411 | 
            -
                io = StringIO.new
         | 
| 412 | 
            -
                body("/signup", "rack.input" => io, "QUERY_STRING" => "email=john@doe.com").should == 'john@doe.com'
         | 
| 413 | 
            -
                body("/signup", "rack.input" => io, "QUERY_STRING" => "").should == 'No email'
         | 
| 414 | 
            -
                body("/signup", "rack.input" => io, "QUERY_STRING" => "email=").should == ''
         | 
| 415 | 
            -
              end
         | 
| 416 | 
            -
            end
         | 
| 417 | 
            -
             | 
| 418 408 | 
             
            describe "path matchers" do 
         | 
| 419 409 | 
             
              it "one level path" do
         | 
| 420 410 | 
             
                app do |r|
         | 
| @@ -644,21 +634,6 @@ describe "all matcher" do | |
| 644 634 | 
             
              end
         | 
| 645 635 | 
             
            end
         | 
| 646 636 |  | 
| 647 | 
            -
            describe "extension matcher" do
         | 
| 648 | 
            -
              it "should match given file extensions" do
         | 
| 649 | 
            -
                app do |r|
         | 
| 650 | 
            -
                  r.on "css" do
         | 
| 651 | 
            -
                    r.on :extension=>"css" do |file|
         | 
| 652 | 
            -
                      file
         | 
| 653 | 
            -
                    end
         | 
| 654 | 
            -
                  end
         | 
| 655 | 
            -
                end
         | 
| 656 | 
            -
             | 
| 657 | 
            -
                body("/css/reset.css").should == 'reset'
         | 
| 658 | 
            -
                status("/css/reset.bar").should == 404
         | 
| 659 | 
            -
              end
         | 
| 660 | 
            -
            end
         | 
| 661 | 
            -
             | 
| 662 637 | 
             
            describe "method matcher" do
         | 
| 663 638 | 
             
              it "should match given request types" do
         | 
| 664 639 | 
             
                app do |r|
         | 
| @@ -686,29 +661,3 @@ describe "route block that returns string" do | |
| 686 661 | 
             
                body.should == '+1'
         | 
| 687 662 | 
             
              end
         | 
| 688 663 | 
             
            end
         | 
| 689 | 
            -
             | 
| 690 | 
            -
            describe "hash_matcher" do
         | 
| 691 | 
            -
              it "should enable the handling of arbitrary hash keys" do
         | 
| 692 | 
            -
                app(:bare) do 
         | 
| 693 | 
            -
                  hash_matcher(:foos){|v| consume(self.class.cached_matcher(:"foos-#{v}"){/((?:foo){#{v}})/})}
         | 
| 694 | 
            -
                  route do |r|
         | 
| 695 | 
            -
                    r.is :foos=>1 do |f|
         | 
| 696 | 
            -
                      "1#{f}"
         | 
| 697 | 
            -
                    end
         | 
| 698 | 
            -
                    r.is :foos=>2 do |f|
         | 
| 699 | 
            -
                      "2#{f}"
         | 
| 700 | 
            -
                    end
         | 
| 701 | 
            -
                    r.is :foos=>3 do |f|
         | 
| 702 | 
            -
                      "3#{f}"
         | 
| 703 | 
            -
                    end
         | 
| 704 | 
            -
                  end
         | 
| 705 | 
            -
                end
         | 
| 706 | 
            -
             | 
| 707 | 
            -
                body("/foo").should == '1foo'
         | 
| 708 | 
            -
                body("/foofoo").should == '2foofoo'
         | 
| 709 | 
            -
                body("/foofoofoo").should == '3foofoofoo'
         | 
| 710 | 
            -
                status("/foofoofoofoo").should == 404
         | 
| 711 | 
            -
                status.should == 404
         | 
| 712 | 
            -
              end
         | 
| 713 | 
            -
            end
         | 
| 714 | 
            -
             | 
    
        data/spec/plugin/assets_spec.rb
    CHANGED
    
    | @@ -332,11 +332,11 @@ if run_tests | |
| 332 332 | 
             
                end
         | 
| 333 333 |  | 
| 334 334 | 
             
                it '#assets should include attributes given' do
         | 
| 335 | 
            -
                  app. | 
| 335 | 
            +
                  app.allocate.assets([:js, :head], 'a'=>'b').should == '<script type="text/javascript" a="b" src="/assets/js/head/app.js"></script>'
         | 
| 336 336 | 
             
                end
         | 
| 337 337 |  | 
| 338 338 | 
             
                it '#assets should escape attribute values given' do
         | 
| 339 | 
            -
                  app. | 
| 339 | 
            +
                  app.allocate.assets([:js, :head], 'a'=>'b"e').should == '<script type="text/javascript" a="b"e" src="/assets/js/head/app.js"></script>'
         | 
| 340 340 | 
             
                end
         | 
| 341 341 |  | 
| 342 342 | 
             
                it 'requests for assets should return 304 if the asset has not been modified' do
         | 
| @@ -397,17 +397,17 @@ if run_tests | |
| 397 397 | 
             
                it 'should support :precompiled option' do
         | 
| 398 398 | 
             
                  app.plugin :assets, :precompiled=>metadata_file
         | 
| 399 399 | 
             
                  File.exist?(metadata_file).should == false
         | 
| 400 | 
            -
                  app. | 
| 400 | 
            +
                  app.allocate.assets([:js, :head]).should == '<script type="text/javascript"  src="/assets/js/head/app.js"></script>'
         | 
| 401 401 |  | 
| 402 402 | 
             
                  app.compile_assets
         | 
| 403 403 | 
             
                  File.exist?(metadata_file).should == true
         | 
| 404 | 
            -
                  app. | 
| 404 | 
            +
                  app.allocate.assets([:js, :head]).should =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
         | 
| 405 405 |  | 
| 406 406 | 
             
                  app.plugin :assets, :compiled=>false, :precompiled=>false
         | 
| 407 | 
            -
                  app. | 
| 407 | 
            +
                  app.allocate.assets([:js, :head]).should == '<script type="text/javascript"  src="/assets/js/head/app.js"></script>'
         | 
| 408 408 |  | 
| 409 409 | 
             
                  app.plugin :assets, :precompiled=>metadata_file
         | 
| 410 | 
            -
                  app. | 
| 410 | 
            +
                  app.allocate.assets([:js, :head]).should =~ %r{src="(/assets/app\.head\.[a-f0-9]{40}\.js)"}
         | 
| 411 411 | 
             
                end
         | 
| 412 412 | 
             
              end
         | 
| 413 413 | 
             
            end
         | 
| @@ -24,6 +24,29 @@ describe "error_handler plugin" do | |
| 24 24 | 
             
                status.should == 500
         | 
| 25 25 | 
             
              end
         | 
| 26 26 |  | 
| 27 | 
            +
              it "executes on SyntaxError exceptions" do
         | 
| 28 | 
            +
                app(:bare) do
         | 
| 29 | 
            +
                  plugin :error_handler
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  error do |e|
         | 
| 32 | 
            +
                    e.message
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  route do |r|
         | 
| 36 | 
            +
                    r.on "a" do
         | 
| 37 | 
            +
                      "found"
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    raise SyntaxError, 'bad idea'
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                body("/a").should == 'found'
         | 
| 45 | 
            +
                status("/a").should == 200
         | 
| 46 | 
            +
                body.should == 'bad idea'
         | 
| 47 | 
            +
                status.should == 500
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 27 50 | 
             
              it "can override status inside error block" do
         | 
| 28 51 | 
             
                app(:bare) do
         | 
| 29 52 | 
             
                  plugin :error_handler do |e|
         | 
    
        data/spec/plugin/halt_spec.rb
    CHANGED
    
    | @@ -25,6 +25,18 @@ describe "halt plugin" do | |
| 25 25 | 
             
                status.should == 300 
         | 
| 26 26 | 
             
              end
         | 
| 27 27 |  | 
| 28 | 
            +
              it "should consider other single arguments similar to block bodies" do
         | 
| 29 | 
            +
                app(:bare) do
         | 
| 30 | 
            +
                  plugin :halt
         | 
| 31 | 
            +
                  plugin :json
         | 
| 32 | 
            +
                  route do |r|
         | 
| 33 | 
            +
                    r.halt({'a'=>1})
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                body.should ==  '{"a":1}'
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 28 40 | 
             
              it "should consider 2 arguments as response status and body" do
         | 
| 29 41 | 
             
                app(:halt) do |r|
         | 
| 30 42 | 
             
                  r.halt 300, "foo"
         | 
| @@ -34,6 +46,19 @@ describe "halt plugin" do | |
| 34 46 | 
             
                body.should == "foo"
         | 
| 35 47 | 
             
              end
         | 
| 36 48 |  | 
| 49 | 
            +
              it "should handle 2nd of 2 arguments similar to block bodies" do
         | 
| 50 | 
            +
                app(:bare) do
         | 
| 51 | 
            +
                  plugin :halt
         | 
| 52 | 
            +
                  plugin :json
         | 
| 53 | 
            +
                  route do |r|
         | 
| 54 | 
            +
                    r.halt(300, {'a'=>1})
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                status.should == 300 
         | 
| 59 | 
            +
                body.should ==  '{"a":1}'
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
             | 
| 37 62 | 
             
              it "should consider 3 arguments as response" do
         | 
| 38 63 | 
             
                app(:halt) do |r|
         | 
| 39 64 | 
             
                  r.halt 300, {'a'=>'b'}, "foo"
         | 
| @@ -44,6 +69,20 @@ describe "halt plugin" do | |
| 44 69 | 
             
                body.should == "foo"
         | 
| 45 70 | 
             
              end
         | 
| 46 71 |  | 
| 72 | 
            +
              it "should handle 3rd of 3 arguments similar to block bodies" do
         | 
| 73 | 
            +
                app(:bare) do
         | 
| 74 | 
            +
                  plugin :halt
         | 
| 75 | 
            +
                  plugin :json
         | 
| 76 | 
            +
                  route do |r|
         | 
| 77 | 
            +
                    r.halt(300, {'a'=>'b'}, {'a'=>1})
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                status.should == 300 
         | 
| 82 | 
            +
                header('a').should == 'b'
         | 
| 83 | 
            +
                body.should ==  '{"a":1}'
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
             | 
| 47 86 | 
             
              it "should raise an error for too many arguments" do
         | 
| 48 87 | 
             
                app(:halt) do |r|
         | 
| 49 88 | 
             
                  r.halt 300, {'a'=>'b'}, "foo", 1
         |