rack-modernizr 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -0
- data/README.md +48 -10
- data/lib/rack-modernizr.rb +75 -34
- data/lib/rack-modernizr/version.rb +1 -1
- data/test/spec_rack_modernizr.rb +9 -9
- metadata +10 -3
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.8.7@rack-modernizr
|
data/README.md
CHANGED
@@ -4,24 +4,62 @@
|
|
4
4
|
|
5
5
|
rack-modernizr is a Rack Middleware that includes the Modernizr javascript and stuffs Modernizr's output into a cookie on the first page request.
|
6
6
|
|
7
|
-
|
7
|
+
# Installation
|
8
|
+
|
9
|
+
Include it in your application.rb like so:
|
10
|
+
|
11
|
+
module ModernizrTestApp
|
12
|
+
class Application < Rails::Application
|
13
|
+
config.middleware.use Rack::Modernizr
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
or in your config.ru:
|
18
|
+
|
19
|
+
# Initialize the rails application
|
20
|
+
MyApp::Application.initialize!
|
8
21
|
|
9
22
|
# This file is used by Rack-based servers to start the application.
|
10
23
|
|
11
24
|
require ::File.expand_path('../config/environment', __FILE__)
|
12
25
|
require 'modernizr'
|
26
|
+
|
27
|
+
# WARNING: session storage is not working properly with config.ru initialization :/
|
13
28
|
use Rack::Modernizr
|
14
29
|
|
15
30
|
run MyApp::Application
|
16
31
|
|
17
|
-
|
32
|
+
# Usage
|
18
33
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
34
|
+
In your rails code, Modernizr's client side detected browser functionality is now available from the Rack environment. (w00t!)
|
35
|
+
|
36
|
+
<%= request.env['X-rack-modernizr'].inspect %>
|
37
|
+
|
38
|
+
or
|
39
|
+
|
40
|
+
if 1==request.env['X-rack-modernizr']['video']['h264']
|
41
|
+
# do stuff
|
42
|
+
end
|
43
|
+
|
44
|
+
# Features
|
45
|
+
|
46
|
+
Rack-modernizr chews up 1k of cookie data (yikes!). If you are storing session data in the database or memcache, you can avoid the cookie tax by pushing modernizr data into the session:
|
47
|
+
|
48
|
+
module ModernizrTestApp
|
49
|
+
class Application < Rails::Application
|
50
|
+
config.middleware.use Rack::Modernizr, :storage => "session"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# TODO
|
55
|
+
|
56
|
+
(in no particular order)
|
57
|
+
- Cool kid .accessorize method, like [rack-flash](http://nakajima.github.com/rack-flash/).
|
58
|
+
- Better unit testing for sessions and cookies.
|
59
|
+
- Rails helper to clean up retrieval syntax
|
60
|
+
- compression to cut down on 1k cookie storage size
|
61
|
+
|
62
|
+
# Thanks
|
63
|
+
|
64
|
+
rack-modernizr was inspired by [jamesgpearce](https://github.com/jamesgpearce)'s super awesome [modernizr-server](https://github.com/jamesgpearce/modernizr-server). Some javascript was used from that project.
|
26
65
|
|
27
|
-
rack-modernizr was inspired by [jamesgpearce](https://github.com/jamesgpearce)'s super awesome [modernizr-server](https://github.com/jamesgpearce/modernizr-server). Some javascript was used from that project.
|
data/lib/rack-modernizr.rb
CHANGED
@@ -2,33 +2,79 @@ require 'rack'
|
|
2
2
|
|
3
3
|
module Rack
|
4
4
|
class Modernizr
|
5
|
-
|
5
|
+
attr_accessor :stash
|
6
6
|
|
7
7
|
def initialize(app, options = {})
|
8
8
|
@app, @options = app, options
|
9
9
|
@options[:modernizr_js_url] ||= "http://cachedcommons.org/cache/modernizr/1.5.0/javascripts/modernizr-min.js"
|
10
|
-
@options[:
|
10
|
+
@options[:key_name] ||= "Modernizr"
|
11
|
+
@options[:storage] ||= "cookie"
|
11
12
|
end
|
12
13
|
|
13
14
|
def call(env)
|
14
15
|
@req = Rack::Request.new(env)
|
16
|
+
|
17
|
+
load_modernizr_from_storage if have_modernizr?
|
18
|
+
|
19
|
+
if env['PATH_INFO'] == "/rack-modernizr-endpoint.gif"
|
20
|
+
return persist_modernizr
|
21
|
+
end
|
22
|
+
|
15
23
|
status, headers, response = @app.call(env)
|
16
|
-
|
24
|
+
|
17
25
|
if should_add_modernizr?(status, headers, response)
|
18
|
-
response = add_modernizr
|
26
|
+
response = add_modernizr response
|
19
27
|
fix_content_length(headers, response)
|
20
28
|
end
|
21
29
|
|
30
|
+
|
22
31
|
[status, headers, response]
|
23
32
|
end
|
24
33
|
|
34
|
+
def have_modernizr?
|
35
|
+
!storage[@options[:key_name]].nil?
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_modernizr_from_storage
|
39
|
+
puts "load_modernizr_from_storage"
|
40
|
+
@req.env['X-rack-modernizr'] = Rack::Utils.parse_nested_query(storage[@options[:key_name]])
|
41
|
+
end
|
42
|
+
|
25
43
|
def should_add_modernizr?(status, headers, response)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
44
|
+
!storage.has_key?( @options[:key_name] ) &&
|
45
|
+
status==200 &&
|
46
|
+
headers["Content-Type"] &&
|
47
|
+
headers["Content-Type"].include?("text/html")
|
48
|
+
end
|
49
|
+
|
50
|
+
def persist_modernizr
|
51
|
+
response = Rack::Response.new ["OK"], 200, {}
|
52
|
+
|
53
|
+
s = @req.env['QUERY_STRING']
|
54
|
+
|
55
|
+
case @options[:storage]
|
56
|
+
when "session"
|
57
|
+
@req.env["rack.session"][@options[:key_name]] = s
|
58
|
+
when "cookies"
|
59
|
+
when "cookie"
|
60
|
+
response.set_cookie(@options[:key_name], {:value => s, :path => "/"})
|
61
|
+
end
|
62
|
+
|
63
|
+
response.finish # finish writes out the response in the expected format.
|
30
64
|
end
|
31
|
-
|
65
|
+
|
66
|
+
def storage
|
67
|
+
case @options[:storage]
|
68
|
+
when "session"
|
69
|
+
@req.env["rack.session"] ||= {}
|
70
|
+
@req.env["rack.session"]
|
71
|
+
when "cookies"
|
72
|
+
when "cookie"
|
73
|
+
@req.cookies ||= {}
|
74
|
+
@req.cookies
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
32
78
|
def fix_content_length(headers, response)
|
33
79
|
# Set new Content-Length, if it was set before we mutated the response body
|
34
80
|
if headers['Content-Length']
|
@@ -41,32 +87,27 @@ module Rack
|
|
41
87
|
response.each{ |s| body << s.to_s }
|
42
88
|
[body.gsub(/\<\/body\>/, "#{modernizr_js}</body>")]
|
43
89
|
end
|
44
|
-
|
90
|
+
|
45
91
|
def modernizr_js
|
46
|
-
"<script src=\"#{@options[:modernizr_js_url]}\" type=\"text/javascript\"></script>" +
|
47
|
-
"<script type
|
92
|
+
"<div id='modernizr_img'></div><script src=\"#{@options[:modernizr_js_url]}\" type=\"text/javascript\"></script>" +
|
93
|
+
"<script type='text/javascript'>#{set_modernizr_js}</script>"
|
48
94
|
end
|
49
|
-
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
"c+=';path=/';" +
|
66
|
-
"try{" +
|
67
|
-
"document.cookie=c;" +
|
68
|
-
"}catch(e){}" +
|
69
|
-
""
|
95
|
+
|
96
|
+
def set_modernizr_js
|
97
|
+
"var m=Modernizr,c='';" +
|
98
|
+
"for(var f in m){" +
|
99
|
+
"if(f[0]=='_'){continue;}" +
|
100
|
+
"var t=typeof m[f];" +
|
101
|
+
"if(t=='function'){continue;}" +
|
102
|
+
"if(t=='object'){" +
|
103
|
+
"for(var s in m[f]){" +
|
104
|
+
"c+='&'+f+'['+s+']='+(m[f][s]?'1':'0');" +
|
105
|
+
"}" +
|
106
|
+
"}else{" +
|
107
|
+
"c+='&'+f+'='+(m[f]?'1':'0');" +
|
108
|
+
"}" +
|
109
|
+
"}" +
|
110
|
+
"document.getElementById('modernizr_img').innerHTML = \"<img src='/rack-modernizr-endpoint.gif?\"+c+\"'></img>\";"
|
70
111
|
end
|
71
112
|
end
|
72
|
-
end
|
113
|
+
end
|
data/test/spec_rack_modernizr.rb
CHANGED
@@ -36,15 +36,16 @@ context "Rack::Modernizr" do
|
|
36
36
|
app = lambda { |env| [200, {'Content-Type' => 'text/html; charset=utf-8'}, [test_body]] }
|
37
37
|
request = Rack::MockRequest.env_for("/test.html")
|
38
38
|
body = Rack::Modernizr.new(app, :modernizr_js_url => "http://distinctive.domain.com/modernizr.js").call(request).last
|
39
|
-
body[0].should.include? "distinctive.domain.com"
|
39
|
+
body[0].should.include? "http://distinctive.domain.com/modernizr.js"
|
40
40
|
end
|
41
41
|
|
42
42
|
specify "should use cookie name if initialized" do
|
43
43
|
test_body = "<html><body>Hello World</body></html>"
|
44
44
|
app = lambda { |env| [200, {'Content-Type' => 'text/html; charset=utf-8'}, [test_body]] }
|
45
|
-
request = Rack::MockRequest.env_for("/
|
46
|
-
|
47
|
-
|
45
|
+
request = Rack::MockRequest.env_for("/rack-modernizr-endpoint.gif?a=b&c=d&e=f")
|
46
|
+
status, headers, response = Rack::Modernizr.new(app, {:key_name => "distinctive_name", :storage => "cookie"}).call(request)
|
47
|
+
headers['Set-Cookie'].should.not.be.nil
|
48
|
+
headers['Set-Cookie'].should.include? "distinctive_name"
|
48
49
|
end
|
49
50
|
|
50
51
|
specify "should work if request body is fragmented" do
|
@@ -80,15 +81,14 @@ context "Rack::Modernizr" do
|
|
80
81
|
end
|
81
82
|
end
|
82
83
|
|
83
|
-
|
84
|
+
# cookie storage
|
84
85
|
context "when a modernizr cookie has already been set" do
|
85
86
|
specify "should not mess with the response in any way" do
|
86
87
|
test_body = "<html><body>Hello World</body></html>"
|
87
88
|
app = lambda { |env| [200, {'Content-Type' => 'text/html'}, [test_body]] }
|
88
|
-
request = Rack::MockRequest.env_for("/test.html", "HTTP_COOKIE" => "Modernizr=
|
89
|
-
|
90
|
-
|
91
|
-
body[0].should.not.include? "script"
|
89
|
+
request = Rack::MockRequest.env_for("/test.html", "HTTP_COOKIE" => "Modernizr=a")
|
90
|
+
status, headers, response = Rack::Modernizr.new(app, :storage => 'cookie').call(request)
|
91
|
+
response[0].should.not.include? "script"
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-modernizr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Marshall Yount
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-14 00:00:00 -06:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
@@ -25,6 +26,7 @@ dependencies:
|
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
28
30
|
segments:
|
29
31
|
- 0
|
30
32
|
version: "0"
|
@@ -38,6 +40,7 @@ dependencies:
|
|
38
40
|
requirements:
|
39
41
|
- - ">="
|
40
42
|
- !ruby/object:Gem::Version
|
43
|
+
hash: 59
|
41
44
|
segments:
|
42
45
|
- 0
|
43
46
|
- 9
|
@@ -53,6 +56,7 @@ dependencies:
|
|
53
56
|
requirements:
|
54
57
|
- - ">="
|
55
58
|
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
56
60
|
segments:
|
57
61
|
- 0
|
58
62
|
version: "0"
|
@@ -69,6 +73,7 @@ extra_rdoc_files: []
|
|
69
73
|
|
70
74
|
files:
|
71
75
|
- .gitignore
|
76
|
+
- .rvmrc
|
72
77
|
- Gemfile
|
73
78
|
- Gemfile.lock
|
74
79
|
- LICENSE
|
@@ -92,6 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
97
|
requirements:
|
93
98
|
- - ">="
|
94
99
|
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
95
101
|
segments:
|
96
102
|
- 0
|
97
103
|
version: "0"
|
@@ -100,6 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
106
|
requirements:
|
101
107
|
- - ">="
|
102
108
|
- !ruby/object:Gem::Version
|
109
|
+
hash: 3
|
103
110
|
segments:
|
104
111
|
- 0
|
105
112
|
version: "0"
|