device_detector 1.0.2 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +49 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +5 -6
  5. data/CHANGELOG.md +11 -0
  6. data/README.md +8 -7
  7. data/Rakefile +7 -4
  8. data/device_detector.gemspec +1 -0
  9. data/lib/device_detector/bot.rb +2 -2
  10. data/lib/device_detector/browser.rb +364 -0
  11. data/lib/device_detector/client.rb +11 -2
  12. data/lib/device_detector/device.rb +1168 -22
  13. data/lib/device_detector/memory_cache.rb +5 -5
  14. data/lib/device_detector/metadata_extractor.rb +7 -8
  15. data/lib/device_detector/model_extractor.rb +3 -3
  16. data/lib/device_detector/name_extractor.rb +2 -2
  17. data/lib/device_detector/os.rb +148 -116
  18. data/lib/device_detector/parser.rb +22 -9
  19. data/lib/device_detector/version.rb +1 -1
  20. data/lib/device_detector/version_extractor.rb +10 -2
  21. data/lib/device_detector.rb +73 -40
  22. data/regexes/bots.yml +909 -59
  23. data/regexes/client/browser_engine.yml +14 -2
  24. data/regexes/client/browsers.yml +1356 -241
  25. data/regexes/client/feed_readers.yml +10 -10
  26. data/regexes/client/libraries.yml +75 -1
  27. data/regexes/client/mediaplayers.yml +39 -3
  28. data/regexes/client/mobile_apps.yml +524 -45
  29. data/regexes/client/pim.yml +55 -2
  30. data/regexes/device/cameras.yml +6 -6
  31. data/regexes/device/car_browsers.yml +23 -3
  32. data/regexes/device/consoles.yml +9 -3
  33. data/regexes/device/mobiles.yml +16903 -3199
  34. data/regexes/device/notebooks.yml +114 -0
  35. data/regexes/device/portable_media_player.yml +20 -3
  36. data/regexes/device/shell_tv.yml +117 -0
  37. data/regexes/device/televisions.yml +440 -35
  38. data/regexes/oss.yml +603 -165
  39. data/regexes/vendorfragments.yml +6 -2
  40. data/spec/device_detector/concrete_user_agent_spec.rb +38 -51
  41. data/spec/device_detector/detector_fixtures_spec.rb +36 -37
  42. data/spec/device_detector/device_spec.rb +52 -56
  43. data/spec/device_detector/memory_cache_spec.rb +19 -19
  44. data/spec/device_detector/model_extractor_spec.rb +3 -3
  45. data/spec/device_detector/version_extractor_spec.rb +5 -6
  46. data/spec/device_detector_spec.rb +26 -26
  47. data/spec/fixtures/client/browser.yml +2617 -555
  48. data/spec/fixtures/client/feed_reader.yml +34 -52
  49. data/spec/fixtures/client/library.yml +129 -38
  50. data/spec/fixtures/client/mediaplayer.yml +59 -28
  51. data/spec/fixtures/client/mobile_app.yml +589 -20
  52. data/spec/fixtures/client/pim.yml +92 -19
  53. data/spec/fixtures/detector/bots.yml +1749 -458
  54. data/spec/fixtures/detector/camera.yml +30 -24
  55. data/spec/fixtures/detector/car_browser.yml +199 -3
  56. data/spec/fixtures/detector/console.yml +107 -45
  57. data/spec/fixtures/detector/desktop.yml +3216 -758
  58. data/spec/fixtures/detector/feature_phone.yml +935 -181
  59. data/spec/fixtures/detector/feed_reader.yml +181 -193
  60. data/spec/fixtures/detector/mediaplayer.yml +157 -60
  61. data/spec/fixtures/detector/mobile_apps.yml +914 -136
  62. data/spec/fixtures/detector/peripheral.yml +271 -0
  63. data/spec/fixtures/detector/phablet.yml +5593 -1533
  64. data/spec/fixtures/detector/portable_media_player.yml +398 -32
  65. data/spec/fixtures/detector/smart_display.yml +183 -9
  66. data/spec/fixtures/detector/smart_speaker.yml +60 -0
  67. data/spec/fixtures/detector/smartphone-1.yml +3930 -4239
  68. data/spec/fixtures/detector/smartphone-10.yml +3985 -7366
  69. data/spec/fixtures/detector/smartphone-11.yml +5083 -3784
  70. data/spec/fixtures/detector/smartphone-12.yml +8989 -0
  71. data/spec/fixtures/detector/smartphone-13.yml +9412 -0
  72. data/spec/fixtures/detector/smartphone-14.yml +9477 -0
  73. data/spec/fixtures/detector/smartphone-15.yml +9281 -0
  74. data/spec/fixtures/detector/smartphone-16.yml +9678 -0
  75. data/spec/fixtures/detector/smartphone-17.yml +9965 -0
  76. data/spec/fixtures/detector/smartphone-18.yml +9806 -0
  77. data/spec/fixtures/detector/smartphone-19.yml +9965 -0
  78. data/spec/fixtures/detector/smartphone-2.yml +6670 -4375
  79. data/spec/fixtures/detector/smartphone-20.yml +9710 -0
  80. data/spec/fixtures/detector/smartphone-21.yml +8693 -0
  81. data/spec/fixtures/detector/smartphone-22.yml +10178 -0
  82. data/spec/fixtures/detector/smartphone-23.yml +9453 -0
  83. data/spec/fixtures/detector/smartphone-24.yml +9843 -0
  84. data/spec/fixtures/detector/smartphone-25.yml +9703 -0
  85. data/spec/fixtures/detector/smartphone-26.yml +10007 -0
  86. data/spec/fixtures/detector/smartphone-27.yml +4927 -0
  87. data/spec/fixtures/detector/smartphone-3.yml +4656 -4711
  88. data/spec/fixtures/detector/smartphone-4.yml +3518 -4479
  89. data/spec/fixtures/detector/smartphone-5.yml +3805 -4803
  90. data/spec/fixtures/detector/smartphone-6.yml +3745 -4693
  91. data/spec/fixtures/detector/smartphone-7.yml +3721 -4645
  92. data/spec/fixtures/detector/smartphone-8.yml +4564 -4699
  93. data/spec/fixtures/detector/smartphone-9.yml +3897 -4888
  94. data/spec/fixtures/detector/smartphone.yml +3154 -4141
  95. data/spec/fixtures/detector/tablet-1.yml +4742 -4576
  96. data/spec/fixtures/detector/tablet-2.yml +3803 -4731
  97. data/spec/fixtures/detector/tablet-3.yml +6210 -2309
  98. data/spec/fixtures/detector/tablet-4.yml +9062 -0
  99. data/spec/fixtures/detector/tablet-5.yml +9273 -0
  100. data/spec/fixtures/detector/tablet-6.yml +4588 -0
  101. data/spec/fixtures/detector/tablet.yml +3629 -4613
  102. data/spec/fixtures/detector/tv-1.yml +2501 -0
  103. data/spec/fixtures/detector/tv.yml +8856 -2064
  104. data/spec/fixtures/detector/unknown.yml +412 -587
  105. data/spec/fixtures/detector/wearable.yml +915 -0
  106. data/spec/fixtures/device/camera.yml +4 -3
  107. data/spec/fixtures/device/car_browser.yml +9 -2
  108. data/spec/fixtures/device/console.yml +15 -14
  109. data/spec/fixtures/device/notebook.yml +7 -0
  110. data/spec/fixtures/parser/oss.yml +1392 -21
  111. data/spec/fixtures/parser/vendorfragments.yml +57 -51
  112. metadata +70 -4
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
 
