merb-core 0.9.5 → 0.9.6
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.
- data/CHANGELOG +925 -0
- data/CONTRIBUTORS +93 -0
- data/PUBLIC_CHANGELOG +85 -0
- data/Rakefile +18 -28
- data/bin/merb +34 -5
- data/lib/merb-core/autoload.rb +2 -3
- data/lib/merb-core/bootloader.rb +60 -66
- data/lib/merb-core/config.rb +7 -1
- data/lib/merb-core/controller/abstract_controller.rb +35 -21
- data/lib/merb-core/controller/merb_controller.rb +15 -42
- data/lib/merb-core/controller/mixins/authentication.rb +42 -6
- data/lib/merb-core/controller/mixins/conditional_get.rb +83 -0
- data/lib/merb-core/controller/mixins/render.rb +3 -3
- data/lib/merb-core/core_ext/kernel.rb +6 -19
- data/lib/merb-core/dispatch/cookies.rb +96 -80
- data/lib/merb-core/dispatch/default_exception/views/index.html.erb +2 -0
- data/lib/merb-core/dispatch/request.rb +18 -16
- data/lib/merb-core/dispatch/router/route.rb +6 -0
- data/lib/merb-core/dispatch/router.rb +4 -1
- data/lib/merb-core/dispatch/session/container.rb +64 -0
- data/lib/merb-core/dispatch/session/cookie.rb +91 -101
- data/lib/merb-core/dispatch/session/memcached.rb +38 -174
- data/lib/merb-core/dispatch/session/memory.rb +62 -208
- data/lib/merb-core/dispatch/session/store_container.rb +145 -0
- data/lib/merb-core/dispatch/session.rb +174 -48
- data/lib/merb-core/rack/middleware/conditional_get.rb +14 -8
- data/lib/merb-core/rack/middleware/csrf.rb +73 -0
- data/lib/merb-core/rack.rb +1 -0
- data/lib/merb-core/script.rb +112 -0
- data/lib/merb-core/server.rb +2 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +25 -0
- data/lib/merb-core/test/helpers/request_helper.rb +40 -3
- data/lib/merb-core/test/run_specs.rb +4 -3
- data/lib/merb-core/vendor/facets/inflect.rb +7 -10
- data/lib/merb-core/version.rb +1 -1
- data/lib/merb-core.rb +11 -40
- data/spec/private/core_ext/kernel_spec.rb +0 -11
- data/spec/private/dispatch/fixture/log/merb_test.log +893 -0
- data/spec/private/router/fixture/log/merb_test.log +12 -1728
- data/spec/private/router/route_spec.rb +4 -0
- data/spec/private/router/router_spec.rb +8 -0
- data/spec/private/vendor/facets/plural_spec.rb +1 -1
- data/spec/private/vendor/facets/singular_spec.rb +1 -1
- data/spec/public/abstract_controller/controllers/display.rb +8 -2
- data/spec/public/abstract_controller/controllers/filters.rb +18 -0
- data/spec/public/abstract_controller/display_spec.rb +6 -2
- data/spec/public/abstract_controller/filter_spec.rb +4 -0
- data/spec/public/controller/authentication_spec.rb +114 -43
- data/spec/public/controller/base_spec.rb +8 -0
- data/spec/public/controller/conditional_get_spec.rb +100 -0
- data/spec/public/controller/config/init.rb +1 -1
- data/spec/public/controller/controllers/authentication.rb +29 -0
- data/spec/public/controller/controllers/base.rb +13 -0
- data/spec/public/controller/controllers/conditional_get.rb +35 -0
- data/spec/public/controller/controllers/cookies.rb +10 -1
- data/spec/public/controller/cookies_spec.rb +38 -9
- data/spec/public/controller/spec_helper.rb +1 -0
- data/spec/public/controller/url_spec.rb +70 -1
- data/spec/public/directory_structure/directory/log/merb_test.log +461 -0
- data/spec/public/rack/conditinal_get_middleware_spec.rb +77 -89
- data/spec/public/rack/csrf_middleware_spec.rb +70 -0
- data/spec/public/reloading/directory/log/merb_test.log +52 -0
- data/spec/public/request/request_spec.rb +19 -1
- data/spec/public/router/fixation_spec.rb +26 -4
- data/spec/public/router/fixture/log/merb_test.log +234 -30332
- data/spec/public/session/controllers/sessions.rb +52 -0
- data/spec/public/session/cookie_session_spec.rb +73 -0
- data/spec/public/session/memcached_session_spec.rb +31 -0
- data/spec/public/session/memory_session_spec.rb +28 -0
- data/spec/public/session/multiple_sessions_spec.rb +74 -0
- data/spec/public/session/no_session_spec.rb +12 -0
- data/spec/public/session/session_spec.rb +91 -0
- data/spec/public/test/controllers/spec_helper_controller.rb +2 -1
- data/spec/public/test/request_helper_spec.rb +15 -0
- data/spec/spec_helper.rb +2 -2
- metadata +23 -5
- data/spec/private/dispatch/cookies_spec.rb +0 -219
- data/spec/private/dispatch/session_mixin_spec.rb +0 -47
| @@ -27,7 +27,7 @@ | |
| 27 27 | 
             
            #   before :some_filter
         | 
| 28 28 | 
             
            #   before :authenticate, :exclude => [:login, :signup]
         | 
| 29 29 | 
             
            #   before :has_role, :with => ["Admin"], :exclude => [:index, :show]
         | 
| 30 | 
            -
            #   before Proc.new { | 
| 30 | 
            +
            #   before Proc.new { some_method }, :only => :foo
         | 
| 31 31 | 
             
            #   before :authorize, :unless => :logged_in?  
         | 
| 32 32 | 
             
            #
         | 
| 33 33 | 
             
            # You can use either <code>:only => :actionname</code> or 
         | 
| @@ -64,8 +64,8 @@ | |
| 64 64 | 
             
            #   If the second arg is a Proc, it will be called and its return
         | 
| 65 65 | 
             
            #   value will be what is rendered to the browser:
         | 
| 66 66 | 
             
            #
         | 
| 67 | 
            -
            #     throw :halt, proc { | 
| 68 | 
            -
            #     throw :halt, proc { | 
| 67 | 
            +
            #     throw :halt, proc { access_denied }
         | 
| 68 | 
            +
            #     throw :halt, proc { Tidy.new(c.index) }
         | 
| 69 69 | 
             
            #
         | 
| 70 70 | 
             
            # ===== Filter Options (.before, .after, .add_filter, .if, .unless)
         | 
| 71 71 | 
             
            # :only<Symbol, Array[Symbol]>::
         | 
| @@ -98,6 +98,7 @@ class Merb::AbstractController | |
| 98 98 |  | 
| 99 99 | 
             
              class_inheritable_accessor :_layout, :_template_root, :template_roots
         | 
| 100 100 | 
             
              class_inheritable_accessor :_before_filters, :_after_filters
         | 
| 101 | 
            +
              class_inheritable_accessor :_before_dispatch_callbacks, :_after_dispatch_callbacks
         | 
| 101 102 |  | 
| 102 103 | 
             
              cattr_accessor :_abstract_subclasses
         | 
| 103 104 |  | 
| @@ -113,6 +114,7 @@ class Merb::AbstractController | |
| 113 114 | 
             
              FILTER_OPTIONS = [:only, :exclude, :if, :unless, :with]
         | 
| 114 115 |  | 
| 115 116 | 
             
              self._before_filters, self._after_filters = [], []
         | 
| 117 | 
            +
              self._before_dispatch_callbacks, self._after_dispatch_callbacks = [], []
         | 
| 116 118 |  | 
| 117 119 | 
             
              #---
         | 
| 118 120 | 
             
              # We're using abstract_subclasses so that Merb::Controller can have its
         | 
| @@ -217,7 +219,7 @@ class Merb::AbstractController | |
| 217 219 | 
             
                    include Object.full_const_get("#{helper_module_name}") rescue nil
         | 
| 218 220 | 
             
                  HERE
         | 
| 219 221 | 
             
                  super
         | 
| 220 | 
            -
                end
         | 
| 222 | 
            +
                end    
         | 
| 221 223 | 
             
              end
         | 
| 222 224 |  | 
| 223 225 | 
             
              # ==== Parameters
         | 
| @@ -228,7 +230,7 @@ class Merb::AbstractController | |
| 228 230 | 
             
                @_template_stack = []
         | 
| 229 231 | 
             
              end
         | 
| 230 232 |  | 
| 231 | 
            -
              # This will dispatch the request, calling  | 
| 233 | 
            +
              # This will dispatch the request, calling internal before/after dispatch_callbacks
         | 
| 232 234 | 
             
              # 
         | 
| 233 235 | 
             
              # ==== Parameters
         | 
| 234 236 | 
             
              # action<~to_s>::
         | 
| @@ -238,7 +240,7 @@ class Merb::AbstractController | |
| 238 240 | 
             
              # ==== Raises
         | 
| 239 241 | 
             
              # MerbControllerError:: Invalid body content caught.
         | 
