useragent_parser 0.0.4 → 0.1.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,38 @@
1
+ # encoding: utf-8
2
+
3
+ module UseragentParser
4
+ class DeviceParser
5
+ attr_accessor :pattern, :user_agent_re, :device_replacement
6
+
7
+ def initialize(pattern, device_replacement = nil)
8
+ @pattern = pattern
9
+ @user_agent_re = Regexp.compile(pattern)
10
+ @device_replacement = device_replacement
11
+ end
12
+
13
+ def match_spans(user_agent_string)
14
+ match_spans = []
15
+ match = @user_agent_re.match(user_agent_string)
16
+ if match
17
+ # Return the offsets
18
+ end
19
+ end
20
+
21
+ def parse(user_agent_string)
22
+ device = nil
23
+ match = @user_agent_re.match(user_agent_string)
24
+ if match
25
+ if @device_replacement
26
+ if %r'\$1'.match @device_replacement
27
+ device = @device_replacement.gsub(%r'\$1', match[1])
28
+ else
29
+ device = @device_replacement
30
+ end
31
+ else
32
+ device = match[1]
33
+ end
34
+ end
35
+ return device
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ module UseragentParser
4
+ class OSParser
5
+ attr_accessor :pattern, :user_agent_re, :family_replacement, :major_replacement
6
+
7
+ def initialize(pattern, os_replacement = nil)
8
+ @pattern = pattern
9
+ @user_agent_re = Regexp.compile(pattern)
10
+ @os_replacement = os_replacement
11
+ end
12
+
13
+ def match_spans(user_agent_string)
14
+ match_spans = []
15
+ match = @user_agent_re.match(user_agent_string)
16
+ if match
17
+ # Return the offsets
18
+ end
19
+ end
20
+
21
+ def parse(user_agent_string)
22
+ os, os_v1, os_v2, os_v3, os_v4 = nil, nil, nil, nil, nil
23
+ match = @user_agent_re.match(user_agent_string)
24
+ if match
25
+ if @os_replacement
26
+ os = @os_replacement
27
+ else
28
+ os = match[1]
29
+ end
30
+
31
+ os_v1 = match[2] if match.size >= 3
32
+ os_v2 = match[3] if match.size >= 4
33
+ os_v3 = match[4] if match.size >= 5
34
+ os_v4 = match[5] if match.size >= 6
35
+ end
36
+ return os, os_v1, os_v2, os_v3, os_v4
37
+ end
38
+ end
39
+ end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module UseragentParser
4
- class Parser
4
+ class UserAgentParser
5
5
  attr_accessor :pattern, :user_agent_re, :family_replacement, :v1_replacement
6
6
 
7
7
  def initialize(pattern, family_replacement = nil, v1_replacement = nil)
@@ -38,12 +38,8 @@ module UseragentParser
38
38
  v1 = match[2]
39
39
  end
40
40
 
41
- if match.size >= 4
42
- v2 = match[3]
43
- if match.size >= 5
44
- v3 = match[4]
45
- end
46
- end
41
+ v2 = match[3] if match.size >= 4
42
+ v3 = match[4] if match.size >= 5
47
43
  end
48
44
  return family, v1, v2, v3
49
45
  end
@@ -4,15 +4,37 @@ module UseragentParser
4
4
  attr_reader :os, :os_family, :os_version, :os_major_version, :os_minor_version, :os_patch_version
5
5
 
6
6
  def initialize(details = {})
7
- @browser_family = details['family'] || 'Other'
8
- @browser_major_version = details['v1']
9
- @browser_minor_version = details['v2']
10
- @browser_patch_version = details['v3']
11
-
12
- @os_family = details['os_family'] || 'Other'
13
- @os_major_version = details['os_v1']
14
- @os_minor_version = details['os_v2']
15
- @os_patch_version = details['os_v3']
7
+ if user_agent = details['user_agent']
8
+ @browser_family = user_agent['family'] || 'Other'
9
+ @browser_major_version = user_agent['major']
10
+ @browser_minor_version = user_agent['minor']
11
+ @browser_patch_version = user_agent['patch']
12
+ end
13
+
14
+ if os = details['os']
15
+ @os_family = os['family'] || 'Other'
16
+ @os_major_version = os['major']
17
+ @os_minor_version = os['minor']
18
+ @os_patch_version = os['patch']
19
+ end
20
+
21
+ if device = details['device']
22
+ @device = device['family']
23
+ @is_mobile = device['is_mobile']
24
+ @is_spider = device['is_spider']
25
+ end
26
+ end
27
+
28
+ def device
29
+ @device
30
+ end
31
+
32
+ def is_mobile?
33
+ !!@is_mobile
34
+ end
35
+
36
+ def is_spider?
37
+ !!@is_spider
16
38
  end
