device_detector 1.0.3 → 1.0.7

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 (94) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +8 -7
  4. data/lib/device_detector/bot.rb +2 -2
  5. data/lib/device_detector/browser.rb +364 -0
  6. data/lib/device_detector/client.rb +11 -2
  7. data/lib/device_detector/device.rb +1247 -22
  8. data/lib/device_detector/memory_cache.rb +5 -5
  9. data/lib/device_detector/metadata_extractor.rb +7 -8
  10. data/lib/device_detector/model_extractor.rb +3 -3
  11. data/lib/device_detector/name_extractor.rb +2 -2
  12. data/lib/device_detector/os.rb +150 -116
  13. data/lib/device_detector/parser.rb +23 -10
  14. data/lib/device_detector/version.rb +1 -1
  15. data/lib/device_detector/version_extractor.rb +29 -2
  16. data/lib/device_detector.rb +73 -40
  17. data/regexes/bots.yml +868 -62
  18. data/regexes/client/browser_engine.yml +11 -2
  19. data/regexes/client/browsers.yml +1132 -112
  20. data/regexes/client/feed_readers.yml +5 -11
  21. data/regexes/client/libraries.yml +86 -2
  22. data/regexes/client/mediaplayers.yml +39 -3
  23. data/regexes/client/mobile_apps.yml +940 -66
  24. data/regexes/client/pim.yml +66 -3
  25. data/regexes/device/cameras.yml +6 -6
  26. data/regexes/device/car_browsers.yml +23 -3
  27. data/regexes/device/consoles.yml +15 -3
  28. data/regexes/device/mobiles.yml +18351 -3566
  29. data/regexes/device/notebooks.yml +114 -0
  30. data/regexes/device/portable_media_player.yml +36 -9
  31. data/regexes/device/shell_tv.yml +117 -0
  32. data/regexes/device/televisions.yml +440 -35
  33. data/regexes/oss.yml +635 -284
  34. data/regexes/vendorfragments.yml +5 -1
  35. metadata +21 -118
  36. data/.gitignore +0 -14
  37. data/.travis.yml +0 -14
  38. data/Gemfile +0 -8
  39. data/Rakefile +0 -96
  40. data/device_detector.gemspec +0 -26
  41. data/spec/device_detector/bot_fixtures_spec.rb +0 -30
  42. data/spec/device_detector/client_fixtures_spec.rb +0 -31
  43. data/spec/device_detector/concrete_user_agent_spec.rb +0 -135
  44. data/spec/device_detector/detector_fixtures_spec.rb +0 -100
  45. data/spec/device_detector/device_fixtures_spec.rb +0 -36
  46. data/spec/device_detector/device_spec.rb +0 -151
  47. data/spec/device_detector/memory_cache_spec.rb +0 -148
  48. data/spec/device_detector/model_extractor_spec.rb +0 -63
  49. data/spec/device_detector/os_fixtures_spec.rb +0 -26
  50. data/spec/device_detector/version_extractor_spec.rb +0 -79
  51. data/spec/device_detector_spec.rb +0 -189
  52. data/spec/fixtures/client/browser.yml +0 -2206
  53. data/spec/fixtures/client/feed_reader.yml +0 -199
  54. data/spec/fixtures/client/library.yml +0 -175
  55. data/spec/fixtures/client/mediaplayer.yml +0 -163
  56. data/spec/fixtures/client/mobile_app.yml +0 -193
  57. data/spec/fixtures/client/pim.yml +0 -115
  58. data/spec/fixtures/detector/bots.yml +0 -3260
  59. data/spec/fixtures/detector/camera.yml +0 -121
  60. data/spec/fixtures/detector/car_browser.yml +0 -21
  61. data/spec/fixtures/detector/console.yml +0 -281
  62. data/spec/fixtures/detector/desktop.yml +0 -5361
  63. data/spec/fixtures/detector/feature_phone.yml +0 -891
  64. data/spec/fixtures/detector/feed_reader.yml +0 -551
  65. data/spec/fixtures/detector/mediaplayer.yml +0 -210
  66. data/spec/fixtures/detector/mobile_apps.yml +0 -456
  67. data/spec/fixtures/detector/phablet.yml +0 -3785
  68. data/spec/fixtures/detector/portable_media_player.yml +0 -178
  69. data/spec/fixtures/detector/smart_display.yml +0 -61
  70. data/spec/fixtures/detector/smartphone-1.yml +0 -9953
  71. data/spec/fixtures/detector/smartphone-10.yml +0 -9924
  72. data/spec/fixtures/detector/smartphone-11.yml +0 -9889
  73. data/spec/fixtures/detector/smartphone-12.yml +0 -8655
  74. data/spec/fixtures/detector/smartphone-2.yml +0 -9967
  75. data/spec/fixtures/detector/smartphone-3.yml +0 -9887
  76. data/spec/fixtures/detector/smartphone-4.yml +0 -9911
  77. data/spec/fixtures/detector/smartphone-5.yml +0 -9933
  78. data/spec/fixtures/detector/smartphone-6.yml +0 -9923
  79. data/spec/fixtures/detector/smartphone-7.yml +0 -9892
  80. data/spec/fixtures/detector/smartphone-8.yml +0 -9896
  81. data/spec/fixtures/detector/smartphone-9.yml +0 -9928
  82. data/spec/fixtures/detector/smartphone.yml +0 -9984
  83. data/spec/fixtures/detector/tablet-1.yml +0 -10023
  84. data/spec/fixtures/detector/tablet-2.yml +0 -9968
  85. data/spec/fixtures/detector/tablet-3.yml +0 -7787
  86. data/spec/fixtures/detector/tablet.yml +0 -9951
  87. data/spec/fixtures/detector/tv.yml +0 -3333
  88. data/spec/fixtures/detector/unknown.yml +0 -3283
  89. data/spec/fixtures/device/camera.yml +0 -19
  90. data/spec/fixtures/device/car_browser.yml +0 -7
  91. data/spec/fixtures/device/console.yml +0 -79
  92. data/spec/fixtures/parser/oss.yml +0 -1047
  93. data/spec/fixtures/parser/vendorfragments.yml +0 -162
  94. data/spec/spec_helper.rb +0 -9
@@ -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