rack-flash3 1.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.
- data/README.md +93 -0
- data/Rakefile +28 -0
- data/VERSION.yml +5 -0
- data/example/base_app.ru +22 -0
- data/example/sinatra_app.rb +36 -0
- data/example/views/index.erb +28 -0
- data/example/views/layout.erb +131 -0
- data/example/views/show.erb +15 -0
- data/lib/rack-flash.rb +1 -0
- data/lib/rack/flash.rb +138 -0
- data/lib/rack/flash/test.rb +14 -0
- data/test/helper.rb +51 -0
- data/test/test_flash.rb +157 -0
- metadata +81 -0
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            # Rack Flash
         | 
| 2 | 
            +
             | 
| 3 | 
            +
                flash[:notice] = "You can stop rolling your own now."
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Simple flash hash implementation for Rack apps.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            [View the RDoc](http://gitrdoc.com/nakajima/rack-flash/tree/master).
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## Usage
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Here's how to use it.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ### Vanilla Rack apps
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            You can access flash entries via `env['x-rack.flash']`. You can treat it either
         | 
| 16 | 
            +
            like a regular flash hash:
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                env['x-rack.flash'][:notice] = 'You have logged out.'
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            Or you can pass the `:accessorize` option to declare your flash types. Each of
         | 
| 21 | 
            +
            these will have accessors defined on the flash object:
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                use Rack::Flash, :accessorize => [:notice, :error]
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                # Set a flash entry
         | 
| 26 | 
            +
                env['x-rack.flash'].notice = 'You have logged out.'
         | 
| 27 | 
            +
                
         | 
| 28 | 
            +
                # Get a flash entry
         | 
| 29 | 
            +
                env['x-rack.flash'].notice # => 'You have logged out.'
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                # Set a a flash entry for only the current request
         | 
| 32 | 
            +
                env['x-rack.flash'].notice! 'You have logged out.'
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Sample rack app:
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                get = proc { |env|
         | 
| 37 | 
            +
                  [200, {},
         | 
| 38 | 
            +
                    env['x-rack.flash'].notice || 'No flash set. Try going to /set'
         | 
| 39 | 
            +
                  ]
         | 
| 40 | 
            +
                }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                set = proc { |env|
         | 
| 43 | 
            +
                  env['x-rack.flash'].notice = 'Hey, the flash was set!'
         | 
| 44 | 
            +
                  [302, {'Location' => '/'},
         | 
| 45 | 
            +
                    'You are being redirected.'
         | 
| 46 | 
            +
                  ]
         | 
| 47 | 
            +
                }
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                builder = Rack::Builder.new do
         | 
| 50 | 
            +
                  use Rack::Session::Cookie
         | 
| 51 | 
            +
                  use Rack::Flash, :accessorize => true
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  map('/set') { run set }
         | 
| 54 | 
            +
                  map('/')    { run get }
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                Rack::Handler::Mongrel.run builder, :Port => 9292
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            ### Sinatra
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            If you're using Sinatra, you can use the flash hash just like in Rails:
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                require 'sinatra/base'
         | 
| 64 | 
            +
                require 'rack-flash'
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                class MyApp < Sinatra::Base
         | 
| 67 | 
            +
                  enable :sessions
         | 
| 68 | 
            +
                  use Rack::Flash
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  post '/set-flash' do
         | 
| 71 | 
            +
                    # Set a flash entry
         | 
| 72 | 
            +
                    flash[:notice] = "Thanks for signing up!"
         | 
| 73 | 
            +
                    
         | 
| 74 | 
            +
                    # Get a flash entry
         | 
| 75 | 
            +
                    flash[:notice] # => "Thanks for signing up!"
         | 
| 76 | 
            +
                    
         | 
| 77 | 
            +
                    # Set a flash entry for only the current request
         | 
| 78 | 
            +
                    flash.now[:notice] = "Thanks for signing up!"
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            If you've got any ideas on how to simplify access to the flash hash for vanilla
         | 
| 83 | 
            +
            Rack apps, let me know. It still feels a bit off to me.
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            ## Sweeping stale entries
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            By default Rack::Flash has slightly different behavior than Rails in that it
         | 
| 88 | 
            +
            doesn't delete entries until they are used. If you want entries to be cleared
         | 
| 89 | 
            +
            even if they are not ever accessed, you can use the `:sweep` option:
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                use Rack::Flash, :sweep => true
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            This will sweep stale flash entries, whether or not you actually use them.
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'rake'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            begin
         | 
| 5 | 
            +
              require 'jeweler2'
         | 
| 6 | 
            +
              Jeweler::Tasks.new do |gem|
         | 
| 7 | 
            +
                gem.name = "rack-flash3"
         | 
| 8 | 
            +
                gem.summary = "Flash hash implementation for Rack apps."
         | 
| 9 | 
            +
                gem.description = "Flash hash implementation for Rack apps."
         | 
| 10 | 
            +
                gem.email = "treeder@gmail.com"
         | 
| 11 | 
            +
                gem.homepage = "http://www.iron.io"
         | 
| 12 | 
            +
                gem.authors = ["Pat Nakajima", "Travis Reeder"]
         | 
| 13 | 
            +
                gem.add_dependency 'rack'
         | 
| 14 | 
            +
                gem.required_ruby_version = '>= 1.9'
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
              Jeweler::GemcutterTasks.new
         | 
| 17 | 
            +
            rescue LoadError
         | 
| 18 | 
            +
              puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler2"
         | 
| 19 | 
            +
            end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            require 'rake/testtask'
         | 
| 22 | 
            +
            Rake::TestTask.new(:test) do |test|
         | 
| 23 | 
            +
              test.libs << 'lib' << 'test'
         | 
| 24 | 
            +
              test.pattern = 'test/**/test_*.rb'
         | 
| 25 | 
            +
              test.verbose = true
         | 
| 26 | 
            +
            end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            task :default => :test
         | 
    
        data/VERSION.yml
    ADDED
    
    
    
        data/example/base_app.ru
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            require 'rack/request'
         | 
| 2 | 
            +
            require 'rack/response'
         | 
| 3 | 
            +
            require 'rack/showexceptions'
         | 
| 4 | 
            +
            require 'rack/session/cookie'
         | 
| 5 | 
            +
            require File.dirname(__FILE__) + '/../lib/rack-flash'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            class Base
         | 
| 8 | 
            +
              attr_accessor :env
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              def call(env)
         | 
| 11 | 
            +
                @env = env
         | 
| 12 | 
            +
                flash['err'] = "IT'S ALIVE"
         | 
| 13 | 
            +
                res = Rack::Response.new
         | 
| 14 | 
            +
                res.write "<title>Flashy</title>"
         | 
| 15 | 
            +
                res.write "#{flash['err']}"
         | 
| 16 | 
            +
                res.finish
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
            use Rack::Session::Cookie
         | 
| 20 | 
            +
            use Rack::Flash#, :flash_app_class => Base
         | 
| 21 | 
            +
            use Rack::ShowExceptions
         | 
| 22 | 
            +
            run Base.new
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'sinatra/base'
         | 
| 3 | 
            +
            require File.dirname(__FILE__) + '/../lib/rack-flash'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class MyApp < Sinatra::Base
         | 
| 6 | 
            +
              use Rack::Flash
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              set :root, File.dirname(__FILE__)
         | 
| 9 | 
            +
              set :layout, true
         | 
| 10 | 
            +
              set :logging, true
         | 
| 11 | 
            +
              set :sessions, true
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              get '/' do
         | 
| 14 | 
            +
                erb :index
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              # View the value of any given flash
         | 
| 18 | 
            +
              get '/:name' do
         | 
| 19 | 
            +
                erb :show
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              post '/:name' do
         | 
| 23 | 
            +
                if params[:message].strip.empty?
         | 
| 24 | 
            +
                  flash["err"] = "You must enter a message."
         | 
| 25 | 
            +
                  flash["err_on_#{params[:name]}"] = 1
         | 
| 26 | 
            +
                  redirect('/')
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                flash[:ok] = "Set flash entry!"
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                flash[params[:name]] = params[:message]
         | 
| 32 | 
            +
                redirect '/'
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              run!
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            <% if flash.has?(:err) %>
         | 
| 2 | 
            +
              <h3 class="err"><%= flash[:err] %></h3>
         | 
| 3 | 
            +
            <% end %>
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            <% if flash.has?(:ok) %>
         | 
| 6 | 
            +
              <h3 class="ok"><%= flash[:ok] %></h3>
         | 
| 7 | 
            +
            <% end %>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            <% [:notice, :error, :success, :whatevz, :bliggety].each do |name| %>
         | 
| 10 | 
            +
              <form action="/<%= name %>" method="post" accept-charset="utf-8">
         | 
| 11 | 
            +
                <label>
         | 
| 12 | 
            +
                  <span>
         | 
| 13 | 
            +
                    <% if flash.has?(name) %>
         | 
| 14 | 
            +
                      <a href="/<%= name %>">View Current</a>
         | 
| 15 | 
            +
                    <% end %>
         | 
| 16 | 
            +
                    
         | 
| 17 | 
            +
                    Set <code>flash[:<%= name %>]</code>
         | 
| 18 | 
            +
                    
         | 
| 19 | 
            +
                    <% if err = flash["err_on_#{name}"] %>
         | 
| 20 | 
            +
                      <strong class="err_on">Required!</strong>
         | 
| 21 | 
            +
                    <% end %>
         | 
| 22 | 
            +
                  </span>
         | 
| 23 | 
            +
                  <input type="text" name="message" value="" id="message">
         | 
| 24 | 
            +
                </label>
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                <input type="submit" value="Set Flash">
         | 
| 27 | 
            +
              </form>
         | 
| 28 | 
            +
            <% end %>
         | 
| @@ -0,0 +1,131 @@ | |
| 1 | 
            +
            <html>
         | 
| 2 | 
            +
              <head>
         | 
| 3 | 
            +
                <title>Flash Examples</title>
         | 
| 4 | 
            +
                <style type="text/css" media="screen">
         | 
| 5 | 
            +
                  * {
         | 
| 6 | 
            +
                    margin: 0;
         | 
| 7 | 
            +
                    padding: 0;
         | 
| 8 | 
            +
                  }
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
                  body {
         | 
| 11 | 
            +
                    font-family: Helvetica;
         | 
| 12 | 
            +
                    font-size: 18px;
         | 
| 13 | 
            +
                  }
         | 
| 14 | 
            +
                  
         | 
| 15 | 
            +
                  a {
         | 
| 16 | 
            +
                    color: #f09;
         | 
| 17 | 
            +
                    text-decoration: none;
         | 
| 18 | 
            +
                    padding: 0px 3px;
         | 
| 19 | 
            +
                  }
         | 
| 20 | 
            +
                  
         | 
| 21 | 
            +
                  a:hover {
         | 
| 22 | 
            +
                    background: #f09;
         | 
| 23 | 
            +
                    color: #fff;
         | 
| 24 | 
            +
                  }
         | 
| 25 | 
            +
                  
         | 
| 26 | 
            +
                  a:active {
         | 
| 27 | 
            +
                    text-decoration: underline;
         | 
| 28 | 
            +
                  }
         | 
| 29 | 
            +
                  
         | 
| 30 | 
            +
                  h1 {
         | 
| 31 | 
            +
                    text-align: center;
         | 
| 32 | 
            +
                  }
         | 
| 33 | 
            +
                  
         | 
| 34 | 
            +
                  code {
         | 
| 35 | 
            +
                    font-family: Bitstream Vera Sans Mono , monospace;
         | 
| 36 | 
            +
                    background: #D4EBF7;
         | 
| 37 | 
            +
                  }
         | 
| 38 | 
            +
                  
         | 
| 39 | 
            +
                  form {
         | 
| 40 | 
            +
                    margin: 0.4em auto;
         | 
| 41 | 
            +
                    display: inline-block;
         | 
| 42 | 
            +
                  }
         | 
| 43 | 
            +
                  
         | 
| 44 | 
            +
                  label {
         | 
| 45 | 
            +
                    line-height: 1em;
         | 
| 46 | 
            +
                    height: 1em;
         | 
| 47 | 
            +
                  }
         | 
| 48 | 
            +
                  
         | 
| 49 | 
            +
                  label span {
         | 
| 50 | 
            +
                    display: block;
         | 
| 51 | 
            +
                    font-size: 12px;
         | 
| 52 | 
            +
                    margin-bottom: 1px;
         | 
| 53 | 
            +
                  }
         | 
| 54 | 
            +
                  
         | 
| 55 | 
            +
                  label a {
         | 
| 56 | 
            +
                    font-weight: bold;
         | 
| 57 | 
            +
                    float: right;
         | 
| 58 | 
            +
                    margin-right: 79px;
         | 
| 59 | 
            +
                    line-height: 1.5em;
         | 
| 60 | 
            +
                  }
         | 
| 61 | 
            +
                  
         | 
| 62 | 
            +
                  input[type="text"] {
         | 
| 63 | 
            +
                    padding: 2px;
         | 
| 64 | 
            +
                    font-size: 18px;
         | 
| 65 | 
            +
                    width: 610px;
         | 
| 66 | 
            +
                    margin-right: 10px;
         | 
| 67 | 
            +
                  }
         | 
| 68 | 
            +
                  
         | 
| 69 | 
            +
                  input[type="submit"] {
         | 
| 70 | 
            +
                    cursor: pointer;
         | 
| 71 | 
            +
                    vertical-align: 20%;
         | 
| 72 | 
            +
                  }
         | 
| 73 | 
            +
                  
         | 
| 74 | 
            +
                  .err, .ok {
         | 
| 75 | 
            +
                    margin: 0.3em 0;
         | 
| 76 | 
            +
                    padding: 5px 7px;
         | 
| 77 | 
            +
                    text-align: center;
         | 
| 78 | 
            +
                    color: #fff;
         | 
| 79 | 
            +
                  }
         | 
| 80 | 
            +
                  
         | 
| 81 | 
            +
                  .ok {
         | 
| 82 | 
            +
                    background: #00A8FF;
         | 
| 83 | 
            +
                  }
         | 
| 84 | 
            +
                  
         | 
| 85 | 
            +
                  .err {
         | 
| 86 | 
            +
                    background: #f10;
         | 
| 87 | 
            +
                  }
         | 
| 88 | 
            +
                  
         | 
| 89 | 
            +
                  .err_on {
         | 
| 90 | 
            +
                    display: inline-block;
         | 
| 91 | 
            +
                    padding: 0px 3px;
         | 
| 92 | 
            +
                    color: #f10;
         | 
| 93 | 
            +
                    font-weight: bold;
         | 
| 94 | 
            +
                  }
         | 
| 95 | 
            +
                  
         | 
| 96 | 
            +
                  .highlight {
         | 
| 97 | 
            +
                    background: #ffc;
         | 
| 98 | 
            +
                    padding: 10px;
         | 
| 99 | 
            +
                    margin-bottom: 10px;
         | 
| 100 | 
            +
                  }
         | 
| 101 | 
            +
                  
         | 
| 102 | 
            +
                  #content {
         | 
| 103 | 
            +
                    width: 700px;
         | 
| 104 | 
            +
                    margin: 1em auto;
         | 
| 105 | 
            +
                  }
         | 
