rack-flash3 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 1
3
+ :minor: 0
4
+ :patch: 0
5
+ :build: !!null
@@ -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
@@ -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: []