3
5
  require 'device_detector/version'
@@ -11,9 +13,9 @@ require 'device_detector/bot'
11
13
  require 'device_detector/client'
12
14
  require 'device_detector/device'
13
15
  require 'device_detector/os'
16
+ require 'device_detector/browser'
14
17
 
15
18
  class DeviceDetector
16
-
17
19
  attr_reader :user_agent
18
20
 
19
21
  def initialize(user_agent)
@@ -45,7 +47,10 @@ class DeviceDetector
45
47
  end
46
48
 
47
49
  def device_brand
48
- device.brand
50
+ # Assume all devices running iOS / Mac OS are from Apple
51
+ brand = device.brand
52
+ brand = 'Apple' if brand.nil? && ['Apple TV', 'iOS', 'Mac'].include?(os_name)
53
+ brand
49
54
  end
50
55
 
51
56
  def device_type
@@ -54,21 +59,24 @@ class DeviceDetector
54
59
  # Chrome on Android passes the device type based on the keyword 'Mobile'
55
60
  # If it is present the device should be a smartphone, otherwise it's a tablet
56
61
  # See https://developer.chrome.com/multidevice/user-agent#chrome_for_android_user_agent
57
- if t.nil? && os.family == 'Android' && ['Chrome', 'Chrome Mobile'].include?(name)
58
- if user_agent =~ build_regex('Chrome\/[\.0-9]* Mobile')
62
+ # Note: We do not check for browser (family) here, as there might be mobile apps using Chrome,
63
+ # that won't have a detected browser, but can still be detected. So we check the useragent for
64
+ # Chrome instead.
65
+ if t.nil? && os.family == 'Android' && user_agent =~ build_regex('Chrome\/[\.0-9]*')
66
+ if user_agent =~ build_regex('(?:Mobile|eliboM) Safari\/')
59
67
  t = 'smartphone'
