useragent_parser 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: