double_agent 0.2.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +15 -0
- data/README.rdoc +33 -47
- data/data/browsers.yml +39 -35
- data/data/oses.yml +63 -37
- data/lib/double_agent/double_agent.rb +60 -0
- data/lib/double_agent/parser.rb +35 -155
- data/lib/double_agent/{resources.rb → resource.rb} +24 -31
- data/lib/double_agent/user_agent.rb +14 -0
- data/lib/double_agent/version.rb +1 -1
- data/lib/double_agent.rb +7 -1
- metadata +8 -16
- data/lib/double_agent/all.rb +0 -5
- data/lib/double_agent/logs.rb +0 -110
- data/lib/double_agent/stats.rb +0 -65
- data/spec/data/httpd.access.log +0 -20
- data/spec/data/httpd.access.log.1.gz +0 -0
- data/spec/data_spec.rb +0 -105
- data/spec/parser_spec.rb +0 -114
- data/spec/resources_spec.rb +0 -78
- data/spec/spec_helper.rb +0 -19
- data/spec/stats_spec.rb +0 -64
data/CHANGELOG
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
== Release 1.0.0 (November 11, 2012) ==
|
2
|
+
|
3
|
+
* Changes to parser API
|
4
|
+
* Add "mobile?" method to detect mobile OS's
|
5
|
+
* Android's browser isn't part of the Chromium family
|
6
|
+
* Android OS isn't part of the GNU/Linux family
|
7
|
+
* iOS isn't part of the OS X family
|
8
|
+
* Add iPhone and iPad
|
9
|
+
* Add Kindle, Kindle Fire
|
10
|
+
* Refactor the Logs module
|
11
|
+
* Drop Stats module (use the "graphene" gem instead)
|
12
|
+
* Drop Logs module
|
13
|
+
* Drop icon methods - they just don't make much sense in the library
|
14
|
+
* Drop support for Ruby 1.8
|
15
|
+
|
1
16
|
== Release 0.2.3 (July 14, 2012) ==
|
2
17
|
|
3
18
|
* Handle exceptions on encoding errors
|
data/README.rdoc
CHANGED
@@ -3,41 +3,50 @@
|
|
3
3
|
double_agent is a library for parsing browser and operating system info out of user
|
4
4
|
agent strings. It is designed for parsing large sets for review or analysis.
|
5
5
|
|
6
|
-
|
6
|
+
*NOTE* Support for Ruby 1.8 was dropped after version 0.2.3.
|
7
7
|
|
8
|
-
|
8
|
+
== Installation
|
9
9
|
|
10
|
-
|
10
|
+
[sudo] gem install double_agent
|
11
|
+
# Or add "double_agent" to your Gemfile
|
11
12
|
|
12
|
-
|
13
|
+
Read the full documentation at http://jordanhollinger.com/docs/double_agent/
|
13
14
|
|
14
|
-
|
15
|
-
require 'double_agent'
|
15
|
+
== Parser
|
16
16
|
|
17
|
-
|
18
|
-
require 'double_agent/parser|resources|stats|logs|all'
|
17
|
+
user_agent = DoubleAgent.parse("Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/12.04 Chromium/18.0.1025.168 Chrome/18.0.1025.168 Safari/535.19")
|
19
18
|
|
20
|
-
|
19
|
+
user_agent.browser
|
20
|
+
=> "Chrome 18"
|
21
21
|
|
22
|
-
|
22
|
+
user_agent.browser_name
|
23
|
+
=> "Chrome"
|
23
24
|
|
24
|
-
|
25
|
-
=> "
|
25
|
+
user_agent.browser_version
|
26
|
+
=> "18"
|
26
27
|
|
27
|
-
|
28
|
+
user_agent.browser_family
|
28
29
|
=> "Chromium"
|
29
30
|
|
30
|
-
|
31
|
+
user_agent.os
|
31
32
|
=> "Ubuntu"
|
32
33
|
|
33
|
-
|
34
|
+
user_agent.os_family
|
34
35
|
=> "GNU/Linux"
|
35
36
|
|
36
|
-
|
37
|
+
user_agent.mobile?
|
38
|
+
=> false
|
39
|
+
|
40
|
+
# Or
|
37
41
|
|
38
|
-
|
42
|
+
DoubleAgent.browser("Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/12.04 Chromium/18.0.1025.168 Chrome/18.0.1025.168 Safari/535.19")
|
43
|
+
=> "Chrome 18"
|
39
44
|
|
40
|
-
|
45
|
+
See the DoubleAgent module for more info.
|
46
|
+
|
47
|
+
== Resources
|
48
|
+
|
49
|
+
DoubleAgent::Resource is a mix-in for objects with a user_agent method.
|
41
50
|
It gives that class's objects all of the above methods and more.
|
42
51
|
|
43
52
|
class Login
|
@@ -56,36 +65,13 @@ It gives that class's objects all of the above methods and more.
|
|
56
65
|
login.os_family
|
57
66
|
=> "OS X"
|
58
67
|
|
59
|
-
|
60
|
-
|
61
|
-
Calculate browser and OS shares for large sets of DoubleAgent::Resource objects with DoubleAgent::Stats::percentages_for.
|
62
|
-
|
63
|
-
logins = Login.all
|
64
|
-
p logins.size
|
65
|
-
=> 1000
|
66
|
-
|
67
|
-
stats = DoubleAgent::Stats.percentages_for(logins, :browser_family, :os_family)
|
68
|
-
p stats
|
69
|
-
=> [["Firefox", "Windows", 50.0, 500], ["Internet Explorer", "Windows", 20.0, 200], ["Safari", "OS X", 20.0, 200], ["Firefox", "GNU/Linux", 10.0, 100]]
|
70
|
-
|
71
|
-
stats.each do |browser_family, os_family, percent, real_num|
|
72
|
-
puts "#{browser_family} on #{os_family} - #{percent}% (#{real_num} hits)"
|
73
|
-
end
|
74
|
-
=> "Firefox on Windows - 50% (500 hits)"
|
75
|
-
=> "Internet Explorer on Windows - 20% (200 hits)"
|
76
|
-
=> "Safari on OS X - 20% (200 hits)"
|
77
|
-
=> "Firefox on GNU/Linux - 10% (100 hits)"
|
78
|
-
|
79
|
-
= Logs
|
68
|
+
See the DoubleAgent::Resource module for more info.
|
80
69
|
|
81
|
-
|
82
|
-
object. It even reads gzipped logs (requires zlib)! Since the DoubleAgent::Logs::Entry class mixes in DoubleAgent::Resource, you
|
83
|
-
can easily calculate browser and/or OS share on your site.
|
70
|
+
== Where did stats and logs go?
|
84
71
|
|
85
|
-
|
86
|
-
stats = DoubleAgent::Stats.percentages_for(entries, :browser)
|
72
|
+
As of version 1.0.0, double_agent underwent a downsizing. Stats were dropped and moved to their own more generic gem called Graphene. More info at https://github.com/jhollinger/graphene. Logs were also dropped; there are several HTTP log parsers for Ruby, including http-log-parser and Beaver.
|
87
73
|
|
88
|
-
|
89
|
-
|
74
|
+
== License
|
75
|
+
Copyright 2011 Jordan Hollinger
|
90
76
|
|
91
|
-
|
77
|
+
Licensed under the Apache License
|
data/data/browsers.yml
CHANGED
@@ -1,65 +1,69 @@
|
|
1
1
|
# The ordering is very important; matches are performed in the specified order.
|
2
2
|
# This allows for greatly simplified regexes.
|
3
3
|
|
4
|
-
|
5
|
-
:
|
4
|
+
:msie:
|
5
|
+
:name: Internet Explorer
|
6
6
|
:regex: msie \d+
|
7
7
|
:version: (?<=msie )[0-9]+
|
8
|
-
:safe_version: ["msie [0-9]+", "[0-9]+"]
|
9
8
|
|
10
|
-
|
11
|
-
:
|
9
|
+
:epiphany:
|
10
|
+
:name: Epiphany
|
11
|
+
:regex: epiphany
|
12
|
+
:version: (?<=epiphany/)[0-9]+
|
13
|
+
|
14
|
+
:chrome:
|
15
|
+
:name: Chrome
|
12
16
|
:family_sym: :chromium
|
13
17
|
:regex: chrome/\d+
|
14
18
|
:version: (?<=chrome/)[0-9]+
|
15
|
-
:safe_version: ["chrome/[0-9]+", "[0-9]+"]
|
16
19
|
|
17
|
-
|
18
|
-
:
|
20
|
+
:chromium:
|
21
|
+
:name: Chromium
|
19
22
|
:regex: chromium/\d+
|
20
23
|
:version: (?<=chromium/)[0-9]+
|
21
|
-
:safe_version: ["chromium/[0-9]+", "[0-9]+"]
|
22
24
|
|
23
|
-
|
24
|
-
:
|
25
|
+
:opera:
|
26
|
+
:name: Opera
|
25
27
|
:regex: opera
|
26
28
|
:version: ((?<=version/)[0-9]+)|((?<=opera )[0-9]+)
|
27
|
-
:safe_version: ["(version/[0-9]+)|(opera [0-9]+)", "[0-9]+"]
|
28
29
|
|
29
|
-
|
30
|
-
:
|
30
|
+
:firefox:
|
31
|
+
:name: Firefox
|
31
32
|
:regex: firefox
|
32
33
|
:version: (?<=firefox/)[0-9]+
|
33
|
-
:safe_version: ["firefox/[0-9]+", "[0-9]+"]
|
34
34
|
|
35
|
-
|
36
|
-
:
|
37
|
-
:family_sym: :
|
35
|
+
:kindle_fire_silk:
|
36
|
+
:name: Kindle Fire (Silk)
|
37
|
+
:family_sym: :kindle
|
38
|
+
:regex: silk-accelerated
|
39
|
+
|
40
|
+
:kindle_fire:
|
41
|
+
:name: Kindle Fire
|
42
|
+
:family_sym: :kindle
|
43
|
+
:regex: kindle fire
|
44
|
+
|
45
|
+
:kindle:
|
46
|
+
:name: Kindle
|
47
|
+
:regex: kindle
|
48
|
+
|
49
|
+
:android:
|
50
|
+
:name: Android
|
38
51
|
:regex: android
|
39
52
|
:version: (?<=android )[0-9]+(\.[0-9]+)?
|
40
|
-
:safe_version: ["android [0-9]+(\\.[0-9]+)?", "[0-9]+(\\.[0-9]+)?"]
|
41
53
|
|
42
|
-
|
43
|
-
:
|
54
|
+
:blackberry:
|
55
|
+
:name: BlackBerry
|
44
56
|
:regex: blackberry
|
45
57
|
|
46
|
-
|
47
|
-
:
|
48
|
-
:regex: epiphany
|
49
|
-
:version: (?<=epiphany/)[0-9]+
|
50
|
-
:safe_version: ["epiphany/[0-9]+", "[0-9]+"]
|
51
|
-
|
52
|
-
- :name: Safari %s
|
53
|
-
:sym: :safari
|
58
|
+
:safari:
|
59
|
+
:name: Safari
|
54
60
|
:regex: safari
|
55
61
|
:version: (?<=version/)[0-9]+
|
56
|
-
:safe_version: ["version/[0-9]+", "[0-9]+"]
|
57
62
|
|
58
|
-
|
59
|
-
:
|
63
|
+
:konqueror:
|
64
|
+
:name: Konqueror
|
60
65
|
:regex: konqueror
|
61
66
|
|
62
|
-
|
63
|
-
:
|
67
|
+
:unknown:
|
68
|
+
:name: Unknown
|
64
69
|
:regex: .*
|
65
|
-
:version: .*
|
data/data/oses.yml
CHANGED
@@ -1,72 +1,98 @@
|
|
1
|
-
|
2
|
-
:
|
1
|
+
:windows_8:
|
2
|
+
:name: Windows 8
|
3
3
|
:family_sym: :windows
|
4
4
|
:regex: windows nt 6\.2
|
5
|
-
:icon: windows
|
6
5
|
|
7
|
-
|
8
|
-
:
|
6
|
+
:windows_7:
|
7
|
+
:name: Windows 7
|
9
8
|
:family_sym: :windows
|
10
9
|
:regex: windows nt 6\.1
|
11
|
-
:icon: windows
|
12
10
|
|
13
|
-
|
14
|
-
:
|
11
|
+
:windows_vista:
|
12
|
+
:name: Windows Vista
|
15
13
|
:family_sym: :windows
|
16
14
|
:regex: windows nt 6\.0
|
17
|
-
:icon: windows
|
18
15
|
|
19
|
-
|
20
|
-
:
|
16
|
+
:windows_xp:
|
17
|
+
:name: Windows XP
|
21
18
|
:family_sym: :windows
|
22
19
|
:regex: windows nt 5\.[12]
|
23
|
-
:icon: windows
|
24
20
|
|
25
|
-
|
26
|
-
:
|
21
|
+
:windows:
|
22
|
+
:name: Windows
|
27
23
|
:regex: windows
|
28
24
|
|
29
|
-
|
30
|
-
:
|
31
|
-
:family_sym: :
|
32
|
-
:regex: (
|
25
|
+
:kindle_fire:
|
26
|
+
:name: Kindle Fire
|
27
|
+
:family_sym: :kindle
|
28
|
+
:regex: (kindle fire)|(silk-accelerated)
|
29
|
+
:mobile: true
|
33
30
|
|
34
|
-
|
35
|
-
:
|
31
|
+
:kindle:
|
32
|
+
:name: Kindle
|
33
|
+
:regex: kindle
|
34
|
+
:mobile: true
|
35
|
+
|
36
|
+
:ipod:
|
37
|
+
:name: iPod
|
38
|
+
:family_sym: :ios
|
39
|
+
:regex: \(ipod;
|
40
|
+
:mobile: true
|
41
|
+
|
42
|
+
:iphone:
|
43
|
+
:name: iPhone
|
44
|
+
:family_sym: :ios
|
45
|
+
:regex: \(iphone;
|
46
|
+
:mobile: true
|
47
|
+
|
48
|
+
:ipad:
|
49
|
+
:name: iPad
|
50
|
+
:family_sym: :ios
|
51
|
+
:regex: \(ipad;
|
52
|
+
:mobile: true
|
53
|
+
|
54
|
+
:ios:
|
55
|
+
:name: iOS
|
56
|
+
:regex: \(i\w+; .* like mac os x;
|
57
|
+
:mobile: true
|
58
|
+
|
59
|
+
:osx:
|
60
|
+
:name: OS X
|
36
61
|
:regex: macintosh
|
37
62
|
|
38
|
-
|
39
|
-
:
|
40
|
-
:family_sym: :linux
|
63
|
+
:android:
|
64
|
+
:name: Android
|
41
65
|
:regex: android
|
66
|
+
:mobile: true
|
42
67
|
|
43
|
-
|
44
|
-
:
|
68
|
+
:ubuntu:
|
69
|
+
:name: Ubuntu
|
45
70
|
:family_sym: :linux
|
46
71
|
:regex: ubuntu
|
47
72
|
|
48
|
-
|
49
|
-
:
|
73
|
+
:fedora:
|
74
|
+
:name: Fedora
|
50
75
|
:family_sym: :linux
|
51
76
|
:regex: fedora
|
52
77
|
|
53
|
-
|
54
|
-
:
|
78
|
+
:slackware:
|
79
|
+
:name: Slackware
|
55
80
|
:family_sym: :linux
|
56
81
|
:regex: slackware
|
57
82
|
|
58
|
-
|
59
|
-
:
|
83
|
+
:linux:
|
84
|
+
:name: GNU/Linux
|
60
85
|
:regex: linux
|
61
86
|
|
62
|
-
|
63
|
-
:
|
87
|
+
:freebsd:
|
88
|
+
:name: FreeBSD
|
64
89
|
:regex: freebsd
|
65
90
|
|
66
|
-
|
67
|
-
:
|
91
|
+
:blackberry:
|
92
|
+
:name: BlackBerry
|
68
93
|
:regex: blackberry
|
94
|
+
:mobile: true
|
69
95
|
|
70
|
-
|
71
|
-
:
|
96
|
+
:unknown:
|
97
|
+
:name: Unknown
|
72
98
|
:regex: .*
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# A browser user agent string parser. Use DoubleAgent.parse(user_agent) to return a DoubleAgent::UserAgent object, which you can
|
2
|
+
# query with methods like "browser_name" or "os". The DoubleAgent module itself responds to those same method - just
|
3
|
+
# pass the user agent string as an argument.
|
4
|
+
module DoubleAgent
|
5
|
+
# A hash of browser data, the basis for browser parsing. You may edit this data and call load_browsers! to customize parsing.
|
6
|
+
BROWSER_DATA = Psych.load_file(File.expand_path('../../../data/browsers.yml', __FILE__))
|
7
|
+
|
8
|
+
# A hash of OS hashes, the basis for OS parsing. You may edit this data and call load_oses! to customize parsing.
|
9
|
+
OS_DATA = Psych.load_file(File.expand_path('../../../data/oses.yml', __FILE__))
|
10
|
+
|
11
|
+
BROWSER_PARSERS, OS_PARSERS = {}, {} # :nodoc:
|
12
|
+
|
13
|
+
# Returns a new UserAgent object
|
14
|
+
def self.parse(user_agent_string)
|
15
|
+
UserAgent.new(user_agent_string)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Forwards calls to a UserAgent object
|
19
|
+
def self.method_missing(method, *args, &block)
|
20
|
+
parse(args.first).send(method)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Transforms BROWSER_DATA into a case statement inside of the _browser_sym method
|
24
|
+
def self.load_browsers!
|
25
|
+
BROWSER_PARSERS.clear.merge! Hash[BROWSER_DATA.map { |sym, data| [sym, BrowserParser.new(sym, data)] }]
|
26
|
+
|
27
|
+
module_eval <<-CODEZ
|
28
|
+
def self._browser_sym(user_agent)
|
29
|
+
case user_agent.to_s
|
30
|
+
#{BROWSER_DATA.map { |sym, data| "when %r{#{data[:regex]}}i then :\"#{sym}\"" }.join("\n")}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
CODEZ
|
34
|
+
end
|
35
|
+
|
36
|
+
# Transforms OS_DATA into a case statement inside of the _os_sym method
|
37
|
+
def self.load_oses!
|
38
|
+
OS_PARSERS.clear.merge! Hash[OS_DATA.map { |sym, data| [sym, OSParser.new(sym, data)] }]
|
39
|
+
|
40
|
+
module_eval <<-CODEZ
|
41
|
+
def self._os_sym(user_agent)
|
42
|
+
case user_agent.to_s
|
43
|
+
#{OS_DATA.map { |sym, data| "when %r{#{data[:regex]}}i then :\"#{sym}\"" }.join("\n")}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
CODEZ
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# Returns the correct BrowerParser for the given user agent or symbol
|
52
|
+
def self.browser_parser(ua_or_sym)
|
53
|
+
BROWSER_PARSERS[ua_or_sym.is_a?(Symbol) ? ua_or_sym : _browser_sym(ua_or_sym)]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the correct OSParser for the given user agent or symbol
|
57
|
+
def self.os_parser(ua_or_sym)
|
58
|
+
OS_PARSERS[ua_or_sym.is_a?(Symbol) ? ua_or_sym : _os_sym(ua_or_sym)]
|
59
|
+
end
|
60
|
+
end
|
data/lib/double_agent/parser.rb
CHANGED
@@ -1,192 +1,72 @@
|
|
1
|
-
begin
|
2
|
-
require 'psych'
|
3
|
-
rescue LoadError
|
4
|
-
end
|
5
|
-
require 'yaml'
|
6
|
-
|
7
1
|
module DoubleAgent
|
8
|
-
# An array of "browser knowledge hashes," the basis of browser parsing. You may edit this data and call load_browsers! to customize parsing.
|
9
|
-
BROWSER_DATA = YAML.load_file(File.expand_path('../../../data/browsers.yml', __FILE__))
|
10
|
-
|
11
|
-
# An array of "OS knowledge hashes," the basis of OS parsing. You may edit this data and call load_oses! to customize parsing.
|
12
|
-
OS_DATA = YAML.load_file(File.expand_path('../../../data/oses.yml', __FILE__))
|
13
|
-
|
14
|
-
# An array of BrowserParser objects created from the data in BROWSER_DATA.
|
15
|
-
BROWSERS = {}
|
16
|
-
|
17
|
-
# An array of OSParser objects created from the data in OS_DATA.
|
18
|
-
OSES = {}
|
19
|
-
|
20
2
|
# Each browser in BROWSER_DATA gets its own BrowserParser object. These
|
21
3
|
# parser objects are then used to parse specific data out of a user agent string.
|
22
|
-
|
23
4
|
class BrowserParser
|
24
|
-
|
25
|
-
|
26
|
-
|
5
|
+
# The browser name
|
6
|
+
attr_reader :name
|
7
|
+
# The browser name as a symbol
|
8
|
+
attr_reader :sym
|
9
|
+
# The browser family name as a symbol
|
10
|
+
attr_reader :family_sym
|
27
11
|
|
28
12
|
# Instantiate a new BrowserParser using a "browser family" element from BROWSER_DATA
|
29
|
-
def initialize(attrs={})
|
30
|
-
@sym =
|
13
|
+
def initialize(sym, attrs={})
|
14
|
+
@sym = sym
|
31
15
|
@family_sym = attrs[:family_sym] || @sym
|
32
16
|
@name = attrs[:name]
|
33
|
-
|
34
|
-
|
35
|
-
@safe_version = attrs[:safe_version].map { |r| Regexp.new r, Regexp::IGNORECASE }
|
36
|
-
elsif attrs[:version]
|
37
|
-
@version = Regexp.new(attrs[:version], Regexp::IGNORECASE)
|
17
|
+
if attrs[:version]
|
18
|
+
@version_pattern = Regexp.new(attrs[:version], Regexp::IGNORECASE)
|
38
19
|
end
|
39
20
|
end
|
40
21
|
|
41
22
|
# Returns the browser's name. If you provide a user agent string as an argument,
|
42
23
|
# it will attempt to also return the major version number. E.g. "Firefox 4".
|
43
24
|
def browser(ua=nil)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
25
|
+
(ua and @version_pattern) ? "#{name} #{version(ua)}" : name
|
26
|
+
end
|
27
|
+
|
28
|
+
# Attempts to parse and return the browser's version from a user agent string. Returns
|
29
|
+
# nil if nothing is found.
|
30
|
+
def version(ua)
|
31
|
+
ua.slice(@version_pattern)
|
49
32
|
end
|
50
33
|
|
51
34
|
# Returns the BrowserParser for this BrowserParser object's Family. E.g. the Chrome
|
52
35
|
# BrowserParser would return the Chromium BrowserParser. For browsers that are their
|
53
36
|
# own family (e.g. Firefox, IE) it will end up returning itself.
|
54
37
|
def family
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
# Attempts to parse and return the browser's version from a user agent string. Returns
|
61
|
-
# nil if nothing is found.
|
62
|
-
def version(ua)
|
63
|
-
if @safe_version
|
64
|
-
ua.slice(@safe_version[0]).slice(@safe_version[1]) rescue nil
|
65
|
-
else
|
66
|
-
ua.slice(@version)
|
67
|
-
end
|
38
|
+
BROWSER_PARSERS[family_sym]
|
68
39
|
end
|
69
40
|
end
|
70
41
|
|
71
|
-
# Each OS in OS_DATA gets its own
|
72
|
-
# objects
|
73
|
-
# that is not currently happening.
|
74
|
-
|
42
|
+
# Each OS in OS_DATA gets its own BrowserParser object. These
|
43
|
+
# parser objects are then used to parse specific data out of a user agent string.
|
75
44
|
class OSParser
|
76
|
-
|
45
|
+
# The operating system name
|
46
|
+
attr_reader :os
|
47
|
+
# The operating system name as a symbol
|
48
|
+
attr_reader :sym
|
49
|
+
# The operating system family name as a symbol
|
50
|
+
attr_reader :family_sym
|
77
51
|
|
78
52
|
# Instantiate a new OSParser using an "OS family" element from OS_DATA
|
79
|
-
def initialize(attrs={})
|
80
|
-
@sym =
|
53
|
+
def initialize(sym, attrs={})
|
54
|
+
@sym = sym
|
81
55
|
@family_sym = attrs[:family_sym] || @sym
|
82
56
|
@os = attrs[:name]
|
83
|
-
@
|
57
|
+
@mobile = attrs[:mobile] || false
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returs true if this is mobile OS, false if not
|
61
|
+
def mobile?
|
62
|
+
@mobile
|
84
63
|
end
|
85
64
|
|
86
65
|
# Returns the OSParser for this OSParser object's Family. E.g. the Ubuntu
|
87
66
|
# OSParser would return the GNU/Linux OSerParser. For OSes that are their own
|
88
67
|
# family (e.g. OS X) it will end up returning itself.
|
89
68
|
def family
|
90
|
-
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# Returns the browser's name, possibly including the version number, e.g. "Chrome 12"
|
95
|
-
def self.browser(ua)
|
96
|
-
browser_parser(ua).browser(ua)
|
97
|
-
end
|
98
|
-
|
99
|
-
# Returns the browser's symbol name, e.g. :chrome
|
100
|
-
def self.browser_sym(user_agent)
|
101
|
-
# This method is overwitten by load_browsers!
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns the browser's icon name, e.g. :chrome
|
105
|
-
def self.browser_icon(ua)
|
106
|
-
browser_parser(ua).icon
|
107
|
-
end
|
108
|
-
|
109
|
-
# Returns the browser's family name, e.g. "Chromium"
|
110
|
-
def self.browser_family(ua)
|
111
|
-
browser_parser(ua).family.browser
|
112
|
-
end
|
113
|
-
|
114
|
-
# Returns the browser's family's symbol name, e.g. :chromium
|
115
|
-
def self.browser_family_sym(ua)
|
116
|
-
browser_parser(ua).family_sym
|
117
|
-
end
|
118
|
-
|
119
|
-
# Returns the browser's family's icon name, e.g. :chromium
|
120
|
-
def self.browser_family_icon(ua)
|
121
|
-
browser_parser(ua).family.icon
|
122
|
-
end
|
123
|
-
|
124
|
-
# Returns the OS's name, e.g. "Ubuntu"
|
125
|
-
def self.os(ua)
|
126
|
-
os_parser(ua).os
|
127
|
-
end
|
128
|
-
|
129
|
-
# Returns the OS's symbol name, e.g. :ubuntu
|
130
|
-
def self.os_sym(user_agent)
|
131
|
-
# This method is overwitten by load_oses!
|
132
|
-
end
|
133
|
-
|
134
|
-
# Returns the OS's icon name, e.g. :ubuntu
|
135
|
-
def self.os_icon(ua)
|
136
|
-
os_parser(ua).icon
|
137
|
-
end
|
138
|
-
|
139
|
-
# Returns the OS's family, e.g. "GNU/Linux"
|
140
|
-
def self.os_family(ua)
|
141
|
-
os_parser(ua).family.os
|
142
|
-
end
|
143
|
-
|
144
|
-
# Returns the OS's family's symbol name, e.g. :linux
|
145
|
-
def self.os_family_sym(ua)
|
146
|
-
os_parser(ua).family_sym
|
147
|
-
end
|
148
|
-
|
149
|
-
# Returns the OS's family's symbol icon, e.g. :linux
|
150
|
-
def self.os_family_icon(ua)
|
151
|
-
os_parser(ua).family.icon
|
152
|
-
end
|
153
|
-
|
154
|
-
# Returns the correct BrowerParser for the given user agent or symbol
|
155
|
-
def self.browser_parser(ua_or_sym)
|
156
|
-
BROWSERS[ua_or_sym.is_a?(Symbol) ? ua_or_sym : browser_sym(ua_or_sym)]
|
157
|
-
end
|
158
|
-
|
159
|
-
# Returns the correct OSParser for the given user agent or symbol
|
160
|
-
def self.os_parser(ua_or_sym)
|
161
|
-
OSES[ua_or_sym.is_a?(Symbol) ? ua_or_sym : os_sym(ua_or_sym)]
|
162
|
-
end
|
163
|
-
|
164
|
-
# Parses BROWSER_DATA into BROWSERS, a hash of BrowserParser objects indexed by their symbol names.
|
165
|
-
# Parses and evals BROWSER_DATA into a case statement inside of the browser_sym method.
|
166
|
-
def self.load_browsers!
|
167
|
-
BROWSERS.clear
|
168
|
-
str = "case user_agent.to_s\n"
|
169
|
-
BROWSER_DATA.each do |data|
|
170
|
-
BROWSERS[data[:sym]] = BrowserParser.new(data)
|
171
|
-
str << " when %r{#{data[:regex]}}i then :#{data[:sym]}\n"
|
69
|
+
OS_PARSERS[family_sym]
|
172
70
|
end
|
173
|
-
str << 'end'
|
174
|
-
module_eval "def self.browser_sym(user_agent); #{str}; end"
|
175
|
-
end
|
176
|
-
|
177
|
-
# Parses OS_DATA into OSES, a hash of OSParser objects indexed by their symbol names.
|
178
|
-
# Parses and evals OS_DATA into a case statement inside of the os_sym method.
|
179
|
-
def self.load_oses!
|
180
|
-
OSES.clear
|
181
|
-
str = "case user_agent.to_s\n"
|
182
|
-
OS_DATA.each do |data|
|
183
|
-
OSES[data[:sym]] = OSParser.new(data)
|
184
|
-
str << " when %r{#{data[:regex]}}i then :#{data[:sym]}\n"
|
185
|
-
end
|
186
|
-
str << 'end'
|
187
|
-
module_eval "def self.os_sym(user_agent); #{str}; end"
|
188
71
|
end
|
189
72
|
end
|
190
|
-
|
191
|
-
DoubleAgent.load_browsers!
|
192
|
-
DoubleAgent.load_oses!
|