rack-reshow 0.1.0 → 0.2.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/VERSION +1 -1
- data/lib/rack/__reshow__/reshow.js +35 -4
- data/lib/rack/reshow.rb +122 -44
- data/spec/public/v1.css +143 -0
- data/spec/public/v1.html +73 -0
- data/spec/public/v2.css +3 -0
- data/spec/public/v2.html +73 -0
- data/spec/reshow_spec.rb +44 -12
- metadata +6 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -16,12 +16,18 @@ jQuery(document).ready( function(){
|
|
16
16
|
|
17
17
|
var __reshow__ = {
|
18
18
|
prev: function(){
|
19
|
-
var active = jQuery('.__reshow_active__');
|
19
|
+
var active = jQuery('div.__reshow_active__');
|
20
20
|
var el = jQuery(this);
|
21
|
+
var css = jQuery('link.__reshow_active__');
|
21
22
|
if(active.prev().length > 0){
|
22
23
|
active.animate({opacity: 0},
|
23
24
|
{
|
24
25
|
complete: function(){
|
26
|
+
css.toggleClass('__reshow_active__');
|
27
|
+
css[0].disabled = true;
|
28
|
+
css = css.prev();
|
29
|
+
css.toggleClass('__reshow_active__');
|
30
|
+
css[0].disabled = false;
|
25
31
|
active.css('display', 'none');
|
26
32
|
active.toggleClass('__reshow_active__')
|
27
33
|
active = active.prev('.__reshow_body__');
|
@@ -33,7 +39,6 @@ jQuery(document).ready( function(){
|
|
33
39
|
version = (version < 10 ? '0' : '') + version
|
34
40
|
jQuery('#__reshow_version__').text(version);
|
35
41
|
// Okay, bind the click again.
|
36
|
-
el.one('click', __reshow__.prev);
|
37
42
|
if(active.prev().length > 0){
|
38
43
|
// Okay, bind the click again.
|
39
44
|
el.one('click', __reshow__.prev);
|
@@ -48,12 +53,18 @@ jQuery(document).ready( function(){
|
|
48
53
|
}
|
49
54
|
},
|
50
55
|
next: function(){
|
51
|
-
var active = jQuery('.__reshow_active__');
|
56
|
+
var active = jQuery('div.__reshow_active__');
|
52
57
|
var el = jQuery(this);
|
58
|
+
var css = jQuery('link.__reshow_active__');
|
53
59
|
if(active.next().length > 0){
|
54
60
|
active.animate({opacity: 0},
|
55
61
|
{
|
56
62
|
complete: function(){
|
63
|
+
css.toggleClass('__reshow_active__');
|
64
|
+
css[0].disabled = true;
|
65
|
+
css = css.next();
|
66
|
+
css.toggleClass('__reshow_active__');
|
67
|
+
css[0].disabled = false;
|
57
68
|
active.css('display', 'none');
|
58
69
|
active.toggleClass('__reshow_active__')
|
59
70
|
active = active.next()
|
@@ -79,14 +90,34 @@ jQuery(document).ready( function(){
|
|
79
90
|
}
|
80
91
|
};
|
81
92
|
|
93
|
+
// Disable all stylesheets except for reshow.css
|
94
|
+
|
95
|
+
jQuery('link[rel*=style]').each( function(){
|
96
|
+
if(jQuery(this).attr('href') != '/__reshow__/reshow.css')
|
97
|
+
this.disabled = true;
|
98
|
+
});
|
99
|
+
|
100
|
+
// Enable most recent stylesheet
|
101
|
+
|
102
|
+
jQuery('link[rel*=style]:last').each( function(){
|
103
|
+
this.disabled = false;
|
104
|
+
jQuery(this).toggleClass('__reshow_active__');
|
105
|
+
});
|
106
|
+
|
107
|
+
// Bind initial clicks
|
108
|
+
|
82
109
|
jQuery('.__reshow_body__:last').toggleClass('__reshow_active__');
|
83
|
-
if(jQuery('.__reshow_active__').prev().length > 0)
|
110
|
+
if(jQuery('div.__reshow_active__').prev().length > 0)
|
84
111
|
jQuery('#__reshow_prev__').one('click', __reshow__.prev);
|
112
|
+
else
|
113
|
+
jQuery('#__reshow_prev__').css({opacity: 0.33});
|
85
114
|
//jQuery('#__reshow_next__').one('click', __reshow__.next);
|
86
115
|
jQuery('#__reshow_info__').click( function(){
|
87
116
|
console.log("To be replaced with a Swift.js tooltip.");
|
88
117
|
});
|
89
118
|
|
119
|
+
// Bar animation
|
120
|
+
|
90
121
|
var bar = jQuery('#__reshow_bar__');
|
91
122
|
|
92
123
|
setTimeout(function(){
|
data/lib/rack/reshow.rb
CHANGED
@@ -1,8 +1,90 @@
|
|
1
1
|
require 'pstore'
|
2
2
|
require 'rack/static'
|
3
|
+
require 'open-uri'
|
3
4
|
|
4
5
|
module Rack
|
5
6
|
class Reshow
|
7
|
+
|
8
|
+
class Page
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def tag(type, content, options={})
|
12
|
+
options = options.map {|key, value| "#{key}=\"#{value}\""}.join(' ')
|
13
|
+
<<-EOF
|
14
|
+
<#{type} #{options}">
|
15
|
+
#{content}
|
16
|
+
</#{type}>
|
17
|
+
EOF
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(html, path, app)
|
22
|
+
@html = html
|
23
|
+
@path = path
|
24
|
+
self.stylesheets!(app)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
@html
|
29
|
+
end
|
30
|
+
|
31
|
+
def head
|
32
|
+
@html.scan(/<head>(.*?)<\/head>/m).flatten.first
|
33
|
+
end
|
34
|
+
|
35
|
+
def head=(content)
|
36
|
+
@html.sub! /<head>.*<\/head>/m, "<head>#{content}</head>"
|
37
|
+
end
|
38
|
+
|
39
|
+
def body
|
40
|
+
@html.scan(/<body>(.*?)<\/body>/m).flatten.first
|
41
|
+
end
|
42
|
+
|
43
|
+
def body=(content)
|
44
|
+
@html.sub! /<body>.*<\/body>/m, "<body>#{content}</body>"
|
45
|
+
end
|
46
|
+
|
47
|
+
def stylesheets
|
48
|
+
@stylesheets.each_value.to_a.join
|
49
|
+
end
|
50
|
+
|
51
|
+
def stylesheets!(app)
|
52
|
+
@stylesheets ||= begin
|
53
|
+
@stylesheets = {}
|
54
|
+
links = head.scan(/<link.*?rel=['|"]+stylesheet['|"]+.*?>/)
|
55
|
+
links.each do |link|
|
56
|
+
href = link.scan(/href=['|"]+(.*?)['|"]+/).flatten.first
|
57
|
+
if href[/https?:\/\//]
|
58
|
+
@stylesheets[href] = open(href).read
|
59
|
+
else
|
60
|
+
href = @path + href unless href[0] == ?/
|
61
|
+
status, headers, body = app.call Rack::MockRequest.env_for(href)
|
62
|
+
sheet = ''
|
63
|
+
body.each {|part| sheet << part}
|
64
|
+
@stylesheets[href] = sheet
|
65
|
+
end
|
66
|
+
end
|
67
|
+
@stylesheets
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def length
|
72
|
+
@html.length
|
73
|
+
end
|
74
|
+
|
75
|
+
def eql?(page)
|
76
|
+
body == page.body and stylesheets == page.stylesheets
|
77
|
+
end
|
78
|
+
|
79
|
+
def prepend_to_tag(tag, string)
|
80
|
+
@html.sub! /#{tag}/, "#{tag}\n" + string
|
81
|
+
end
|
82
|
+
|
83
|
+
def append_to_tag(tag, string)
|
84
|
+
@html.sub! /#{tag}/, string + "\n#{tag}"
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
6
88
|
|
7
89
|
class RackStaticBugAvoider
|
8
90
|
def initialize(app, static_app)
|
@@ -28,25 +110,38 @@ module Rack
|
|
28
110
|
end
|
29
111
|
|
30
112
|
def call( env )
|
31
|
-
status, headers, body = @app.call(env)
|
32
113
|
request = Request.new(env)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
114
|
+
path = request.path
|
115
|
+
return serve_stylesheet(request) if path =~ /__reshow__\/assets/
|
116
|
+
status, headers, body = @app.call(env)
|
117
|
+
if status == 200 and body.respond_to? :join
|
118
|
+
body = body.join
|
119
|
+
page = Page.new body, path, @app
|
120
|
+
# Store response
|
121
|
+
@store.transaction do |store|
|
122
|
+
store[path] ||= []
|
123
|
+
store[path] << page unless body.nil? or store[path].last.eql?(page)
|
124
|
+
end
|
125
|
+
# Insert Reshow assets
|
126
|
+
page.append_to_tag '</head>', [style, javascript].join("\n")
|
127
|
+
# Prepare for Reshow bar
|
128
|
+
@store.transaction(true) do |store|
|
129
|
+
page.body = %q{<div id="__reshow_bodies__"></div>}
|
130
|
+
store[path].reverse.each do |p|
|
131
|
+
page.prepend_to_tag '<div id="__reshow_bodies__">', Page.tag(:div, p.body, :class => '__reshow_body__')
|
132
|
+
end
|
133
|
+
versions = store[path].count
|
134
|
+
# Insert Reshow Bar
|
135
|
+
page.append_to_tag '</body>', toolbar(versions)
|
136
|
+
# Insert versioned stylesheets
|
137
|
+
versions.times do |v|
|
138
|
+
escaped_path = Rack::Utils.escape(path)
|
139
|
+
href = "/__reshow__/assets?path=#{escaped_path}&version=#{v}"
|
140
|
+
page.append_to_tag '</head>', "<link charset='utf-8' href='#{href}' rel='stylesheet' type='text/css'>"
|
46
141
|
end
|
47
|
-
headers['Content-Length'] = body.length.to_s
|
48
|
-
body = [body]
|
49
142
|
end
|
143
|
+
headers['Content-Length'] = page.length
|
144
|
+
body = [page.to_s]
|
50
145
|
end
|
51
146
|
[status, headers, body]
|
52
147
|
end
|
@@ -61,28 +156,13 @@ module Rack
|
|
61
156
|
|
62
157
|
private
|
63
158
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
159
|
+
def serve_stylesheet(request)
|
160
|
+
version = request.params['version'].to_i
|
161
|
+
stylesheets = ''
|
162
|
+
@store.transaction(true) do |store|
|
163
|
+
stylesheets = store[request.params['path']][version].stylesheets
|
164
|
+
end
|
165
|
+
[200, {'Content-Length' => stylesheets.length.to_s, 'Content-Type' => 'text/css'}, [stylesheets]]
|
86
166
|
end
|
87
167
|
|
88
168
|
def toolbar(versions)
|
@@ -104,12 +184,10 @@ module Rack
|
|
104
184
|
end
|
105
185
|
|
106
186
|
def javascript
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
%q{<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>}
|
187
|
+
<<-EOF
|
188
|
+
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
189
|
+
<script src="/__reshow__/reshow.js"></script>
|
190
|
+
EOF
|
112
191
|
end
|
113
|
-
|
114
192
|
end
|
115
193
|
end
|
data/spec/public/v1.css
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
*{
|
2
|
+
padding: 0;
|
3
|
+
margin: 0;
|
4
|
+
font-family: helvetica, arial, sans-serif;
|
5
|
+
color: #111;
|
6
|
+
}
|
7
|
+
|
8
|
+
body{
|
9
|
+
min-height: 100%;
|
10
|
+
min-width: 800px;
|
11
|
+
}
|
12
|
+
|
13
|
+
a{
|
14
|
+
text-decoration: none;
|
15
|
+
}
|
16
|
+
|
17
|
+
a:hover{
|
18
|
+
color: #027dff;
|
19
|
+
}
|
20
|
+
|
21
|
+
a:visited{
|
22
|
+
text-decoration: line-through;
|
23
|
+
}
|
24
|
+
|
25
|
+
img{
|
26
|
+
border: 0;
|
27
|
+
}
|
28
|
+
|
29
|
+
#logo{
|
30
|
+
background: url(/img/logo.png);
|
31
|
+
height: 94px;
|
32
|
+
width: 411px;
|
33
|
+
position: fixed;
|
34
|
+
bottom: 0;
|
35
|
+
left: 0;
|
36
|
+
margin: 0 0 40px 20px;
|
37
|
+
}
|
38
|
+
|
39
|
+
#logo:hover{
|
40
|
+
background: url(/img/logo_color.png);
|
41
|
+
}
|
42
|
+
|
43
|
+
#are{
|
44
|
+
float: left;
|
45
|
+
width: 449px;
|
46
|
+
}
|
47
|
+
|
48
|
+
.is{
|
49
|
+
float: left;
|
50
|
+
width: 200px;
|
51
|
+
padding: 20px 0px 0 20px;
|
52
|
+
cursor: pointer;
|
53
|
+
}
|
54
|
+
|
55
|
+
.who{
|
56
|
+
font-weight: bold;
|
57
|
+
font-size: 25px;
|
58
|
+
color: #ccc;
|
59
|
+
}
|
60
|
+
|
61
|
+
.name{
|
62
|
+
display: inline;
|
63
|
+
color: #ccc;
|
64
|
+
}
|
65
|
+
|
66
|
+
.what{
|
67
|
+
font-size: 20px;
|
68
|
+
color: #ddd;
|
69
|
+
}
|
70
|
+
|
71
|
+
.is:hover .name{
|
72
|
+
color: #8fd92a;
|
73
|
+
}
|
74
|
+
|
75
|
+
.is:hover .what{
|
76
|
+
color: #111;
|
77
|
+
}
|
78
|
+
|
79
|
+
.bacon{
|
80
|
+
position: absolute;
|
81
|
+
top: 110px;
|
82
|
+
}
|
83
|
+
|
84
|
+
.twitter{
|
85
|
+
height: 82px;
|
86
|
+
width: 100px;
|
87
|
+
background: url(/img/twitter.png);
|
88
|
+
}
|
89
|
+
|
90
|
+
.twitter:hover{
|
91
|
+
background: url(/img/twitter_color.png);
|
92
|
+
}
|
93
|
+
|
94
|
+
.github{
|
95
|
+
height: 60px;
|
96
|
+
width: 123px;
|
97
|
+
background: url(/img/github.png);
|
98
|
+
opacity: 0.5;
|
99
|
+
}
|
100
|
+
|
101
|
+
.github:hover{
|
102
|
+
opacity: 1;
|
103
|
+
}
|
104
|
+
|
105
|
+
.flickr{
|
106
|
+
height: 35px;
|
107
|
+
width: 130px;
|
108
|
+
background: url(/img/flickr.png);
|
109
|
+
}
|
110
|
+
|
111
|
+
.flickr:hover{
|
112
|
+
background: url(/img/flickr_color.png);
|
113
|
+
}
|
114
|
+
|
115
|
+
#rofls{
|
116
|
+
margin-left: 449px;
|
117
|
+
}
|
118
|
+
|
119
|
+
.rofl{
|
120
|
+
cursor: pointer;
|
121
|
+
position: relative;
|
122
|
+
padding: 5px 0 5px 10px;
|
123
|
+
border-left: 10px solid #fafafa;
|
124
|
+
}
|
125
|
+
|
126
|
+
.rofl:nth-child(even){
|
127
|
+
background: #fafafa;
|
128
|
+
}
|
129
|
+
|
130
|
+
.rofl_title{
|
131
|
+
font-size: 32px;
|
132
|
+
font-weight: bold;
|
133
|
+
}
|
134
|
+
|
135
|
+
.rofl:hover .rofl_date{
|
136
|
+
color: #027dff;
|
137
|
+
}
|
138
|
+
|
139
|
+
.rofl_date{
|
140
|
+
color: #ccc;
|
141
|
+
font-size: 32px;
|
142
|
+
display: inline;
|
143
|
+
}
|
data/spec/public/v1.html
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Blog.new :copypastel</title>
|
5
|
+
<link charset='utf-8' href='/public/v1.css' rel='stylesheet' type='text/css'>
|
6
|
+
<link href='rofls.rss' rel='alternate' title='copypastel' type='application/rss+xml'>
|
7
|
+
<meta charset='utf-8' content='text/html' http-equiv='Content-Type'>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<a href='http://copypastel.com'>
|
11
|
+
<div id='logo'></div>
|
12
|
+
</a>
|
13
|
+
<div id='are'>
|
14
|
+
<div class='is'>
|
15
|
+
<div class='who'>
|
16
|
+
<div class='name'>ecin</div>
|
17
|
+
is...
|
18
|
+
</div>
|
19
|
+
<div class='what'>working for 2 weeks as work-for-hire.</div>
|
20
|
+
<div class='bacon'>
|
21
|
+
<a href='http://twitter.com/ecin'>
|
22
|
+
<div class='twitter'></div>
|
23
|
+
</a>
|
24
|
+
<a href='http://flickr.com/photos/ecin'>
|
25
|
+
<div class='flickr'></div>
|
26
|
+
</a>
|
27
|
+
<a href='http://github.com/ecin'>
|
28
|
+
<div class='github'></div>
|
29
|
+
</a>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
<div class='is'>
|
33
|
+
<div class='who'>
|
34
|
+
<div class='name'>daicoden</div>
|
35
|
+
is...
|
36
|
+
</div>
|
37
|
+
<div class='what'>building a startup.</div>
|
38
|
+
<div class='bacon'>
|
39
|
+
<a href='http://twitter.com/daicoden'>
|
40
|
+
<div class='twitter'></div>
|
41
|
+
</a>
|
42
|
+
<a href='http://flickr.com/photos/daicoden'>
|
43
|
+
<div class='flickr'></div>
|
44
|
+
</a>
|
45
|
+
<a href='http://github.com/daicoden'>
|
46
|
+
<div class='github'></div>
|
47
|
+
</a>
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
</div>
|
51
|
+
<div id='rofls'>
|
52
|
+
<a href='/rofl/Singletasking'>
|
53
|
+
<div class='rofl'>
|
54
|
+
<div class='rofl_title'>
|
55
|
+
<div class='rofl_date'>16.09.09</div>
|
56
|
+
Singletasking
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
</a>
|
60
|
+
<a href='/rofl/Rehashing_Hashapass'>
|
61
|
+
<div class='rofl'>
|
62
|
+
<div class='rofl_title'>
|
63
|
+
<div class='rofl_date'>29.09.09</div>
|
64
|
+
Rehashing Hashapass
|
65
|
+
</div>
|
66
|
+
</div>
|
67
|
+
</a>
|
68
|
+
</div>
|
69
|
+
<img src='/img/logo_color.png' style='display: none;'>
|
70
|
+
<img src='/img/flickr_color.png' style='display: none;'>
|
71
|
+
<img src='/img/twitter_color.png' style='display: none;'>
|
72
|
+
</body>
|
73
|
+
</html>
|
data/spec/public/v2.css
ADDED
data/spec/public/v2.html
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Blog.new :copypastel</title>
|
5
|
+
<link charset='utf-8' href='/public/v2.css' rel='stylesheet' type='text/css'>
|
6
|
+
<link href='rofls.rss' rel='alternate' title='copypastel' type='application/rss+xml'>
|
7
|
+
<meta charset='utf-8' content='text/html' http-equiv='Content-Type'>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<a href='http://copypastel.com'>
|
11
|
+
<div id='logo'></div>
|
12
|
+
</a>
|
13
|
+
<div id='are'>
|
14
|
+
<div class='is'>
|
15
|
+
<div class='who'>
|
16
|
+
<div class='name'>ecin</div>
|
17
|
+
is...
|
18
|
+
</div>
|
19
|
+
<div class='what'>testing Rack::Reshow.</div>
|
20
|
+
<div class='bacon'>
|
21
|
+
<a href='http://twitter.com/ecin'>
|
22
|
+
<div class='twitter'></div>
|
23
|
+
</a>
|
24
|
+
<a href='http://flickr.com/photos/ecin'>
|
25
|
+
<div class='flickr'></div>
|
26
|
+
</a>
|
27
|
+
<a href='http://github.com/ecin'>
|
28
|
+
<div class='github'></div>
|
29
|
+
</a>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
<div class='is'>
|
33
|
+
<div class='who'>
|
34
|
+
<div class='name'>daicoden</div>
|
35
|
+
is...
|
36
|
+
</div>
|
37
|
+
<div class='what'>building a startup.</div>
|
38
|
+
<div class='bacon'>
|
39
|
+
<a href='http://twitter.com/daicoden'>
|
40
|
+
<div class='twitter'></div>
|
41
|
+
</a>
|
42
|
+
<a href='http://flickr.com/photos/daicoden'>
|
43
|
+
<div class='flickr'></div>
|
44
|
+
</a>
|
45
|
+
<a href='http://github.com/daicoden'>
|
46
|
+
<div class='github'></div>
|
47
|
+
</a>
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
</div>
|
51
|
+
<div id='rofls'>
|
52
|
+
<a href='/rofl/Singletasking'>
|
53
|
+
<div class='rofl'>
|
54
|
+
<div class='rofl_title'>
|
55
|
+
<div class='rofl_date'>16.09.09</div>
|
56
|
+
Singletasking
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
</a>
|
60
|
+
<a href='/rofl/Rehashing_Hashapass'>
|
61
|
+
<div class='rofl'>
|
62
|
+
<div class='rofl_title'>
|
63
|
+
<div class='rofl_date'>29.09.09</div>
|
64
|
+
Rehashing Hashapass
|
65
|
+
</div>
|
66
|
+
</div>
|
67
|
+
</a>
|
68
|
+
</div>
|
69
|
+
<img src='/img/logo_color.png' style='display: none;'>
|
70
|
+
<img src='/img/flickr_color.png' style='display: none;'>
|
71
|
+
<img src='/img/twitter_color.png' style='display: none;'>
|
72
|
+
</body>
|
73
|
+
</html>
|
data/spec/reshow_spec.rb
CHANGED
@@ -6,16 +6,18 @@ include Rack
|
|
6
6
|
class Rack::Reshow; attr_accessor :app; end
|
7
7
|
|
8
8
|
describe Rack::Reshow do
|
9
|
+
include Rack::Test::Methods
|
9
10
|
|
10
|
-
# Set up configuration
|
11
|
-
|
11
|
+
# Set up configuration
|
12
12
|
before :all do
|
13
|
-
@
|
13
|
+
@root = Object::File.expand_path(Object::File.dirname(__FILE__))
|
14
14
|
@env = Rack::MockRequest.env_for '/'
|
15
|
-
|
16
|
-
@
|
17
|
-
@
|
18
|
-
@
|
15
|
+
@body = [File.open(@root + '/public/v1.html').read]
|
16
|
+
@body2 = [File.open(@root + '/public/v2.html').read]
|
17
|
+
@css = File.open(@root + '/public/v1.css').read
|
18
|
+
@css2 = File.open(@root + '/public/v2.css').read
|
19
|
+
app = lambda {|env| [200, {}, @body]}
|
20
|
+
@app = Rack::Static.new(app, :urls => ["/public"], :root => @root)
|
19
21
|
end
|
20
22
|
|
21
23
|
# Rack::Reshow middleware can be instantiated
|
@@ -45,7 +47,7 @@ describe Rack::Reshow do
|
|
45
47
|
response = @middleware.call @env
|
46
48
|
response.class.should be(Array)
|
47
49
|
response.size.should == 3
|
48
|
-
response
|
50
|
+
response.last.should respond_to(:each)
|
49
51
|
end
|
50
52
|
|
51
53
|
it 'should save a version of a page when the content changes' do
|
@@ -54,16 +56,46 @@ describe Rack::Reshow do
|
|
54
56
|
@middleware.call @env
|
55
57
|
@middleware['/'].size.should == 2
|
56
58
|
versions = @middleware['/']
|
57
|
-
versions[0].should match(
|
58
|
-
versions[1].should match(
|
59
|
+
versions[0].body.should match(/#{@body.to_s.scan(/<body>(.*?)<\/body>/m).flatten.first}/)
|
60
|
+
versions[1].body.should match(/#{@body2.to_s.scan(/<body>(.*?)<\/body>/m).flatten.first}/)
|
59
61
|
end
|
60
62
|
|
61
63
|
it 'should return all bodies in history (though hidden by css)' do
|
62
64
|
@middleware.call @env
|
63
65
|
@middleware.app = lambda {|env| [200, {}, @body2]}
|
64
66
|
status, headers, body = @middleware.call @env
|
65
|
-
body.to_s.should match(/
|
66
|
-
body.to_s.should match(/
|
67
|
+
body.to_s.should match(/#{@body.join.scan(/<body>(.*?)<\/body>/m).flatten.first}/)
|
68
|
+
body.to_s.should match(/#{@body2.join.scan(/<body>(.*?)<\/body>/m).flatten.first}/)
|
69
|
+
body.to_s.scan(/class="__reshow_body__"/).count.should == 2
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should insert a <link> tag for each version in history' do
|
73
|
+
status, headers, body = @middleware.call @env
|
74
|
+
count = body.to_s.scan(/<link.*?>/).count
|
75
|
+
@middleware.app = lambda {|env| [200, {}, @body2]}
|
76
|
+
status, headers, body = @middleware.call @env
|
77
|
+
body.to_s.scan(/<link.*?>/).count.should == count + 1
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should save external stylesheets and insert them as separate <link> tags' do
|
81
|
+
status, headers, body = @middleware.call @env
|
82
|
+
body.to_s.should match(/<link.*?href='\/__reshow__\/assets\?path=\%2F&version=0'.*?>/)
|
83
|
+
app = lambda {|env| [200, {}, @body2]}
|
84
|
+
@middleware.app = Rack::Static.new(app, :urls => ["/public"], :@root => @root)
|
85
|
+
status, headers, body = @middleware.call @env
|
86
|
+
body.to_s.should match(/<link.*?href='\/__reshow__\/assets\?path=\%2F&version=0'.*?>/)
|
87
|
+
body.to_s.should match(/<link.*?href='\/__reshow__\/assets\?path=\%2F&version=1'.*?>/)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should serve versioned stylesheets' do
|
91
|
+
@middleware.call @env
|
92
|
+
status, headers, body = @middleware.call Rack::MockRequest.env_for '/__reshow__/assets?path=%2F&version=0'
|
93
|
+
body.to_s.should eql(@css)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should insert a Reshow bar to allow users to view different versions' do
|
97
|
+
status, headers, body = @middleware.call @env
|
98
|
+
body.to_s[/id="__reshow_bar__"/].should_not be_nil
|
67
99
|
end
|
68
100
|
|
69
101
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-reshow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ecin
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-12 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -54,6 +54,10 @@ files:
|
|
54
54
|
- lib/rack/__reshow__/reshow.css
|
55
55
|
- lib/rack/__reshow__/reshow.js
|
56
56
|
- lib/rack/reshow.rb
|
57
|
+
- spec/public/v1.css
|
58
|
+
- spec/public/v1.html
|
59
|
+
- spec/public/v2.css
|
60
|
+
- spec/public/v2.html
|
57
61
|
- spec/reshow_spec.rb
|
58
62
|
- spec/spec.opts
|
59
63
|
- spec/spec_helper.rb
|