browser_sniffer 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.
@@ -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