| 240 242 | 
             
              def _dispatch(action)
         | 
| 241 | 
            -
                 | 
| 243 | 
            +
                self._before_dispatch_callbacks.each { |cb| cb.call(self) }
         | 
| 242 244 | 
             
                self.action_name = action
         | 
| 243 245 |  | 
| 244 246 | 
             
                caught = catch(:halt) do
         | 
| @@ -253,14 +255,16 @@ class Merb::AbstractController | |
| 253 255 | 
             
                when String                   then caught
         | 
| 254 256 | 
             
                when nil                      then _filters_halted
         | 
| 255 257 | 
             
                when Symbol                   then __send__(caught)
         | 
| 256 | 
            -
                when Proc                     then  | 
| 258 | 
            +
                when Proc                     then self.instance_eval(&caught)
         | 
| 257 259 | 
             
                else
         | 
| 258 260 | 
             
                  raise ArgumentError, "Threw :halt, #{caught}. Expected String, nil, Symbol, Proc."
         | 
| 259 261 | 
             
                end
         | 
| 260 262 | 
             
                start = Time.now
         | 
| 261 263 | 
             
                _call_filters(_after_filters)
         | 
| 262 264 | 
             
                @_benchmarks[:after_filters_time] = Time.now - start if _after_filters
         | 
| 263 | 
            -
                 | 
| 265 | 
            +
                
         | 
| 266 | 
            +
                self._after_dispatch_callbacks.each { |cb| cb.call(self) }
         | 
| 267 | 
            +
                
         | 
| 264 268 | 
             
                @body
         | 
| 265 269 | 
             
              end
         | 
| 266 270 |  | 
| @@ -298,7 +302,7 @@ class Merb::AbstractController | |
| 298 302 | 
             
                      else
         | 
| 299 303 | 
             
                        send(filter)
         | 
| 300 304 | 
             
                      end
         | 
| 301 | 
            -
                    when Proc | 
| 305 | 
            +
                    when Proc then self.instance_eval(&filter)
         | 
| 302 306 | 
             
                    end
         | 
| 303 307 | 
             
                  end
         | 
| 304 308 | 
             
                end
         | 
| @@ -360,7 +364,7 @@ class Merb::AbstractController | |
| 360 364 | 
             
              def _evaluate_condition(condition)
         | 
| 361 365 | 
             
                case condition
         | 
| 362 366 | 
             
                when Symbol : self.send(condition)
         | 
| 363 | 
            -
                when Proc :  | 
| 367 | 
            +
                when Proc : self.instance_eval(&condition)
         | 
| 364 368 | 
             
                else
         | 
| 365 369 | 
             
                  raise ArgumentError,
         | 
| 366 370 | 
             
                        'Filter condtions need to be either a Symbol or a Proc'
         | 
| @@ -412,14 +416,6 @@ class Merb::AbstractController | |
| 412 416 | 
             
              #---
         | 
| 413 417 | 
             
              # Defaults that can be overridden by plugins, other mixins, or subclasses
         | 
| 414 418 | 
             
              def _filters_halted()   "<html><body><h1>Filter Chain Halted!</h1></body></html>"  end
         | 
| 415 | 
            -
             | 
| 416 | 
            -
              # Method stub for setting up the session. This will be overriden by session
         | 
| 417 | 
            -
              # modules.
         | 
| 418 | 
            -
              def setup_session()    end
         | 
| 419 | 
            -
             | 
| 420 | 
            -
              # Method stub for finalizing up the session. This will be overriden by
         | 
| 421 | 
            -
              # session modules.
         | 
| 422 | 
            -
              def finalize_session() end  
         | 
| 423 419 |  | 
| 424 420 | 
             
              # ==== Parameters
         | 
| 425 421 | 
             
              # name<~to_sym, Hash>:: The name of the URL to generate.
         | 
| @@ -453,11 +449,24 @@ class Merb::AbstractController | |
| 453 449 | 
             
              # ==== Returns
         | 
| 454 450 | 
             
              # String:: The generated url with protocol + hostname + URL.
         | 
| 455 451 | 
             
              #
         | 
| 452 | 
            +
              # ==== Options
         | 
| 453 | 
            +
              #
         | 
| 454 | 
            +
              # :protocol and :host options are special: use them to explicitly
         | 
| 455 | 
            +
              # specify protocol and host of resulting url. If you omit them,
         | 
| 456 | 
            +
              # protocol and host of request are used.
         | 
| 457 | 
            +
              #
         | 
| 456 458 | 
             
              # ==== Alternatives
         | 
| 457 459 | 
             
              # If a hash is used as the first argument, a default route will be
         | 
| 458 460 | 
             
              # generated based on it and rparams.
         | 
| 459 461 | 
             
              def absolute_url(name, rparams={})
         | 
| 460 | 
            -
                 | 
| 462 | 
            +
                # FIXME: arrgh, why request.protocol returns http://?
         | 
| 463 | 
            +
                # :// is not part of protocol name
         | 
| 464 | 
            +
                protocol = rparams.delete(:protocol)
         | 
| 465 | 
            +
                protocol << "://" if protocol
         | 
| 466 | 
            +
                
         | 
| 467 | 
            +
                (protocol || request.protocol) +
         | 
| 468 | 
            +
                  (rparams.delete(:host) || request.host) +
         | 
| 469 | 
            +
                  url(name, rparams)
         | 
| 461 470 | 
             
              end
         | 
| 462 471 |  | 
| 463 472 | 
             
              # Calls the capture method for the selected template engine.
         | 
| @@ -506,9 +515,14 @@ class Merb::AbstractController | |
| 506 515 | 
             
                end
         | 
| 507 516 |  | 
| 508 517 | 
             
                opts = normalize_filters!(opts)
         | 
| 509 | 
            -
             | 
| 518 | 
            +
                
         | 
| 510 519 | 
             
                case filter
         | 
| 511 | 
            -
                when  | 
| 520 | 
            +
                when Proc
         | 
| 521 | 
            +
                  # filters with procs created via class methods have identical signature
         | 
| 522 | 
            +
                  # regardless if they handle content differently or not. So procs just
         | 
| 523 | 
            +
                  # get appended
         | 
| 524 | 
            +
                  filters << [filter, opts]
         | 
| 525 | 
            +
                when Symbol, String
         | 
| 512 526 | 
             
                  if existing_filter = filters.find {|f| f.first.to_s[filter.to_s]}
         | 
| 513 527 | 
             
                    filters[ filters.index(existing_filter) ] = [filter, opts]
         | 
| 514 528 | 
             
                  else
         | 
| @@ -1,24 +1,19 @@ | |
| 1 1 | 
             
            class Merb::Controller < Merb::AbstractController
         | 
| 2 2 |  | 
| 3 | 
            -
              class_inheritable_accessor :_hidden_actions, :_shown_actions | 
| 4 | 
            -
                                         :_session_id_key, :_session_secret_key, :_session_expiry, :_session_cookie_domain
         | 
| 3 | 
            +
              class_inheritable_accessor :_hidden_actions, :_shown_actions
         | 
| 5 4 |  | 
| 6 5 | 
             
              self._hidden_actions ||= []
         | 
| 7 | 
            -
              self._shown_actions | 
| 8 | 
            -
             | 
| 6 | 
            +
              self._shown_actions  ||= []
         | 
| 7 | 
            +
             | 
| 9 8 | 
             
              cattr_accessor :_subclasses
         | 
| 10 9 | 
             
              self._subclasses = Set.new
         | 
| 11 10 |  | 
| 12 11 | 
             
              def self.subclasses_list() _subclasses end
         | 
| 13 12 |  | 
| 14 | 
            -
              self._session_secret_key = nil
         | 
| 15 | 
            -
              self._session_id_key = Merb::Config[:session_id_key] || '_session_id'
         | 
| 16 | 
            -
              self._session_expiry = Merb::Config[:session_expiry] || Merb::Const::WEEK * 2
         | 
| 17 | 
            -
              self._session_cookie_domain = Merb::Config[:session_cookie_domain]
         | 
| 18 | 
            -
             | 
| 19 13 | 
             
              include Merb::ResponderMixin
         | 
| 20 14 | 
             
              include Merb::ControllerMixin
         | 
| 21 15 | 
             
              include Merb::AuthenticationMixin
         | 
| 16 | 
            +
              include Merb::ConditionalGetMixin
         | 
| 22 17 |  | 
| 23 18 | 
             
              class << self
         | 
| 24 19 |  | 
| @@ -102,7 +97,7 @@ class Merb::Controller < Merb::AbstractController | |
| 102 97 | 
             
                end
         | 
| 103 98 |  | 
| 104 99 | 
             
                private
         | 
| 105 | 
            -
             | 
| 100 | 
            +
             | 
| 106 101 | 
             
                # All methods that are callable as actions.
         | 
| 107 102 | 
             
                #
         | 
| 108 103 | 
             
                # ==== Returns
         | 
| @@ -140,15 +135,15 @@ class Merb::Controller < Merb::AbstractController | |
| 140 135 | 
             
              def _template_location(context, type, controller)
         | 