60
- elsif user_agent =~ build_regex('Chrome\/[\.0-9]* (?!Mobile)')
68
+ elsif user_agent =~ build_regex('(?!Mobile )Safari\/')
61
69
  t = 'tablet'
62
70
  end
63
71
  end
64
72
 
65
- if t.nil? && android_tablet_fragment? || opera_tablet?
66
- t = 'tablet'
67
- end
73
+ # Some UA contain the fragment 'Android; Tablet;' or 'Opera Tablet', so we assume those devices
74
+ # as tablets
75
+ t = 'tablet' if t.nil? && android_tablet_fragment? || opera_tablet?
68
76
 
69
- if t.nil? && android_mobile_fragment?
70
- t = 'smartphone'
71
- end
77
+ # Some user agents simply contain the fragment 'Android; Mobile;', so we assume those devices
78
+ # as smartphones
79
+ t = 'smartphone' if t.nil? && android_mobile_fragment?
72
80
 
73
81
  # Android up to 3.0 was designed for smartphones only. But as 3.0,
74
82
  # which was tablet only, was published too late, there were a
@@ -78,46 +86,53 @@ class DeviceDetector
78
86
  # So were are expecting that all devices running Android < 2 are
79
87
  # smartphones Devices running Android 3.X are tablets. Device type
80
88
  # of Android 2.X and 4.X+ are unknown
81
- if t.nil? && os.short_name == 'AND' && os.full_version && !os.full_version.empty?
82
- if os.full_version < '2'
89
+ if t.nil? && os_name == 'Android' && os.full_version && !os.full_version.empty?
90
+ full_version = Gem::Version.new(os.full_version)
91
+ if full_version < VersionExtractor::MAJOR_VERSION_2
83
92
  t = 'smartphone'
84
- elsif os.full_version >= '3' && os.full_version < '4'
93
+ elsif full_version >= VersionExtractor::MAJOR_VERSION_3 && \
94
+ full_version < VersionExtractor::MAJOR_VERSION_4
85
95
  t = 'tablet'
86
96
  end
87
97
  end
88
98
 
89
99
  # All detected feature phones running android are more likely a smartphone
90
- if t == 'feature phone' && os.family == 'Android'
91
- t = 'smartphone'
92
- end
100
+ t = 'smartphone' if t == 'feature phone' && os.family == 'Android'
101
+
102
+ # All unknown devices under running Java ME are more likely a features phones
103
+ t = 'feature phone' if t.nil? && os_name == 'Java ME'
93
104
 
94
105
  # According to http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
95
- # Internet Explorer 10 introduces the "Touch" UA string token. If this token is present at the end of the
96
- # UA string, the computer has touch capability, and is running Windows 8 (or later).
106
+ # Internet Explorer 10 introduces the "Touch" UA string token. If this token is present at the
107
+ # end of the UA string, the computer has touch capability, and is running Windows 8 (or later).
97
108
  # This UA string will be transmitted on a touch-enabled system running Windows 8 (RT)
98
109
  #