| 106 | 
            +
                  
         | 
| 107 | 
            +
                  #result {
         | 
| 108 | 
            +
                    font-size: 48px;
         | 
| 109 | 
            +
                    margin: 10% auto 20%;
         | 
| 110 | 
            +
                    text-align: center;
         | 
| 111 | 
            +
                    display: block;
         | 
| 112 | 
            +
                  }
         | 
| 113 | 
            +
                  
         | 
| 114 | 
            +
                  #result cite {
         | 
| 115 | 
            +
                    font-size: 14px;
         | 
| 116 | 
            +
                    display: block;
         | 
| 117 | 
            +
                    text-align: right;
         | 
| 118 | 
            +
                  }
         | 
| 119 | 
            +
                  
         | 
| 120 | 
            +
                  #result cite code {
         | 
| 121 | 
            +
                    font-style: normal;
         | 
| 122 | 
            +
                  }
         | 
| 123 | 
            +
                </style>
         | 
| 124 | 
            +
              </head>
         | 
| 125 | 
            +
              <body>
         | 
| 126 | 
            +
                <div id="content">
         | 
| 127 | 
            +
                  <h1><code>Sinatra::Flash</code></h1>
         | 
| 128 | 
            +
                  <%= yield %>
         | 
| 129 | 
            +
                </div>
         | 