| 141 136 | 
             
                _conditionally_append_extension(controller ? "#{controller}/#{context}" : "#{context}", type)
         | 
| 142 137 | 
             
              end
         | 
| 143 | 
            -
             | 
| 144 | 
            -
              # The location to look for a template and mime-type. This is overridden | 
| 145 | 
            -
              # from AbstractController, which defines a version of this that does not | 
| 138 | 
            +
             | 
| 139 | 
            +
              # The location to look for a template and mime-type. This is overridden
         | 
| 140 | 
            +
              # from AbstractController, which defines a version of this that does not
         | 
| 146 141 | 
             
              # involve mime-types.
         | 
| 147 142 | 
             
              #
         | 
| 148 143 | 
             
              # ==== Parameters
         | 
| 149 | 
            -
              # template<String>:: | 
| 144 | 
            +
              # template<String>::
         | 
| 150 145 | 
             
              #    The absolute path to a template - without mime and template extension.
         | 
| 151 | 
            -
              #    The mime-type extension is optional - it will be appended from the | 
| 146 | 
            +
              #    The mime-type extension is optional - it will be appended from the
         | 
| 152 147 | 
             
              #    current content type if it hasn't been added already.
         | 
| 153 148 | 
             
              # type<~to_s>::
         | 
| 154 149 | 
             
              #    The mime-type of the template that will be rendered. Defaults to nil.
         | 
| @@ -163,11 +158,8 @@ class Merb::Controller < Merb::AbstractController | |
| 163 158 | 
             
              # Sets the variables that came in through the dispatch as available to
         | 
| 164 159 | 
             
              # the controller.
         | 
| 165 160 | 
             
              #
         | 
| 166 | 
            -
              # This method uses the :session_id_cookie_only and :query_string_whitelist
         | 
| 167 | 
            -
              # configuration options. See CONFIG for more details.
         | 
| 168 | 
            -
              #
         | 
| 169 161 | 
             
              # ==== Parameters
         | 
| 170 | 
            -
              # request<Merb::Request>:: The Merb::Request that came in from  | 
| 162 | 
            +
              # request<Merb::Request>:: The Merb::Request that came in from Rack.
         | 
| 171 163 | 
             
              # status<Integer>:: An integer code for the status. Defaults to 200.
         | 
| 172 164 | 
             
              # headers<Hash{header => value}>::
         | 
| 173 165 | 
             
              #   A hash of headers to start the controller with. These headers can be
         | 
| @@ -204,7 +196,7 @@ class Merb::Controller < Merb::AbstractController | |
| 204 196 | 
             
              end
         | 
| 205 197 |  | 
| 206 198 | 
             
              attr_reader :request, :headers
         | 
| 207 | 
            -
             | 
| 199 | 
            +
             | 
| 208 200 | 
             
              def status
         | 
| 209 201 | 
             
                @_status
         | 
| 210 202 | 
             
              end
         | 
| @@ -227,20 +219,6 @@ class Merb::Controller < Merb::AbstractController | |
| 227 219 | 
             
              # Hash:: The parameters from the request object
         | 
| 228 220 | 
             
              def params()  request.params  end
         | 
| 229 221 |  | 
| 230 | 
            -
              # ==== Returns
         | 
| 231 | 
            -
              # Merb::Cookies::
         | 
| 232 | 
            -
              #   A new Merb::Cookies instance representing the cookies that came in
         | 
| 233 | 
            -
              #   from the request object
         | 
| 234 | 
            -
              #
         | 
| 235 | 
            -
              # ==== Notes
         | 
| 236 | 
            -
              # Headers are passed into the cookie object so that you can do:
         | 
| 237 | 
            -
              #   cookies[:foo] = "bar"
         | 
| 238 | 
            -
              def cookies() @_cookies ||= _setup_cookies end
         | 
| 239 | 
            -
             | 
| 240 | 
            -
              # ==== Returns
         | 
| 241 | 
            -
              # Hash:: The session that was extracted from the request object.
         | 
| 242 | 
            -
              def session() request.session end
         | 
| 243 | 
            -
              
         | 
| 244 222 | 
             
              # The results of the controller's render, to be returned to Rack.
         | 
| 245 223 | 
             
              #
         | 
| 246 224 | 
             
              # ==== Returns
         | 
| @@ -249,19 +227,14 @@ class Merb::Controller < Merb::AbstractController | |
| 249 227 | 
             
              def rack_response
         | 
| 250 228 | 
             
                [status, headers, body]
         | 
| 251 229 | 
             
              end
         | 
| 252 | 
            -
             | 