17
39
 
18
40
  def browser_version
@@ -1,3 +1,3 @@
1
1
  module UseragentParser
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,45 +1,56 @@
1
1
  require "useragent_parser/version"
2
- require "useragent_parser/parser"
2
+ require "useragent_parser/parsers/user_agent_parser"
3
+ require "useragent_parser/parsers/os_parser"
4
+ require "useragent_parser/parsers/device_parser"
3
5
  require "useragent_parser/user_agent"
4
6
 
5
7
  module UseragentParser
6
8
  USER_AGENT_PARSERS = []
7
9
  OS_PARSERS = []
10
+ DEVICE_PARSERS = []
11
+ MOBILE_USER_AGENT_FAMILIES = []
12
+ MOBILE_OS_FAMILIES = []
8
13
 
9
- def UseragentParser.load_parsers!
10
- YAML.load_file(File.expand_path(File.dirname(__FILE__)) + "/../config/user_agent_parser.yaml")['user_agent_parsers'].each do |parser|
14
+ def self.load_parsers!
15
+ yaml = YAML.load_file(File.expand_path(File.dirname(__FILE__)) + "/../config/regexes.yaml")
16
+ yaml['user_agent_parsers'].each do |parser|
11
17
  regex = parser['regex']
12
- family_replacement, v1_replacement = nil, nil
13
- if parser.has_key?('family_replacement')
14
- family_replacement = parser['family_replacement']
15
- end
16
-
17
- if parser.has_key?('v1_replacement')
18
- v1_replacement = parser['v1_replacement']
19
- end
18
+ family_replacement = parser.fetch('family_replacement', nil)
19
+ v1_replacement = parser.fetch('v1_replacement', nil)
20
20
 
21
- USER_AGENT_PARSERS.push UseragentParser::Parser.new(regex, family_replacement, v1_replacement)
21
+ USER_AGENT_PARSERS.push UseragentParser::UserAgentParser.new(regex, family_replacement, v1_replacement)
22
22
  end
23
23
 
24
- YAML.load_file(File.expand_path(File.dirname(__FILE__)) + "/../config/user_agent_parser.yaml")['os_parsers'].each do |parser|
24
+ yaml['os_parsers'].each do |parser|
25
25
  regex = parser['regex']
26
- family_replacement, v1_replacement, code_name = nil, nil, nil
27
- if parser.has_key?('family_replacement')
28
- family_replacement = parser['family_replacement']
29
- end
26
+ os_replacement = parser.fetch('os_replacement', nil)
30
27
 
31
- if parser.has_key?('v1_replacement')
32
- v1_replacement = parser['v1_replacement']
33
- end
28
+ OS_PARSERS.push UseragentParser::OSParser.new(regex, os_replacement)
29
+ end
34
30
 
35
- OS_PARSERS.push UseragentParser::Parser.new(regex, family_replacement, v1_replacement)
31
+ yaml['device_parsers'].each do |parser|
32
+ regex = parser['regex']
33
+ device_replacement = parser.fetch('device_replacement', nil)
34
+
35
+ DEVICE_PARSERS.push UseragentParser::DeviceParser.new(regex, device_replacement)
36
36
  end
37
+
38
+ MOBILE_USER_AGENT_FAMILIES.push *yaml['mobile_user_agent_families']
39
+ MOBILE_OS_FAMILIES.push *yaml['mobile_os_families']
37
40
  end
38
41
 
39
- def UseragentParser.parse(user_agent_string, js_user_agent_string = nil, js_user_agent_family = nil, js_user_agent_v1 = nil, js_user_agent_v2 = nil, js_user_agent_v3 = nil)
40
- family, v1, v2, v3 = nil, nil, nil, nil
41
- os_family, os_v1, os_v2, os_v3 = nil, nil, nil, nil
42
+ def self.parse_all(user_agent_string, *js_args)
43
+ # UseragentParser::UserAgent.new{
44
+ {
45
+ 'user_agent' => self.parse_user_agent(user_agent_string, *js_args),
46
+ 'os' => self.parse_os(user_agent_string, *js_args),
47
+ 'device' => self.parse_device(user_agent_string, *js_args),
48
+ 'string' => user_agent_string
49
+ }
50
+ end
42
51
 
52
+ def self.parse_user_agent(user_agent_string, js_user_agent_string = nil, js_user_agent_family = nil, js_user_agent_v1 = nil, js_user_agent_v2 = nil, js_user_agent_v3 = nil)
53
+ family, v1, v2, v3 = nil
43
54
  # Override via JS properties.