| 130 | 
            +
              </body>
         | 
| 131 | 
            +
            </html>
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            <div id="result">
         | 
| 2 | 
            +
              <% if flash.has?(params[:name]) %>
         | 
| 3 | 
            +
                <h1 class="highlight"><%= flash[params[:name]] %></h1>
         | 
| 4 | 
            +
                <cite>- from <code>flash[:<%= params[:name] %>]</code></cite>
         | 
| 5 | 
            +
              <% else %>
         | 
| 6 | 
            +
                <p>No flash message for <code>flash[:<%= params[:name] %>]</code></p>
         | 
| 7 | 
            +
              <% end %>
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
              <br>
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              <small>
         | 
| 12 | 
            +
                <a href="/">Go Back Home</a>
         | 
| 13 | 
            +
              </small>
         | 
| 14 | 
            +
            </div>
         | 
| 15 | 
            +
             | 
    
        data/lib/rack-flash.rb
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            require File.join(File.dirname(__FILE__), *%w[rack flash])
         | 
    
        data/lib/rack/flash.rb
    ADDED
    
    | @@ -0,0 +1,138 @@ | |
| 1 | 
            +
            module Rack
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              class Flash
         | 
| 4 | 
            +
                # Raised when the session passed to FlashHash initialize is nil. This
         | 
