user_agent_parser 0.1.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of user_agent_parser might be problematic. Click here for more details.

@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZDY2ZWUzN2RkZmIzYWU2NDcwZmM2Zjk0OTUxMGE3ZDVmNTZjN2ZkNQ==
5
+ data.tar.gz: !binary |-
6
+ NWE4ODE2OTY3NjIwOGY2MWYxY2E3YmEzMjgxYWIxYzU3YTJiZGYxZQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MGJhMmVmNjMxMDk0ZWUzNDM1MDlmM2NmY2JlNDk4MTVjYzEyNjIxZGFjMDli
10
+ MWYyMzg1ZTIwZTdkNzIxNmRjZTI3NTMyNWU1YzFhNDE1ZGMxZjM5MTZjMTYw
11
+ ZGM3NWFmODMyY2NkZWRiMjkwNTcyODUwY2ZhZWM4Njg4YTk4ZDc=
12
+ data.tar.gz: !binary |-
13
+ ZWU1ZjE4YTQ1MmFiNjZlZGE0NGQzOTQ2ODQ2OGEwZmE0MTBhYWZkOGIzZjE5
14
+ ZWQwYjJjZDI1MGJmMWMyMDVlYTE4YzkxNmRhZjJlMDYyNGQ2YWEzY2IyYTE0
15
+ ZmQ4MjM4ZjlhOTA2MDQ1MGZiZGVjMmEwNjAwMjE4OTIxN2Q1Zjk=
data/Readme.md CHANGED
@@ -1,12 +1,10 @@
1
1
  # UserAgentParser [![Build Status](https://secure.travis-ci.org/toolmantim/user_agent_parser.png?branch=master)](http://travis-ci.org/toolmantim/user_agent_parser)
2
2
 
