rack-reshow 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.textile +52 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/rack/__reshow__/action_back.gif +0 -0
- data/lib/rack/__reshow__/action_forward.gif +0 -0
- data/lib/rack/__reshow__/border.png +0 -0
- data/lib/rack/__reshow__/icon_alert.gif +0 -0
- data/lib/rack/__reshow__/reshow.css +44 -0
- data/lib/rack/__reshow__/reshow.js +107 -0
- data/lib/rack/reshow.rb +115 -0
- data/spec/reshow_spec.rb +69 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +90 -0
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 copypastel
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
h1. rack-reshow
|
2
|
+
|
3
|
+
h2. the little toolbar that could
|
4
|
+
|
5
|
+
p. @Rack::Reshow@ adds a toolbar to rendered views that stores different versions of the page. Afterwards, reviewing and comparing outputted changes is a single click away.
|
6
|
+
|
7
|
+
h2. use
|
8
|
+
|
9
|
+
To install:
|
10
|
+
|
11
|
+
@gem install rack-reshow@
|
12
|
+
|
13
|
+
With Rails:
|
14
|
+
|
15
|
+
bq. config.gem "rack-reshow", :lib => "rack/reshow"
|
16
|
+
config.middleware.use "Rack::Reshow"
|
17
|
+
|
18
|
+
In your rackup file:
|
19
|
+
|
20
|
+
bq. require 'rack/reshow'
|
21
|
+
use Rack::Reshow
|
22
|
+
|
23
|
+
|
24
|
+
h2. why
|
25
|
+
|
26
|
+
p. Development of a view is a trial and error process by far: change code, reload the browser, change to previous version, reload the browser, compare the two versions, repeat until satisfied.
|
27
|
+
|
28
|
+
p. By storing the rendered views each time they change, @Rack::Reshow@ tightens the review loop, effectively creating a history for each page that can be clicked through.
|
29
|
+
|
30
|
+
h2. how
|
31
|
+
|
32
|
+
p. @Rack::Reshow@ uses @PStore@ to store different versions of a page.
|
33
|
+
|
34
|
+
p. Each time a request is received, @Rack::Reshow@ checks if the @<body>@ of the response differs from what it last was. If so, it adds it to the store. Afterwards, it injects all previous versions into the response, and makes them transversable via a small, elegant bar.
|
35
|
+
|
36
|
+
h2. limitations
|
37
|
+
|
38
|
+
p. @Rack::Reshow@ only works on responses that have a @<head>@ and @<body>@, namely the type of page one works with when dealing with a layout's look and feel.
|
39
|
+
|
40
|
+
p. Furthermore, it works best when javascript is applied unobtrusively; if there's any javascript inside the response's @<body>@, it'll get called once for each time said javascript code appears in the page's history.
|
41
|
+
|
42
|
+
p. Finally, the same page may have different content depending on session variables (i.e. after one logs in), or simply dynamic variables (i.e. displaying the date/time). @Rack::Reshow@ will store both versions separately, even though there's no code modification going on behind the scenes.
|
43
|
+
|
44
|
+
h2. thanks
|
45
|
+
|
46
|
+
p. "famfamfam":http://famfamfam.com for the elegant icons.
|
47
|
+
"Rack::Bug":http://github.com/brynary/rack-bug for insight into how to serve static content and inject content into a response.
|
48
|
+
"Jeweler":http://github.com/technicalpickles/jeweler for making publishing gems so simple.
|
49
|
+
|
50
|
+
h2. copyright
|
51
|
+
|
52
|
+
p. Copyright (c) 2010 copypastel. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "rack-reshow"
|
8
|
+
gem.summary = %Q{Time machine for your views in the shape of a Rack middleware.}
|
9
|
+
#gem.description = %Q{TODO: longer description of your gem}
|
10
|
+
gem.email = "ecin@copypastel.com"
|
11
|
+
gem.homepage = "http://github.com/ecin/rack-reshow"
|
12
|
+
gem.authors = ["ecin"]
|
13
|
+
gem.add_dependency "rack", ">= 1.0"
|
14
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "rack-reshow #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#__reshow_bar__{
|
2
|
+
padding: 3px 15px 3px 15px;
|
3
|
+
margin: 0;
|
4
|
+
font-family: helvetica;
|
5
|
+
text-align: center;
|
6
|
+
position: fixed;
|
7
|
+
top: -25px;
|
8
|
+
left: 50px;
|
9
|
+
height: 25px;
|
10
|
+
background: url(/__reshow__/border.png) white repeat-x bottom left;
|
11
|
+
border-left: 1px solid #ccc;
|
12
|
+
border-right: 1px solid #ccc;
|
13
|
+
z-index: 1024;
|
14
|
+
}
|
15
|
+
|
16
|
+
#__reshow_bar__ img{
|
17
|
+
cursor: pointer;
|
18
|
+
position: relative;
|
19
|
+
top: 3px;
|
20
|
+
}
|
21
|
+
|
22
|
+
#__reshow_version__{
|
23
|
+
font-weight: bold;
|
24
|
+
margin-right: 10px;
|
25
|
+
color: steelblue;
|
26
|
+
}
|
27
|
+
|
28
|
+
#__reshow_info__{
|
29
|
+
opacity: 0.33;
|
30
|
+
}
|
31
|
+
|
32
|
+
#__reshow_next__{
|
33
|
+
opacity: 0.33;
|
34
|
+
}
|
35
|
+
|
36
|
+
.__reshow_body__{
|
37
|
+
opacity: 0;
|
38
|
+
display: none;
|
39
|
+
}
|
40
|
+
|
41
|
+
.__reshow_active__{
|
42
|
+
opacity: 1;
|
43
|
+
display: block;
|
44
|
+
}
|
@@ -0,0 +1,107 @@
|
|
1
|
+
jQuery(document).ready( function(){
|
2
|
+
|
3
|
+
jQuery.extend( jQuery.easing, {
|
4
|
+
'easeOutBounce': function(x, t, b, c, d) {
|
5
|
+
if ((t/=d) < (1/2.75)) {
|
6
|
+
return c*(7.5625*t*t) + b;
|
7
|
+
} else if (t < (2/2.75)) {
|
8
|
+
return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
|
9
|
+
} else if (t < (2.5/2.75)) {
|
10
|
+
return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
|
11
|
+
} else {
|
12
|
+
return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
});
|
16
|
+
|
17
|
+
var __reshow__ = {
|
18
|
+
prev: function(){
|
19
|
+
var active = jQuery('.__reshow_active__');
|
20
|
+
var el = jQuery(this);
|
21
|
+
if(active.prev().length > 0){
|
22
|
+
active.animate({opacity: 0},
|
23
|
+
{
|
24
|
+
complete: function(){
|
25
|
+
active.css('display', 'none');
|
26
|
+
active.toggleClass('__reshow_active__')
|
27
|
+
active = active.prev('.__reshow_body__');
|
28
|
+
active.toggleClass( '__reshow_active__')
|
29
|
+
active.css('opacity', 0);
|
30
|
+
active.css('display', 'block');
|
31
|
+
active.animate({opacity: 1});
|
32
|
+
var version = Number(jQuery('#__reshow_version__').text()) - 1;
|
33
|
+
version = (version < 10 ? '0' : '') + version
|
34
|
+
jQuery('#__reshow_version__').text(version);
|
35
|
+
// Okay, bind the click again.
|
36
|
+
el.one('click', __reshow__.prev);
|
37
|
+
if(active.prev().length > 0){
|
38
|
+
// Okay, bind the click again.
|
39
|
+
el.one('click', __reshow__.prev);
|
40
|
+
} else{
|
41
|
+
el.animate({opacity: 0.33});
|
42
|
+
}
|
43
|
+
jQuery('#__reshow_next__').animate({opacity: 1}).one('click', __reshow__.next);
|
44
|
+
}
|
45
|
+
});
|
46
|
+
} else{
|
47
|
+
el.one('click', __reshow__.prev);
|
48
|
+
}
|
49
|
+
},
|
50
|
+
next: function(){
|
51
|
+
var active = jQuery('.__reshow_active__');
|
52
|
+
var el = jQuery(this);
|
53
|
+
if(active.next().length > 0){
|
54
|
+
active.animate({opacity: 0},
|
55
|
+
{
|
56
|
+
complete: function(){
|
57
|
+
active.css('display', 'none');
|
58
|
+
active.toggleClass('__reshow_active__')
|
59
|
+
active = active.next()
|
60
|
+
active.toggleClass( '__reshow_active__')
|
61
|
+
active.css('opacity', 0);
|
62
|
+
active.css('display', 'block');
|
63
|
+
active.animate({opacity: 1});
|
64
|
+
var version = Number(jQuery('#__reshow_version__').text()) + 1;
|
65
|
+
version = (version < 10 ? '0' : '') + version
|
66
|
+
jQuery('#__reshow_version__').text(version);
|
67
|
+
if(active.next().length > 0){
|
68
|
+
// Okay, bind the click again.
|
69
|
+
el.one('click', __reshow__.next);
|
70
|
+
} else{
|
71
|
+
el.animate({opacity: 0.33});
|
72
|
+
}
|
73
|
+
jQuery('#__reshow_prev__').animate({opacity: 1}).one('click', __reshow__.prev);
|
74
|
+
}
|
75
|
+
});
|
76
|
+
} else{
|
77
|
+
el.one('click', __reshow__.next);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
};
|
81
|
+
|
82
|
+
jQuery('.__reshow_body__:last').toggleClass('__reshow_active__');
|
83
|
+
if(jQuery('.__reshow_active__').prev().length > 0)
|
84
|
+
jQuery('#__reshow_prev__').one('click', __reshow__.prev);
|
85
|
+
//jQuery('#__reshow_next__').one('click', __reshow__.next);
|
86
|
+
jQuery('#__reshow_info__').click( function(){
|
87
|
+
console.log("To be replaced with a Swift.js tooltip.");
|
88
|
+
});
|
89
|
+
|
90
|
+
var bar = jQuery('#__reshow_bar__');
|
91
|
+
|
92
|
+
setTimeout(function(){
|
93
|
+
bar.animate({'top': 0}, 'slow', 'easeOutBounce').animate({'opacity': 0.3},
|
94
|
+
{
|
95
|
+
complete: function(){
|
96
|
+
bar.bind('mouseover', function(){
|
97
|
+
jQuery(this).stop().animate({'opacity': 1});
|
98
|
+
});
|
99
|
+
|
100
|
+
bar.bind('mouseout', function(){
|
101
|
+
jQuery(this).stop().animate({'opacity': 0.3});
|
102
|
+
});
|
103
|
+
}
|
104
|
+
});
|
105
|
+
}, 1000);
|
106
|
+
|
107
|
+
});
|
data/lib/rack/reshow.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'pstore'
|
2
|
+
require 'rack/static'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class Reshow
|
6
|
+
|
7
|
+
class RackStaticBugAvoider
|
8
|
+
def initialize(app, static_app)
|
9
|
+
@app = app
|
10
|
+
@static_app = static_app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
if env["PATH_INFO"]
|
15
|
+
@static_app.call(env)
|
16
|
+
else
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
@@store_file = 'reshow.ps'
|
23
|
+
|
24
|
+
def initialize( app, opts = {} )
|
25
|
+
root = Object::File.expand_path(Object::File.dirname(__FILE__))
|
26
|
+
@app = RackStaticBugAvoider.new(app, Rack::Static.new(app, :urls => ["/__reshow__"], :root => root))
|
27
|
+
@store = PStore.new(@@store_file)
|
28
|
+
end
|
29
|
+
|
30
|
+
def call( env )
|
31
|
+
status, headers, body = @app.call(env)
|
32
|
+
request = Request.new(env)
|
33
|
+
if request.get? and status == 200
|
34
|
+
path = request.path
|
35
|
+
if body.respond_to? :join
|
36
|
+
body = body.join
|
37
|
+
@store.transaction do |store|
|
38
|
+
store[path] ||= []
|
39
|
+
content = body.scan(/<body>(.*?)<\/body>/m).flatten.first
|
40
|
+
store[path] << content unless content.nil? or store[path].last.eql?(content)
|
41
|
+
body.sub! /<body>.*<\/body>/m, %q{<body><div id="__reshow_bodies__"></div></body>}
|
42
|
+
store[path].reverse.each do |c|
|
43
|
+
prepend_to_tag '<div id="__reshow_bodies__">', body, tag(:div, c, :class => '__reshow_body__')
|
44
|
+
end
|
45
|
+
insert_reshow_bar body, store[path].size
|
46
|
+
end
|
47
|
+
headers['Content-Length'] = body.length.to_s
|
48
|
+
body = [body]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
[status, headers, body]
|
52
|
+
end
|
53
|
+
|
54
|
+
def []( path )
|
55
|
+
@store.transaction(true) {|store| store[path] || Array.new}
|
56
|
+
end
|
57
|
+
|
58
|
+
def purge!
|
59
|
+
Object::File.delete(@@store_file) if Object::File.exists?(@@store_file)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def prepend_to_tag(tag, page, string)
|
65
|
+
page.sub! /#{tag}/, "#{tag}\n" + string
|
66
|
+
end
|
67
|
+
|
68
|
+
def append_to_tag(tag, page, string)
|
69
|
+
page.sub! /#{tag}/, string + "\n#{tag}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def insert_reshow_bar(page, versions)
|
73
|
+
append_to_tag '</head>', page, style
|
74
|
+
append_to_tag '</head>', page, jquery
|
75
|
+
append_to_tag '</head>', page, javascript
|
76
|
+
append_to_tag '</body>', page, toolbar(versions)
|
77
|
+
end
|
78
|
+
|
79
|
+
def tag(type, body, options={})
|
80
|
+
options = options.map {|key, value| "#{key}=\"#{value}\""}.join(' ')
|
81
|
+
<<-EOF
|
82
|
+
<#{type} #{options}">
|
83
|
+
#{body}
|
84
|
+
</#{type}>
|
85
|
+
EOF
|
86
|
+
end
|
87
|
+
|
88
|
+
def toolbar(versions)
|
89
|
+
versions = (versions < 10 ? '0' : '') + versions.to_s
|
90
|
+
<<-EOF
|
91
|
+
<div id="__reshow_bar__">
|
92
|
+
<span id="__reshow_version__">#{versions}</span>
|
93
|
+
<span style="margin-right: 10px;">
|
94
|
+
<img id="__reshow_prev__" src="/__reshow__/action_back.gif" style="margin-right: 7px;"/>
|
95
|
+
<img id="__reshow_next__" src="/__reshow__/action_forward.gif" />
|
96
|
+
</span>
|
97
|
+
<span><img id="__reshow_info__" src="/__reshow__/icon_alert.gif" /></span>
|
98
|
+
</div>
|
99
|
+
EOF
|
100
|
+
end
|
101
|
+
|
102
|
+
def style
|
103
|
+
%q{<link charset='utf-8' href="/__reshow__/reshow.css" rel='stylesheet' type='text/css'>}
|
104
|
+
end
|
105
|
+
|
106
|
+
def javascript
|
107
|
+
%q{<script src="/__reshow__/reshow.js"></script>}
|
108
|
+
end
|
109
|
+
|
110
|
+
def jquery
|
111
|
+
%q{<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>}
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
data/spec/reshow_spec.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
include Rack
|
4
|
+
|
5
|
+
# Need to change the app for some test cases
|
6
|
+
class Rack::Reshow; attr_accessor :app; end
|
7
|
+
|
8
|
+
describe Rack::Reshow do
|
9
|
+
|
10
|
+
# Set up configuration variables
|
11
|
+
|
12
|
+
before :all do
|
13
|
+
@post_url = '/comments'
|
14
|
+
@env = Rack::MockRequest.env_for '/'
|
15
|
+
# The Lambdacat App
|
16
|
+
@body = ["<body>Lambda, lambda, lambda app, hoooo!</body>"]
|
17
|
+
@body2 = ["<body>Lambda app is on the run, lambda app is loose!</body>"]
|
18
|
+
@app = lambda {|env| [200, {}, @body]}
|
19
|
+
end
|
20
|
+
|
21
|
+
# Rack::Reshow middleware can be instantiated
|
22
|
+
it 'should accept an :app and an :opts hash at instantiation' do
|
23
|
+
lambda { Reshow.new(@app, {}) }.should_not raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
before(:each) { @middleware = Reshow.new @app }
|
27
|
+
|
28
|
+
it 'should return an array with stored versions given a path' do
|
29
|
+
@middleware['/'].should be_empty
|
30
|
+
@middleware.call @env
|
31
|
+
@middleware['/'].size.should == 1
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should allow to purge the pstore' do
|
35
|
+
@middleware.call @env
|
36
|
+
@middleware['/'].should_not be_empty
|
37
|
+
@middleware.purge!
|
38
|
+
@middleware['/'].should be_empty
|
39
|
+
end
|
40
|
+
|
41
|
+
after(:each) { @middleware.purge! }
|
42
|
+
|
43
|
+
# Rack::Reshow#call is defined, as in any middleware
|
44
|
+
it 'should return an array with status, headers, and body when sent :call' do
|
45
|
+
response = @middleware.call @env
|
46
|
+
response.class.should be(Array)
|
47
|
+
response.size.should == 3
|
48
|
+
response[2] == @body.to_s.scan(/<body>(.*?)<\/body>/m).flatten.first
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should save a version of a page when the content changes' do
|
52
|
+
@middleware.call @env
|
53
|
+
@middleware.app = lambda {|env| [200, {}, @body2]}
|
54
|
+
@middleware.call @env
|
55
|
+
@middleware['/'].size.should == 2
|
56
|
+
versions = @middleware['/']
|
57
|
+
versions[0].should match("Lambda, lambda, lambda app, hoooo!")
|
58
|
+
versions[1].should match("Lambda app is on the run, lambda app is loose!")
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should return all bodies in history (though hidden by css)' do
|
62
|
+
@middleware.call @env
|
63
|
+
@middleware.app = lambda {|env| [200, {}, @body2]}
|
64
|
+
status, headers, body = @middleware.call @env
|
65
|
+
body.to_s.should match(/Lambda app is on the run, lambda app is loose!/)
|
66
|
+
body.to_s.should match(/Lambda, lambda, lambda app, hoooo!/)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-reshow
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ecin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-07 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rack
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "1.0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.2.9
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: ecin@copypastel.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.textile
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- LICENSE
|
47
|
+
- README.textile
|
48
|
+
- Rakefile
|
49
|
+
- VERSION
|
50
|
+
- lib/rack/__reshow__/action_back.gif
|
51
|
+
- lib/rack/__reshow__/action_forward.gif
|
52
|
+
- lib/rack/__reshow__/border.png
|
53
|
+
- lib/rack/__reshow__/icon_alert.gif
|
54
|
+
- lib/rack/__reshow__/reshow.css
|
55
|
+
- lib/rack/__reshow__/reshow.js
|
56
|
+
- lib/rack/reshow.rb
|
57
|
+
- spec/reshow_spec.rb
|
58
|
+
- spec/spec.opts
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://github.com/ecin/rack-reshow
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options:
|
66
|
+
- --charset=UTF-8
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
version:
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.3.5
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: Time machine for your views in the shape of a Rack middleware.
|
88
|
+
test_files:
|
89
|
+
- spec/reshow_spec.rb
|
90
|
+
- spec/spec_helper.rb
|