sinatra-flash 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.markdown
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE.markdown
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
@@ -0,0 +1,113 @@
1
+ The Don't Be a Dick License
2
+ ===========================
3
+ _version 0.2_
4
+
5
+ **Project:** [Sinatra::Flash](http://github.com/SFEley/sinatra-flash)
6
+ **Author:** Stephen Eley (<sfeley@gmail.com>)
7
+
8
+ This is a proposed draft of the **Don't Be a Dick** license for open source projects. The purpose of this license is to permit the broadest feasible scope for reuse and modification of creative work, restricted only by the requirement that one is not a dick about it.
9
+
10
+ 1. Legal Parameters
11
+ -------------------
12
+ For legal purposes, the DBAD license is a superset of the [Apache License, Version 2.0][1] and incorporates all terms, conditions, privileges and limitations therein. The following text is a binding part of this license for this project:
13
+
14
+ > Copyright 2010 Stephen Eley
15
+
16
+ > Licensed under the Apache License, Version 2.0 (the "License");
17
+ you may not use this file except in compliance with the License.
18
+ You may obtain a copy of the License at
19
+
20
+ > <http://www.apache.org/licenses/LICENSE-2.0>
21
+
22
+ > Unless required by applicable law or agreed to in writing, software
23
+ distributed under the License is distributed on an "AS IS" BASIS,
24
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25
+ See the License for the specific language governing permissions and
26
+ limitations under the License.
27
+
28
+ Nothing in the following text should be construed to inhibit, contradict, or override any part of the Apache License, Version 2.0.
29
+
30
+ 2. Definitions
31
+ --------------
32
+ The following terms and definitions shall be in effect for the rest of this document.
33
+
34
+ > **NOTE:** Singular nouns and pronouns are used throughout this License for
35
+ grammatical convenience. However, any of the terms below _may_ refer to a
36
+ collective work or group of people. If this pegs your punctiliousness, you
37
+ are directed to mentally substitute "Person _or persons_," "Dick _or
38
+ dicks,_" etc., throughout this license. Just don't tell us about it.
39
+
40
+ ### A. Project
41
+
42
+ A creative work of (software | writing | visual art | music) into which significant time and energy have been invested by people who _are not you,_ and which has been released into the world for the benefit of the general public (_including you._)
43
+
44
+ The **Project** may include, incorporate, derive from, or be inspired by other works. The Author, being a Reasonable Person, has made use of such source materials only as permitted by their own licenses or applicable law. The License you are reading applies only to those portions of the Project which are original and distinct to it. Source materials may be covered by their own licenses or conditions, and should not be assumed to have coverage under this License. (However, you are strongly encouraged not to be a dick about them either.)
45
+
46
+ ### B. Author
47
+
48
+ A person who has invested significant time and energy into the Project licensed herein. Given the Author's release of the Project to the world under a liberal license, the Author is declared a Reasonable Person (at least within this context) and inherits all attributes, freedoms, and responsibilities thereof. No other assumptions are made about the Author, nor should you make any.
49
+
50
+ ### C. Reasonable Person
51
+
52
+ A person who respects the time and energy that have been invested in the Project licensed herein, and acts accordingly. A Reasonable Person is broadly characterized as one who exercises his or her privilege to use, _not_ use, redistribute, modify, improve, worsen, review, report issues upon, participate in the community of, or ignore the work _without_ placing undue demands upon the Author. I.e., a Reasonable Person is a constituent of the majority of open source users and the population at large who are not Dicks.
53
+
54
+ ### D. Dick
55
+
56
+ A person who _does not_ respect the time and energy that have been invested in the Project, and acts to punish such effort by giving others associated with the Project -- including, but not limited to, the Author -- a hard time. A Dick is nearly always selfish, but not necessarily with deliberate intent; some Dicks are merely thoughtless. The distinguishing characteristic of a Dick is that he or she places burdens upon Reasonable People, reducing their motivation to engage in open source activities. This damping effect is a significant detriment to the Project, to open source in general, to the production of new intellectual value in the world -- and, ultimately, to the Dick himself or herself.
57
+
58
+ > **NOTE:** Despite its original gender association, the word "Dick" is used herein in a _cultural_ context and not a _genital_ context. This License has chosen to adopt the term for its linguistic force and psychological impact, and sincerely regrets any inference of sexism. For purposes of the terms and conditions contained herein, it is understood that both men and women are equally capable of being Dicks.
59
+
60
+ > (But they shouldn't be.)
61
+
62
+ 3. Permissions
63
+ --------------
64
+
65
+ The following privileges are granted explicitly and exclusively to Reasonable People. Although the Author acknowledges the practical unfeasibility of barring Dicks from enjoying the same privileges, they are nevertheless asked to refrain from any activity related to the Project _and/or_ to reconsider their behavior and stop being Dicks.
66
+
67
+ 1. You are permitted to use the Project or any component of the Project.
68
+
69
+ 2. You are permitted to redistribute the Project or any component of the Project, by itself or as part of a different work, provided that you give fair and reasonable credit back to the Author.
70
+
71
+ 3. You are permitted to change the Project for your own needs or anyone else's. You may keep your changes to yourself or submit them back to the Author or the community, as you see fit, provided you are not a Dick about it.
72
+
73
+ 4. You are permitted and encouraged to participate in any community related to the Project, or to create new communities.
74
+
75
+ 5. You are permitted to report issues or problems with the Project, and to request that they be addressed, so long as the request is made in a reasonable fashion. (This privilege does _not_ oblige the Author to respond.)
76
+
77
+ 6. You are permitted to make money from the Project. No recompense is owed to the Author unless by separate agreement, although sharing opportunities for mutual benefit is by no means discouraged.
78
+
79
+ 7. You are permitted to discuss the Project in any medium, in any positive or negative spirit, so long as criticism is not libelous nor _ad hominem._ (I.e., don't lie, and keep it about the _work_ and not the _people._)
80
+
81
+ 8. You are permitted to ignore the Project completely and make no use of it whatsoever. This right is irrevocable and absolute, and extended to Dicks and Reasonable People alike.
82
+
83
+ 4. Limitations
84
+ --------------
85
+
86
+ The following restrictions are imposed explicitly and exclusively upon Dicks. These limitations are the inverse of the above privileges and are also tautological, as the prohibited actions are those _definitive_ of Dickhood.
87
+
88
+ 1. You may not impede Reasonable People from exercising their privilege to use, redistribute, change, participate in, profit from, discuss, or ignore the Project.
89
+
90
+ 2. You may not withhold the Author's credit for the Project, nor otherwise present the work of anyone else as your own.
91
+
92
+ 3. You may not hold the Author responsible for any use or abuse of the Project by you or anyone else.
93
+
94
+ 4. You may not troll, flame, nor dumb down any community associated with the Project.
95
+
96
+ 5. Barring separate agreements, you may not _demand_ any time or attention on the part of the Author nor anyone else in the community. You may not hold the Author personally accountable for any issues you discover nor otherwise spread your own problems to other people.
97
+
98
+ 6. You may not attempt to _compel_ time nor money from the Author nor any other community member by any means, including but not limited to legal action, intimidation, or annoyance.
99
+
100
+ 7. You may not engage in _ad hominem_ (i.e. personal) attacks or criticism of the Author in the course of criticizing the Project.
101
+
102
+ 8. You may not impede the absolute and irrevocable privilege of the Author and other members of the community to ignore you.
103
+
104
+ 5. Use of This License
105
+ ----------------------
106
+ The Don't Be a Dick License is released under the terms of the Don't Be a Dick License. Projects released under this License should remain under the License, and the terms of the License may not be modified by anyone other than the Project's original Author.
107
+
108
+ If you wish to make use of the License for your own open work, you may do so without asking permission, provided said work is truly your own, truly open, and you are truly not a Dick. You may modify the terms of the License to suit your own needs, but are strongly advised to annotate said changes. Modifications may not reduce the freedoms granted to Reasonable People as described in Section 3.
109
+
110
+ Reasonable People are _invited,_ but not compelled, to visit the Web site at <http://dbad-license.org> and browse or add their project to the repository of works released under the License.
111
+
112
+
113
+ [1]: http://apache.org/licenses/LICENSE-2.0
@@ -0,0 +1,157 @@
1
+ Sinatra::Flash
2
+ ==============
3
+ This is an implementation of show-'em-once 'flash' messages for the [Sinatra][1] Web framework. It offers the following feature set:
4
+
5
+ * Simplicity (less than 50 significant lines of code)
6
+ * Implements the documented [behavior][3] and [public API][4] of the Rails flash that many developers are used to
7
+ * Acts entirely like a hash, including iterations and merging
8
+ * Zero configuration for a Sinatra 'classic' app -- it'll even turn sessions on if you didn't already
9
+ * Optional multiple named flash collections, each with their own message hash, so that different embedded applications can access different sets of messages
10
+ * An HTML helper for displaying flash messages with CSS styling
11
+ * Verbose documentation in [YARD][5] format
12
+ * Full RSpec tests
13
+
14
+ The primary catch for experienced Rack developers is that it _does not_ function as standalone Rack middleware. (You could get to the messages inside the session if you needed to, but the message rotation occurs in a Sinatra `after` hook.) It should function just fine across multiple Sinatra apps, but if you need flash that's accessible from non-Sinatra applications, consider the [Rack::Flash][2] middleware.
15
+
16
+ Setting Up
17
+ ----------
18
+ You should know this part:
19
+
20
+ $ gem install sinatra-flash
21
+
22
+ (Or `sudo gem install` if you're the last person on Earth who isn't using [RVM][6] yet.)
23
+
24
+ If you're developing a Sinatra ['classic'][7] application, then all you need to do is require the library:
25
+
26
+ # blah_app.rb
27
+ require 'sinatra'
28
+ require 'sinatra/flash'
29
+
30
+ post '/blah' do
31
+ # This message won't be seen until the NEXT Web request that accesses the flash collection
32
+ flash[:blah] = "You were feeling blah at #{Time.now}."
33
+
34
+ # Accessing the flash displays messages set from the LAST request
35
+ "Feeling blah again? That's too bad. #{flash[:blah]}"
36
+ end
37
+
38
+ If you're using the [Sinatra::Base][7] style, you also need to register the extension:
39
+
40
+ # bleh_app.rb
41
+ require 'sinatra/base'
42
+ require 'sinatra/flash'
43
+
44
+ class BlehApp < Sinatra::Base
45
+ register Sinatra::Flash
46
+
47
+ get '/bleh' do
48
+ if flash[:blah]
49
+ # The flash collection is cleared after any request that uses it
50
+ "Have you ever felt blah? Oh yes. #{flash[:blah]} Remember?"
51
+ else
52
+ "Oh, now you're only feeling bleh?"
53
+ end
54
+ end
55
+ end
56
+
57
+ See the Sinatra documentation on [using extensions][8] for more detail and rationale.
58
+
59
+ styled_flash
60
+ ------------
61
+ The gem comes with a handy view helper that iterates through current flash messages and renders them in styled HTML:
62
+
63
+ # Using HAML, 'cause the cool kids are all doing it
64
+ %html
65
+ %body
66
+ =styled_flash
67
+
68
+ Yields (assuming three flash messages with different keys):
69
+
70
+ <html>
71
+ <body>
72
+ <div id='flash'>
73
+ <div class='flash info'>I'm sorry, Dave. I'm afraid I can't do that.</div>
74
+ <div class='flash warning'>This mission is too important for me to allow you to jeopardize it.</div>
75
+ <div class='flash fatal'>Without your space helmet, Dave, you're going to find reaching the emergency airlock rather difficult.</div>
76
+ </div>
77
+ </body>
78
+ </html>
79
+
80
+ Styling the CSS for the #flash id, the .flash class, or any of the key-based classes is entirely up to you.
81
+
82
+ (_Side note:_ This view helper was my initial reason for making this gem. I'd gotten used to pasting this little method in on every Rails project, and when I switched to Sinatra was distraught to discover that [Rack::Flash][2] couldn't do it, because the FlashHash isn't really a hash and you can't iterate it. Reinventing flash was sort of a side effect.)
83
+
84
+ Advanced Tips
85
+ -------------
86
+ ### Now vs. Next
87
+ The flash object acts like a hash, but it's really _two_ hashes:
88
+
89
+ * The **now** hash displays messages for the current request.
90
+ * The **next** hash stores messages to be displayed in the _next_ request.
91
+
92
+ When you access the **flash** helper, the _now_ hash is initialized from a session value. (Named `:flash` by default, but see 'Scoped Flash' below.) Every method except assignment (`[]=`) is delegated to _now_; assignments occur on the _next_ hash. At the end of the request, a Sinatra `after` hook sets the session value to the _next_ hash, effectively rotating it to _now_ for the next request that uses it.
93
+
94
+ This is usually what you want, and you don't have to worry about the details. However, you occasionally want to set a message to display during _this_ request, or access values that are coming up. In these cases you can access the `.now` and `.next` hashes directly:
95
+
96
+ # This will be displayed during the current request
97
+ flash.now[:error] = "We're shutting down now. Goodbye!"
98
+
99
+ # Look at messages upcoming in the next request
100
+ @weapon = Stake.new if flash.next[:warning] == "The vampire is attacking."
101
+
102
+ In practice, you'll probably want to set `.now` any time you're displaying errors with an immediate render instead of redirecting. It's hard to think of a common reason to check `.next` -- but it's there if you want it.
103
+
104
+ ### Keep, Discard, and Sweep
105
+ These convenience methods allow you to modify the standard rotation cycle, and are based directly on the [Rails flash API][4]:
106
+
107
+ flash.keep # Will show all messages again
108
+ flash.keep(:groundhog) # Will show the message on key :groundhog again
109
+ flash.discard # Clears the next messages without showing them
110
+ flash.discard(:amnesia) # Clears only the message on key :amnesia
111
+ flash.sweep # Rotates the flash manually, discarding _now_ and moving _next_ into its place
112
+
113
+ ### Sessions
114
+ The basic _concept_ of flash messages relies on having an active session for your application. Sinatra::Flash is built on the assumption that Sinatra's `session` helper points to something useful, and ensures that it does. If you've already set up Rack::Session::Cookie or done `enable sessions` or whatever, that session will be used. If you haven't, the `after` hook will enable sessions on your behalf using Sinatra's defaults. You'll probably get better results by configuring it yourself.
115
+
116
+ ### Scoped Flash
117
+ If one flash collection isn't exciting enough for your application stack, you can have multiple sets of flash messages scoped by a symbol. Each has its own lifecycle and will _not_ be rotated by any Web request that ignores it.
118
+
119
+ get "/complicated" do
120
+ flash(:one)[:hello] = "This will appear the next time flash(:one) is called"
121
+ flash(:two).discard(:hello) # Clear a message someone else set on flash(:two)
122
+ "A message for you on line three: #{flash(:three)[:hello]}"
123
+ end
124
+
125
+ Both the **flash** and **styled_flash** helper methods accept such keys as optional parameters. If don't specify one, the default key is `:flash`. Whatever keys you use will become session keys as well, so take heed that you don't run into naming conflicts.
126
+
127
+ Do you need this? Probably not. The principal use case is for complex application stacks in which some messages are only relevant within specific subsystems. If you _do_ use it, be sure to model your message flows carefully, and don't confuse collection keys with message keys.
128
+
129
+ Credit, Support, and Contributions
130
+ ----------------------------------
131
+ This extension is the fault of **Stephen Eley**. You can reach me at <sfeley@gmail.com>. If you like science fiction stories, I know a [good podcast][9] for them as well.
132
+
133
+ If you find bugs, please report them on the [Github issue tracker][10].
134
+
135
+ The documentation can of course be found on [RDoc.info][11].
136
+
137
+ Contributions are welcome. I'm not sure how much more _must_ be done on a flash message extension, but I'm sure there's plenty that _could_ be done. Please note that the test suite uses RSpec, and you'll need the [Sessionography][14] helper for testing sessions. (I actually developed Sessionography in order to TDD _this_ gem.)
138
+
139
+ License
140
+ -------
141
+ This project is licensed under the **Don't Be a Dick License**, version 0.2, and is copyright 2010 by Stephen Eley. See the [LICENSE.markdown][12] file or the [DBAD License site][13] for elaboration on not being a dick.
142
+
143
+
144
+ [1]: http://sinatrarb.com
145
+ [2]: http://nakajima.github.com/rack-flash/
146
+ [3]: http://api.rubyonrails.org/classes/ActionController/Flash.html
147
+ [4]: http://api.rubyonrails.org/classes/ActionController/Flash/FlashHash.html
148
+ [5]: http://yardoc.org
149
+ [6]: http://rvm.beginrescueend.com
150
+ [7]: https://sinatra.lighthouseapp.com/projects/9779/tickets/240-sinatrabase-vs-sinatradefault-vs-sinatraapplication
151
+ [8]: http://www.sinatrarb.com/extensions-wild.html
152
+ [9]: http://escapepod.org
153
+ [10]: http://github.com/SFEley/sinatra-flash/issues
154
+ [11]: http://rdoc.info/projects/SFEley/sinatra-flash
155
+ [12]: http://github.com/SFEley/sinatra-flash/blob/master/LICENSE.markdown
156
+ [13]: http://dbad-license.org
157
+ [14]: http://github.com/SFEley/sinatra-sessionography
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "sinatra-flash"
8
+ gem.summary = %Q{Proper flash messages in Sinatra}
9
+ gem.description = %Q{A Sinatra extension for setting and showing Rails-like flash messages. This extension improves on the Rack::Flash gem by being simpler to use, providing a full range of hash operations (including iterating through various flash keys, testing the size of the hash, etc.), and offering a 'styled_flash' view helper to render the entire flash hash with sensible CSS classes. The downside is reduced flexibility -- these methods will *only* work in Sinatra.}
10
+ gem.email = "sfeley@gmail.com"
11
+ gem.homepage = "http://github.com/SFEley/sinatra-flash"
12
+ gem.authors = ["Stephen Eley"]
13
+ gem.add_dependency "sinatra", ">= 1.0.0"
14
+ gem.add_development_dependency "rspec", ">= 1.2.9"
15
+ gem.add_development_dependency "yard", ">= 0"
16
+ gem.add_development_dependency "sinatra-sessionography"
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+ require 'spec/rake/spectask'
25
+ Spec::Rake::SpecTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.spec_files = FileList['spec/**/*_spec.rb']
28
+ end
29
+
30
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.pattern = 'spec/**/*_spec.rb'
33
+ spec.rcov = true
34
+ end
35
+
36
+ task :spec => :check_dependencies
37
+
38
+ task :default => :spec
39
+
40
+ begin
41
+ require 'yard'
42
+ YARD::Rake::YardocTask.new
43
+ rescue LoadError
44
+ task :yardoc do
45
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
46
+ end
47
+ end
48
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,20 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/flash/storage'
3
+ require 'sinatra/flash/style'
4
+
5
+
6
+ module Sinatra
7
+ module Flash
8
+
9
+ # This callback rotates any flash structure we referenced, placing the 'next' hash into the session
10
+ # for the next request.
11
+ after do
12
+ set :sessions, true unless session # If you do not have a session, one will be appointed for you by the court.
13
+ @flash.each{|key, flash| session[key] = @flash[key].next}
14
+ end
15
+
16
+ helpers Storage
17
+ helpers Style
18
+ end
19
+ register Flash
20
+ end
@@ -0,0 +1,49 @@
1
+ require 'delegate'
2
+
3
+ module Sinatra
4
+ module Flash
5
+
6
+ # A subclass of Hash that "remembers forward" by exactly one action.
7
+ # Tastes just like the API of Rails's ActionController::Flash::FlashHash, but with fewer calories.
8
+ class FlashHash < DelegateClass(Hash)
9
+ attr_reader :now, :next
10
+
11
+ # Builds a new FlashHash. It takes the hash for this action's values as an initialization variable.
12
+ def initialize(session)
13
+ @now = session || Hash.new
14
+ @next = Hash.new
15
+ super(@now)
16
+ end
17
+
18
+ # We assign to the _next_ hash, but retrieve values from the _now_ hash. Freaky, huh?
19
+ def []=(key, value)
20
+ self.next[key] = value
21
+ end
22
+
23
+ # Swaps out the current flash for the future flash, then returns it.
24
+ def sweep
25
+ @now.replace(@next)
26
+ @next = Hash.new
27
+ @now
28
+ end
29
+
30
+ # Keep all or one of the current values for next time.
31
+ def keep(key=nil)
32
+ if key
33
+ @next[key] = @now[key]
34
+ else
35
+ @next.merge!(@now)
36
+ end
37
+ end
38
+
39
+ # Tosses any values or one value before next time.
40
+ def discard(key=nil)
41
+ if key
42
+ @next.delete(key)
43
+ else
44
+ @next = Hash.new
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,23 @@
1
+ require 'sinatra/flash/hash'
2
+
3
+ module Sinatra
4
+ module Flash
5
+ module Storage
6
+
7
+ # The main Sinatra helper for accessing the flash. You can have multiple flash collections (e.g.,
8
+ # for different apps in your Rack stack) by passing a symbol to it.
9
+ #
10
+ # @param [optional, String, Symbol] key Specifies which key in the session contains the hash
11
+ # you want to reference. Defaults to ':flash'. If there is no session or the key is not found,
12
+ # an empty hash is used. Note that this is only used in the case of multiple flash _collections_,
13
+ # which is rarer than multiple flash messages.
14
+ #
15
+ # @return [FlashHash] Assign to this like any other hash.
16
+ def flash(key=:flash)
17
+ @flash ||= {}
18
+ @flash[key.to_sym] ||= FlashHash.new((session ? session[key.to_sym] : {}))
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ module Sinatra
2
+ module Flash
3
+ module Style
4
+
5
+ # A view helper for rendering flash messages to HTML with reasonable CSS structure. Handles
6
+ # multiple flash messages in one request. Wraps them in a <div> tag with id #flash containing
7
+ # a <div> for each message with classes of .flash and the message type. E.g.:
8
+ #
9
+ # @example
10
+ # <div id='flash'>
11
+ # <div class='flash info'>Today is Tuesday, April 27th.</div>
12
+ # <div class='flash warning'>Missiles are headed to destroy the Earth!</div>
13
+ # </div>
14
+ #
15
+ # It is your responsibility to style these classes the way you want in your stylesheets.
16
+ #
17
+ # @param[optional, String, Symbol] key Specifies which flash collection you want to display.
18
+ # If you use this, the collection key will be appended to the top-level div id (e.g.,
19
+ # 'flash_login' if you pass a key of :login).
20
+ #
21
+ # @return [String] Styled HTML if the flash contains messages, or an empty string if it's empty.
22
+ def styled_flash(key=:flash)
23
+ return "" if flash(key).empty?
24
+ id = (key == :flash ? "flash" : "flash_#{key}")
25
+ messages = flash(key).collect {|message| " <div class='flash #{message[0]}'>#{message[1]}</div>\n"}
26
+ "<div id='#{id}'>\n" + messages.join + "</div>"
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+
33
+
@@ -0,0 +1,20 @@
1
+ # require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ #
3
+ # # Make sure it behaves properly in a top-level 'classic' app
4
+ #
5
+ # require 'sinatra'
6
+ # require 'sinatra/flash'
7
+ # # set test environment
8
+ # set :environment, :test
9
+ # set :run, false
10
+ # set :raise_errors, true
11
+ # set :logging, false
12
+ #
13
+ # get "/first" do
14
+ # flash[:info] = 'You should see this on the second page.'
15
+ # erb "<%= styled_flash%><h1>There should be no flash here!</h1>"
16
+ # end
17
+ #
18
+ # describe "A Sinatra classic app" do
19
+ #
20
+ # end
@@ -0,0 +1,88 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Sinatra::Flash
4
+ describe FlashHash do
5
+ before(:each) do
6
+ @flash = {:do => 'A deer, a female deer', :re => 'A drop of golden sun'}
7
+ @this = FlashHash.new(@flash) # Stubbing out the session with a simple hash
8
+ @this[:one] = "My thumb"
9
+ @this[:two] = "My shoe"
10
+ @this[:three] = "My knee"
11
+ end
12
+
13
+ it "requires a session to be passed to it" do
14
+ lambda{FlashHash.new}.should raise_error(ArgumentError)
15
+ end
16
+
17
+ it "acts just like a Hash" do
18
+ Hash.instance_methods.each do |method|
19
+ @this.should respond_to(method)
20
+ end
21
+ end
22
+
23
+ it "knows its length" do
24
+ @this.length.should == 2
25
+ end
26
+
27
+ it "swaps its contents after one sweep" do
28
+ @this.sweep
29
+ @this.length.should == 3
30
+ end
31
+
32
+ it "gets rid of its contents after two sweeps" do
33
+ @this.sweep
34
+ @this.sweep
35
+ @this.should be_empty
36
+ end
37
+
38
+ it "can discard the whole flash" do
39
+ @this.discard
40
+ @this.sweep
41
+ @this.should be_empty
42
+ end
43
+
44
+ it "can discard just one key" do
45
+ @this.discard(:two)
46
+ @this.sweep
47
+ @this.length.should == 2
48
+ end
49
+
50
+ it "can keep the whole flash" do
51
+ @this.sweep
52
+ @this.keep
53
+ @this.sweep
54
+ @this.length.should == 3
55
+ end
56
+
57
+ it "can keep just one key" do
58
+ @this.sweep
59
+ @this.keep(:three)
60
+ @this.sweep
61
+ @this.length.should == 1
62
+ end
63
+
64
+ it "doesn't know the values you set right away" do
65
+ @this[:foo] = "bar"
66
+ @this[:foo].should be_nil
67
+ end
68
+
69
+ it "knows the values you set next time" do
70
+ @this[:foo] = "bar"
71
+ @this.sweep
72
+ @this[:foo].should == "bar"
73
+ end
74
+
75
+ it "can set values only for now" do
76
+ @this.now[:foo] = "bar"
77
+ @this[:foo].should == "bar"
78
+ end
79
+
80
+ it "forgets values you set only for now next time" do
81
+ @this.now[:foo] = "bar"
82
+ @this.sweep
83
+ @this.now[:foo].should be_nil
84
+ end
85
+
86
+
87
+ end
88
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'sinatra/flash/style'
3
+
4
+ describe 'styled_flash method' do
5
+ include Sinatra::Sessionography # for the 'session' method
6
+ include Sinatra::Flash::Storage
7
+ include Sinatra::Flash::Style
8
+
9
+ before(:each) do
10
+ Sinatra::Sessionography.session = {:flash => {:foo=>:bar, :too=>'tar'},
11
+ :smash => {:yoo=>:yar, :zoo=>'zar'}}
12
+ end
13
+
14
+ it "returns an empty string if the flash is empty" do
15
+ Sinatra::Sessionography.session = {}
16
+ styled_flash.should == ""
17
+ end
18
+
19
+ it "returns a div of #flash if the structure is the default" do
20
+ styled_flash.should =~ /<div id='flash'>/
21
+ end
22
+
23
+ it "contains each key as a class" do
24
+ styled_flash.should =~ /<div class='flash foo'>bar<\/div>/
25
+ styled_flash.should =~ /<div class='flash too'>tar<\/div>/
26
+ end
27
+
28
+ describe "if a key is passed" do
29
+ it "returns an empty string if that structure is empty" do
30
+ styled_flash(:trash).should == ""
31
+ end
32
+
33
+ it "returns a div containing the key name if a key is passed" do
34
+ styled_flash(:smash).should =~ /<div id='flash_smash'>/
35
+ end
36
+
37
+ it "returns each of the keys within that key as a class" do
38
+ styled_flash(:smash).should =~ /<div class='flash yoo'>yar<\/div>/
39
+ styled_flash(:smash).should =~ /<div class='flash zoo'>zar<\/div>/
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ # See the spec_helper for the 'app' that we're testing.
4
+ describe Sinatra::Flash do
5
+ before(:each) do
6
+ Sinatra::Sessionography.session = {
7
+ :flash => {:marco => :polo},
8
+ :smash => {:applecore => :baltimore}}
9
+ end
10
+
11
+ it "provides a 'flash' helper" do
12
+ get '/flash'
13
+ last_response.body.should =~ /\{.*\}/
14
+ end
15
+
16
+ it "looks up the :flash variable in the session by default" do
17
+ get '/flash'
18
+ last_response.body.should == "{:marco=>:polo}"
19
+ end
20
+
21
+ it "is empty, not nil, if there's no session" do
22
+ Sinatra::Sessionography.session = nil
23
+ get '/flash'
24
+ last_response.body.should == "{}"
25
+ end
26
+
27
+ it "can take a different flash key" do
28
+ get '/flash', {:key => :smash}
29
+ last_response.body.should == "{:applecore=>:baltimore}"
30
+ end
31
+
32
+ it "is empty, not nil, if the session doesn't have the flash key" do
33
+ get '/flash', {:key => :trash}
34
+ last_response.body.should == "{}"
35
+ end
36
+
37
+ it "can set the flash for the future" do
38
+ post '/flash', {:fire => :ice}
39
+ last_response.body.should == "{:marco=>:polo}"
40
+ end
41
+
42
+ it "knows the future flash" do
43
+ post '/flash', {:fire => :ice}
44
+ get '/flash'
45
+ last_response.body.should == "{:fire=>:ice}"
46
+ end
47
+
48
+ it "can set a different flash key for the future" do
49
+ post '/flash', {:key => :smash, :knockknock => :whosthere}
50
+ get '/flash', {:key => :smash}
51
+ last_response.body.should == "{:knockknock=>:whosthere}"
52
+ end
53
+
54
+ it "sweeps only the flash that gets used" do
55
+ post '/flash', {:hi => :ho}
56
+ post '/flash', {:aweem => :owep, :key => :smash}
57
+ get '/flash', {:key => :smash}
58
+ last_response.body.should == "{:aweem=>:owep}"
59
+ get '/flash'
60
+ last_response.body.should == "{:hi=>:ho}"
61
+ end
62
+ end
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,42 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'sinatra'
4
+ require 'rack/test'
5
+ require 'spec'
6
+ require 'spec/autorun'
7
+
8
+ set :environment, :test
9
+ require 'sinatra/flash'
10
+ require 'sinatra/sessionography'
11
+
12
+ get '/flash' do
13
+ if params[:key]
14
+ flash(params[:key]).inspect
15
+ else
16
+ flash.inspect
17
+ end
18
+ end
19
+
20
+ post '/flash' do
21
+ if (key = params.delete('key'))
22
+ params.each{|k,v| flash(key)[k.to_sym] = v.to_sym}
23
+ flash(key).inspect
24
+ else
25
+ params.each{|k,v| flash[k.to_sym] = v.to_sym}
26
+ flash.inspect
27
+ end
28
+ end
29
+
30
+
31
+ # Stub out our application; it's silly, but we have to do it. (http://www.sinatrarb.com/testing.html)
32
+ module SinatraApp
33
+ def app
34
+ Sinatra::Application
35
+ end
36
+ end
37
+
38
+ Spec::Runner.configure do |config|
39
+ include SinatraApp
40
+ include Rack::Test::Methods
41
+
42
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-flash
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Stephen Eley
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-26 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: sinatra
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 0
30
+ - 0
31
+ version: 1.0.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 2
44
+ - 9
45
+ version: 1.2.9
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: yard
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ type: :development
59
+ version_requirements: *id003
60
+ - !ruby/object:Gem::Dependency
61
+ name: sinatra-sessionography
62
+ prerelease: false
63
+ requirement: &id004 !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ type: :development
71
+ version_requirements: *id004
72
+ description: A Sinatra extension for setting and showing Rails-like flash messages. This extension improves on the Rack::Flash gem by being simpler to use, providing a full range of hash operations (including iterating through various flash keys, testing the size of the hash, etc.), and offering a 'styled_flash' view helper to render the entire flash hash with sensible CSS classes. The downside is reduced flexibility -- these methods will *only* work in Sinatra.
73
+ email: sfeley@gmail.com
74
+ executables: []
75
+
76
+ extensions: []
77
+
78
+ extra_rdoc_files:
79
+ - LICENSE.markdown
80
+ - README.markdown
81
+ files:
82
+ - .document
83
+ - .gitignore
84
+ - LICENSE.markdown
85
+ - README.markdown
86
+ - Rakefile
87
+ - VERSION
88
+ - lib/sinatra/flash.rb
89
+ - lib/sinatra/flash/hash.rb
90
+ - lib/sinatra/flash/storage.rb
91
+ - lib/sinatra/flash/style.rb
92
+ - spec/classic_spec.rb
93
+ - spec/flash/hash_spec.rb
94
+ - spec/flash/style_spec.rb
95
+ - spec/flash_spec.rb
96
+ - spec/spec.opts
97
+ - spec/spec_helper.rb
98
+ has_rdoc: true
99
+ homepage: http://github.com/SFEley/sinatra-flash
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options:
104
+ - --charset=UTF-8
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ requirements: []
122
+
123
+ rubyforge_project:
124
+ rubygems_version: 1.3.6
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Proper flash messages in Sinatra
128
+ test_files:
129
+ - spec/classic_spec.rb
130
+ - spec/flash/hash_spec.rb
131
+ - spec/flash/style_spec.rb
132
+ - spec/flash_spec.rb
133
+ - spec/spec_helper.rb