browser_sniffer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - jruby-19mode
6
+ script: bundle exec rake test
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in browser_sniffer.gemspec
4
+ gemspec
@@ -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.
@@ -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
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ desc 'Default: run unit tests.'
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'lib'
9
+ t.libs << 'test'
10
+ t.pattern = 'test/*_test.rb'
11
+ t.verbose = true
12
+ end
@@ -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,3 @@
1
+ class BrowserSniffer
2
+ VERSION = "1.0.0"
3
+ 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
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_support/all'
4
+
5
+ require "#{File.dirname(__FILE__)}/../init"
6
+
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