browser 3.0.2 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +1 -1
  3. data/.prettierignore +1 -0
  4. data/.rubocop.yml +9 -0
  5. data/.travis.yml +3 -3
  6. data/CHANGELOG.md +81 -18
  7. data/FUNDING.yml +3 -0
  8. data/README.md +113 -88
  9. data/bots.yml +300 -294
  10. data/browser.gemspec +3 -1
  11. data/lib/browser/base.rb +63 -7
  12. data/lib/browser/browser.rb +27 -26
  13. data/lib/browser/chrome.rb +12 -2
  14. data/lib/browser/device.rb +2 -2
  15. data/lib/browser/device/unknown.rb +1 -1
  16. data/lib/browser/duck_duck_go.rb +22 -0
  17. data/lib/browser/edge.rb +2 -2
  18. data/lib/browser/google_search_app.rb +21 -0
  19. data/lib/browser/huawei_browser.rb +21 -0
  20. data/lib/browser/maxthon.rb +21 -0
  21. data/lib/browser/meta.rb +0 -1
  22. data/lib/browser/meta/base.rb +0 -1
  23. data/lib/browser/miui_browser.rb +21 -0
  24. data/lib/browser/platform.rb +5 -5
  25. data/lib/browser/platform/base.rb +3 -2
  26. data/lib/browser/platform/ios.rb +1 -1
  27. data/lib/browser/platform/mac.rb +4 -2
  28. data/lib/browser/platform/{other.rb → unknown.rb} +3 -3
  29. data/lib/browser/platform/windows.rb +1 -1
  30. data/lib/browser/safari.rb +16 -1
  31. data/lib/browser/samsung_browser.rb +21 -0
  32. data/lib/browser/sougou_browser.rb +24 -0
  33. data/lib/browser/{generic.rb → unknown.rb} +3 -3
  34. data/lib/browser/version.rb +1 -1
  35. data/test/browser_test.rb +23 -6
  36. data/test/test_helper.rb +8 -0
  37. data/test/ua.yml +17 -1
  38. data/test/ua_bots.yml +8 -2
  39. data/test/unit/adobe_air_test.rb +1 -1
  40. data/test/unit/alipay_test.rb +6 -0
  41. data/test/unit/console_test.rb +2 -2
  42. data/test/unit/device_test.rb +2 -2
  43. data/test/unit/duck_duck_go_test.rb +37 -0
  44. data/test/unit/edge_test.rb +34 -2
  45. data/test/unit/google_search_app_test.rb +54 -0
  46. data/test/unit/huawei_browser_test.rb +25 -0
  47. data/test/unit/maxthon_test.rb +25 -0
  48. data/test/unit/meta_test.rb +9 -0
  49. data/test/unit/micro_messenger_test.rb +21 -6
  50. data/test/unit/miui_browser_test.rb +25 -0
  51. data/test/unit/opera_test.rb +1 -0
  52. data/test/unit/platform_test.rb +12 -7
  53. data/test/unit/qq_test.rb +12 -0
  54. data/test/unit/safari_test.rb +12 -7
  55. data/test/unit/samsung_browser_test.rb +23 -0
  56. data/test/unit/sougou_browser_test.rb +41 -0
  57. metadata +33 -10
  58. data/lib/browser/meta/modern.rb +0 -11
@@ -8,11 +8,13 @@ Gem::Specification.new do |s|
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Nando Vieira"]
10
10
  s.email = ["fnando.vieira@gmail.com"]
11
- s.homepage = "http://github.com/fnando/browser"
11
+ s.homepage = "https://github.com/fnando/browser"
12
12
  s.summary = "Do some browser detection with Ruby."
13
13
  s.description = s.summary
14
14
  s.license = "MIT"
15
15
 
16
+ s.metadata["changelog_uri"] = "https://github.com/fnando/browser/blob/master/CHANGELOG.md"
17
+
16
18
  s.files = `git ls-files`.split("\n")
17
19
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
20
  s.executables = `git ls-files -- exe/*`
@@ -10,6 +10,9 @@ module Browser
10
10
  attr_reader :accept_language
11
11
 
12
12
  def initialize(ua, accept_language: nil)
13
+ validate_size(:user_agent, ua.to_s)
14
+ validate_size(:accept_language, accept_language.to_s)
15
+
13
16
  @ua = ua
14
17
  @accept_language = AcceptLanguage.parse(accept_language)
15
18
  end
@@ -50,11 +53,6 @@ module Browser
50
53
  @device ||= Device.new(ua)
51
54
  end
52
55
 
53
- # Return true if browser is modern (Webkit, Firefox 17+, IE9+, Opera 12+).
54
- def modern?
55
- Browser.modern_rules.any? {|rule| rule === self } # rubocop:disable Style/CaseEquality
56
- end
57
-
58
56
  # Detect if browser is Microsoft Internet Explorer.
59
57
  def ie?(expected_version = nil)
60
58
  InternetExplorer.new(ua).match? &&
@@ -127,7 +125,7 @@ module Browser
127
125
 
128
126
  # Detect if browser is Safari.
129
127
  def safari?(expected_version = nil)
130
- Safari.new(ua).match? && detect_version?(version, expected_version)
128
+ Safari.new(ua).match? && detect_version?(full_version, expected_version)
131
129
  end
132
130
 
133
131
  def safari_webapp_mode?
@@ -192,12 +190,59 @@ module Browser
192
190
  ua =~ /Opera Mini/ && detect_version?(full_version, expected_version)
193
191
  end
194
192
 
193
+ # Detect if browser is DuckDuckGo.
194
+ def duck_duck_go?(expected_version = nil)
195
+ ua =~ /DuckDuckGo/ && detect_version?(full_version, expected_version)
196
+ end
197
+
198
+ # Detect if browser is Samsung.
199
+ def samsung_browser?(expected_version = nil)
200
+ ua =~ /SamsungBrowser/ && detect_version?(full_version, expected_version)
201
+ end
202
+
203
+ # Detect if browser is Huawei.
204
+ def huawei_browser?(expected_version = nil)
205
+ HuaweiBrowser.new(ua).match? &&
206
+ detect_version?(full_version, expected_version)
207
+ end
208
+
209
+ # Detect if browser is Xiaomi Miui.
210
+ def miui_browser?(expected_version = nil)
211
+ MiuiBrowser.new(ua).match? &&
212
+ detect_version?(full_version, expected_version)
213
+ end
214
+
215
+ # Detect if browser is Maxthon.
216
+ def maxthon?(expected_version = nil)
217
+ Maxthon.new(ua).match? && detect_version?(full_version, expected_version)
218
+ end
219
+
220
+ # Detect if browser is QQ.
221
+ def qq?(expected_version = nil)
222
+ QQ.new(ua).match? && detect_version?(full_version, expected_version)
223
+ end
224
+
225
+ # Detect if browser is Sougou.
226
+ def sougou_browser?(expected_version = nil)
227
+ SougouBrowser.new(ua).match? &&
228
+ detect_version?(full_version, expected_version)
229
+ end
230
+
231
+ # Detect if browser is Google Search App
232
+ def google_search_app?(expected_version = nil)
233
+ ua =~ /GSA/ && detect_version?(full_version, expected_version)
234
+ end
235
+
195
236
  def webkit_full_version
196
237
  ua[%r{AppleWebKit/([\d.]+)}, 1] || "0.0"
197
238
  end
198
239
 
199
240
  def known?
200
- id != :generic
241
+ !unknown?
242
+ end
243
+
244
+ def unknown?
245
+ id == :unknown_browser
201
246
  end
202
247
 
203
248
  # Detect if browser is a proxy browser.
@@ -209,5 +254,16 @@ module Browser
209
254
  def electron?(expected_version = nil)
210
255
  Electron.new(ua).match? && detect_version?(full_version, expected_version)
211
256
  end
257
+
258
+ private def validate_size(subject, input)
259
+ actual_bytesize = input.bytesize
260
+ size_limit = Browser.public_send("#{subject}_size_limit")
261
+
262
+ return if actual_bytesize < size_limit
263
+
264
+ raise Error,
265
+ "#{subject} cannot be larger than #{size_limit} bytes; " \
266
+ "actual size is #{actual_bytesize}"
267
+ end
212
268
  end
213
269
  end
@@ -15,7 +15,7 @@ require_relative "firefox"
15
15
  require_relative "edge"
16
16
  require_relative "opera"
17
17
  require_relative "blackberry"
18
- require_relative "generic"
18
+ require_relative "unknown"
19
19
  require_relative "phantom_js"
20
20
  require_relative "uc_browser"
21
21
  require_relative "nokia"
@@ -30,6 +30,13 @@ require_relative "instagram"
30
30
  require_relative "yandex"
31
31
  require_relative "sputnik"
32
32
  require_relative "snapchat"
33
+ require_relative "duck_duck_go"
34
+ require_relative "samsung_browser"
35
+ require_relative "huawei_browser"
36
+ require_relative "miui_browser"
37
+ require_relative "maxthon"
38
+ require_relative "sougou_browser"
39
+ require_relative "google_search_app"
33
40
 
34
41
  require_relative "bot"
35
42
  require_relative "bot/empty_user_agent_matcher"
@@ -44,10 +51,20 @@ require_relative "meta"
44
51
  module Browser
45
52
  EMPTY_STRING = ""
46
53
 
54
+ Error = Class.new(StandardError)
55
+
47
56
  def self.root
48
57
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
49
58
  end
50
59
 
60
+ class << self
61
+ attr_accessor :user_agent_size_limit
62
+ attr_accessor :accept_language_size_limit
63
+ end
64
+
65
+ self.user_agent_size_limit = 512
66
+ self.accept_language_size_limit = 256
67
+
51
68
  # Hold the list of browser matchers.
52
69
  # Order is important.
53
70
  def self.matchers
@@ -65,41 +82,25 @@ module Browser
65
82
  Instagram, # must be placed before Chrome and Safari
66
83
  Snapchat, # must be placed before Chrome and Safari
67
84
  Weibo, # must be placed before Chrome and Safari
85
+ MicroMessenger, # must be placed before QQ
68
86
  QQ, # must be placed before Chrome and Safari
69
87
  Alipay, # must be placed before Chrome and Safari
70
88
  Electron, # must be placed before Chrome and Safari
71
89
  Yandex, # must be placed before Chrome and Safari
72
90
  Sputnik, # must be placed before Chrome and Safari
91
+ DuckDuckGo, # must be placed before Chrome and Safari
92
+ SamsungBrowser, # must be placed before Chrome and Safari
93
+ HuaweiBrowser, # must be placed before Chrome and Safari
94
+ MiuiBrowser, # must be placed before Chrome and Safari
95
+ Maxthon, # must be placed before Chrome and Safari
96
+ SougouBrowser, # must be placed before Chrome and Safari
97
+ GoogleSearchApp, # must be placed before Chrome and Safari
73
98
  Chrome,
74
99
  Safari,
75
- MicroMessenger,
76
- Generic
100
+ Unknown
77
101
  ]
78
102
  end
79
103
 
80
- # Define the rules which define a modern browser.
81
- # A rule must be a proc/lambda or any object that implements the method
82
- # === and accepts the browser object.
83
- #
84
- # To redefine all rules, clear the existing rules before adding your own.
85
- #
86
- # # Only Chrome Canary is considered modern.
87
- # Browser.modern_rules.clear
88
- # Browser.modern_rules << -> b { b.chrome? && b.version >= "37" }
89
- #
90
- def self.modern_rules
91
- @modern_rules ||= []
92
- end
93
-
94
- modern_rules.tap do |rules|
95
- rules << ->(b) { b.chrome? && b.version.to_i >= 65 }
96
- rules << ->(b) { b.safari? && b.version.to_i >= 10 }
97
- rules << ->(b) { b.firefox? && b.version.to_i >= 52 }
98
- rules << ->(b) { b.ie? && b.version.to_i >= 11 && !b.compatibility_view? }
99
- rules << ->(b) { b.edge? && b.version.to_i >= 15 }
100
- rules << ->(b) { b.opera? && b.version.to_i >= 50 }
101
- end
102
-
103
104
  def self.new(user_agent, **kwargs)
104
105
  matchers
105
106
  .map {|klass| klass.new(user_agent || EMPTY_STRING, **kwargs) }
@@ -21,9 +21,19 @@ module Browser
21
21
 
22
22
  def match?
23
23
  ua =~ /Chrome|CriOS/ &&
24
- ua !~ /PhantomJS|FxiOS|YaBrowser|SputnikBrowser|ArchiveBot/ &&
24
+ ua !~ /PhantomJS|FxiOS|ArchiveBot/ &&
25
25
  !opera? &&
26
- !edge?
26
+ !edge? &&
27
+ !duck_duck_go? &&
28
+ !yandex? &&
29
+ !sputnik? &&
30
+ !samsung_browser? &&
31
+ !huawei_browser? &&
32
+ !miui_browser? &&
33
+ !maxthon? &&
34
+ !qq? &&
35
+ !sougou_browser? &&
36
+ !google_search_app?
27
37
  end
28
38
  end
29
39
  end
@@ -88,7 +88,7 @@ module Browser
88
88
  end
89
89
 
90
90
  def unknown?
91
- id == :unknown
91
+ id == :unknown_device
92
92
  end
93
93
 
94
94
  def ipod_touch?
@@ -197,7 +197,7 @@ module Browser
197
197
  psp? ||
198
198
  /zunewp7/i.match(ua) ||
199
199
  %r{(android|bb\d+|meego).+mobile|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino}i.match(ua) ||
200
- %r{1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-}i.match(ua[0..3])
200
+ %r{1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-}i.match(ua[0..3])
201
201
  end
202
202
  # rubocop:enable Layout/LineLength
203
203
 
@@ -4,7 +4,7 @@ module Browser
4
4
  class Device
5
5
  class Unknown < Base
6
6
  def id
7
- :unknown
7
+ :unknown_device
8
8
  end
9
9
 
10
10
  def name
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class DuckDuckGo < Base
5
+ def id
6
+ :duckduckgo
7
+ end
8
+
9
+ def name
10
+ "DuckDuckGo"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{DuckDuckGo/([\d.]+)}, 1] ||
15
+ "0.0"
16
+ end
17
+
18
+ def match?
19
+ ua =~ /DuckDuckGo/
20
+ end
21
+ end
22
+ end
@@ -11,11 +11,11 @@ module Browser
11
11
  end
12
12
 
13
13
  def full_version
14
- ua[%r{(?:Edge|Edg)/([\d.]+)}, 1] || super
14
+ ua[%r{(?:Edge|Edg|EdgiOS|EdgA)/([\d.]+)}, 1] || super
15
15
  end
16
16
 
17
17
  def match?
18
- ua =~ %r{((?:Edge|Edg)/[\d.]+|Trident/8)}
18
+ ua =~ %r{((?:Edge|Edg|EdgiOS|EdgA)/[\d.]+|Trident/8)}
19
19
  end
20
20
 
21
21
  def chrome_based?
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class GoogleSearchApp < Chrome
5
+ def id
6
+ :google_search_app
7
+ end
8
+
9
+ def name
10
+ "Google Search App"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{GSA/([\d.]+\d)}, 1] || super
15
+ end
16
+
17
+ def match?
18
+ ua =~ /GSA/
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class HuaweiBrowser < Base
5
+ def id
6
+ :huawei_browser
7
+ end
8
+
9
+ def name
10
+ "Huawei Browser"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{(?:HuaweiBrowser)/([\d.]+)}i, 1] || "0.0"
15
+ end
16
+
17
+ def match?
18
+ ua =~ /HuaweiBrowser/i
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class Maxthon < Base
5
+ def id
6
+ :maxthon
7
+ end
8
+
9
+ def name
10
+ "Maxthon"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{(?:Maxthon)/([\d.]+)}i, 1] || "0.0"
15
+ end
16
+
17
+ def match?
18
+ ua =~ /Maxthon/i
19
+ end
20
+ end
21
+ end
@@ -6,7 +6,6 @@ require_relative "meta/id"
6
6
  require_relative "meta/ie"
7
7
  require_relative "meta/ios"
8
8
  require_relative "meta/mobile"
9
- require_relative "meta/modern"
10
9
  require_relative "meta/platform"
11
10
  require_relative "meta/proxy"
12
11
  require_relative "meta/safari"
@@ -10,7 +10,6 @@ module Browser
10
10
  IE,
11
11
  IOS,
12
12
  Mobile,
13
- Modern,
14
13
  Platform,
15
14
  Proxy,
16
15
  Safari,
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Browser
4
+ class MiuiBrowser < Base
5
+ def id
6
+ :miui_browser
7
+ end
8
+
9
+ def name
10
+ "Miui Browser"
11
+ end
12
+
13
+ def full_version
14
+ ua[%r{MiuiBrowser/([\d.]+)}, 1] || "0.0"
15
+ end
16
+
17
+ def match?
18
+ ua =~ /MiuiBrowser/
19
+ end
20
+ end
21
+ end
@@ -10,7 +10,7 @@ require_relative "platform/windows_mobile"
10
10
  require_relative "platform/firefox_os"
11
11
  require_relative "platform/blackberry"
12
12
  require_relative "platform/android"
13
- require_relative "platform/other"
13
+ require_relative "platform/unknown"
14
14
  require_relative "platform/chrome_os"
15
15
  require_relative "platform/adobe_air"
16
16
 
@@ -35,7 +35,7 @@ module Browser
35
35
  FirefoxOS,
36
36
  Windows,
37
37
  Linux,
38
- Other
38
+ Unknown
39
39
  ]
40
40
  end
41
41
 
@@ -45,7 +45,7 @@ module Browser
45
45
 
46
46
  def subject
47
47
  @subject ||= self.class.matchers
48
- .map {|matcher| matcher.new(ua) }
48
+ .map {|matcher| matcher.new(ua, self) }
49
49
  .find(&:match?)
50
50
  end
51
51
 
@@ -61,8 +61,8 @@ module Browser
61
61
  id == :android && detect_version?(version, expected_version)
62
62
  end
63
63
 
64
- def other?
65
- id == :other
64
+ def unknown?
65
+ id == :unknown_platform
66
66
  end
67
67
 
68
68
  def linux?