browser 4.0.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests.yml +57 -0
  3. data/.prettierignore +1 -0
  4. data/.rubocop.yml +6 -0
  5. data/CHANGELOG.md +51 -1
  6. data/FUNDING.yml +3 -0
  7. data/README.md +97 -61
  8. data/bots.yml +300 -296
  9. data/browser.gemspec +4 -2
  10. data/lib/browser/accept_language.rb +4 -4
  11. data/lib/browser/alipay.rb +1 -1
  12. data/lib/browser/base.rb +76 -12
  13. data/lib/browser/blackberry.rb +1 -1
  14. data/lib/browser/bot/keyword_matcher.rb +1 -1
  15. data/lib/browser/browser.rb +24 -3
  16. data/lib/browser/chrome.rb +10 -3
  17. data/lib/browser/device.rb +12 -5
  18. data/lib/browser/device/android.rb +1 -1
  19. data/lib/browser/device/blackberry_playbook.rb +1 -1
  20. data/lib/browser/device/ipad.rb +1 -1
  21. data/lib/browser/device/iphone.rb +1 -1
  22. data/lib/browser/device/ipod_touch.rb +1 -1
  23. data/lib/browser/device/kindle.rb +1 -1
  24. data/lib/browser/device/kindle_fire.rb +1 -1
  25. data/lib/browser/device/playstation3.rb +1 -1
  26. data/lib/browser/device/playstation4.rb +1 -1
  27. data/lib/browser/device/psp.rb +1 -1
  28. data/lib/browser/device/psvita.rb +1 -1
  29. data/lib/browser/device/samsung.rb +33 -0
  30. data/lib/browser/device/surface.rb +1 -1
  31. data/lib/browser/device/switch.rb +1 -1
  32. data/lib/browser/device/tv.rb +1 -1
  33. data/lib/browser/device/unknown.rb +1 -1
  34. data/lib/browser/device/wii.rb +1 -1
  35. data/lib/browser/device/wiiu.rb +1 -1
  36. data/lib/browser/device/xbox_360.rb +1 -1
  37. data/lib/browser/device/xbox_one.rb +1 -1
  38. data/lib/browser/duck_duck_go.rb +1 -1
  39. data/lib/browser/edge.rb +3 -3
  40. data/lib/browser/electron.rb +1 -1
  41. data/lib/browser/facebook.rb +1 -1
  42. data/lib/browser/firefox.rb +1 -1
  43. data/lib/browser/google_search_app.rb +21 -0
  44. data/lib/browser/huawei_browser.rb +21 -0
  45. data/lib/browser/instagram.rb +1 -1
  46. data/lib/browser/internet_explorer.rb +2 -2
  47. data/lib/browser/maxthon.rb +21 -0
  48. data/lib/browser/micro_messenger.rb +1 -1
  49. data/lib/browser/miui_browser.rb +21 -0
  50. data/lib/browser/nokia.rb +1 -1
  51. data/lib/browser/opera.rb +1 -1
  52. data/lib/browser/otter.rb +1 -1
  53. data/lib/browser/phantom_js.rb +1 -1
  54. data/lib/browser/platform.rb +21 -15
  55. data/lib/browser/platform/adobe_air.rb +1 -1
  56. data/lib/browser/platform/android.rb +1 -1
  57. data/lib/browser/platform/blackberry.rb +1 -1
  58. data/lib/browser/platform/chrome_os.rb +1 -1
  59. data/lib/browser/platform/firefox_os.rb +1 -1
  60. data/lib/browser/platform/ios.rb +2 -2
  61. data/lib/browser/platform/kai_os.rb +23 -0
  62. data/lib/browser/platform/linux.rb +1 -1
  63. data/lib/browser/platform/mac.rb +2 -2
  64. data/lib/browser/platform/{other.rb → unknown.rb} +3 -3
  65. data/lib/browser/platform/windows.rb +2 -2
  66. data/lib/browser/platform/windows_mobile.rb +1 -1
  67. data/lib/browser/platform/windows_phone.rb +1 -1
  68. data/lib/browser/qq.rb +1 -1
  69. data/lib/browser/safari.rb +12 -3
  70. data/lib/browser/samsung_browser.rb +21 -0
  71. data/lib/browser/snapchat.rb +1 -1
  72. data/lib/browser/sougou_browser.rb +24 -0
  73. data/lib/browser/sputnik.rb +1 -1
  74. data/lib/browser/uc_browser.rb +1 -1
  75. data/lib/browser/{generic.rb → unknown.rb} +3 -3
  76. data/lib/browser/version.rb +1 -1
  77. data/lib/browser/weibo.rb +1 -1
  78. data/lib/browser/yandex.rb +1 -1
  79. data/samsung.yml +138 -0
  80. data/test/browser_test.rb +37 -6
  81. data/test/ua.yml +20 -2
  82. data/test/ua_bots.yml +7 -3
  83. data/test/unit/adobe_air_test.rb +1 -1
  84. data/test/unit/alipay_test.rb +6 -0
  85. data/test/unit/bots_test.rb +1 -1
  86. data/test/unit/console_test.rb +2 -2
  87. data/test/unit/device_test.rb +30 -3
  88. data/test/unit/duck_duck_go_test.rb +2 -0
  89. data/test/unit/edge_test.rb +34 -2
  90. data/test/unit/google_search_app_test.rb +54 -0
  91. data/test/unit/huawei_browser_test.rb +25 -0
  92. data/test/unit/kai_os_test.rb +31 -0
  93. data/test/unit/maxthon_test.rb +25 -0
  94. data/test/unit/meta_test.rb +10 -1
  95. data/test/unit/micro_messenger_test.rb +21 -6
  96. data/test/unit/miui_browser_test.rb +25 -0
  97. data/test/unit/opera_test.rb +1 -0
  98. data/test/unit/platform_test.rb +7 -7
  99. data/test/unit/qq_test.rb +12 -0
  100. data/test/unit/safari_test.rb +12 -7
  101. data/test/unit/samsung_browser_test.rb +23 -0
  102. data/test/unit/sougou_browser_test.rb +41 -0
  103. metadata +41 -15
  104. data/.travis.yml +0 -23