| 230 | 
            +
             | 
| 253 231 | 
             
              # Hide any methods that may have been exposed as actions before.
         | 
| 254 232 | 
             
              hide_action(*_callable_methods)
         | 
| 255 | 
            -
             | 
| 233 | 
            +
             | 
| 256 234 | 
             
              private
         | 
| 257 235 |  | 
| 258 236 | 
             
              # If not already added, add the proper mime extension to the template path.
         | 
| 259 237 | 
             
              def _conditionally_append_extension(template, type)
         | 
| 260 238 | 
             
                type && !template.match(/\.#{type.to_s.escape_regexp}$/) ? "#{template}.#{type}" : template
         | 
| 261 239 | 
             
              end
         | 
| 262 | 
            -
             | 
| 263 | 
            -
              # Create a default cookie jar, and pre-set a fixation cookie if fixation is enabled.
         | 
| 264 | 
            -
              def _setup_cookies
         | 
| 265 | 
            -
                ::Merb::Cookies.new(request.cookies, @headers)
         | 
| 266 | 
            -
              end
         | 
| 267 | 
            -
            end
         | 
| 240 | 
            +
            end
         | 
| @@ -45,10 +45,27 @@ module Merb::AuthenticationMixin | |
| 45 45 | 
             
              #     
         | 
| 46 46 | 
             
              #     end
         | 
| 47 47 | 
             
              #
         | 
| 48 | 
            +
              # If you need to request basic authentication inside an action you need to use the request! method.
         | 
| 49 | 
            +
              #
         | 
| 50 | 
            +
              # ====Example
         | 
| 51 | 
            +
              #
         | 
| 52 | 
            +
              #    class Sessions < Application
         | 
| 53 | 
            +
              #  
         | 
| 54 | 
            +
              #      def new
         | 
| 55 | 
            +
              #        case content_type
         | 
| 56 | 
            +
              #        when :html
         | 
| 57 | 
            +
              #          render
         | 
| 58 | 
            +
              #        else
         | 
| 59 | 
            +
              #          basic_authentication.request!
         | 
| 60 | 
            +
              #        end
         | 
| 61 | 
            +
              #      end
         | 
| 62 | 
            +
              # 
         | 
| 63 | 
            +
              #    end 
         | 
| 64 | 
            +
              #
         | 
| 48 65 | 
             
              #---
         | 
| 49 66 | 
             
              # @public
         | 
| 50 67 | 
             
              def basic_authentication(realm = "Application", &authenticator)
         | 
| 51 | 
            -
                BasicAuthentication.new(self, realm, &authenticator)
         | 
| 68 | 
            +
                @_basic_authentication ||= BasicAuthentication.new(self, realm, &authenticator)
         | 
| 52 69 | 
             
              end
         | 
| 53 70 |  | 
| 54 71 | 
             
              class BasicAuthentication
         | 
| @@ -58,24 +75,43 @@ module Merb::AuthenticationMixin | |
| 58 75 | 
             
                def initialize(controller, realm = "Application", &authenticator)
         | 
| 59 76 | 
             
                  @controller = controller
         | 
| 60 77 | 
             
                  @realm = realm
         | 
| 78 | 
            +
                  @auth = Rack::Auth::Basic::Request.new(@controller.request.env)
         | 
| 61 79 | 
             
                  authenticate_or_request(&authenticator) if authenticator
         | 
| 62 80 | 
             
                end
         | 
| 63 81 |  | 
| 64 82 | 
             
                def authenticate(&authenticator)
         | 
| 65 | 
            -
                  auth  | 
| 66 | 
            -
             | 
| 67 | 
            -
                  if auth.provided? and auth.basic?
         | 
| 68 | 
            -
                    authenticator.call(*auth.credentials)
         | 
| 83 | 
            +
                  if @auth.provided? and @auth.basic?
         | 
| 84 | 
            +
                    authenticator.call(*@auth.credentials)
         | 
| 69 85 | 
             
                  else
         | 
| 70 86 | 
             
                    false
         | 
| 71 87 | 
             
                  end
         | 
| 72 88 | 
             
                end
         | 
| 73 89 |  | 
| 74 90 | 
             
                def request
         | 
| 75 | 
            -
                   | 
| 91 | 
            +
                  request!
         | 
| 76 92 | 
             
                  throw :halt, @controller.render("HTTP Basic: Access denied.\n", :status => Unauthorized.status, :layout => false)
         | 
| 77 93 | 
             
                end
         | 
| 78 94 |  | 
| 95 | 
            +
                # This is a special case for use outside a before filter.  Use this if you need to 
         | 
| 96 | 
            +
                # request basic authenticaiton as part of an action
         | 
| 97 | 
            +
                def request!
         | 
| 98 | 
            +
                  @controller.status = Unauthorized.status
         | 
| 99 | 
            +
                  @controller.headers['WWW-Authenticate'] = 'Basic realm="%s"' % @realm
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
                
         | 
| 102 | 
            +
                # Checks to see if there has been any basic authentication credentials provided
         | 
| 103 | 
            +
                def provided?
         | 
| 104 | 
            +
                  @auth.provided?
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
                
         | 
| 107 | 
            +
                def username
         | 
| 108 | 
            +
                  provided? ? @auth.credentials.first : nil
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
                
         | 
| 111 | 
            +
                def password
         | 
| 112 | 
            +
                  provided? ? @auth.credentials.last : nil
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
                
         | 
| 79 115 | 
             
                protected
         | 
| 80 116 |  | 
| 81 117 | 
             
                def authenticate_or_request(&authenticator)
         | 
| @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            # Provides conditional get support in Merb core.
         | 
| 2 | 
            +
            # Conditional get support is intentionally
         | 
| 3 | 
            +
            # simple and does not do fancy stuff like making
         | 
| 4 | 
            +
            # ETag value from Ruby objects for you.
         | 
| 5 | 
            +
            #
         | 
| 6 | 
            +
            # The most interesting method for end user is
         | 
| 7 | 
            +
            # +request_fresh?+ that is used after setting of
         | 
| 8 | 
            +
            # last modification time or ETag:
         | 
| 9 | 
            +
            #
         | 
| 10 | 
            +
            # ==== Example
         | 
| 11 | 
            +
            #
         | 
| 12 | 
            +
            # def show
         | 
| 13 | 
            +
            #   self.etag = Digest::SHA1.hexdigest(calculate_cache_key(params))
         | 
| 14 | 
            +
            #
         | 
| 15 | 
            +
            #   if request_fresh?
         | 
| 16 | 
            +
            #     self.status = 304
         | 
| 17 | 
            +
            #     return ''
         | 
| 18 | 
            +
            #   else
         | 
| 19 | 
            +
            #     @product = Product.get(params[:id])
         | 
| 20 | 
            +
            #     display @product
         | 
| 21 | 
            +
            #   end
         | 
| 22 | 
            +
            # end
         | 
| 23 | 
            +
            module Merb::ConditionalGetMixin
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              # Sets ETag response header by calling
         | 
| 26 | 
            +
              # #to_s on the argument.
         | 
| 27 | 
            +
              #
         | 
| 28 | 
            +
              # ==== Parameters
         | 
| 29 | 
            +
              # tag<~to_s>::
         | 
| 30 | 
            +
              #   value of ETag header enclosed in double quotes
         | 
| 31 | 
            +
              #   as required by the RFC
         | 
| 32 | 
            +
              def etag=(tag)
         | 
| 33 | 
            +
                headers[Merb::Const::ETAG] = %("#{tag}")
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              # ==== Returns
         | 
| 37 | 
            +
              # <String>::
         | 
| 38 | 
            +
              #   Value of ETag response header or nil if it's not set.
         | 
| 39 | 
            +
              def etag
         | 
| 40 | 
            +
                headers[Merb::Const::ETAG]
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              # ==== Returns
         | 
| 44 | 
            +
              # <Boolean>::
         | 
| 45 | 
            +
              # true if ETag response header equals If-None-Match request header,
         | 
| 46 | 
            +
              # false otherwise
         | 
| 47 | 
            +
              def etag_matches?(tag = self.etag)
         | 
| 48 | 
            +
                tag == self.request.if_none_match
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              # Sets Last-Modified response header.
         | 
| 52 | 
            +
              #
         | 
| 53 | 
            +
              # ==== Parameters
         | 
| 54 | 
            +
              # tag<Time>::
         | 
| 55 | 
            +
              # resource modification timestamp converted into format
         | 
| 56 | 
            +
              # required by the RFC
         | 
| 57 | 
            +
              def last_modified=(time)
         | 
| 58 | 
            +
                headers[Merb::Const::LAST_MODIFIED] = time.httpdate
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              # ==== Returns
         | 
| 62 | 
            +
              # <String>::
         | 
| 63 | 
            +
              #   Value of Last-Modified response header or nil if it's not set.
         | 
| 64 | 
            +
              def last_modified
         | 
| 65 | 
            +
                Time.rfc2822(headers[Merb::Const::LAST_MODIFIED])
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              # ==== Returns
         | 
| 69 | 
            +
              # <Boolean>::
         | 
| 70 | 
            +
              # true if Last-Modified response header is < than
         | 
| 71 | 
            +
              # If-Modified-Since request header value, false otherwise.
         | 
| 72 | 
            +
              def not_modified?(time = self.last_modified)
         | 
| 73 | 
            +
                request.if_modified_since && time && time <= request.if_modified_since
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              # ==== Returns
         | 
| 77 | 
            +
              # <Boolean>::
         | 
| 78 | 
            +
              # true if either ETag matches or entity is not modified,
         | 
| 79 | 
            +
              # so request is fresh; false otherwise
         | 
| 80 | 
            +
              def request_fresh?
         | 
| 81 | 
            +
                etag_matches?(self.etag) || not_modified?(self.last_modified)
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         | 
| @@ -41,7 +41,7 @@ module Merb::RenderMixin | |
| 41 41 | 
             
                # ==== Returns
         | 
| 42 42 | 
             
                # Hash:: The default render options.
         | 
| 43 43 | 
             
                def layout(layout)
         | 
| 44 | 
            -
                  self.default_render_options.update(:layout => (layout  | 
| 44 | 
            +
                  self.default_render_options.update(:layout => (layout || false))
         | 
| 45 45 | 
             
                end
         | 
| 46 46 |  | 
| 47 47 | 
             
                # Enable the default layout logic - reset the layout option.
         | 
| @@ -95,7 +95,7 @@ module Merb::RenderMixin | |
| 95 95 | 
             
                thing ||= action_name.to_sym
         | 
| 96 96 |  | 
| 97 97 | 
             
                # Content negotiation
         | 
| 98 | 
            -
                 | 
| 98 | 
            +
                self.content_type = opts[:format] if opts[:format]
         | 
| 99 99 |  | 
| 100 100 | 
             
                # Handle options (:status)
         | 
| 101 101 | 
             
                _handle_options!(opts)
         | 
| @@ -189,7 +189,7 @@ module Merb::RenderMixin | |
| 189 189 | 
             
              # explicitly passed in the opts.
         | 
| 190 190 | 
             
              #
         | 
| 191 191 | 
             
              def display(object, thing = nil, opts = {})
         | 
| 192 | 
            -
                template_opt = opts.delete(:template)
         | 
| 192 | 
            +
                template_opt = thing.is_a?(Hash) ? thing.delete(:template) : opts.delete(:template)
         | 
| 193 193 |  | 
| 194 194 | 
             
                case thing
         | 
| 195 195 | 
             
                # display @object, "path/to/foo" means display @object, nil, :template => "path/to/foo"
         | 
| @@ -37,27 +37,14 @@ module Kernel | |
| 37 37 | 
             
              #   If the gem cannot be found, the method will attempt to require the string
         | 
| 38 38 | 
             
              #   as a library.
         | 
| 39 39 | 
             
              def load_dependency(name, *ver)
         | 
| 40 | 
            -
                try_framework = Merb.frozen?
         | 
| 41 40 | 
             
                begin
         | 
| 42 | 
            -
                   | 
| 43 | 
            -
                   | 
| 44 | 
            -
                   | 
| 45 | 
            -
                  if name =~ /^merb/ && try_framework
         | 
| 46 | 
            -
                    require name
         | 
| 47 | 
            -
                  else
         | 
| 48 | 
            -
                    gem(name, *ver) if ver
         | 
| 49 | 
            -
                    require name
         | 
| 50 | 
            -
                    Merb.logger.info!("loading gem '#{name}' ...")
         | 
| 51 | 
            -
                  end
         | 
| 41 | 
            +
                  gem(name, *ver) if ver
         | 
| 42 | 
            +
                  require name
         | 
| 43 | 
            +
                  Merb.logger.info!("loading gem '#{name}' ...")
         | 
| 52 44 | 
             
                rescue LoadError
         | 
| 53 | 
            -
                   | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
                  else
         | 
| 57 | 
            -
                    Merb.logger.info!("loading gem '#{name}' ...")
         | 
| 58 | 
            -
                    # Failed requiring as a gem, let's try loading with a normal require.
         | 
| 59 | 
            -
                    require name
         | 
| 60 | 
            -
                  end
         | 
| 45 | 
            +
                  Merb.logger.info!("loading gem '#{name}' ...")
         | 
| 46 | 
            +
                  # Failed requiring as a gem, let's try loading with a normal require.
         | 
| 47 | 
            +
                  require name
         | 
| 61 48 | 
             
                end
         | 
| 62 49 | 
             
              end
         | 
| 63 50 |  |