user_agent_parser 1.0.1 → 2.1.2

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 066f29cb9f46c928c8dbca73076bdf2e6da63b2c
4
+ data.tar.gz: 0a171a4c0efa6c0601a4844a68f49bf1316f18d6
5
+ SHA512:
6
+ metadata.gz: 2636ff74bef1fcef2c8be5070d97fdd0a70c969faafc76106531bf8986fa8336ca744cabe0babf5d6198d1455a3b25e04246abac9a1afb77b16dc5d79890d9dc
7
+ data.tar.gz: 06836d83ae49433ffdace34ebcf8f838768e7f533228ba4f48e662e5968744f7a0c29c4c9c64b60e7c9c196fd286f649e9ff577b25dc096065368235666b5059
data/Readme.md CHANGED
@@ -4,9 +4,7 @@ UserAgentParser is a simple, comprehensive Ruby gem for parsing user agent strin
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,48 +17,62 @@ $ 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
22
+ user_agent.to_s
25
23
  => "IE 9.0"
26
- ua.family
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.major
31
- => 9
32
- ua.version.minor
33
- => 0
34
- os = ua.os
28
+ user_agent.version.major
29
+ => "9"
30
+ user_agent.version.minor
31
+ => "0"
32
+ operating_system = user_agent.os
35
33
  => #<UserAgentParser::OperatingSystem Windows Vista>
36
- os.to_s
34
+ operating_system.to_s
37
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)>
38
44
  ```
39
45
 
40
- ## The pattern database
46
+ In a larger application, you could store a parser in a global to avoid repeat pattern loading:
41
47
 
42
- 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!).
48
+ ```ruby
49
+ module MyApplication
43
50
 
44
- You can also specify the path to your own, updated and/or customised `regexes.yaml` file:
51
+ # Instantiate the parser on load as it's quite expensive
52
+ USER_AGENT_PARSER = UserAgentParser::Parser.new
45
53
 
46
- ```ruby
47
- UserAgentParser.patterns_path = '/some/path/to/regexes.yaml'
54
+ def self.user_agent_parser
55
+ USER_AGENT_PARSER
56
+ end
57
+
58
+ end
48
59
  ```
49
60
 
50
- ## Comprehensive you say?
61
+ ## The pattern database
51
62
 
52
- ```bash
53
- $ rake test
54
- ...
55
-
56
- Finished tests in 144.220280s, 89.0027 tests/s, 234.9739 assertions/s.
63
+ 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!).
64
+
65
+ You can also specify the path to your own, updated and/or customised `regexes.yaml` file as a second argument to `UserAgentParser.parse`:
57
66
 
58
- 12836 tests, 33888 assertions, 0 failures, 0 errors, 0 skips
67
+ ```ruby
68
+ UserAgentParser.parse(ua_string, patterns_path: '/some/path/to/regexes.yaml')
59
69
  ```
60
70
 
61
- ## Limitations
71
+ or when instantiating a `UserAgentParser::Parser`:
62
72
 
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/).
73
+ ```ruby
74
+ UserAgentParser::Parser.new(patterns_path: '/some/path/to/regexes.yaml').parse(ua_string)
75
+ ```
64
76
 
65
77
  ## Contributing
66
78
 
@@ -71,6 +83,18 @@ There's no support for providing overrides from Javascript user agent detection
71
83
 
72
84
  All accepted pull requests will earn you commit and release rights.
73
85
 
86
+ ## Releasing a new version
87
+
88
+ 1. Update the version in `user_agent_parser.gemspec`
89
+ 2. `git commit user_agent_parser.gemspec` with the following message format:
90
+
91
+ Version x.x.x
92
+
93
+ Changelog:
94
+ * Some new feature
95
+ * Some new bug fix
96
+ 3. `rake release`
97
+
74
98
  ## License
75
99
 
76
- MIT
100
+ 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,33 +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
16
+ string = name
17
+ string += " #{version}" if version
18
+ string
17
19
  end
18
20
 
19
21
  def inspect
20
- s = to_s
21
- s += " (#{os})" if os
22
- "#<#{self.class} #{s}>"
22
+ string = to_s
23
+ string += " (#{os})" if os
24
+ string += " (#{device})" if device
25
+ "#<#{self.class} #{string}>"
23
26
  end
24
-
25
- def ==(other)
26
- family == other.family &&
27
+
28
+ def eql?(other)
29
+ self.class.eql?(other.class) &&
30
+ name == other.name &&
27
31
  version == other.version &&
28
32
  os == other.os
29
33
  end
30
34
 
35
+ alias_method :==, :eql?
31
36
  end
32
-
33
37
  end