rack-html5 1.0.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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ coverage
3
+ rdoc
4
+ doc
5
+ pkg
data/README.rdoc ADDED
@@ -0,0 +1,59 @@
1
+ = rack-html5
2
+
3
+ This is work in progress.
4
+
5
+ Rack::Html5 detects the browser and its version by parsing the user agent. It then matches the features available for the current request.
6
+
7
+ == Usage
8
+
9
+ gem install rack-html5
10
+ require 'rack-html5'
11
+ use Rack::Html5
12
+ app = lambda { |env| [200, { 'Content-Type' => 'text/html' }, '<html><body><p></p></body></html>'] }
13
+ run app
14
+
15
+ Rack::Html5 then sets the following HTTP headers:
16
+
17
+ * *X-Detected-Browser:* Browser that has been detected, eg.: Firefox
18
+ * *X-Detected-Version:* Version of the browser that has been detected, eg.: 3.6.6
19
+ * *X-Html5-Wysiwyg:* WYSIWYG editable elements
20
+ * *X-Html5-Classname:* getElementsByClassName
21
+ * *X-Html5-Elements:* Stylable HTML5 elements
22
+ * *X-Html5-Canvas:* Canvas (basic support)
23
+ * *X-Html5-Messaging:* Cross-document messaging
24
+ * *X-Html5-Audio:* Audio element
25
+ * *X-Html5-Video:* Video element
26
+ * *X-Html5-Textapi:* Text API for canvas
27
+ * *X-Html5-Draganddrop:* Drag and drop
28
+ * *X-Html5-Offline:* Offline web applications
29
+ * *X-Html5-Svg:* Inline SVG
30
+ * *X-Html5-Form:* Form features (Web Forms 2.0)
31
+
32
+ == Rails
33
+
34
+ I plan on providing some rails helpers in the future.
35
+
36
+ === Configuration for Rails 2
37
+
38
+ Add the following lines to the config block in your environment.rb file:
39
+ config.gem "rack-html5"
40
+ config.middleware.use "Rack::Html5"
41
+
42
+ === Configuration for Rails 3
43
+
44
+ Add the gem dependency to Gemfile:
45
+ gem 'rack-html5'
46
+
47
+ Install the gem with bundler:
48
+ sudo bundler install
49
+
50
+ Add the Rack middleware to config.ru:
51
+ use Rack::Html5
52
+
53
+ == Notices
54
+
55
+ * The matching is done based on the information provided on: http://caniuse.com/#eras=farpast,past,now&cats=HTML5&statuses=rec,pr,cr,wd,ietf&nodetails=1
56
+ * If the feature is not supported, the header will not be set.
57
+ * If a browser implements a feature only partially, the corresponding header will not be set.
58
+ * It is assumed that future versions will still implement a certain feature if it's implemented now.
59
+ * User agent matching is a dirty thing. Feel free to help improving the matching rules.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ # Load all tasks in rake directory
2
+ Dir[File.join(File.expand_path(File.dirname(__FILE__)), "rake", "**", "*.rb")].each { |file| require file }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/lib/rack-html5.rb ADDED
@@ -0,0 +1 @@
1
+ require "rack/html5"
data/lib/rack/html5.rb ADDED
@@ -0,0 +1,177 @@
1
+ module Rack # :nodoc:
2
+
3
+ # Rack::Html5 sets custom headers for each HTML5 feature the browser supports.
4
+ # It does this by parsing the user agent and matching the features to the browser version based on information provided on: http://caniuse.com/#eras=farpast,past,now&cats=HTML5&statuses=rec,pr,cr,wd,ietf&nodetails=1
5
+ #
6
+ # The headers that are being set:
7
+ # * *X-Detected-Browser:* Browser that has been detected, eg.: Firefox
8
+ # * *X-Detected-Version:* Version of the browser that has been detected, eg.: 3.6.6
9
+ # * *X-Html5-Wysiwyg:* WYSIWYG editable elements
10
+ # * *X-Html5-Classname:* getElementsByClassName
11
+ # * *X-Html5-Elements:* Stylable HTML5 elements
12
+ # * *X-Html5-Canvas:* Canvas (basic support)
13
+ # * *X-Html5-Messaging:* Cross-document messaging
14
+ # * *X-Html5-Audio:* Audio element
15
+ # * *X-Html5-Video:* Video element
16
+ # * *X-Html5-Textapi:* Text API for canvas
17
+ # * *X-Html5-Draganddrop:* Drag and drop
18
+ # * *X-Html5-Offline:* Offline web applications
19
+ # * *X-Html5-Svg:* Inline SVG
20
+ # * *X-Html5-Form:* Form features (Web Forms 2.0)
21
+ #
22
+ # Please note:
23
+ # * If the feature is not supported, the header will not be set.
24
+ # * If a browser implements a feature only partially, the corresponding header will not be set.
25
+ class Html5
26
+ attr_accessor :version, :browser, :user_agent, :features, :headers
27
+
28
+ def initialize(app)
29
+ @app = app
30
+ end
31
+
32
+ def generate_headers
33
+ headers['x-detected-version'] = version
34
+ headers['x-detected-browser'] = browser.to_s
35
+ @features.each do |feature|
36
+ headers["x-html5-#{feature}"] = "true"
37
+ end
38
+ end
39
+
40
+ def call(env)
41
+ status, headers, response = @app.call(env)
42
+ @user_agent = env['HTTP_USER_AGENT']
43
+ @features = []
44
+ @headers = headers
45
+
46
+ detect_browser
47
+ detect_features
48
+ generate_headers
49
+
50
+ [status, @headers, response]
51
+ end
52
+
53
+ # Detects the browser and version based on the user agent
54
+ def detect_browser
55
+ user_agent_matcher.each do |browser, regexp|
56
+ match = @user_agent.match(regexp)
57
+ version = match.captures.first if match
58
+ if version
59
+ @browser = browser
60
+ @version = version
61
+ break
62
+ end
63
+ end
64
+ end
65
+
66
+ # Detects the HTML5 features the browser supports
67
+ def detect_features
68
+ return unless @browser && @version
69
+ feature_mapping[browser].each do |feature, version|
70
+ if version
71
+ raise "Versions are not comparable: #{version}, #{@version}" if comparable_version(version).length != comparable_version(@version).length
72
+ if comparable_version(@version) >= comparable_version(version)
73
+ @features << feature
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ # New features are only being shipped with major version updated.
80
+ # So we'll be on the safe side using the first two parts of the version number for comparisation.
81
+ # eg. version 10.5.6a will be cut down to 10.5, dots will be stripped, return value would be 105
82
+ def comparable_version(v)
83
+ v.split(".")[0..1].join
84
+ end
85
+
86
+ private
87
+
88
+ # Feature to browser version mapping according to the information provided on: http://caniuse.com/#eras=farpast,past,now&cats=HTML5&statuses=rec,pr,cr,wd,ietf&nodetails=1
89
+ def feature_mapping
90
+ {
91
+ :firefox => {
92
+ :wysiwyg => "3.5",
93
+ :classname => "3.0",
94
+ :elements => "3.0",
95
+ :canvas => "3.0",
96
+ :messaging => "3.0",
97
+ :audio => "3.5",
98
+ :video => "3.5",
99
+ :textapi => "3.5",
100
+ :draganddrop => "3.5",
101
+ :offline => "3.5",
102
+ :forms => nil,
103
+ :svg => nil
104
+ },
105
+ :ie => {
106
+ :wysiwyg => "6.0",
107
+ :classname => nil,
108
+ :elements => nil,
109
+ :canvas => nil,
110
+ :messaging => "8.0",
111
+ :audio => nil,
112
+ :video => nil,
113
+ :textapi => nil,
114
+ :draganddrop => nil,
115
+ :offline => nil,
116
+ :forms => nil,
117
+ :svg => nil
118
+ },
119
+ :opera => {
120
+ :wysiwyg => "10.1",
121
+ :classname => "10.1",
122
+ :elements => "10.1",
123
+ :canvas => "10.1",
124
+ :messaging => "10.1",
125
+ :audio => "10.5",
126
+ :video => "10.5",
127
+ :textapi => "10.5",
128
+ :draganddrop => nil,
129
+ :offline => "10.6",
130
+ :forms => "10.1",
131
+ :svg => nil
132
+ },
133
+ :chrome => {
134
+ :wysiwyg => "3.0",
135
+ :classname => "3.0",
136
+ :elements => "3.0",
137
+ :canvas => "3.0",
138
+ :messaging => "3.0",
139
+ :audio => "3.0",
140
+ :video => "3.0",
141
+ :textapi => "3.0",
142
+ :draganddrop => "3.0",
143
+ :offline => "4.0",
144
+ :forms => nil,
145
+ :svg => nil
146
+ },
147
+ :safari => {
148
+ :wysiwyg => "3.2",
149
+ :classname => "3.2",
150
+ :elements => "3.2",
151
+ :canvas => "3.2",
152
+ :messaging => "4.0",
153
+ :audio => "3.2",
154
+ :video => "3.2",
155
+ :textapi => "4.2",
156
+ :draganddrop => "4.0",
157
+ :offline => "4.0",
158
+ :forms => nil,
159
+ :svg => nil
160
+ }
161
+ }
162
+ end
163
+
164
+ # Browser to user agent matching
165
+ def user_agent_matcher
166
+ regexp_version = /((\d+\.?)+)/
167
+ {
168
+ :firefox => /Firefox\/#{regexp_version}/, # eg. Firefox/1.5.0.12
169
+ :ie => /MSIE #{regexp_version}/, # eg. compatible; MSIE 7.0;
170
+ :chrome => /Chrome\/#{regexp_version}/, # eg. Chrome/5.0.307.11 Safari/532.9
171
+ :safari => /AppleWebKit\/.*Version\/#{regexp_version}/, # eg. AppleWebKit/531.21.8 Version/4.0.4 Safari/531.21.10
172
+ :opera => /Opera\/#{regexp_version}/, # eg. Opera/9.80
173
+ }
174
+ end
175
+
176
+ end
177
+ end
@@ -0,0 +1,55 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rack-html5}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Christian Felder (masone)"]
12
+ s.date = %q{2010-07-14}
13
+ s.description = %q{Rack::Html5 sets custom headers for each HTML5 feature the browser supports.}
14
+ s.email = %q{ema@rh-productions.ch}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "lib/rack-html5.rb",
24
+ "lib/rack/html5.rb",
25
+ "rack-html5.gemspec",
26
+ "rake/jeweler.rb",
27
+ "rake/rdoc.rb",
28
+ "rake/test.rb",
29
+ "test/rack/html5_test.rb",
30
+ "test/test_helper.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/masone/rack-html5}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.7}
36
+ s.summary = %q{Rack::Html5 sets custom headers for each HTML5 feature the browser supports.}
37
+ s.test_files = [
38
+ "test/rack/html5_test.rb",
39
+ "test/test_helper.rb"
40
+ ]
41
+
42
+ if s.respond_to? :specification_version then
43
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<shoulda>, [">= 0"])
50
+ end
51
+ else
52
+ s.add_dependency(%q<shoulda>, [">= 0"])
53
+ end
54
+ end
55
+
data/rake/jeweler.rb ADDED
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |s|
4
+ s.name = "rack-html5"
5
+ s.summary = "Rack::Html5 sets custom headers for each HTML5 feature the browser supports."
6
+ s.description = "Rack::Html5 sets custom headers for each HTML5 feature the browser supports."
7
+ s.email = "ema@rh-productions.ch"
8
+ s.homepage = "http://github.com/masone/rack-html5"
9
+ s.authors = ["Christian Felder (masone)"]
10
+ s.add_development_dependency "shoulda"
11
+ end
12
+ Jeweler::GemcutterTasks.new
13
+ rescue LoadError
14
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
15
+ end
data/rake/rdoc.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'hanna/rdoctask'
2
+
3
+ desc 'Generate RDoc documentation'
4
+ Rake::RDocTask.new(:rdoc) do |rdoc|
5
+ rdoc.rdoc_files.include('README.rdoc').
6
+ include('*.rb').
7
+ include('lib/**/*.rb').
8
+ exclude('test/*').
9
+ exclude('rake/*').
10
+ exclude('pkg/*')
11
+
12
+ rdoc.main = "README.rdoc" # page to start on
13
+ rdoc.title = "Rack::Html5"
14
+
15
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
16
+ end
data/rake/test.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ desc 'Run test suite'
5
+ task :test do
6
+ Rake::TestTask.new do |t|
7
+ t.libs << "test"
8
+ t.test_files = FileList['test/**/*_test.rb']
9
+ t.verbose = true
10
+ end
11
+ end
@@ -0,0 +1,117 @@
1
+ require 'test_helper'
2
+ require 'rack/html5'
3
+
4
+ class Rack::Html5Test < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @app = lambda { |env| [200, {}, [""]] }
8
+ @rack = Rack::Html5.new(@app)
9
+ end
10
+
11
+ context "browser detection" do
12
+
13
+ should "detect firefox from Firefox/3.6.6" do
14
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (X11; U; Darwin Power Macintosh; en-US; rv:1.8.0.12) Gecko/20070803 Firefox/3.6.6 Fink Community Edition" }
15
+ @rack.call(env)
16
+ assert_equal :firefox, @rack.browser
17
+ end
18
+
19
+ should "detect ie from MSIE 7.0" do
20
+ env = { 'HTTP_USER_AGENT' => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6.4; .NET CLR 1.1.4322; FDM; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" }
21
+ @rack.call(env)
22
+ assert_equal :ie, @rack.browser
23
+ end
24
+
25
+ should "detect opera from Opera/9.80" do
26
+ env = { 'HTTP_USER_AGENT' => "Opera/9.62 (Windows NT 5.1; U; en) Presto/2.1.1" }
27
+ @rack.call(env)
28
+ assert_equal :opera, @rack.browser
29
+ end
30
+
31
+ should "detect safari from AppleWebKit/525.19" do
32
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21" }
33
+ @rack.call(env)
34
+ assert_equal :safari, @rack.browser
35
+ end
36
+
37
+ should "detect chrome from Chrome/5.0.307.11" do
38
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.11 Safari/532.9" }
39
+ @rack.call(env)
40
+ assert_equal :chrome, @rack.browser
41
+ end
42
+
43
+ end
44
+
45
+ context "version detection" do
46
+
47
+ should "detect 3.6.6 from Firefox/3.6.6" do
48
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (X11; U; Darwin Power Macintosh; en-US; rv:1.8.0.12) Gecko/20070803 Firefox/3.6.6 Fink Community Edition" }
49
+ @rack.call(env)
50
+ assert_equal "3.6.6", @rack.version
51
+ end
52
+
53
+ should "detect 7.0 from MSIE 7.0" do
54
+ env = { 'HTTP_USER_AGENT' => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6.4; .NET CLR 1.1.4322; FDM; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" }
55
+ @rack.call(env)
56
+ assert_equal "7.0", @rack.version
57
+ end
58
+
59
+ should "detect 9.80 from Opera/9.80" do
60
+ env = { 'HTTP_USER_AGENT' => "Opera/9.80 (Windows NT 5.1; U; en) Presto/2.1.1" }
61
+ @rack.call(env)
62
+ assert_equal "9.80", @rack.version
63
+ end
64
+
65
+ should "detect 3.1.2 from AppleWebKit/525.19 Version/3.1.2" do
66
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21" }
67
+ @rack.call(env)
68
+ assert_equal "3.1.2", @rack.version
69
+ end
70
+
71
+ should "detect 5.0.307.11 from Chrome/5.0.307.11" do
72
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.11 Safari/532.9" }
73
+ @rack.call(env)
74
+ assert_equal "5.0.307.11", @rack.version
75
+ end
76
+
77
+ end
78
+
79
+ context "features" do
80
+
81
+ should "detect features for Firefox 5.0" do
82
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (X11; U; Darwin Power Macintosh; en-US; rv:1.8.0.12) Gecko/20070803 Firefox/5.0.10 Fink Community Edition" }
83
+ status, headers, response = @rack.call(env)
84
+ assert @rack.features.length > 0
85
+ end
86
+
87
+ # TODO: mock features and test them
88
+
89
+ end
90
+
91
+ context "headers" do
92
+
93
+ should "set the x-detected-version header to 5.0.307.11" do
94
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.11 Safari/532.9" }
95
+ status, headers, response = @rack.call(env)
96
+ assert_equal "5.0.307.11", headers['x-detected-version']
97
+ end
98
+
99
+ should "set the x-detected-browser header to " do
100
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.11 Safari/532.9" }
101
+ status, headers, response = @rack.call(env)
102
+ assert_equal "chrome", headers['x-detected-browser']
103
+ end
104
+
105
+ should "set the x-html5-elements header to true for Firefox 5.0" do
106
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 (X11; U; Darwin Power Macintosh; en-US; rv:1.8.0.12) Gecko/20070803 Firefox/5.0.10 Fink Community Edition" }
107
+ status, headers, response = @rack.call(env)
108
+ assert_equal "true", headers['x-html5-elements']
109
+ end
110
+
111
+ should "not include the x headers if user agent cannot be detected properly" do
112
+ env = { 'HTTP_USER_AGENT' => "Mozilla/5.0 Gecko/20070803 Notabrowser/9.9.99" }
113
+ status, headers, response = @rack.call(env)
114
+ assert_equal false, headers.include?('x-html5-wysiwyg')
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require 'shoulda'
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-html5
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Christian Felder (masone)
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-14 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: shoulda
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ description: Rack::Html5 sets custom headers for each HTML5 feature the browser supports.
34
+ email: ema@rh-productions.ch
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - README.rdoc
41
+ files:
42
+ - .gitignore
43
+ - README.rdoc
44
+ - Rakefile
45
+ - VERSION
46
+ - lib/rack-html5.rb
47
+ - lib/rack/html5.rb
48
+ - rack-html5.gemspec
49
+ - rake/jeweler.rb
50
+ - rake/rdoc.rb
51
+ - rake/test.rb
52
+ - test/rack/html5_test.rb
53
+ - test/test_helper.rb
54
+ has_rdoc: true
55
+ homepage: http://github.com/masone/rack-html5
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options:
60
+ - --charset=UTF-8
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
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.7
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Rack::Html5 sets custom headers for each HTML5 feature the browser supports.
86
+ test_files:
87
+ - test/rack/html5_test.rb
88
+ - test/test_helper.rb