double_agent 0.2.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
- == Installation
6
+ *NOTE* Support for Ruby 1.8 was dropped after version 0.2.3.
7
7
 
8
- gem install double_agent
8
+ == Installation
9
9
 
10
- == Loading
10
+ [sudo] gem install double_agent
11
+ # Or add "double_agent" to your Gemfile
11
12
 
12
- Double Agent is broken up into modules - Parser, Resources, Stats and Logs.
13
+ Read the full documentation at http://jordanhollinger.com/docs/double_agent/
13
14
 
14
- # Load the core modules (Parser, Resources)
15
- require 'double_agent'
15
+ == Parser
16
16
 
17
- # Load modules individually
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
- = Parser
19
+ user_agent.browser
20
+ => "Chrome 18"
21
21
 
22
- ua_string = "I'm a user agent string for Chrome 11 on Ubuntu"
22
+ user_agent.browser_name
23
+ => "Chrome"
23
24
 
24
- DoubleAgent.browser(ua_string)
25
- => "Chrome 11"
25
+ user_agent.browser_version
26
+ => "18"
26
27
 
27
- DoubleAgent.browser_family(ua_string)
28
+ user_agent.browser_family
28
29
  => "Chromium"
29
30
 
30
- DoubleAgent.os(ua_string)
31
+ user_agent.os
31
32
  => "Ubuntu"
32
33
 
33
- DoubleAgent.os_family(ua_string)
34
+ user_agent.os_family
34
35
  => "GNU/Linux"
35
36
 
36
- See the DoubleAgent module for more.
37
+ user_agent.mobile?
38
+ => false
39
+
40
+ # Or
37
41
 
38
- = Resources
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
- DoubleAgent::Resource is a mix-in for objects with a user_agent method or attribute.
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
- = Stats
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
- DoubleAgent::Logs::entries parses through Apache and Nginx access logs, instantiating each log line into a DoubleAgent::Logs::Entry
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
- entries = DoubleAgent::Logs.entries("/var/log/nginx/my-site.access.log*")
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
- p stats
89
- => [["Firefox 4", 20.0, 650], ["Internet Explorer 8", 18.0, 587], ...]
74
+ == License
75
+ Copyright 2011 Jordan Hollinger
90
76
 
91
- Check out the DoubleAgent::Logs::Entry class for more methods besides user_agent.
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
- - :name: Internet Explorer %s
5
- :sym: :msie
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
- - :name: Chrome %s
11
- :sym: :chrome
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
- - :name: Chromium %s
18
- :sym: :chromium
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
- - :name: Opera %s
24
- :sym: :opera
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
- - :name: Firefox %s
30
- :sym: :firefox
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
- - :name: Android %s
36
- :sym: :android
37
- :family_sym: :chromium
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
- - :name: BlackBerry
43
- :sym: :blackberry
54
+ :blackberry:
55
+ :name: BlackBerry
44
56
  :regex: blackberry
45
57
 
46
- - :name: Epiphany
47
- :sym: :epiphany
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
- - :name: Konqueror
59
- :sym: :konqueror
63
+ :konqueror:
64
+ :name: Konqueror
60
65
  :regex: konqueror
61
66
 
62
- - :name: Unknown
63
- :sym: :unknown
67
+ :unknown:
68
+ :name: Unknown
64
69
  :regex: .*
65
- :version: .*
data/data/oses.yml CHANGED
@@ -1,72 +1,98 @@
1
- - :name: Windows 8
2
- :sym: :windows_8
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
- - :name: Windows 7
8
- :sym: :windows_7
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
- - :name: Windows Vista
14
- :sym: :windows_vista
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
- - :name: Windows XP
20
- :sym: :windows_xp
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
- - :name: Windows
26
- :sym: :windows
21
+ :windows:
22
+ :name: Windows
27
23
  :regex: windows
28
24
 
29
- - :name: iOS
30
- :sym: :ios
31
- :family_sym: :osx
32
- :regex: (iphone)|(ipad)
25
+ :kindle_fire:
26
+ :name: Kindle Fire
27
+ :family_sym: :kindle
28
+ :regex: (kindle fire)|(silk-accelerated)
29
+ :mobile: true
33
30
 
34
- - :name: OS X
35
- :sym: :osx
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
- - :name: Android
39
- :sym: :android
40
- :family_sym: :linux
63
+ :android:
64
+ :name: Android
41
65
  :regex: android
66
+ :mobile: true
42
67
 
43
- - :name: Ubuntu
44
- :sym: :ubuntu
68
+ :ubuntu:
69
+ :name: Ubuntu
45
70
  :family_sym: :linux
46
71
  :regex: ubuntu
47
72
 
48
- - :name: Fedora
49
- :sym: :fedora
73
+ :fedora:
74
+ :name: Fedora
50
75
  :family_sym: :linux
51
76
  :regex: fedora
52
77
 
53
- - :name: Slackware
54
- :sym: :slackware
78
+ :slackware:
79
+ :name: Slackware
55
80
  :family_sym: :linux
56
81
  :regex: slackware
57
82
 
58
- - :name: GNU/Linux
59
- :sym: :linux
83
+ :linux:
84
+ :name: GNU/Linux
60
85
  :regex: linux
61
86
 
62
- - :name: FreeBSD
63
- :sym: :freebsd
87
+ :freebsd:
88
+ :name: FreeBSD
64
89
  :regex: freebsd
65
90
 
66
- - :name: BlackBerry
67
- :sym: :blackberry
91
+ :blackberry:
92
+ :name: BlackBerry
68
93
  :regex: blackberry
94
+ :mobile: true
69
95
 
70
- - :name: Unknown
71
- :sym: :unknown
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
@@ -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
- BLANK = ''
25
- MIN_VERSION = '1.9.2'
26
- attr_reader :sym, :family_sym, :icon
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 = attrs[:sym]
13
+ def initialize(sym, attrs={})
14
+ @sym = sym
31
15
  @family_sym = attrs[:family_sym] || @sym
32
16
  @name = attrs[:name]
33
- @icon = attrs[:icon] || @sym
34
- if RUBY_VERSION < MIN_VERSION and attrs[:safe_version]
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
- if ua and (@version or @safe_version)
45
- @name % version(ua)
46
- else
47
- (@name % BLANK).rstrip
48
- end
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
- BROWSERS[@family_sym]
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 OSParser object. In theory, these parser
72
- # objects can then be used to grab further info from user agent strings, though
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
- attr_reader :os, :sym, :family_sym, :icon
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 = attrs[:sym]
53
+ def initialize(sym, attrs={})
54
+ @sym = sym
81
55
  @family_sym = attrs[:family_sym] || @sym
82
56
  @os = attrs[:name]
83
- @icon = attrs[:icon] || @sym
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
- OSES[@family_sym]
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!