| 5 | 
            +
                # is usually an indicator that session middleware is not in use.
         | 
| 6 | 
            +
                class SessionUnavailable < StandardError; end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                # Implements bracket accessors for storing and retrieving flash entries.
         | 
| 9 | 
            +
                class FlashHash
         | 
| 10 | 
            +
                  attr_reader :flagged
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def initialize(store, opts={})
         | 
| 13 | 
            +
                    raise Rack::Flash::SessionUnavailable \
         | 
| 14 | 
            +
                      .new('Rack::Flash depends on session middleware.') unless store
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    @opts = opts
         | 
| 17 | 
            +
                    @store = store
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    if accessors = @opts[:accessorize]
         | 
| 20 | 
            +
                      accessors.each { |opt| def_accessor(opt) }
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # Remove an entry from the session and return its value. Cache result in
         | 
| 25 | 
            +
                  # the instance cache.
         | 
| 26 | 
            +
                  def [](key)
         | 
| 27 | 
            +
                    key = key.to_sym
         | 
| 28 | 
            +
                    cache[key] ||= values.delete(key)
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  # Store the entry in the session, updating the instance cache as well.
         | 
| 32 | 
            +
                  def []=(key,val)
         | 
| 33 | 
            +
                    key = key.to_sym
         | 
| 34 | 
            +
                    cache[key] = values[key] = val
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # Store a flash entry for only the current request, swept regardless of
         | 
| 38 | 
            +
                  # whether or not it was actually accessed. Useful for AJAX requests, where
         | 
| 39 | 
            +
                  # you want a flash message, even though you're response isn't redirecting.
         | 
| 40 | 
            +
                  def now
         | 
| 41 | 
            +
                    cache
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  # Checks for the presence of a flash entry without retrieving or removing
         | 
| 45 | 
            +
                  # it from the cache or store.
         | 
| 46 | 
            +
                  def has?(key)
         | 
| 47 | 
            +
                    [cache, values].any? { |store| store.keys.include?(key.to_sym) }
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                  alias_method :include?, :has?
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  # Mark existing entries to allow for sweeping.
         | 
| 52 | 
            +
                  def flag!
         | 
| 53 | 
            +
                    @flagged = values.keys
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  # Remove flagged entries from flash session, clear flagged list.
         | 
| 57 | 
            +
                  def sweep!
         | 
| 58 | 
            +
                    Array(flagged).each { |key| values.delete(key) }
         | 
| 59 | 
            +
                    flagged.clear
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  # Hide the underlying :__FLASH__ session key and only expose values stored
         | 
| 63 | 
            +
                  # in the flash.
         | 
| 64 | 
            +
                  def inspect
         | 
| 65 | 
            +
                    '#<FlashHash @values=%s @cache=%s>' % [values.inspect, cache.inspect]
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  # Human readable for logging.
         | 
| 69 | 
            +
                  def to_s
         | 
| 70 | 
            +
                    values.inspect
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  private
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  # Maintain an instance-level cache of retrieved flash entries. These
         | 
| 76 | 
            +
                  # entries will have been removed from the session, but are still available
         | 
| 77 | 
            +
                  # through the cache.
         | 
| 78 | 
            +
                  def cache
         | 
| 79 | 
            +
                    @cache ||= {}
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  # Helper to access flash entries from :__FLASH__ session value. This key
         | 
| 83 | 
            +
                  # is used to prevent collisions with other user-defined session values.
         | 
| 84 | 
            +
                  def values
         | 
| 85 | 
            +
                    @store[:__FLASH__] ||= {}
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  # Generate accessor methods for the given entry key if :accessorize is true.
         | 
| 89 | 
            +
                  def def_accessor(key)
         | 
| 90 | 
            +
                    raise ArgumentError.new('Invalid entry type: %s' % key) if respond_to?(key)
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                    class << self; self end.class_eval do
         | 
| 93 | 
            +
                      define_method(key) { |*args| val = args.first; val ? (self[key]=val) : self[key] }
         | 
| 94 | 
            +
                      define_method("#{key}=") { |val| self[key] = val }
         | 
| 95 | 
            +
                      define_method("#{key}!") { |val| cache[key] = val }
         | 
| 96 | 
            +
                    end
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                # -------------------------------------------------------------------------
         | 
| 101 | 
            +
                # - Rack Middleware implementation
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                def initialize(app, opts={})
         | 
| 104 | 
            +
                  if klass = app_class(app, opts)
         | 
| 105 | 
            +
                    klass.class_eval do
         | 
| 106 | 
            +
                      def flash; env['x-rack.flash'] end
         | 
| 107 | 
            +
                    end
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                  @app, @opts = app, opts
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                def call(env)
         | 