44
55
  if js_user_agent_family.nil?
45
56
  USER_AGENT_PARSERS.each do |parser|
@@ -56,16 +67,46 @@ module UseragentParser
56
67
  # Override for Chrome Frame IFF Chrome is enabled.
57
68
  if js_user_agent_string && js_user_agent_string.include?('Chrome/') && user_agent_string.include?('chromeframe')
58
69
  family = 'Chrome Frame (%s %s)' % [ family, v1 ]
59
- js_ua = UseragentParser.parse(js_user_agent_string)
60
- cf_family, v1, v2, v3 = js_ua.browser_family, js_ua.browser_major_version, js_ua.browser_minor_version, js_ua.browser_patch_version
70
+ js_ua = self.parse_user_agent(js_user_agent_string)
71
+ cf_family, v1, v2, v3 = js_ua['family'], js_ua['major'], js_ua['minor'], js_ua['patch']
61
72
  end
62
73
 
74
+ family ||= 'Other'
75
+ { 'family' => family, 'major' => v1, 'minor' => v2, 'patch' => v3 }
76
+ end
77
+
78
+ def self.parse_os(user_agent_string, js_user_agent_string = nil, js_user_agent_family = nil, js_user_agent_v1 = nil, js_user_agent_v2 = nil, js_user_agent_v3 = nil)
79
+ os, os_v1, os_v2, os_v3, os_v4 = nil, nil, nil, nil, nil
63
80
  OS_PARSERS.each do |parser|
64
- os_family, os_v1, os_v2, os_v3 = parser.parse(user_agent_string)
65
- break unless os_family.nil?
81
+ os, os_v1, os_v2, os_v3, os_v4 = parser.parse(user_agent_string)
82
+ break unless os.nil?
83
+ end
84
+
85
+ os ||= 'Other'
86
+ { 'family' => os, 'major' => os_v1, 'minor' => os_v2, 'patch' => os_v3, 'patch_minor' => os_v4 }
87
+ end
88
+
89
+ def self.parse_device(user_agent_string, ua_family = nil, os_family = nil)
90
+ device = nil
91
+ DEVICE_PARSERS.each do |parser|
92
+ device = parser.parse(user_agent_string)
93
+ break unless device.nil?
94
+ end
95
+
96
+ os_family = device || 'Other'
97
+
98
+ ua_family = self.parse_user_agent(user_agent_string)['family'] if ua_family.nil?
99
+ os_family = self.parse_os(user_agent_string)['family'] if os_family.nil?
100
+
101
+ if MOBILE_USER_AGENT_FAMILIES.include?(ua_family)
102
+ is_mobile = true
103
+ elsif MOBILE_OS_FAMILIES.include?(os_family)
104
+ is_mobile = true
105
+ else
106
+ is_mobile = false
66
107
  end
67
108
 
68
- UseragentParser::UserAgent.new({ 'family' => family, 'v1' => v1, 'v2' => v2, 'v3' => v3, 'os_family' => os_family, 'os_v1' => os_v1, 'os_v2' => os_v2, 'os_v3' => os_v3 })
109
+ { 'family' => device, 'is_mobile' => is_mobile, 'is_spider' => (device == 'Spider') }
69
110
  end
70
111
  end
71
112
 