3
- UserAgentParser is a simple, comprehensive Ruby gem for parsing user agent strings. It uses [BrowserScope](http://www.browserscope.org/)'s parsing patterns via the most excellent [ua-parser project](https://github.com/tobie/ua-parser) by [Tobie Langel](https://github.com/tobie/).
3
+ UserAgentParser is a simple, comprehensive Ruby gem for parsing user agent strings. It uses [BrowserScope](http://www.browserscope.org/)'s [parsing patterns](https://github.com/tobie/ua-parser).
4
4
 
5
5
  ## Requirements
6
6
 
7
- * Ruby >= 1.9.2
8
-
9
- Note: Ruby 1.8.7 is not supported due to the requirement for the newer psych YAML parser. If you can get it working on 1.8.7 please send a pull request.
7
+ * Ruby >= 1.8.7
10
8
 
11
9
  ## Installation
12
10
 
@@ -19,49 +17,48 @@ $ gem install user_agent_parser
19
17
  ```ruby
20
18
  require 'user_agent_parser'
21
19
  => true
22
- ua = UserAgentParser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
20
+ user_agent = UserAgentParser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
23
21
  => #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
24
- ua.to_s
25
- => "IE 9.0 (Windows Vista)"
26
- ua.family
22
+ user_agent.to_s
23
+ => "IE 9.0"
24
+ user_agent.name
27
25
  => "IE"
28
- ua.version.to_s
26
+ user_agent.version.to_s
29
27
  => "9.0"
30
- ua.version[0]
31
- => 9
32
- ua.version[1]
33
- => 0
34
- ua.os.name
28
+ user_agent.version.major
29
+ => "9"
30
+ user_agent.version.minor
31
+ => "0"
32
+ operating_system = user_agent.os
33
+ => #<UserAgentParser::OperatingSystem Windows Vista>
34
+ operating_system.to_s
35
35
  => "Windows Vista"
36
+
37
+ # The parser database will be loaded and parsed on every call to
38
+ # UserAgentParser.parse. To avoid this, instantiate your own Parser instance.
39
+ parser = UserAgentParser::Parser.new
40
+ parser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
41
+ => #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
42
+ parser.parse 'Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.53'
43
+ => #<UserAgentParser::UserAgent Opera 10.53 (Windows XP)>
36
44
  ```
37
45
 
38
46
  ## The pattern database
39
47
 
40
48
  The [ua-parser database](https://github.com/tobie/ua-parser/blob/master/regexes.yaml) is included via a [git submodule](http://help.github.com/submodules/). To update the database the submodule needs to be updated and the gem re-released (pull requests for this are very welcome!).
41
49
 
42
- You can also specify the path to your own, updated and/or customised `regexes.yaml` file:
50
+ You can also specify the path to your own, updated and/or customised `regexes.yaml` file as a second argument to `UserAgentParser.parse`:
43
51
 
44
52
  ```ruby
45
- UserAgentParser.patterns_path = '/some/path/to/regexes.yaml'
53
+ UserAgentParser.parse(ua_string, patterns_path: '/some/path/to/regexes.yaml')
46
54
  ```
47
55
 
48
- ## Comprehensive you say?
56
+ or when instantiating a `UserAgentParser::Parser`:
49
57
 
50
- ```bash
51
- $ rake test
52
- ...
53
-
54
- Finished tests in 144.220280s, 89.0027 tests/s, 234.9739 assertions/s.
55
-
56
- 12836 tests, 33888 assertions, 0 failures, 0 errors, 0 skips
58
+ ```ruby
59
+ UserAgentParser::Parser.new(patterns_path: '/some/path/to/regexes.yaml').parse(ua_string)
57
60
  ```
58
61
 
59
- ## Limitations
60
-
61
- Chrome Frame detection is not yet included, but once [ua-parser issue #14](https://github.com/tobie/ua-parser/issues/14) is resolved this gem will be updated along with it.
62
-
63
- There's no support for providing overrides from Javascript user agent detection like there is with original BrowserScope library. The Javascript overrides were only necessary for detecting IE 9 Platform Preview and older versions of [Chrome Frame](https://developers.google.com/chrome/chrome-frame/).
64
-
65
62
  ## Contributing
66
63
 
67
64
  1. Fork
@@ -71,6 +68,12 @@ There's no support for providing overrides from Javascript user agent detection
71
68
 
72
69
  All accepted pull requests will earn you commit and release rights.
73
70
 
71
+ ## Releasing a new version
72
+
73
+ 1. Update the version in user_agent_parser.gemspec
74
+ 2. `git commit user_agent_parser.gemspec -m 'Version bump'`
75
+ 3. `rake release`
76
+
74
77
  ## License
75
78
 
76
- MIT
79
+ MIT
@@ -2,24 +2,13 @@ require 'user_agent_parser/parser'
2
2
  require 'user_agent_parser/user_agent'
3
3
  require 'user_agent_parser/version'
4
4
  require 'user_agent_parser/operating_system'
5
+ require 'user_agent_parser/device'
5
6
 
6
7
  module UserAgentParser
7
-
8
- # Path to the ua-parser regexes pattern database
9
- def self.patterns_path
10
- @patterns_path
11
- end
12
-
13
- # Sets the path to the ua-parser regexes pattern database
14
- def self.patterns_path=(path)
15
- @patterns_path = path
16
- end
17
-
18
- self.patterns_path = File.join(File.dirname(__FILE__), "../vendor/ua-parser/regexes.yaml")
8
+ DefaultPatternsPath = File.join(File.dirname(__FILE__), "../vendor/ua-parser/regexes.yaml")
19
9
 
20
10
  # Parse the given +user_agent_string+, returning a +UserAgent+
21
- def self.parse user_agent_string
22
- Parser.new.parse user_agent_string
11
+ def self.parse(user_agent_string, options={})
12
+ Parser.new(options).parse(user_agent_string)
23
13
  end
24
-
25
14
  end
@@ -0,0 +1,23 @@
1
+ module UserAgentParser
2
+ class Device
3
+ attr_reader :name
4
+
5
+ def initialize(name = nil)
6
+ @name = name || 'Other'
7
+ end
8
+
9
+ def to_s
10
+ name
11
+ end
12
+
13
+ def inspect
14
+ "#<#{self.class} #{to_s}>"
15
+ end
16
+
17
+ def eql?(other)
18
+ self.class.eql?(other.class) && name == other.name
19
+ end
20
+
21
+ alias_method :==, :eql?
22
+ end
23
+ end
@@ -1,28 +1,30 @@
1
1
  module UserAgentParser
2
-
3
2
  class OperatingSystem
4
-
5
- attr_accessor :name, :version
6
-
7
- def initialize(name="Other", version=nil)
8
- self.name = name
9
- self.version = version
3
+ attr_reader :name, :version
4
+
5
+ def initialize(name = 'Other', version = nil)
6
+ @name = name
7
+ @version = version
10
8
  end
11
-
9
+
12
10
  def to_s
13
- s = name
14
- s += " #{version}" if version
15
- s
11
+ string = name
12
+ unless version.nil?
13
+ string += " #{version}"
14
+ end
15
+ string
16
16
  end
17
-
17
+
18
18
  def inspect
19
19
  "#<#{self.class} #{to_s}>"
20
20
  end
21
-
22
- def ==(other)
23
- name == other.name && version == other.version
21
+
22
+ def eql?(other)
23
+ self.class.eql?(other.class) &&
24
+ name == other.name &&
25
+ version == other.version
24
26
  end
25
-
26
- end
27
27
 
28
- end
28
+ alias_method :==, :eql?
29
+ end
30
+ end
@@ -1,41 +1,49 @@
1
1
  require 'yaml'
2
2
 
3
3
  module UserAgentParser
4
-
4
+
5
5
  class Parser
6
+ attr_reader :patterns_path
6
7
 
7
- def parse user_agent
8
- ua = parse_ua(user_agent)
9
- ua.os = parse_os(user_agent)
10
- ua
8
+ def initialize(options={})
9
+ @patterns_path = options[:patterns_path] || UserAgentParser::DefaultPatternsPath
10
+ @ua_patterns, @os_patterns, @device_patterns = load_patterns(patterns_path)
11
11
  end
12
-
13
- private
14
12
 
15
- def all_patterns
16
- @all_patterns ||= YAML.load_file(UserAgentParser.patterns_path)
13
+ def parse(user_agent)
14
+ os = parse_os(user_agent)
15
+ device = parse_device(user_agent)
16
+ parse_ua(user_agent, os, device)
17
17
  end
18
18
 
19
- def patterns type
20
- @patterns ||= {}
21
- @patterns[type] ||= begin
22
- all_patterns[type].each do |p|
23
- p["regex"] = Regexp.new(p["regex"])
19
+ private
20
+
21
+ def load_patterns(path)
22
+ yml = YAML.load_file(path)
23
+
24
+ # Parse all the regexs
25
+ yml.each_pair do |type, patterns|
26
+ patterns.each do |pattern|
27
+ pattern["regex"] = Regexp.new(pattern["regex"])
24
28
  end
25
29
  end
30
+
31
+ [ yml["user_agent_parsers"], yml["os_parsers"], yml["device_parsers"] ]
26
32
  end
27
-
28
- def parse_ua user_agent
29
- pattern, match = first_pattern_match(patterns("user_agent_parsers"), user_agent)
33
+
34
+ def parse_ua(user_agent, os = nil, device = nil)
35
+ pattern, match = first_pattern_match(@ua_patterns, user_agent)
36
+
30
37
  if match
31
- user_agent_from_pattern_match(pattern, match)
38
+ user_agent_from_pattern_match(pattern, match, os, device)
32
39
  else
33
- UserAgent.new
40
+ UserAgent.new(nil, nil, os, device)
34
41
  end
35
42
  end
36
-
37
- def parse_os user_agent
38
- pattern, match = first_pattern_match(patterns("os_parsers"), user_agent)
43
+
44
+ def parse_os(user_agent)
45
+ pattern, match = first_pattern_match(@os_patterns, user_agent)
46
+
39
47
  if match
40
48
  os_from_pattern_match(pattern, match)
41
49
  else
@@ -43,45 +51,94 @@ module UserAgentParser
43
51
  end
44
52
  end
45
53
 
46
- def first_pattern_match patterns, value
47
- for p in patterns
48
- if m = p["regex"].match(value)
49
- return [p, m]
54
+ def parse_device(user_agent)
55
+ pattern, match = first_pattern_match(@device_patterns, user_agent)
56
+
57
+ if match
58
+ device_from_pattern_match(pattern, match)
59
+ else
60
+ Device.new
61
+ end
62
+ end
63
+
64
+ def first_pattern_match(patterns, value)
65
+ patterns.each do |pattern|
66
+ if match = pattern["regex"].match(value)
67
+ return [pattern, match]
50
68
  end
51
69
  end
52
70
  nil
53
71
  end
54
72
 
55
- def user_agent_from_pattern_match pattern, match
56
- family, v1, v2, v3 = match[1], match[2], match[3], match[4]
73
+ def user_agent_from_pattern_match(pattern, match, os = nil, device = nil)
74
+ name, v1, v2, v3, v4 = match[1], match[2], match[3], match[4], match[5]
75
+
57
76
  if pattern["family_replacement"]
58
- family = pattern["family_replacement"].sub('$1', family || '')
59
- end
60
- v1 = pattern["v1_replacement"].sub('$1', v1 || '') if pattern["v1_replacement"]
61
- v2 = pattern["v2_replacement"].sub('$1', v2 || '') if pattern["v2_replacement"]
62
- v3 = pattern["v3_replacement"].sub('$1', v3 || '') if pattern["v3_replacement"]
63
- ua = UserAgent.new(family)
64
- ua.version = version_from_segments(v1, v2, v3)
65
- ua
77
+ name = pattern["family_replacement"].sub('$1', name || '')
78
+ end
79
+
80
+ if pattern["v1_replacement"]
81
+ v1 = pattern["v1_replacement"].sub('$1', v1 || '')
82
+ end
83
+
84
+ if pattern["v2_replacement"]
85
+ v2 = pattern["v2_replacement"].sub('$1', v2 || '')
86
+ end
87
+
88
+ if pattern["v3_replacement"]
89
+ v3 = pattern["v3_replacement"].sub('$1', v3 || '')
90
+ end
91
+
92
+ if pattern["v4_replacement"]
93
+ v4 = pattern["v4_replacement"].sub('$1', v4 || '')
94
+ end
95
+
96
+ version = version_from_segments(v1, v2, v3, v4)
97
+
98
+ UserAgent.new(name, version, os, device)
66
99
  end
67
-
68
- def os_from_pattern_match pattern, match
100
+
101
+ def os_from_pattern_match(pattern, match)
69
102
  os, v1, v2, v3, v4 = match[1], match[2], match[3], match[4], match[5]
70
- os = pattern["os_replacement"].sub('$1', os || '') if pattern["os_replacement"]
71
- v1 = pattern["v1_replacement"].sub('$1', v1 || '') if pattern["v1_replacement"]
72
- v2 = pattern["v2_replacement"].sub('$1', v2 || '') if pattern["v2_replacement"]
73
- v3 = pattern["v3_replacement"].sub('$1', v3 || '') if pattern["v3_replacement"]
74
- v4 = pattern["v3_replacement"].sub('$1', v3 || '') if pattern["v4_replacement"]
75
- os = OperatingSystem.new(os)
76
- os.version = version_from_segments(v1, v2, v3, v4)
77
- os
103
+
104
+ if pattern["os_replacement"]
105
+ os = pattern["os_replacement"].sub('$1', os || '')
106
+ end
107
+
108
+ if pattern["os_v1_replacement"]
109
+ v1 = pattern["os_v1_replacement"].sub('$1', v1 || '')
110
+ end
111
+
112
+ if pattern["os_v2_replacement"]
113
+ v2 = pattern["os_v2_replacement"].sub('$1', v2 || '')
114
+ end
115
+
116
+ if pattern["os_v3_replacement"]
117
+ v3 = pattern["os_v3_replacement"].sub('$1', v3 || '')
118
+ end
119
+
120
+ if pattern["os_v4_replacement"]
121
+ v4 = pattern["os_v4_replacement"].sub('$1', v4 || '')
122
+ end
123
+
124
+ version = version_from_segments(v1, v2, v3, v4)
125
+
126
+ OperatingSystem.new(os, version)
78
127
  end
79
-
128
+
129
+ def device_from_pattern_match(pattern, match)
130
+ device = match[1]
131
+
132
+ if pattern["device_replacement"]
133
+ device = pattern["device_replacement"].sub('$1', device || '')
134
+ end
135
+
136
+ Device.new(device)
137
+ end
138
+
80
139
  def version_from_segments(*segments)
81
140
  version_string = segments.compact.join(".")
82
141
  version_string.empty? ? nil : Version.new(version_string)
83
142
  end
84
-
85
143
  end
86
-
87
144
  end
@@ -1,32 +1,37 @@
1
1
  module UserAgentParser
2
-
3
2
  class UserAgent
3
+ attr_reader :name, :version, :os, :device
4
4
 
5
- attr_accessor :family, :version, :os
5
+ # For backwards compatibility with older versions of this gem.
6
+ alias_method :family, :name
6
7
 
7
- def initialize(family="Other", version=nil, os=nil)
8
- self.family = family
9
- self.version = version
10
- self.os = os
8
+ def initialize(name = nil, version = nil, os = nil, device = nil)
9
+ @name = name || 'Other'
10
+ @version = version
11
+ @os = os
12
+ @device = device
11
13
  end
12
14
 
13
15
  def to_s
14
- s = family
15
- s += " #{version}" if version
16
- s += " (#{os})" if os
17
- s
16
+ string = name
17
+ string += " #{version}" if version
18
+ string
18
19
  end
19
20
 
20
21
  def inspect
21
- "#<#{self.class} #{to_s}>"
22
+ string = to_s
23
+ string += " (#{os})" if os
24
+ string += " (#{device})" if device
25
+ "#<#{self.class} #{string}>"
22
26
  end
23
-
24
- def ==(other)
25
- family == other.family &&
27
+
28
+ def eql?(other)
29
+ self.class.eql?(other.class) &&
30
+ name == other.name &&
26
31
  version == other.version &&
27
32
  os == other.os
28
33
  end
29
34
 
35
+ alias_method :==, :eql?
30
36
  end
31
-
32
37
  end