@@ -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/main/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/*`
@@ -29,6 +31,6 @@ Gem::Specification.new do |s|
29
31
  s.add_development_dependency "rails"
30
32
  s.add_development_dependency "rake"
31
33
  s.add_development_dependency "rubocop"
32
- s.add_development_dependency "rubocop-fnando", "~> 0.0.3"
34
+ s.add_development_dependency "rubocop-fnando"
33
35
  s.add_development_dependency "simplecov"
34
36
  end
@@ -48,15 +48,15 @@ module Browser
48
48
  def quality
49
49
  @quality ||= begin
50
50
  Float(quality_value || 1.0)
51
- rescue ArgumentError
52
- 0.1
51
+ rescue ArgumentError
52
+ 0.1
53
53
  end
54
54
  end
55
55
 
56
56
  private def quality_value
57
57
  qvalue = part[/;q=([\d.]+)/, 1]
58
- qvalue = qvalue =~ /\A0\.0?\z/ ? "0.0" : qvalue
59
- qvalue = qvalue.gsub(/\.+/, ".") if qvalue
58
+ qvalue = /\A0\.0?\z/.match?(qvalue) ? "0.0" : qvalue
59
+ qvalue = qvalue.squeeze(".") if qvalue
60
60
  qvalue
61
61
  end
62
62
  end
@@ -15,7 +15,7 @@ module Browser
15
15
  end
16
16
 
17
17
  def match?
18
- ua =~ /AlipayClient/i
18
+ ua.match?(/AlipayClient/i)
19
19
  end
20
20
  end
21
21
  end
@@ -6,12 +6,11 @@ module Browser
6
6
 
7
7
  attr_reader :ua
8
8
 
9
- # Return an array with all preferred languages that this browser accepts.
10
- attr_reader :accept_language
11
-
12
9
  def initialize(ua, accept_language: nil)
10
+ validate_size(:user_agent, ua.to_s)
11
+
13
12
  @ua = ua
14
- @accept_language = AcceptLanguage.parse(accept_language)
13
+ @accept_language_raw = accept_language.to_s
15
14
  end
16
15
 
17
16
  # Return a meta info about this browser.
@@ -19,6 +18,14 @@ module Browser
19
18
  Meta.get(self)
20
19
  end
21
20
 
21
+ # Return an array with all preferred languages that this browser accepts.
22
+ def accept_language
23
+ @accept_language ||= begin
24
+ validate_size(:accept_language, @accept_language_raw)
25
+ AcceptLanguage.parse(@accept_language_raw)
26
+ end
27
+ end
28
+
22
29
  alias_method :to_a, :meta
23
30
 
24
31
  # Return meta representation as string.
@@ -99,19 +106,20 @@ module Browser
99
106
 
100
107
  # Detect if browser is WebKit-based.
101
108
  def webkit?(expected_version = nil)
102
- ua =~ /AppleWebKit/i &&
109
+ ua.match?(/AppleWebKit/i) &&
103
110
  (!edge? || Edge.new(ua).chrome_based?) &&
104
111
  detect_version?(webkit_full_version, expected_version)
105
112
  end
106
113
 
107
114
  # Detect if browser is QuickTime
108
115
  def quicktime?(expected_version = nil)
109
- ua =~ /QuickTime/i && detect_version?(full_version, expected_version)
116
+ ua.match?(/QuickTime/i) && detect_version?(full_version, expected_version)
110
117
  end
111
118
 
112
119
  # Detect if browser is Apple CoreMedia.
113
120
  def core_media?(expected_version = nil)
114
- ua =~ /CoreMedia/ && detect_version?(full_version, expected_version)
121
+ ua.include?("CoreMedia") && detect_version?(full_version,
122
+ expected_version)
115
123
  end
116
124
 
117
125
  # Detect if browser is PhantomJS
@@ -122,11 +130,11 @@ module Browser
122
130
 
123
131
  # Detect if browser is Safari.
124
132
  def safari?(expected_version = nil)
125
- Safari.new(ua).match? && detect_version?(version, expected_version)
133
+ Safari.new(ua).match? && detect_version?(full_version, expected_version)
126
134
  end
127
135
 
128
136
  def safari_webapp_mode?
129
- (device.ipad? || device.iphone?) && ua =~ /AppleWebKit/
137
+ (device.ipad? || device.iphone?) && ua.include?("AppleWebKit")
130
138
  end
131
139
 
132
140
  # Detect if browser is Firefox.
@@ -184,12 +192,53 @@ module Browser
184
192
 
185
193
  # Detect if browser is Opera Mini.
186
194
  def opera_mini?(expected_version = nil)
187
- ua =~ /Opera Mini/ && detect_version?(full_version, expected_version)
195
+ ua.include?("Opera Mini") && detect_version?(full_version,
196
+ expected_version)
188
197
  end
189
198
 
190
199
  # Detect if browser is DuckDuckGo.
191
200
  def duck_duck_go?(expected_version = nil)
192
- ua =~ /DuckDuckGo/ && detect_version?(full_version, expected_version)
201
+ ua.include?("DuckDuckGo") && detect_version?(full_version,
202
+ expected_version)
203
+ end
204
+
205
+ # Detect if browser is Samsung.
206
+ def samsung_browser?(expected_version = nil)
207
+ ua.include?("SamsungBrowser") && detect_version?(full_version,
208
+ expected_version)
209
+ end
210
+
211
+ # Detect if browser is Huawei.
212
+ def huawei_browser?(expected_version = nil)
213
+ HuaweiBrowser.new(ua).match? &&
214
+ detect_version?(full_version, expected_version)
215
+ end
216
+
217
+ # Detect if browser is Xiaomi Miui.
218
+ def miui_browser?(expected_version = nil)
219
+ MiuiBrowser.new(ua).match? &&
220
+ detect_version?(full_version, expected_version)
221
+ end
222
+
223
+ # Detect if browser is Maxthon.
224
+ def maxthon?(expected_version = nil)
225
+ Maxthon.new(ua).match? && detect_version?(full_version, expected_version)
226
+ end
227
+
228
+ # Detect if browser is QQ.
229
+ def qq?(expected_version = nil)
230
+ QQ.new(ua).match? && detect_version?(full_version, expected_version)
231
+ end
232
+
233
+ # Detect if browser is Sougou.
234
+ def sougou_browser?(expected_version = nil)
235
+ SougouBrowser.new(ua).match? &&
236
+ detect_version?(full_version, expected_version)
237
+ end
238
+
239
+ # Detect if browser is Google Search App
240
+ def google_search_app?(expected_version = nil)
241
+ ua.include?("GSA") && detect_version?(full_version, expected_version)
193
242
  end
194
243
 
195
244
  def webkit_full_version
@@ -197,7 +246,11 @@ module Browser
197
246
  end
198
247
 
199
248
  def known?
200
- id != :generic
249
+ !unknown?
250
+ end
251
+
252
+ def unknown?
253
+ id == :unknown_browser
201
254
  end
202
255
 
203
256
  # Detect if browser is a proxy browser.
@@ -209,5 +262,16 @@ module Browser
209
262
  def electron?(expected_version = nil)
210
263
  Electron.new(ua).match? && detect_version?(full_version, expected_version)
211
264
  end
265
+
266
+ private def validate_size(subject, input)
267
+ actual_bytesize = input.bytesize
268
+ size_limit = Browser.public_send("#{subject}_size_limit")
269
+
270
+ return if actual_bytesize < size_limit
271
+
272
+ raise Error,
273
+ "#{subject} cannot be larger than #{size_limit} bytes; " \
274
+ "actual size is #{actual_bytesize} bytes"
275
+ end
212
276
  end
213
277
  end
@@ -17,7 +17,7 @@ module Browser
17
17
  end
18
18
 
19
19
  def match?
20
- ua =~ /BlackBerry|BB10/
20
+ ua.match?(/BlackBerry|BB10/)
21
21
  end
22
22
  end
23
23
  end
@@ -4,7 +4,7 @@ module Browser
4
4
  class Bot
5
5
  class KeywordMatcher
6
6
  def self.call(ua, _browser)
7
- ua =~ /crawl|fetch|search|monitoring|spider|bot/
7
+ ua.match?(/crawl|fetch|search|monitoring|spider|bot/)
8
8
  end
9
9
  end
10
10
  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"
@@ -31,6 +31,12 @@ require_relative "yandex"
31
31
  require_relative "sputnik"
32
32
  require_relative "snapchat"
33
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"
34
40
 
35
41
  require_relative "bot"
36
42
  require_relative "bot/empty_user_agent_matcher"
@@ -45,10 +51,19 @@ require_relative "meta"
45
51
  module Browser
46
52
  EMPTY_STRING = ""
47
53
 
54
+ Error = Class.new(StandardError)
55
+
48
56
  def self.root
49
57
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
50
58
  end
51
59
 
60
+ class << self
61
+ attr_accessor :user_agent_size_limit, :accept_language_size_limit
62
+ end
63
+
64
+ self.user_agent_size_limit = 2048
65
+ self.accept_language_size_limit = 2048
66
+
52
67
  # Hold the list of browser matchers.
53
68
  # Order is important.
54
69
  def self.matchers
@@ -66,16 +81,22 @@ module Browser
66
81
  Instagram, # must be placed before Chrome and Safari
67
82
  Snapchat, # must be placed before Chrome and Safari
68
83
  Weibo, # must be placed before Chrome and Safari
84
+ MicroMessenger, # must be placed before QQ
69
85
  QQ, # must be placed before Chrome and Safari
70
86
  Alipay, # must be placed before Chrome and Safari
71
87
  Electron, # must be placed before Chrome and Safari
72
88
  Yandex, # must be placed before Chrome and Safari
73
89
  Sputnik, # must be placed before Chrome and Safari
74
90
  DuckDuckGo, # must be placed before Chrome and Safari
91
+ SamsungBrowser, # must be placed before Chrome and Safari
92
+ HuaweiBrowser, # must be placed before Chrome and Safari
93
+ MiuiBrowser, # must be placed before Chrome and Safari
94
+ Maxthon, # must be placed before Chrome and Safari
95
+ SougouBrowser, # must be placed before Chrome and Safari
96
+ GoogleSearchApp, # must be placed before Chrome and Safari
75
97
  Chrome,
76
98
  Safari,
77
- MicroMessenger,
78
- Generic
99
+ Unknown
79
100
  ]
80
101
  end
81
102
 
@@ -20,13 +20,20 @@ module Browser
20
20
  end
21
21
 
22
22
  def match?
23
- ua =~ /Chrome|CriOS/ &&
24
- ua !~ /PhantomJS|FxiOS|ArchiveBot/ &&
23
+ ua.match?(/Chrome|CriOS/) &&
24
+ !ua.match?(/PhantomJS|FxiOS|ArchiveBot/) &&
25
25
  !opera? &&
26
26
  !edge? &&
27
27
  !duck_duck_go? &&
28
28
  !yandex? &&
29
- !sputnik?
29
+ !sputnik? &&
30
+ !samsung_browser? &&
31
+ !huawei_browser? &&
32
+ !miui_browser? &&
33
+ !maxthon? &&
34
+ !qq? &&
35
+ !sougou_browser? &&
36
+ !google_search_app?
30
37
  end
31
38
  end
32
39
  end
@@ -20,6 +20,7 @@ require_relative "device/switch"
20
20
  require_relative "device/tv"
21
21
  require_relative "device/xbox_one"
22
22
  require_relative "device/xbox_360"
23
+ require_relative "device/samsung"
23
24
 
24
25
  module Browser
25
26
  class Device
@@ -29,6 +30,7 @@ module Browser
29
30
  # Order is important.
30
31
  def self.matchers
31
32
  @matchers ||= [
33
+ Samsung,
32
34
  XboxOne,
33
35
  Xbox360,
34
36
  Surface,
@@ -88,7 +90,7 @@ module Browser
88
90
  end
89
91
 
90
92
  def unknown?
91
- id == :unknown
93
+ id == :unknown_device
92
94
  end
93
95
 
94
96
  def ipod_touch?
@@ -158,12 +160,12 @@ module Browser
158
160
 
159
161
  # Detect if browser is Silk.
160
162
  def silk?
161
- ua =~ /Silk/
163
+ ua.include?("Silk")
162
164
  end
163
165
 
164
166
  # Detect if browser is running under Xbox.
165
167
  def xbox?
166
- ua =~ /Xbox/
168
+ ua.include?("Xbox")
167
169
  end
168
170
 
169
171
  # Detect if browser is running under Xbox 360.
@@ -191,13 +193,18 @@ module Browser
191
193
  xbox? || playstation? || nintendo?
192
194
  end
193
195
 
196
+ # Detect if device is a Samsung.
197
+ def samsung?
198
+ id == :samsung
199
+ end
200
+
194
201
  # Regex taken from http://detectmobilebrowsers.com
195
202
  # rubocop:disable Layout/LineLength
196
203
  private def detect_mobile?
197
204
  psp? ||
198
- /zunewp7/i.match(ua) ||
205
+ /zunewp7/i.match?(ua) ||
199
206
  %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])
207
+ %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
208
  end
202
209
  # rubocop:enable Layout/LineLength
203
210
 
@@ -13,7 +13,7 @@ module Browser
13
13
  end
14
14
 
15
15
  def match?
16
- ua =~ /Android/
16
+ ua.include?("Android")
17
17
  end
18
18
  end
19
19
  end
@@ -12,7 +12,7 @@ module Browser
12
12
  end
13
13
 
14
14
  def match?
15
- ua =~ /PlayBook.*?RIM Tablet/
15
+ ua.match?(/PlayBook.*?RIM Tablet/)
16
16
  end
17
17
  end
18
18
  end
@@ -12,7 +12,7 @@ module Browser
12
12
  end
13
13
 
14
14
  def match?
15
- ua =~ /iPad/
15
+ ua.include?("iPad")
16
16
  end
17
17
  end
18
18
  end
@@ -12,7 +12,7 @@ module Browser
12
12
  end
13
13
 
14
14
  def match?
15
- ua =~ /iPhone/
15
+ ua.include?("iPhone")
16
16
  end
17
17
  end
18
18
  end
@@ -12,7 +12,7 @@ module Browser
12
12
  end
13
13
 
14
14
  def match?
15
- ua =~ /iPod/
15
+ ua.include?("iPod")
16
16
  end
17
17
  end
18
18
  end
@@ -12,7 +12,7 @@ module Browser
12
12
  end
13
13
 
14
14
  def match?
15
- ua =~ /Kindle/
15
+ ua.include?("Kindle")
16
16
  end
17
17
  end
18
18
  end
@@ -12,7 +12,7 @@ module Browser
12
12
  end
13
13
 
14
14
  def match?
15
- ua =~ /Kindle Fire|KFTT/
15
+ ua.match?(/Kindle Fire|KFTT/)
16
16
  end
17
17
  end
18
18
  end
@@ -12,7 +12,7 @@ module Browser
12
12
  end
13
13
 
14
14
  def match?
15
- ua =~ /PLAYSTATION 3/i
15
+ ua.match?(/PLAYSTATION 3/i)
16
16
  end
17
17
  end
18
18
  end