@@ -0,0 +1,134 @@
1
+ test_cases:
2
+
3
+ - user_agent_string: 'Mozilla/5.0 (Linux; U; Android 2.1-update1; en-us; Nexus One Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17,gzip(gfe),gzip(gfe)'
4
+ family: 'Android'
5
+ major: '2'
6
+ minor: '1'
7
+ patch: 'update1'
8
+ patch_minor:
9
+
10
+ - user_agent_string: 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X Mach-O; en-en; rv:1.9.0.12) Gecko/2009070609 Firefox/3.0.12,gzip(gfe),gzip(gfe)'
11
+ family: 'Mac OS X'
12
+ major:
13
+ minor:
14
+ patch:
15
+ patch_minor:
16
+
17
+ - user_agent_string: 'Opera/9.80 (iPhone; Opera Mini/5.0.019802/21.572; U; en) Presto/2.5.25 Version/10.54'
18
+ family: 'iOS'
19
+ major:
20
+ minor:
21
+ patch:
22
+ patch_minor:
23
+
24
+ - user_agent_string: 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 NokiaN95/12.0.013; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413'
25
+ family: 'Symbian OS'
26
+ major: '9'
27
+ minor: '2'
28
+ patch:
29
+ patch_minor:
30
+
31
+ - user_agent_string: 'Opera/9.80 (S60; SymbOS; Opera Mobi/499; U; de) Presto/2.4.18 Version/10.00,gzip(gfe),gzip(gfe)'
32
+ family: 'Symbian OS'
33
+ major:
34
+ minor:
35
+ patch:
36
+ patch_minor:
37
+
38
+ - user_agent_string: 'Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaN8-00/010.022; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 BrowserNG/7.2.6.3 3gpp-gba,gzip(gfe),gzip(gfe)'
39
+ family: 'Symbian^3'
40
+ major:
41
+ minor:
42
+ patch:
43
+ patch_minor:
44
+
45
+ - user_agent_string: 'BlackBerry9000/4.6.0.167 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/102'
46
+ family: 'BlackBerry OS'
47
+ major: '4'
48
+ minor: '6'
49
+ patch: '0'
50
+ patch_minor: '167'
51
+
52
+ - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.8) Gecko/20100723 Linux Mint/9 (Isadora) Firefox/3.6.8'
53
+ family: 'Linux Mint'
54
+ major: '9'
55
+ minor:
56
+ patch:
57
+ patch_minor:
58
+
59
+ - user_agent_string: 'Mozilla/5.0 (X11; CrOS i686 13.587.80) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.99 Safari/535.1'
60
+ family: 'Chrome OS'
61
+ major: '13'
62
+ minor: '587'
63
+ patch: '80'
64
+ patch_minor:
65
+
66
+ - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008072310 Red Hat/3.0.1-3.el4 Firefox/3.0.1,gzip(gfe),gzip(gfe)'
67
+ family: 'Red Hat'
68
+ major: '3'
69
+ minor: '0'
70
+ patch: '1'
71
+ patch_minor:
72
+
73
+ - user_agent_string: 'Mozilla/5.0 ( U; Linux x86_32; en-US; rv:1.0) Gecko/20090723 Puppy/3.6.8-0.1.1 Firefox/3.6.7,gzip(gfe),gzip(gfe)'
74
+ family: 'Puppy'
75
+ major: '3'
76
+ minor: '6'
77
+ patch: '8'
78
+ patch_minor:
79
+
80
+ - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110301 PCLinuxOS/1.9.2.14-1pclos2011 (2011) Firefox/3.6.14,gzip(gfe),gzip(gfe),gzip(gfe)'
81
+ family: 'PCLinuxOS'
82
+ major: '1'
83
+ minor: '9'
84
+ patch: '2'
85
+ patch_minor: '14'
86
+
87
+ - user_agent_string: 'Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.0.4) Gecko/2008111217 Fedora/3.0.4-1.fc9 Firefox/3.0.4'
88
+ family: 'Fedora'
89
+ major: '3'
90
+ minor: '0'
91
+ patch: '4'
92
+ patch_minor:
93
+
94
+ - user_agent_string: 'Mozilla/5.0 (X11; 78; CentOS; US-en) AppleWebKit/527+ (KHTML, like Gecko) Bolt/0.862 Version/3.0 Safari/523.15'
95
+ family: 'CentOS'
96
+ major:
97
+ minor:
98
+ patch:
99
+ patch_minor:
100
+
101
+ - user_agent_string: 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9780; en) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.526 Mobile Safari/534.8+,gzip(gfe),gzip(gfe),gzip(gfe)'
102
+ family: 'BlackBerry OS'
103
+ major: '6'
104
+ minor: '0'
105
+ patch: '0'
106
+ patch_minor: '526'
107
+
108
+ - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.2) Gecko/20090807 Mandriva Linux/1.9.1.2-1.1mud2009.1 (2009.1) Firefox/3.5.2 FirePHP/0.3,gzip(gfe),gzip(gfe)'
109
+ family: 'Mandriva'
110
+ major: '1'
111
+ minor: '9'
112
+ patch: '1'
113
+ patch_minor: '2'
114
+
115
+ - user_agent_string: 'Opera/9.80 (X11; Linux x86_64; U; Slackware; lt) Presto/2.8.131 Version/11.11'
116
+ family: 'Slackware'
117
+ major:
118
+ minor:
119
+ patch:
120
+ patch_minor:
121
+
122
+ - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917)'
123
+ family: 'Windows Phone OS'
124
+ major: '7'
125
+ minor: '5'
126
+ patch:
127
+ patch_minor:
128
+
129
+ - user_agent_string: ''
130
+ family: 'Other'
131
+ major:
132
+ minor:
133
+ patch:
134
+ patch_minor: