browser_sniffer 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemspec.rb +51 -0
- data/.gitignore +17 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +47 -0
- data/README.md +49 -0
- data/Rakefile +12 -0
- data/browser_sniffer.gemspec +23 -0
- data/init.rb +1 -0
- data/lib/browser_sniffer.rb +152 -0
- data/lib/browser_sniffer/patterns.rb +240 -0
- data/lib/browser_sniffer/version.rb +3 -0
- data/test/browser_sniffer_test.rb +405 -0
- data/test/test_helper.rb +6 -0
- metadata +97 -0
data/.gemspec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
class Readme < String
|
2
|
+
attr_reader :path
|
3
|
+
|
4
|
+
def initialize(path)
|
5
|
+
@path = path
|
6
|
+
super(File.read(self.path))
|
7
|
+
end
|
8
|
+
|
9
|
+
def summary
|
10
|
+
if self =~ /^# (?:\S+)\s+(.+?)\s{2,}/m
|
11
|
+
scrub $1
|
12
|
+
else
|
13
|
+
raise "could not find summary in #{path}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
if self =~ /^## Description\s+(.+?)\s{2,}/m
|
19
|
+
scrub $1
|
20
|
+
else
|
21
|
+
raise "could not find description in #{path}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def scrub(string)
|
27
|
+
string.delete("\\`").gsub(/\[([^\]]+)\]\([^)]*\)/, "\\1").tr("\n", " ").to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Files < Array
|
32
|
+
def executables
|
33
|
+
grep(%r{^bin/}) { |f| File.basename(f) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def requires
|
37
|
+
["lib"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def tests
|
41
|
+
grep(%r{^(test|spec|features)/})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def files
|
46
|
+
@files ||= Files.new(`git ls-files`.split($/))
|
47
|
+
end
|
48
|
+
|
49
|
+
def readme(path = File.expand_path("./README.md"))
|
50
|
+
(@readmes ||= {})[path] ||= Readme.new(path)
|
51
|
+
end
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
Based off UAParser.js
|
2
|
+
https://github.com/faisalman/ua-parser-js
|
3
|
+
|
4
|
+
Copyright (c) 2013 Shopify
|
5
|
+
Copyright (c) 2012-2013 Faisalman <fyzlman@gmail.com>
|
6
|
+
Dual licensed under GPLv2 & MIT
|
7
|
+
|
8
|
+
---------------------------------------------------
|
9
|
+
|
10
|
+
GPLv2
|
11
|
+
|
12
|
+
This program is free software; you can redistribute it and/or
|
13
|
+
modify it under the terms of the GNU General Public License
|
14
|
+
as published by the Free Software Foundation; either version 2
|
15
|
+
of the License, or (at your option) any later version.
|
16
|
+
|
17
|
+
This program is distributed in the hope that it will be useful,
|
18
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20
|
+
GNU General Public License for more details.
|
21
|
+
|
22
|
+
You should have received a copy of the GNU General Public License
|
23
|
+
along with this program; if not, write to the Free Software
|
24
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
25
|
+
|
26
|
+
---------------------------------------------------
|
27
|
+
|
28
|
+
MIT License
|
29
|
+
|
30
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
31
|
+
a copy of this software and associated documentation files (the
|
32
|
+
"Software"), to deal in the Software without restriction, including
|
33
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
34
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
35
|
+
permit persons to whom the Software is furnished to do so, subject to
|
36
|
+
the following conditions:
|
37
|
+
|
38
|
+
The above copyright notice and this permission notice shall be
|
39
|
+
included in all copies or substantial portions of the Software.
|
40
|
+
|
41
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
42
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
43
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
44
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
45
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
46
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
47
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
[![Build Status](https://secure.travis-ci.org/Shopify/browser_sniffer.png?branch=master)](http://travis-ci.org/Shopify/browser_sniffer)
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/browser_sniffer.png)](http://badge.fury.io/rb/browser_sniffer)
|
3
|
+
|
4
|
+
# BrowserSniffer
|
5
|
+
|
6
|
+
## Description
|
7
|
+
|
8
|
+
Parses user agent strings and boils it all down to a few simple classifications.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem "browser_sniffer"
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle install
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ git clone https://github.com/Shopify/browser_sniffer && cd browser_sniffer && bundle install && rake install
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require "browser_sniffer"
|
28
|
+
|
29
|
+
client_info = BrowserSniffer.new(request.user_agent)
|
30
|
+
client_info.form_factor # => :tablet
|
31
|
+
client_info.browser # => :safari
|
32
|
+
client_info.major_browser_version # => 4
|
33
|
+
client_info.engine # => :webkit
|
34
|
+
client_info.major_engine_version # => 531
|
35
|
+
client_info.os # => :ios
|
36
|
+
client_info.os_version # => 3.2
|
37
|
+
```
|
38
|
+
|
39
|
+
## Contributing
|
40
|
+
|
41
|
+
Fork, branch & pull request.
|
42
|
+
|
43
|
+
## Licensing
|
44
|
+
|
45
|
+
Based off [UAParser.js](https://github.com/faisalman/ua-parser-js)
|
46
|
+
|
47
|
+
Copyright (c) 2013 Shopify
|
48
|
+
Copyright (c) 2012-2013 Faisalman <fyzlman@gmail.com>
|
49
|
+
Dual licensed under GPLv2 & MIT
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.expand_path("../.gemspec", __FILE__)
|
2
|
+
require File.expand_path("../lib/browser_sniffer/version", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "browser_sniffer"
|
6
|
+
spec.version = BrowserSniffer::VERSION
|
7
|
+
spec.authors = ["Shopify"]
|
8
|
+
spec.email = ["gems@shopify.com"]
|
9
|
+
spec.description = readme.description
|
10
|
+
spec.summary = readme.summary
|
11
|
+
spec.homepage = "https://github.com/Shopify/browser_sniffer"
|
12
|
+
spec.license = "GPLv2 & MIT"
|
13
|
+
|
14
|
+
spec.files = files
|
15
|
+
spec.executables = files.executables
|
16
|
+
spec.test_files = files.tests
|
17
|
+
spec.require_paths = files.requires
|
18
|
+
|
19
|
+
spec.required_ruby_version = ">= 1.9.3"
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'browser_sniffer'
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require "browser_sniffer/version"
|
2
|
+
require "browser_sniffer/patterns"
|
3
|
+
|
4
|
+
class BrowserSniffer
|
5
|
+
attr_reader :user_agent
|
6
|
+
|
7
|
+
def initialize(user_agent)
|
8
|
+
@user_agent = user_agent
|
9
|
+
end
|
10
|
+
|
11
|
+
def ios?
|
12
|
+
os == :ios
|
13
|
+
end
|
14
|
+
|
15
|
+
def android?
|
16
|
+
os == :android
|
17
|
+
end
|
18
|
+
|
19
|
+
def ie8?
|
20
|
+
browser == :ie && major_browser_version == 8
|
21
|
+
end
|
22
|
+
|
23
|
+
def handheld?
|
24
|
+
form_factor == :handheld
|
25
|
+
end
|
26
|
+
|
27
|
+
def tablet?
|
28
|
+
form_factor == :tablet
|
29
|
+
end
|
30
|
+
|
31
|
+
def desktop?
|
32
|
+
form_factor == :desktop
|
33
|
+
end
|
34
|
+
|
35
|
+
def form_factor
|
36
|
+
device_info[:type] || :desktop
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
def engine
|
42
|
+
engine_info[:type]
|
43
|
+
end
|
44
|
+
|
45
|
+
def engine_name
|
46
|
+
engine_info[:name]
|
47
|
+
end
|
48
|
+
|
49
|
+
def major_engine_version
|
50
|
+
str = engine_info[:major]
|
51
|
+
str && str.to_i
|
52
|
+
end
|
53
|
+
|
54
|
+
def engine_version
|
55
|
+
engine_info[:version]
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
def browser
|
61
|
+
browser_info[:type]
|
62
|
+
end
|
63
|
+
|
64
|
+
def browser_name
|
65
|
+
browser_info[:name]
|
66
|
+
end
|
67
|
+
|
68
|
+
def major_browser_version
|
69
|
+
str = browser_info[:major]
|
70
|
+
str && str.to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
def browser_version
|
74
|
+
browser_info[:version]
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
def device
|
80
|
+
device_info[:name]
|
81
|
+
end
|
82
|
+
|
83
|
+
def device_name
|
84
|
+
device_info[:model]
|
85
|
+
end
|
86
|
+
|
87
|
+
def device_vendor
|
88
|
+
device_info[:vendor]
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
def os
|
94
|
+
os_info[:type]
|
95
|
+
end
|
96
|
+
|
97
|
+
def os_name
|
98
|
+
os_info[:name]
|
99
|
+
end
|
100
|
+
|
101
|
+
def os_version
|
102
|
+
os_info[:version]
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
def browser_info
|
108
|
+
@browser_info ||= parse_user_agent_for(BrowserSniffer::REGEX_MAP[:browser])
|
109
|
+
end
|
110
|
+
|
111
|
+
def engine_info
|
112
|
+
@engine_info ||= parse_user_agent_for(BrowserSniffer::REGEX_MAP[:engine])
|
113
|
+
end
|
114
|
+
|
115
|
+
def device_info
|
116
|
+
@device_info ||= parse_user_agent_for(BrowserSniffer::REGEX_MAP[:device])
|
117
|
+
end
|
118
|
+
|
119
|
+
def os_info
|
120
|
+
@os_info ||= parse_user_agent_for(BrowserSniffer::REGEX_MAP[:os])
|
121
|
+
end
|
122
|
+
|
123
|
+
def parse_user_agent_for(type)
|
124
|
+
result = {}
|
125
|
+
type.each_slice(2) do |slice|
|
126
|
+
format = slice[1]
|
127
|
+
slice[0].each do |regex|
|
128
|
+
regex.match(user_agent) do |match|
|
129
|
+
format.each_with_index do |field, index|
|
130
|
+
if field.class == Symbol
|
131
|
+
result[field] = match[index + 1]
|
132
|
+
elsif field.class == Array
|
133
|
+
if field[1].class == String || field[1].class == Symbol
|
134
|
+
result[field[0]] = field[1]
|
135
|
+
elsif field[1].class == Hash
|
136
|
+
if field[1][match[index + 1]]
|
137
|
+
result[field[0]] = field[1][match[index + 1]]
|
138
|
+
else
|
139
|
+
result[field[0]] = match[index + 1]
|
140
|
+
end
|
141
|
+
elsif field[1].class == Proc
|
142
|
+
result[field[0]] = field[1].call(match[index + 1])
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
return result
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
result
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
class BrowserSniffer
|
2
|
+
STRING_MAP = {
|
3
|
+
:browser => {
|
4
|
+
:oldsafari => {
|
5
|
+
:major => {
|
6
|
+
'/85' => '1',
|
7
|
+
'/125' => '1',
|
8
|
+
'/312' => '1',
|
9
|
+
'/412' => '2',
|
10
|
+
'/416' => '2',
|
11
|
+
'/417' => '2',
|
12
|
+
'/419' => '2'
|
13
|
+
},
|
14
|
+
:version => {
|
15
|
+
'/85' => '1.0',
|
16
|
+
'/125' => '1.2',
|
17
|
+
'/312' => '1.3',
|
18
|
+
'/412' => '2.0',
|
19
|
+
'/416' => '2.0.2',
|
20
|
+
'/417' => '2.0.3',
|
21
|
+
'/419' => '2.0.4'
|
22
|
+
}
|
23
|
+
}
|
24
|
+
},
|
25
|
+
:os => {
|
26
|
+
:windows => {
|
27
|
+
:version => {
|
28
|
+
'4.90' => 'ME',
|
29
|
+
'NT3.51' => 'NT 3.11',
|
30
|
+
'NT4.0' => 'NT 4.0',
|
31
|
+
'NT 5.0' => '2000',
|
32
|
+
'NT 5.1' => 'XP',
|
33
|
+
'NT 5.2' => 'XP',
|
34
|
+
'NT 6.0' => 'Vista',
|
35
|
+
'NT 6.1' => '7',
|
36
|
+
'NT 6.2' => '8',
|
37
|
+
'ARM' => 'RT'
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
REGEX_MAP = {
|
44
|
+
:browser => [
|
45
|
+
[
|
46
|
+
# Presto based
|
47
|
+
/(opera\smini)\/((\d+)?[\w\.-]+)/i, # Opera Mini
|
48
|
+
/(opera\s[mobiletab]+).+:version\/((\d+)?[\w\.-]+)/i, # Opera Mobi/Tablet
|
49
|
+
/(opera).+:version\/((\d+)?[\w\.]+)/i, # Opera > 9.80
|
50
|
+
/(opera)[\/\s]+((\d+)?[\w\.]+)/i # Opera < 9.80
|
51
|
+
], [:name, :version, :major, [:type, :opera]], [
|
52
|
+
/\s(opr)\/((\d+)?[\w\.]+)/i # Opera Webkit
|
53
|
+
], [[:name, 'Opera'], :version, :major, [:type, :opera]], [
|
54
|
+
# Mixed
|
55
|
+
/(kindle)\/((\d+)?[\w\.]+)/i, # Kindle
|
56
|
+
/(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i, # Lunascape/Maxthon/Netfront/Jasmine/Blazer
|
57
|
+
# Trident based
|
58
|
+
/(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i # Avant/IEMobile/SlimBrowser/Baidu
|
59
|
+
], [:name, :version, :major], [
|
60
|
+
/(?:ms|\()(ie)\s((\d+)?[\w\.]+)/i # Internet Explorer
|
61
|
+
], [:name, :version, :major, [:type, :ie]], [
|
62
|
+
# Webkit/KHTML based
|
63
|
+
/(rekonq)\/?((\d+)[\w\.]+)*/i, # Rekonq
|
64
|
+
/(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt)\/((\d+)?[\w\.-]+)/i # Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt
|
65
|
+
], [:name, :version, :major], [
|
66
|
+
/(yabrowser)\/((\d+)?[\w\.]+)/i # Yandex
|
67
|
+
], [[:name, 'Yandex'], :version, :major], [
|
68
|
+
/(comodo_dragon)\/((\d+)?[\w\.]+)/i # Comodo Dragon
|
69
|
+
], [[:name, 'Comodo Dragon'], :version, :major], [
|
70
|
+
/(chromium)\/((\d+)?[\w\.-]+)/i, # Chromium
|
71
|
+
/(chrome)\/v?((\d+)?[\w\.]+)/i # Chrome
|
72
|
+
], [:name, :version, :major, [:type, :chrome]], [
|
73
|
+
/(omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i # Chrome/OmniWeb/Arora/Tizen/Nokia
|
74
|
+
], [:name, :version, :major], [
|
75
|
+
/(dolfin)\/((\d+)?[\w\.]+)/i # Dolphin
|
76
|
+
], [[:name, 'Dolphin'], :version, :major], [
|
77
|
+
/((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i # Chrome for Android/iOS
|
78
|
+
], [[:name, 'Chrome'], :version, :major, [:type, :chrome]], [
|
79
|
+
/version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i # Mobile Safari
|
80
|
+
], [:version, :major, [:name, 'Mobile Safari'], [:type, :safari]], [
|
81
|
+
/version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i # Safari & Safari Mobile
|
82
|
+
], [:version, :major, :name, [:type, :safari]], [
|
83
|
+
/webkit.+?(mobile\s?safari|safari)((\/[\w]+))/i # Safari < 3.0
|
84
|
+
], [:name, [:major, STRING_MAP[:browser][:oldsafari][:major]], [:version, STRING_MAP[:browser][:oldsafari][:version]], [:type, :safari]], [
|
85
|
+
/(konqueror)\/((\d+)?[\w\.]+)/i, # Konqueror
|
86
|
+
/(webkit|khtml)\/((\d+)?[\w\.]+)/i
|
87
|
+
], [:name, :version, :major], [
|
88
|
+
# Gecko based
|
89
|
+
/(navigator|netscape)\/((\d+)?[\w\.-]+)/i # Netscape
|
90
|
+
], [[:name, 'Netscape'], :version, :major], [
|
91
|
+
/(swiftfox)/i, # Swiftfox
|
92
|
+
/(iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i, # Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
|
93
|
+
/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i # Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
|
94
|
+
], [:name, :version, :major], [
|
95
|
+
/(firefox)\/((\d+)?[\w\.-]+)/i, # Firefox
|
96
|
+
/(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i, # Mozilla
|
97
|
+
], [:name, :version, :major, [:type, :firefox]], [
|
98
|
+
# Other
|
99
|
+
/(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?((\d+)?[\w\.]+)/i, # UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf
|
100
|
+
/(links)\s\(((\d+)?[\w\.]+)/i, # Links
|
101
|
+
/(gobrowser)\/?((\d+)?[\w\.]+)*/i, # GoBrowser
|
102
|
+
/(ice\s?browser)\/v?((\d+)?[\w\._]+)/i, # ICE Browser
|
103
|
+
/(mosaic)[\/\s]((\d+)?[\w\.]+)/i # Mosaic
|
104
|
+
], [:name, :version, :major]
|
105
|
+
],
|
106
|
+
:device => [
|
107
|
+
[
|
108
|
+
/\((playbook);[\w\s\);-]+(rim)/i # PlayBook
|
109
|
+
], [:model, :vendor, [:type, :tablet]], [
|
110
|
+
/\((ipad);[\w\s\);-]+(apple)/i # iPad
|
111
|
+
], [:model, :vendor, [:name, :ipad], [:type, :tablet]], [
|
112
|
+
/(hp).+(touchpad)/i, # HP TouchPad
|
113
|
+
/(kindle)\/([\w\.]+)/i, # Kindle
|
114
|
+
/\s(nook)[\w\s]+build\/(\w+)/i, # Nook
|
115
|
+
/(dell)\s(strea[kpr\s\d]*[\dko])/i # Dell Streak
|
116
|
+
], [:vendor, :model, [:type, :tablet]], [
|
117
|
+
/\((ip[honed]+);.+(apple)/i # iPod/iPhone
|
118
|
+
], [:model, :vendor, [:name, :iphone], [:type, :handheld]], [
|
119
|
+
/(blackberry)[\s-]?(\w+)/i, # BlackBerry
|
120
|
+
/(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|huawei|meizu|motorola)[\s_-]?([\w-]+)*/i, # BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Huawei/Meizu/Motorola
|
121
|
+
/(hp)\s([\w\s]+\w)/i, # HP iPAQ
|
122
|
+
/(asus)-?(\w+)/i # Asus
|
123
|
+
], [:vendor, :model, [:type, :handheld]], [
|
124
|
+
/\((bb10);\s(\w+)/i # BlackBerry 10
|
125
|
+
], [[:vendor, 'BlackBerry'], :model, [:type, :handheld]], [
|
126
|
+
/android.+((transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+))/i # Asus Tablets
|
127
|
+
], [[:vendor, 'Asus'], :model, [:type, :tablet]], [
|
128
|
+
/(sony)\s(tablet\s[ps])/i # Sony Tablets
|
129
|
+
], [:vendor, :model, [:type, :tablet]], [
|
130
|
+
/(nintendo)\s([wids3u]+)/i # Nintendo
|
131
|
+
], [:vendor, :model, [:type, :console]], [
|
132
|
+
/((playstation)\s[3portablevi]+)/i # Playstation
|
133
|
+
], [[:vendor, 'Sony'], :model, [:type, :console]], [
|
134
|
+
/(sprint\s(\w+))/i # Sprint Phones
|
135
|
+
], [:vendor, :model, [:type, :handheld]], [
|
136
|
+
/(htc)[;_\s-]+([\w\s_]+(?=\))|\w+)*/i, # HTC
|
137
|
+
/(zte)-(\w+)*/i, # ZTE
|
138
|
+
/(alcatel|geeksphone|huawei|lenovo|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]+)*/i # Alcatel/GeeksPhone/Huawei/Lenovo/Nexian/Panasonic/Sony
|
139
|
+
], [:vendor, [:model, lambda {|str| str.gsub(/_/, ' ') }], [:type, :handheld]], [
|
140
|
+
/\s((milestone|droid[2x]?))[globa\s]*\sbuild\//i, # Motorola
|
141
|
+
/(mot)[\s-]?(\w+)*/i
|
142
|
+
], [[:vendor, 'Motorola'], :model, [:type, :handheld]], [
|
143
|
+
/android.+\s((mz60\d|xoom[\s2]{0,2}))\sbuild\//i
|
144
|
+
], [[:vendor, 'Motorola'], :model, [:type, :tablet]], [
|
145
|
+
/android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n8000|sgh-t8[56]9))/i
|
146
|
+
], [[:vendor, 'Samsung'], :model, [:type, :tablet]], [
|
147
|
+
# Samsung
|
148
|
+
/((s[cgp]h-\w+|gt-\w+|galaxy\snexus))/i,
|
149
|
+
/(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i,
|
150
|
+
/sec-((sgh\w+))/i
|
151
|
+
], [[:vendor, 'Samsung'], :model, [:type, :handheld]], [
|
152
|
+
/(sie)-(\w+)*/i # Siemens
|
153
|
+
], [[:vendor, 'Siemens'], :model, [:type, :handheld]], [
|
154
|
+
/(maemo|nokia).*(n900|lumia\s\d+)/i, # Nokia
|
155
|
+
/(nokia)[\s_-]?([\w-]+)*/i
|
156
|
+
], [[:vendor, 'Nokia'], :model, [:type, :handheld]], [
|
157
|
+
/android\s3\.[-\s\w;]{10}((a\d{3}))/i # Acer
|
158
|
+
], [[:vendor, 'Acer'], :model, [:type, :tablet]], [
|
159
|
+
/android\s3\.[-\s\w;]{10}(lg?)-([06cv9]{3,4})/i # LG
|
160
|
+
], [[:vendor, 'LG'], :model, [:type, :tablet]], [
|
161
|
+
/((nexus\s4))/i,
|
162
|
+
/(lg)[-e;\s\/]+(\w+)*/i
|
163
|
+
], [[:vendor, 'LG'], :model, [:type, :handheld]], [
|
164
|
+
/opera\smobi/i,
|
165
|
+
/android/i
|
166
|
+
], [[:type, :handheld]], [
|
167
|
+
/nitro/i # Nintendo DS
|
168
|
+
], [[:type, :console]], [
|
169
|
+
/(mobile|tablet);.+rv\:.+gecko\//i # Unidentifiable
|
170
|
+
], [:type, :vendor, :model]
|
171
|
+
],
|
172
|
+
:engine => [
|
173
|
+
[
|
174
|
+
/(presto)\/((\d+)[\w\.]+)/i # Presto
|
175
|
+
], [:name, :version, :major, [:type, :presto]], [
|
176
|
+
/(webkit)\/((\d+)[\w\.]+)/i # WebKit
|
177
|
+
], [:name, :version, :major, [:type, :webkit]], [
|
178
|
+
/(trident)\/((\d+)[\w\.]+)/i # Trident
|
179
|
+
], [:name, :version, :major, [:type, :trident]], [
|
180
|
+
/(netfront|netsurf|amaya|lynx|w3m)\/((\d+)[\w\.]+)/i, # NetFront/NetSurf/Amaya/Lynx/w3m
|
181
|
+
/(khtml|tasman|links)[\/\s]\(?((\d+)[\w\.]+)/i, # KHTML/Tasman/Links
|
182
|
+
/(icab)[\/\s]([23]\.(\d+)[\d\.]+)/i # iCab
|
183
|
+
], [:name, :version, :major], [
|
184
|
+
/rv\:((\d+)[\w\.]+).*(gecko)/i # Gecko
|
185
|
+
], [:version, :major, :name, [:type, :gecko]]
|
186
|
+
],
|
187
|
+
:os => [
|
188
|
+
[
|
189
|
+
# Windows based
|
190
|
+
/(windows)\snt\s6\.2;\s(arm)/i, # Windows RT
|
191
|
+
/(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i,
|
192
|
+
/(microsoft windows)/i
|
193
|
+
], [:name, [:version, STRING_MAP[:os][:windows][:version]], [:type, :windows]], [
|
194
|
+
/(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
|
195
|
+
], [[:name, 'Windows'], [:version, STRING_MAP[:os][:windows][:version]], [:type, :windows]], [
|
196
|
+
# Mobile/Embedded OS
|
197
|
+
/\((bb)(10);/i # BlackBerry 10
|
198
|
+
], [[:name, 'BlackBerry'], :version, [:type, :blackberry]], [
|
199
|
+
/(blackberry)\w*\/?([\w\.]+)*/i, # Blackberry
|
200
|
+
/(rim\stablet\sos)[\/\s-]?([\w\.]+)*/i # RIM
|
201
|
+
], [:name, :version, [:type, :blackberry]], [
|
202
|
+
/(android)[\/\s-]?([\w\.]+)*/i # Android
|
203
|
+
], [:name, :version, [:type, :android]], [
|
204
|
+
/(tizen)\/([\w\.]+)/i, # Tizen
|
205
|
+
/(webos|palm\os|qnx|bada|meego)[\/\s-]?([\w\.]+)*/i # WebOS/Palm/QNX/Bada/MeeGo
|
206
|
+
], [:name, :version], [
|
207
|
+
/(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i # Symbian
|
208
|
+
], [[:name, 'Symbian'], :version],[
|
209
|
+
/mozilla.+\(mobile;.+gecko.+firefox/i # Firefox OS
|
210
|
+
], [[:name, 'Firefox OS'], :version], [
|
211
|
+
# Console
|
212
|
+
/(nintendo|playstation)\s([wids3portablevu]+)/i, # Nintendo/Playstation
|
213
|
+
], [:name, :version], [
|
214
|
+
# GNU/Linux based
|
215
|
+
/(mint)[\/\s\(]?(\w+)*/i, # Mint
|
216
|
+
/(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i, # Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk
|
217
|
+
/(hurd|linux)\s?([\w\.]+)*/i, # Hurd/Linux
|
218
|
+
/(gnu)\s?([\w\.]+)*/i # GNU
|
219
|
+
], [:name, :version, [:type, :linux]], [
|
220
|
+
/(cros)\s[\w]+\s([\w\.]+\w)/i # Chromium OS
|
221
|
+
], [[:name, 'Chromium OS'], :version],[
|
222
|
+
# Solaris
|
223
|
+
/(sunos)\s?([\w\.]+\d)*/i # Solaris
|
224
|
+
], [[:name, 'Solaris'], :version], [
|
225
|
+
# BSD based
|
226
|
+
/\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i # FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
|
227
|
+
], [:name, :version],[
|
228
|
+
/(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i # iOS
|
229
|
+
], [[:name, 'iOS'], [:version, lambda {|str| str.gsub(/_/, '.') }], [:type, :ios]], [
|
230
|
+
/(mac\sos\sx)\s?([\w\s\.]+\w)*/i # Mac OS
|
231
|
+
], [:name, [:version, lambda {|str| str.gsub(/_/, '.') }], [:type, :mac]], [
|
232
|
+
# Other
|
233
|
+
/(haiku)\s(\w+)/i, # Haiku
|
234
|
+
/(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, # AIX
|
235
|
+
/(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i, # Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS
|
236
|
+
/(unix)\s?([\w\.]+)*/i # UNIX
|
237
|
+
], [:name, :version]
|
238
|
+
]
|
239
|
+
}
|
240
|
+
end
|
@@ -0,0 +1,405 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BrowserSnifferTest < ActiveSupport::TestCase
|
4
|
+
AGENTS = {
|
5
|
+
:ipad_old => {
|
6
|
+
:user_agent => "Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10",
|
7
|
+
:form_factor => :tablet,
|
8
|
+
:ios? => true,
|
9
|
+
:android? => false,
|
10
|
+
:desktop? => false,
|
11
|
+
:engine => :webkit,
|
12
|
+
:major_engine_version => 531,
|
13
|
+
:os => :ios,
|
14
|
+
:os_version => '3.2',
|
15
|
+
:browser => :safari,
|
16
|
+
:major_browser_version => 4
|
17
|
+
},
|
18
|
+
:ipad_new => {
|
19
|
+
:user_agent => "Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10",
|
20
|
+
:form_factor => :tablet,
|
21
|
+
:ios? => true,
|
22
|
+
:android? => false,
|
23
|
+
:desktop? => false,
|
24
|
+
:engine => :webkit,
|
25
|
+
:major_engine_version => 531,
|
26
|
+
:os => :ios,
|
27
|
+
:os_version => '3.2',
|
28
|
+
:browser => :safari,
|
29
|
+
:major_browser_version => 4
|
30
|
+
},
|
31
|
+
:ipad_chrome => {
|
32
|
+
:user_agent => "Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X; en-us) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/21.0.1180.82 Mobile/10A523 Safari/7534.48.3",
|
33
|
+
:form_factor => :tablet,
|
34
|
+
:ios? => true,
|
35
|
+
:android? => false,
|
36
|
+
:desktop? => false,
|
37
|
+
:engine => :webkit,
|
38
|
+
:major_engine_version => 534,
|
39
|
+
:os => :ios,
|
40
|
+
:os_version => '6.0.1',
|
41
|
+
:browser => :chrome,
|
42
|
+
:major_browser_version => 21
|
43
|
+
},
|
44
|
+
:iphone => {
|
45
|
+
:user_agent => "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16",
|
46
|
+
:form_factor => :handheld,
|
47
|
+
:ios? => true,
|
48
|
+
:android? => false,
|
49
|
+
:desktop? => false,
|
50
|
+
:engine => :webkit,
|
51
|
+
:major_engine_version => 528,
|
52
|
+
:os => :ios,
|
53
|
+
:os_version => '3.1.2',
|
54
|
+
:browser => :safari,
|
55
|
+
:major_browser_version => 4
|
56
|
+
},
|
57
|
+
:ipod_touch => {
|
58
|
+
:user_agent => "Mozilla/5.0 (iPod; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11a Safari/525.20",
|
59
|
+
:form_factor => :handheld,
|
60
|
+
:ios? => true,
|
61
|
+
:android? => false,
|
62
|
+
:desktop? => false,
|
63
|
+
:engine => :webkit,
|
64
|
+
:major_engine_version => 525,
|
65
|
+
:os => :ios,
|
66
|
+
:os_version => '2.2.1',
|
67
|
+
:browser => :safari,
|
68
|
+
:major_browser_version => 3
|
69
|
+
},
|
70
|
+
:nexus_one => {
|
71
|
+
:user_agent => "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
72
|
+
:form_factor => :handheld,
|
73
|
+
:ios? => false,
|
74
|
+
:android? => true,
|
75
|
+
:desktop? => false,
|
76
|
+
:engine => :webkit,
|
77
|
+
:major_engine_version => 533,
|
78
|
+
:os => :android,
|
79
|
+
:os_version => '2.2',
|
80
|
+
:browser => :safari,
|
81
|
+
:major_browser_version => 4
|
82
|
+
},
|
83
|
+
:htc_droid => {
|
84
|
+
:user_agent => "Mozilla/5.0 (Linux; U; Android 2.2; nl-nl; Desire_A8181 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
85
|
+
:form_factor => :handheld,
|
86
|
+
:ios? => false,
|
87
|
+
:android? => true,
|
88
|
+
:desktop? => false,
|
89
|
+
:engine => :webkit,
|
90
|
+
:major_engine_version => 533,
|
91
|
+
:os => :android,
|
92
|
+
:os_version => '2.2',
|
93
|
+
:browser => :safari,
|
94
|
+
:major_browser_version => 4
|
95
|
+
},
|
96
|
+
:bb_torch => {
|
97
|
+
:user_agent => "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/6.0.0.141 Mobile Safari/534.1+",
|
98
|
+
:form_factor => :handheld,
|
99
|
+
:ios? => false,
|
100
|
+
:android? => false,
|
101
|
+
:desktop? => false,
|
102
|
+
:engine => :webkit,
|
103
|
+
:major_engine_version => 534,
|
104
|
+
:os => :blackberry,
|
105
|
+
:os_version => nil,
|
106
|
+
:browser => :safari,
|
107
|
+
:major_browser_version => 6
|
108
|
+
},
|
109
|
+
:bb_8830 => {
|
110
|
+
:user_agent => "BlackBerry8330/4.3.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/105",
|
111
|
+
:form_factor => :handheld,
|
112
|
+
:ios? => false,
|
113
|
+
:android? => false,
|
114
|
+
:desktop? => false,
|
115
|
+
:engine => nil,
|
116
|
+
:major_engine_version => nil,
|
117
|
+
:os => :blackberry,
|
118
|
+
:os_version => '4.3.0',
|
119
|
+
:browser => nil,
|
120
|
+
:major_browser_version => nil
|
121
|
+
},
|
122
|
+
:kindle => {
|
123
|
+
:user_agent => "Mozilla/4.0 (compatible; Linux 2.6.22) NetFront/3.4 Kindle/2.0 (screen 600x800)",
|
124
|
+
:form_factor => :tablet,
|
125
|
+
:ios? => false,
|
126
|
+
:android? => false,
|
127
|
+
:desktop? => false,
|
128
|
+
:engine => nil,
|
129
|
+
:major_engine_version => 3,
|
130
|
+
:os => :linux,
|
131
|
+
:os_version => '2.6.22',
|
132
|
+
:browser => nil,
|
133
|
+
:major_browser_version => 2
|
134
|
+
},
|
135
|
+
:nokia_classic => {
|
136
|
+
:user_agent => "Nokia3120Classic/2.0 (06.20) Profile/MIDP-2.1 Configuration/CLDC-1.1",
|
137
|
+
:form_factor => :handheld,
|
138
|
+
:ios? => false,
|
139
|
+
:android? => false,
|
140
|
+
:desktop? => false,
|
141
|
+
:engine => nil,
|
142
|
+
:major_engine_version => nil,
|
143
|
+
:os => nil,
|
144
|
+
:os_version => nil,
|
145
|
+
:browser => nil,
|
146
|
+
:major_browser_version => nil
|
147
|
+
},
|
148
|
+
:nokia_3200 => {
|
149
|
+
:user_agent => "Nokia3200/1.0 (5.29) Profile/MIDP-1.0 Configuration/CLDC-1.0\nUP.Link/6.3.1.13.0",
|
150
|
+
:form_factor => :handheld,
|
151
|
+
:ios? => false,
|
152
|
+
:android? => false,
|
153
|
+
:desktop? => false,
|
154
|
+
:engine => nil,
|
155
|
+
:major_engine_version => nil,
|
156
|
+
:os => nil,
|
157
|
+
:os_version => nil,
|
158
|
+
:browser => nil,
|
159
|
+
:major_browser_version => nil
|
160
|
+
},
|
161
|
+
:att => {
|
162
|
+
:user_agent => "Opera/9.51 Beta (Microsoft Windows; PPC; Opera Mobi/1718; U; en)",
|
163
|
+
:form_factor => :handheld,
|
164
|
+
:ios? => false,
|
165
|
+
:android? => false,
|
166
|
+
:desktop? => false,
|
167
|
+
:engine => nil,
|
168
|
+
:major_engine_version => nil,
|
169
|
+
:os => :windows,
|
170
|
+
:os_version => nil,
|
171
|
+
:browser => :opera,
|
172
|
+
:major_browser_version => 9
|
173
|
+
},
|
174
|
+
:benq => {
|
175
|
+
:user_agent => "BenQ-CF61/1.00/WAP2.0/MIDP2.0/CLDC1.0 UP.Browser/6.3.0.4.c.1.102 (GUI) MMP/2.0",
|
176
|
+
:form_factor => :handheld,
|
177
|
+
:ios? => false,
|
178
|
+
:android? => false,
|
179
|
+
:desktop? => false,
|
180
|
+
:engine => nil,
|
181
|
+
:major_engine_version => nil,
|
182
|
+
:os => nil,
|
183
|
+
:os_version => nil,
|
184
|
+
:browser => nil,
|
185
|
+
:major_browser_version => nil
|
186
|
+
},
|
187
|
+
:dell_streak => {
|
188
|
+
:user_agent => "Mozilla/5.0 (Linux; U; Android 1.6; en-gb; Dell Streak Build/Donut AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/ 525.20.1",
|
189
|
+
:form_factor => :tablet,
|
190
|
+
:ios? => false,
|
191
|
+
:android? => true,
|
192
|
+
:desktop? => false,
|
193
|
+
:engine => :webkit,
|
194
|
+
:major_engine_version => 528,
|
195
|
+
:os => :android,
|
196
|
+
:os_version => '1.6',
|
197
|
+
:os => :android,
|
198
|
+
:major_browser_version => 3
|
199
|
+
},
|
200
|
+
:hp_ipaq => {
|
201
|
+
:user_agent => "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320; HP iPAQ h6300)",
|
202
|
+
:form_factor => :handheld,
|
203
|
+
:ios? => false,
|
204
|
+
:android? => false,
|
205
|
+
:desktop? => false,
|
206
|
+
:engine => nil,
|
207
|
+
:major_engine_version => nil,
|
208
|
+
:os => :windows,
|
209
|
+
:os_version => 'CE',
|
210
|
+
:browser => :ie,
|
211
|
+
:major_browser_version => 4
|
212
|
+
},
|
213
|
+
:nintendo_ds => {
|
214
|
+
:user_agent => "Mozilla/4.0 (compatible; MSIE 6.0; Nitro) Opera 8.50 [en Mozilla/4.0 (compatible; MSIE 6.0; Nitro) Opera 8.50 [ja]",
|
215
|
+
:form_factor => :console,
|
216
|
+
:ios? => false,
|
217
|
+
:android? => false,
|
218
|
+
:desktop? => false,
|
219
|
+
:engine => nil,
|
220
|
+
:major_engine_version => nil,
|
221
|
+
:os => nil,
|
222
|
+
:os_version => nil,
|
223
|
+
:browser => :opera,
|
224
|
+
:major_browser_version => 8
|
225
|
+
},
|
226
|
+
:firefox_linux => {
|
227
|
+
:user_agent => "Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8",
|
228
|
+
:form_factor => :desktop,
|
229
|
+
:ios? => false,
|
230
|
+
:android? => false,
|
231
|
+
:desktop? => true,
|
232
|
+
:engine => :gecko,
|
233
|
+
:major_engine_version => 1,
|
234
|
+
:os => :linux,
|
235
|
+
:os_version => '10.04',
|
236
|
+
:browser => :firefox,
|
237
|
+
:major_browser_version => 3
|
238
|
+
},
|
239
|
+
:safari_mac => {
|
240
|
+
:user_agent => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-ca) AppleWebKit/534.6+ (KHTML, like Gecko) Version/5.0 Safari/533.16",
|
241
|
+
:form_factor => :desktop,
|
242
|
+
:ios? => false,
|
243
|
+
:android? => false,
|
244
|
+
:desktop? => true,
|
245
|
+
:engine => :webkit,
|
246
|
+
:major_engine_version => 534,
|
247
|
+
:os => :mac,
|
248
|
+
:os_version => '10.6.3',
|
249
|
+
:browser => :safari,
|
250
|
+
:major_browser_version => 5
|
251
|
+
},
|
252
|
+
:chrome_mac => {
|
253
|
+
:user_agent => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/534.6 (KHTML, like Gecko) Chrome/6.0.495.0 Safari/534.6",
|
254
|
+
:form_factor => :desktop,
|
255
|
+
:ios? => false,
|
256
|
+
:android? => false,
|
257
|
+
:desktop? => true,
|
258
|
+
:engine => :webkit,
|
259
|
+
:major_engine_version => 534,
|
260
|
+
:os => :mac,
|
261
|
+
:os_version => '10.6.3',
|
262
|
+
:browser => :chrome,
|
263
|
+
:major_browser_version => 6
|
264
|
+
},
|
265
|
+
:chrome_win => {
|
266
|
+
:user_agent => "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.125 Safari/533.4",
|
267
|
+
:form_factor => :desktop,
|
268
|
+
:ios? => false,
|
269
|
+
:android? => false,
|
270
|
+
:desktop? => true,
|
271
|
+
:engine => :webkit,
|
272
|
+
:major_engine_version => 533,
|
273
|
+
:os => :windows,
|
274
|
+
:os_version => 'Vista',
|
275
|
+
:browser => :chrome,
|
276
|
+
:major_browser_version => 5
|
277
|
+
},
|
278
|
+
:ie9 => {
|
279
|
+
:user_agent => "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)",
|
280
|
+
:form_factor => :desktop,
|
281
|
+
:ios? => false,
|
282
|
+
:android? => false,
|
283
|
+
:desktop? => true,
|
284
|
+
:engine => :trident,
|
285
|
+
:major_engine_version => 5,
|
286
|
+
:os => :windows,
|
287
|
+
:os_version => '7',
|
288
|
+
:browser => :ie,
|
289
|
+
:major_browser_version => 9
|
290
|
+
},
|
291
|
+
:ie8 => {
|
292
|
+
:user_agent => "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDC)",
|
293
|
+
:form_factor => :desktop,
|
294
|
+
:ios? => false,
|
295
|
+
:android? => false,
|
296
|
+
:desktop? => true,
|
297
|
+
:engine => :trident,
|
298
|
+
:major_engine_version => 4,
|
299
|
+
:os => :windows,
|
300
|
+
:os_version => '7',
|
301
|
+
:browser => :ie,
|
302
|
+
:major_browser_version => 8
|
303
|
+
},
|
304
|
+
:ie7 => {
|
305
|
+
: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)",
|
306
|
+
:form_factor => :desktop,
|
307
|
+
:ios? => false,
|
308
|
+
:android? => false,
|
309
|
+
:desktop? => true,
|
310
|
+
:engine => nil,
|
311
|
+
:major_engine_version => nil,
|
312
|
+
:os => :windows,
|
313
|
+
:os_version => 'XP',
|
314
|
+
:browser => :ie,
|
315
|
+
:major_browser_version => 7
|
316
|
+
},
|
317
|
+
:opera_win => {
|
318
|
+
:user_agent => "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.5.24 Version/10.54",
|
319
|
+
:form_factor => :desktop,
|
320
|
+
:ios? => false,
|
321
|
+
:android? => false,
|
322
|
+
:desktop? => true,
|
323
|
+
:engine => :presto,
|
324
|
+
:major_engine_version => 2,
|
325
|
+
:os => :windows,
|
326
|
+
:os_version => '7',
|
327
|
+
:browser => :opera,
|
328
|
+
:major_browser_version => 9
|
329
|
+
},
|
330
|
+
:wii => {
|
331
|
+
:user_agent => "Opera/9.00 (Nintendo Wii; U; ; 1038-58; Wii Shop Channel/1.0; en)",
|
332
|
+
:form_factor => :console,
|
333
|
+
:ios? => false,
|
334
|
+
:android? => false,
|
335
|
+
:desktop? => false,
|
336
|
+
:engine => nil,
|
337
|
+
:major_engine_version => nil,
|
338
|
+
:os => nil,
|
339
|
+
:os_version => 'Wii',
|
340
|
+
:browser => :opera,
|
341
|
+
:major_browser_version => 9
|
342
|
+
},
|
343
|
+
:springboard_launched_ipod_browser => {
|
344
|
+
:user_agent => "Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/8J2",
|
345
|
+
:form_factor => :handheld,
|
346
|
+
:ios? => true,
|
347
|
+
:android? => false,
|
348
|
+
:desktop? => false,
|
349
|
+
:engine => :webkit,
|
350
|
+
:major_engine_version => 533,
|
351
|
+
:os => :ios,
|
352
|
+
:os_version => '4.3.3',
|
353
|
+
:browser => nil,
|
354
|
+
:major_browser_version => 533
|
355
|
+
},
|
356
|
+
:ipod_os_4_3_3 => {
|
357
|
+
:user_agent => "Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
|
358
|
+
:form_factor => :handheld,
|
359
|
+
:ios? => true,
|
360
|
+
:android? => false,
|
361
|
+
:desktop? => false,
|
362
|
+
:engine => :webkit,
|
363
|
+
:major_engine_version => 533,
|
364
|
+
:os => :ios,
|
365
|
+
:os_version => '4.3.3',
|
366
|
+
:browser => :safari,
|
367
|
+
:major_browser_version => 5
|
368
|
+
},
|
369
|
+
:iphone_4S => {
|
370
|
+
:user_agent => "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
|
371
|
+
:form_factor => :handheld,
|
372
|
+
:ios? => true,
|
373
|
+
:android? => false,
|
374
|
+
:desktop? => false,
|
375
|
+
:engine => :webkit,
|
376
|
+
:major_engine_version => 534,
|
377
|
+
:os => :ios,
|
378
|
+
:os_version => '5.0',
|
379
|
+
:browser => :safari,
|
380
|
+
:major_browser_version => 5
|
381
|
+
},
|
382
|
+
:ipad_ios5 => {
|
383
|
+
:user_agent => "Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
|
384
|
+
:form_factor => :tablet,
|
385
|
+
:ios? => true,
|
386
|
+
:android? => false,
|
387
|
+
:desktop? => false,
|
388
|
+
:engine => :webkit,
|
389
|
+
:major_engine_version => 534,
|
390
|
+
:os => :ios,
|
391
|
+
:os_version => '5.0',
|
392
|
+
:browser => :safari,
|
393
|
+
:major_browser_version => 5
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
AGENTS.each do |agent, attributes|
|
398
|
+
test "sniff #{agent} correctly" do
|
399
|
+
sniffer = BrowserSniffer.new(attributes[:user_agent])
|
400
|
+
attributes.except(:user_agent).each do |attribute, value|
|
401
|
+
assert_equal value, sniffer.send(attribute), "#{attribute.to_s} did not match"
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: browser_sniffer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Shopify
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: Parses user agent strings and boils it all down to a few simple classifications.
|
47
|
+
email:
|
48
|
+
- gems@shopify.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gemspec.rb
|
54
|
+
- .gitignore
|
55
|
+
- .travis.yml
|
56
|
+
- Gemfile
|
57
|
+
- LICENSE.txt
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- browser_sniffer.gemspec
|
61
|
+
- init.rb
|
62
|
+
- lib/browser_sniffer.rb
|
63
|
+
- lib/browser_sniffer/patterns.rb
|
64
|
+
- lib/browser_sniffer/version.rb
|
65
|
+
- test/browser_sniffer_test.rb
|
66
|
+
- test/test_helper.rb
|
67
|
+
homepage: https://github.com/Shopify/browser_sniffer
|
68
|
+
licenses:
|
69
|
+
- GPLv2 & MIT
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 1.9.3
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
hash: -639204093017043880
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 1.8.25
|
92
|
+
signing_key:
|
93
|
+
specification_version: 3
|
94
|
+
summary: ! '## Description'
|
95
|
+
test_files:
|
96
|
+
- test/browser_sniffer_test.rb
|
97
|
+
- test/test_helper.rb
|