| 114 | 
            +
                  env['x-rack.flash'] ||= Rack::Flash::FlashHash.new(env['rack.session'], @opts)
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                  if @opts[:sweep]
         | 
| 117 | 
            +
                    env['x-rack.flash'].flag!
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                  res = @app.call(env)
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                  if @opts[:sweep]
         | 
| 123 | 
            +
                    env['x-rack.flash'].sweep!
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  res
         | 
| 127 | 
            +
                end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                private
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                def app_class(app, opts)
         | 
| 132 | 
            +
                  return nil if opts.has_key?(:helper) and not opts[:helper]
         | 
| 133 | 
            +
                  opts[:flash_app_class] ||
         | 
| 134 | 
            +
                    defined?(Sinatra::Base) && Sinatra::Base ||
         | 
| 135 | 
            +
                    self.class.rack_builder.leaf_app.class
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            module Rack
         | 
| 2 | 
            +
              class Flash
         | 
| 3 | 
            +
                def self.fake_session
         | 
| 4 | 
            +
                  @fake_session ||= {}
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                alias_method :old_call, :call
         | 
| 8 | 
            +
                def new_call(env)
         | 
| 9 | 
            +
                  env['rack.session'] ||= Rack::Flash.fake_session
         | 
| 10 | 
            +
                  old_call(env)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                alias_method :call, :new_call
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
    
        data/test/helper.rb
    ADDED
    
    | @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            gem 'sinatra', '<=1.3.2'
         | 
| 3 | 
            +
            require 'sinatra/base'
         | 
| 4 | 
            +
            require 'bacon'
         | 
| 5 | 
            +
            require 'rack/test'
         | 
| 6 | 
            +
            require File.join(File.dirname(__FILE__), *%w[.. lib rack-flash])
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class String
         | 
| 9 | 
            +
              [:green, :yellow, :red].each { |c| define_method(c) { self } }
         | 
| 10 | 
            +
            end if ENV['TM_RUBY']
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            # bacon swallows errors alive
         | 
| 13 | 
            +
            def err_explain
         | 
| 14 | 
            +
              begin
         | 
| 15 | 
            +
                yield
         | 
| 16 | 
            +
              rescue => e
         | 
| 17 | 
            +
                puts e.inspect
         | 
| 18 | 
            +
                puts e.backtrace
         | 
| 19 | 
            +
                raise e
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            module Rack
         | 
| 24 | 
            +
              class FakeFlash < Rack::Flash::FlashHash
         | 
| 25 | 
            +
                attr_reader :flagged, :sweeped, :store
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def initialize(*args)
         | 
| 28 | 
            +
                  @flagged, @sweeped = false, false
         | 
| 29 | 
            +
                  @store = {}
         | 
| 30 | 
            +
                  super(@store)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def flag!
         | 
| 34 | 
            +
                  @flagged = true
         | 
| 35 | 
            +
                  super
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def sweep!
         | 
| 39 | 
            +
                  @sweeped = true
         | 
| 40 | 
            +
                  super
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def flagged?
         | 
| 44 | 
            +
                  @flagged
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def swept?
         | 
| 48 | 
            +
                  @sweeped
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
    
        data/test/test_flash.rb
    ADDED
    
    | @@ -0,0 +1,157 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe 'Rack::Flash' do
         | 
| 4 | 
            +
              include Rack::Test::Methods
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def app(&block)
         | 
| 7 | 
            +
                return Sinatra.new &block
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              before do
         | 
| 11 | 
            +
                @fake_session = {}
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def new_flash(entries={})
         | 
| 15 | 
            +
                flash = Rack::Flash::FlashHash.new(@fake_session)
         | 
| 16 | 
            +
                entries.each { |key,val| flash[key] = val }
         | 
| 17 | 
            +
                flash
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              it 'stores entries' do
         | 
| 21 | 
            +
                new_flash[:foo] = 'bar'
         | 
| 22 | 
            +
                new_flash[:foo].should.equal('bar')
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              it 'accepts strings or hashes' do
         | 
| 26 | 
            +
                new_flash[:foo] = 'bar'
         | 
| 27 | 
            +
                new_flash['foo'].should.equal('bar')
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              it 'deletes entries from session after retrieval' do
         | 
| 31 | 
            +
                new_flash[:foo] = 'bar'
         | 
| 32 | 
            +
                new_flash[:foo]
         | 
| 33 | 
            +
                new_flash[:foo].should.be.nil
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              it 'caches retrieved entries in instance' do
         | 
| 37 | 
            +
                flash = new_flash(:foo => 'bar')
         | 
| 38 | 
            +
                flash[:foo].should.equal('bar')
         | 
| 39 | 
            +
                flash[:foo].should.equal('bar')
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              it 'does not step on session keys' do
         | 
| 43 | 
            +
                @fake_session[:foo] = true
         | 
| 44 | 
            +
                new_flash[:foo] = false
         | 
| 45 | 
            +
                @fake_session[:foo].should.be.true
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              it 'can flag existing entries' do
         | 
| 49 | 
            +
                flash = new_flash(:foo => 'bar', :fizz => 'buzz')
         | 
| 50 | 
            +
                flash.flag!
         | 
| 51 | 
            +
                flash.flagged.should.include(:foo)
         | 
| 52 | 
            +
                flash.flagged.should.include(:fizz)
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              it 'can sweep flagged entries' do
         | 
| 56 | 
            +
                err_explain do
         | 
| 57 | 
            +
                  flash = new_flash(:foo => 'bar', :fizz => 'buzz')
         | 
| 58 | 
            +
                  flash.flag!
         | 
| 59 | 
            +
                  flash.sweep!
         | 
| 60 | 
            +
                  flash.flagged.should.be.empty
         | 
| 61 | 
            +
                  new_flash[:foo].should.be.nil
         | 
| 62 | 
            +
                  new_flash[:fizz].should.be.nil
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              it 'allows setters with Flash.now semantics' do
         | 
| 67 | 
            +
                flash = new_flash
         | 
| 68 | 
            +
                flash.now[:foo] = 'bar'
         | 
| 69 | 
            +
                flash[:foo].should.equal('bar')
         | 
| 70 | 
            +
                new_flash[:foo].should.be.nil
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              it 'does not raise an error when session is cleared' do
         | 
| 74 | 
            +
                flash = new_flash
         | 
| 75 | 
            +
                flash[:foo] = 'bar'
         | 
| 76 | 
            +
                @fake_session.clear
         | 
| 77 | 
            +
                flash['foo'].should.equal(nil)
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              describe 'accessorize option' do
         | 
| 81 | 
            +
                def new_flash(entries={})
         | 
| 82 | 
            +
                  flash = Rack::Flash::FlashHash.new(@fake_session, :accessorize => [:foo, :fizz])
         | 
| 83 | 
            +
                  entries.each { |key,val| flash[key] = val }
         | 
| 84 | 
            +
                  flash
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                it 'allows getters' do
         | 
| 88 | 
            +
                  flash = new_flash(:foo => 'bar')
         | 
| 89 | 
            +
                  flash.foo.should.equal('bar')
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                it 'allows setters' do
         | 
| 93 | 
            +
                  flash = new_flash
         | 
| 94 | 
            +
                  flash.fizz = 'buzz'
         | 
| 95 | 
            +
                  flash.fizz.should.equal('buzz')
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                it 'allows declarative setters' do
         | 
| 99 | 
            +
                  flash = new_flash
         | 
| 100 | 
            +
                  flash.fizz 'buzz'
         | 
| 101 | 
            +
                  flash.fizz.should.equal('buzz')
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                it 'allows setters with Flash.now semantics' do
         | 
| 105 | 
            +
                  flash = new_flash
         | 
| 106 | 
            +
                  flash.foo! 'bar'
         | 
| 107 | 
            +
                  flash.foo.should.equal('bar')
         | 
| 108 | 
            +
                  new_flash[:foo].should.be.nil
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                it 'only defines accessors for passed entry types' do
         | 
| 112 | 
            +
                  err_explain do
         | 
| 113 | 
            +
                    flash = new_flash
         | 
| 114 | 
            +
                    proc {
         | 
| 115 | 
            +
                      flash.bliggety = 'blam'
         | 
| 116 | 
            +
                    }.should.raise(NoMethodError)
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              it 'does not provide getters by default' do
         | 
| 122 | 
            +
                proc {
         | 
| 123 | 
            +
                  new_flash(:foo => 'bar').foo
         | 
| 124 | 
            +
                }.should.raise(NoMethodError)
         | 
| 125 | 
            +
              end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
              it 'does not provide setters by default' do
         | 
| 128 | 
            +
                proc {
         | 
| 129 | 
            +
                  flash = new_flash
         | 
| 130 | 
            +
                  flash.fizz = 'buzz'
         | 
| 131 | 
            +
                }.should.raise(NoMethodError)
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
              describe 'integration' do
         | 
| 135 | 
            +
                it 'provides :sweep option to clear unused entries' do
         | 
| 136 | 
            +
                  app {
         | 
| 137 | 
            +
                    use Rack::Flash, :sweep => true
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                    set :sessions, true
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                    get '/' do
         | 
| 142 | 
            +
                      'ok'
         | 
| 143 | 
            +
                    end
         | 
| 144 | 
            +
                  }
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                  fake_flash = Rack::FakeFlash.new(:foo => 'bar')
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  get '/', :env=>{ 'x-rack.flash' => fake_flash }
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  fake_flash.should.be.flagged
         | 
| 151 | 
            +
                  fake_flash.should.be.swept
         | 
| 152 | 
            +
                  fake_flash.store[:foo].should.be.nil
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
              end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
              # Testing sessions is a royal pain in the ass.
         | 
| 157 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: rack-flash3
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 1.0.0
         | 
| 5 | 
            +
              prerelease: 
         | 
| 6 | 
            +
            platform: ruby
         | 
| 7 | 
            +
            authors:
         | 
| 8 | 
            +
            - Pat Nakajima
         | 
| 9 | 
            +
            - Travis Reeder
         | 
| 10 | 
            +
            autorequire: 
         | 
| 11 | 
            +
            bindir: bin
         | 
| 12 | 
            +
            cert_chain: []
         | 
| 13 | 
            +
            date: 2012-03-19 00:00:00.000000000Z
         | 
| 14 | 
            +
            dependencies:
         | 
| 15 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 16 | 
            +
              name: rack
         | 
| 17 | 
            +
              requirement: &11215120 !ruby/object:Gem::Requirement
         | 
| 18 | 
            +
                none: false
         | 
| 19 | 
            +
                requirements:
         | 
| 20 | 
            +
                - - ! '>='
         | 
| 21 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            +
                    version: '0'
         | 
| 23 | 
            +
              type: :runtime
         | 
| 24 | 
            +
              prerelease: false
         | 
| 25 | 
            +
              version_requirements: *11215120
         | 
| 26 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 27 | 
            +
              name: rack
         | 
| 28 | 
            +
              requirement: &11214480 !ruby/object:Gem::Requirement
         | 
| 29 | 
            +
                none: false
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - ! '>='
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '0'
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: *11214480
         | 
| 37 | 
            +
            description: Flash hash implementation for Rack apps.
         | 
| 38 | 
            +
            email: treeder@gmail.com
         | 
| 39 | 
            +
            executables: []
         | 
| 40 | 
            +
            extensions: []
         | 
| 41 | 
            +
            extra_rdoc_files:
         | 
| 42 | 
            +
            - README.md
         | 
| 43 | 
            +
            files:
         | 
| 44 | 
            +
            - README.md
         | 
| 45 | 
            +
            - Rakefile
         | 
| 46 | 
            +
            - VERSION.yml
         | 
| 47 | 
            +
            - example/base_app.ru
         | 
| 48 | 
            +
            - example/sinatra_app.rb
         | 
| 49 | 
            +
            - example/views/index.erb
         | 
| 50 | 
            +
            - example/views/layout.erb
         | 
| 51 | 
            +
            - example/views/show.erb
         | 
| 52 | 
            +
            - lib/rack-flash.rb
         | 
| 53 | 
            +
            - lib/rack/flash.rb
         | 
| 54 | 
            +
            - lib/rack/flash/test.rb
         | 
| 55 | 
            +
            - test/helper.rb
         | 
| 56 | 
            +
            - test/test_flash.rb
         | 
| 57 | 
            +
            homepage: http://www.iron.io
         | 
| 58 | 
            +
            licenses: []
         | 
| 59 | 
            +
            post_install_message: 
         | 
| 60 | 
            +
            rdoc_options: []
         | 
| 61 | 
            +
            require_paths:
         | 
| 62 | 
            +
            - lib
         | 
| 63 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 64 | 
            +
              none: false
         | 
| 65 | 
            +
              requirements:
         | 
| 66 | 
            +
              - - ! '>='
         | 
| 67 | 
            +
                - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                  version: '1.9'
         | 
| 69 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 70 | 
            +
              none: false
         | 
| 71 | 
            +
              requirements:
         | 
| 72 | 
            +
              - - ! '>='
         | 
| 73 | 
            +
                - !ruby/object:Gem::Version
         | 
| 74 | 
            +
                  version: '0'
         | 
| 75 | 
            +
            requirements: []
         | 
| 76 | 
            +
            rubyforge_project: 
         | 
| 77 | 
            +
            rubygems_version: 1.8.15
         | 
| 78 | 
            +
            signing_key: 
         | 
| 79 | 
            +
            specification_version: 3
         | 
| 80 | 
            +
            summary: Flash hash implementation for Rack apps.
         | 
| 81 | 
            +
            test_files: []
         |