99
- # As most touch enabled devices are tablets and only a smaller part are desktops/notebooks we assume that
100
- # all Windows 8 touch devices are tablets.
110
+ # As most touch enabled devices are tablets and only a smaller part are desktops/notebooks we
111
+ # assume that all Windows 8 touch devices are tablets.
101
112
  if t.nil? && touch_enabled? &&
102
- (os.short_name == 'WRT' || (os.short_name == 'WIN' && os.full_version && os.full_version >= '8'))
113
+ (os_name == 'Windows RT' ||
114
+ (os_name == 'Windows' && os.full_version &&
115
+ Gem::Version.new(os.full_version) >= VersionExtractor::MAJOR_VERSION_8))
103
116
  t = 'tablet'
104
117
  end
105
118
 
106
- if opera_tv_store?
107
- t = 'tv'
108
- end
119
+ # All devices running Opera TV Store are assumed to be a tv
120
+ t = 'tv' if opera_tv_store?
109
121
 
110
- if t.nil? && ['Kylo', 'Espial TV Browser'].include?(client.name)
111
- t = 'tv'
112
- end
122
+ # All devices running Tizen TV or SmartTV are assumed to be a tv
123
+ t = 'tv' if t.nil? && tizen_samsung_tv?
113
124
 
114
- # set device type to desktop for all devices running a desktop os that were
115
- # not detected as an other device type
116
- if t.nil? && os.desktop? && !puffin_browser?
117
- t = 'desktop'
118
- end
125
+ # Devices running Kylo or Espital TV Browsers are assumed to be a TV
126
+ t = 'tv' if t.nil? && ['Kylo', 'Espial TV Browser'].include?(client.name)
119
127
 
120
- t
128
+ has_desktop = t != 'desktop' && desktop_string? && desktop_fragment?
129
+ t = 'desktop' if has_desktop
130
+
131
+ # set device type to desktop for all devices running a desktop os that were not detected as
132
+ # another device type
133
+ return t if t || !desktop?
134
+
135
+ 'desktop'
121
136
  end
122
137
 
123
138
  def known?
@@ -133,7 +148,6 @@ class DeviceDetector
133
148
  end
134
149
 
135
150
  class << self
136
-
137
151
  class Configuration
138
152
  attr_accessor :max_cache_keys
139
153
 
@@ -152,11 +166,10 @@ class DeviceDetector
152
166
  @cache ||= MemoryCache.new(config.to_hash)
153
167
  end
154
168
 
155
- def configure(&block)
169
+ def configure
156
170
  @config = Configuration.new
157
171
  yield(config)
158
172
  end
159
-
160
173
  end
161
174
 
162
175
  private
@@ -185,6 +198,10 @@ class DeviceDetector
185
198
  user_agent =~ build_regex('Android(?: \d.\d(?:.\d)?)?; Mobile;')
186
199
  end
187
200
 
201
+ def desktop_fragment?
202
+ user_agent =~ build_regex('Desktop (x(?:32|64)|WOW64);')
203
+ end
204
+
188
205
  def touch_enabled?
189
206
  user_agent =~ build_regex('Touch')
190
207
  end
@@ -197,13 +214,29 @@ class DeviceDetector
197
214
  user_agent =~ build_regex('Opera Tablet')
198
215
  end
199
216
 
217
+ def tizen_samsung_tv?
218
+ user_agent =~ build_regex('SmartTV|Tizen.+ TV .+$')
219
+ end
220
+
221
+ def uses_mobile_browser?
222
+ client.browser? && client.mobile_only_browser?
223
+ end
224
+
200
225
  # This is a workaround until we support detecting mobile only browsers
201
- def puffin_browser?
202
- client.name == 'Puffin'
226
+ def desktop_string?
227
+ user_agent =~ /Desktop/
228
+ end
229
+
230
+ def desktop?
231
+ return false if os_name.nil? || os_name == '' || os_name == 'UNK'
232
+
233
+ # Check for browsers available for mobile devices only
234
+ return false if uses_mobile_browser?
235
+
236
+ os.desktop?
203
237
  end
204
238
 
205
239
  def build_regex(src)
206
240
  Regexp.new('(?:^|[^A-Z0-9\_\-])(?:' + src + ')', Regexp::IGNORECASE)
207
241
  end
208
-
209
242
  end