device_detector 1.0.3 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -51,12 +51,12 @@ class DeviceDetector
51
51
  def purge_cache
52
52
  key_size = data.size
53
53
 
54
- if key_size >= max_keys
55
- # always remove about 1/3 of keys to reduce garbage collecting
56
- amount_of_keys = key_size / 3
54
+ return if key_size < max_keys
57
55
 
58
- data.keys.first(amount_of_keys).each { |key| data.delete(key) }
59
- end
56
+ # always remove about 1/3 of keys to reduce garbage collecting
57
+ amount_of_keys = key_size / 3
58
+
59
+ data.keys.first(amount_of_keys).each { |key| data.delete(key) }
60
60
  end
61
61
  end
62
62
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class DeviceDetector
2
4
  class MetadataExtractor < Struct.new(:user_agent, :regex_meta)
3
-
4
5
  def call
5
6
  regex_meta.any? ? extract_metadata : nil
6
7
  end
@@ -8,22 +9,20 @@ class DeviceDetector
8
9
  private
9
10
 
10
11
  def metadata_string
11
- message = "#{self.name} (a child of MetadataExtractor) must implement the '#{__method__}' method."
12
- fail NotImplementedError, message
12
+ message = "#{name} (a child of MetadataExtractor) must implement the '#{__method__}' method."
13
+ raise NotImplementedError, message
13
14
  end
14
15
 
15
16
  def extract_metadata
16
17
  user_agent.match(regex) do |match_data|
17
- metadata_string.gsub(/\$(\d)/) {
18
- match_data[$1.to_i].to_s
19
- }.strip
18
+ metadata_string.gsub(/\$(\d)/) do
19
+ match_data[Regexp.last_match(1).to_i].to_s
20
+ end.strip
20
21
  end
21
22
  end
22
23
 
23
24
  def regex
24
25
  @regex ||= regex_meta[:regex]
25
26
  end
26
-
27
27
  end
28
28
  end
29
-
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class DeviceDetector
2
4
  class ModelExtractor < MetadataExtractor
3
-
4
5
  def call
5
- s = super.to_s.gsub('_',' ').strip
6
+ s = super.to_s.gsub('_', ' ').strip
6
7
  s = s.gsub(/ TD$/i, '')
7
8
 
8
9
  return nil if s == 'Build'
@@ -19,6 +20,5 @@ class DeviceDetector
19
20
  def regex
20
21
  @regex ||= regex_meta[:regex_model] || regex_meta[:regex]
21
22
  end
22
-
23
23
  end
24
24
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class DeviceDetector
2
4
  class NameExtractor < MetadataExtractor
3
-
4
5
  def call
5
6
  if /\$[0-9]/ =~ metadata_string
6
7
  extract_metadata
@@ -14,6 +15,5 @@ class DeviceDetector
14
15
  def metadata_string
15
16
  regex_meta[:name]
16
17
  end
17
-
18
18
  end
19
19
  end
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  class DeviceDetector
4
6
  class OS < Parser
5
-
6
7
  def name
7
8
  os_info[:name]
8
9
  end
@@ -29,7 +30,7 @@ class DeviceDetector
29
30
  def os_info
30
31
  from_cache(['os_info', self.class.name, user_agent]) do
31
32
  os_name = NameExtractor.new(user_agent, regex_meta).call
32
- if os_name && short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase]
33
+ if os_name && (short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase])
33
34
  os_name = OPERATING_SYSTEMS[short]
34
35
  else
35
36
  short = 'UNK'
@@ -38,128 +39,161 @@ class DeviceDetector
38
39
  end
39
40
  end
40
41
 
41
- DESKTOP_OSS = Set.new(['AmigaOS', 'IBM', 'GNU/Linux', 'Mac', 'Unix', 'Windows', 'BeOS', 'Chrome OS'])
42
+ DESKTOP_OSS = Set.new(
43
+ [
44
+ 'AmigaOS', 'IBM', 'GNU/Linux', 'Mac', 'Unix', 'Windows', 'BeOS', 'Chrome OS'
45
+ ]
46
+ )
42
47
 
43
48
  # OS short codes mapped to long names
44
49
  OPERATING_SYSTEMS = {
45
- 'AIX' => 'AIX',
46
- 'AND' => 'Android',
47
- 'AMG' => 'AmigaOS',
48
- 'ATV' => 'Apple TV',
49
- 'ARL' => 'Arch Linux',
50
- 'BTR' => 'BackTrack',
51
- 'SBA' => 'Bada',
52
- 'BEO' => 'BeOS',
53
- 'BLB' => 'BlackBerry OS',
54
- 'QNX' => 'BlackBerry Tablet OS',
55
- 'BMP' => 'Brew',
56
- 'CES' => 'CentOS',
57
- 'COS' => 'Chrome OS',
58
- 'CYN' => 'CyanogenMod',
59
- 'DEB' => 'Debian',
60
- 'DFB' => 'DragonFly',
61
- 'FED' => 'Fedora',
62
- 'FOS' => 'Firefox OS',
63
- 'FIR' => 'Fire OS',
64
- 'BSD' => 'FreeBSD',
65
- 'GNT' => 'Gentoo',
66
- 'GTV' => 'Google TV',
67
- 'HPX' => 'HP-UX',
68
- 'HAI' => 'Haiku OS',
69
- 'IRI' => 'IRIX',
70
- 'INF' => 'Inferno',
71
- 'KOS' => 'KaiOS',
72
- 'KNO' => 'Knoppix',
73
- 'KBT' => 'Kubuntu',
74
- 'LIN' => 'GNU/Linux',
75
- 'LBT' => 'Lubuntu',
76
- 'VLN' => 'VectorLinux',
77
- 'MAC' => 'Mac',
78
- 'MAE' => 'Maemo',
79
- 'MDR' => 'Mandriva',
80
- 'SMG' => 'MeeGo',
81
- 'MCD' => 'MocorDroid',
82
- 'MIN' => 'Mint',
83
- 'MLD' => 'MildWild',
84
- 'MOR' => 'MorphOS',
85
- 'NBS' => 'NetBSD',
86
- 'MTK' => 'MTK / Nucleus',
87
- 'WII' => 'Nintendo',
88
- 'NDS' => 'Nintendo Mobile',
89
- 'OS2' => 'OS/2',
90
- 'T64' => 'OSF1',
91
- 'OBS' => 'OpenBSD',
92
- 'PSP' => 'PlayStation Portable',
93
- 'PS3' => 'PlayStation',
94
- 'RHT' => 'Red Hat',
95
- 'ROS' => 'RISC OS',
96
- 'REM' => 'Remix OS',
97
- 'RZD' => 'RazoDroiD',
98
- 'SAB' => 'Sabayon',
99
- 'SSE' => 'SUSE',
100
- 'SAF' => 'Sailfish OS',
101
- 'SLW' => 'Slackware',
102
- 'SOS' => 'Solaris',
103
- 'SYL' => 'Syllable',
104
- 'SYM' => 'Symbian',
105
- 'SYS' => 'Symbian OS',
106
- 'S40' => 'Symbian OS Series 40',
107
- 'S60' => 'Symbian OS Series 60',
108
- 'SY3' => 'Symbian^3',
109
- 'TDX' => 'ThreadX',
110
- 'TIZ' => 'Tizen',
111
- 'UBT' => 'Ubuntu',
112
- 'WTV' => 'WebTV',
113
- 'WIN' => 'Windows',
114
- 'WCE' => 'Windows CE',
115
- 'WIO' => 'Windows IoT',
116
- 'WMO' => 'Windows Mobile',
117
- 'WPH' => 'Windows Phone',
118
- 'WRT' => 'Windows RT',
119
- 'XBX' => 'Xbox',
120
- 'XBT' => 'Xubuntu',
121
- 'YNS' => 'YunOs',
122
- 'IOS' => 'iOS',
123
- 'POS' => 'palmOS',
124
- 'WOS' => 'webOS'
125
- }
126
-
127
- DOWNCASED_OPERATING_SYSTEMS = OPERATING_SYSTEMS.each_with_object({}){|(short,long),h| h[long.downcase] = short}
50
+ 'AIX' => 'AIX',
51
+ 'AND' => 'Android',
52
+ 'AMG' => 'AmigaOS',
53
+ 'ATV' => 'tvOS',
54
+ 'ARL' => 'Arch Linux',
55
+ 'BTR' => 'BackTrack',
56
+ 'SBA' => 'Bada',
57
+ 'BEO' => 'BeOS',
58
+ 'BLB' => 'BlackBerry OS',
59
+ 'QNX' => 'BlackBerry Tablet OS',
60
+ 'BMP' => 'Brew',
61
+ 'CAI' => 'Caixa Mágica',
62
+ 'CES' => 'CentOS',
63
+ 'COS' => 'Chrome OS',
64
+ 'CYN' => 'CyanogenMod',
65
+ 'DEB' => 'Debian',
66
+ 'DEE' => 'Deepin',
67
+ 'DFB' => 'DragonFly',
68
+ 'DVK' => 'DVKBuntu',
69
+ 'FED' => 'Fedora',
70
+ 'FEN' => 'Fenix',
71
+ 'FOS' => 'Firefox OS',
72
+ 'FIR' => 'Fire OS',
73
+ 'FRE' => 'Freebox',
74
+ 'BSD' => 'FreeBSD',
75
+ 'FYD' => 'FydeOS',
76
+ 'GNT' => 'Gentoo',
77
+ 'GRI' => 'GridOS',
78
+ 'GTV' => 'Google TV',
79
+ 'HPX' => 'HP-UX',
80
+ 'HAI' => 'Haiku OS',
81
+ 'IPA' => 'iPadOS',
82
+ 'HAR' => 'HarmonyOS',
83
+ 'HAS' => 'HasCodingOS',
84
+ 'IRI' => 'IRIX',
85
+ 'INF' => 'Inferno',
86
+ 'JME' => 'Java ME',
87
+ 'KOS' => 'KaiOS',
88
+ 'KNO' => 'Knoppix',
89
+ 'KBT' => 'Kubuntu',
90
+ 'LIN' => 'GNU/Linux',
91
+ 'LBT' => 'Lubuntu',
92
+ 'LOS' => 'Lumin OS',
93
+ 'VLN' => 'VectorLinux',
94
+ 'MAC' => 'Mac',
95
+ 'MAE' => 'Maemo',
96
+ 'MAG' => 'Mageia',
97
+ 'MDR' => 'Mandriva',
98
+ 'SMG' => 'MeeGo',
99
+ 'MCD' => 'MocorDroid',
100
+ 'MIN' => 'Mint',
101
+ 'MLD' => 'MildWild',
102
+ 'MOR' => 'MorphOS',
103
+ 'NBS' => 'NetBSD',
104
+ 'MTK' => 'MTK / Nucleus',
105
+ 'MRE' => 'MRE',
106
+ 'WII' => 'Nintendo',
107
+ 'NDS' => 'Nintendo Mobile',
108
+ 'OS2' => 'OS/2',
109
+ 'T64' => 'OSF1',
110
+ 'OBS' => 'OpenBSD',
111
+ 'OWR' => 'OpenWrt',
112
+ 'ORD' => 'Ordissimo',
113
+ 'PCL' => 'PCLinuxOS',
114
+ 'PSP' => 'PlayStation Portable',
115
+ 'PS3' => 'PlayStation',
116
+ 'RHT' => 'Red Hat',
117
+ 'ROS' => 'RISC OS',
118
+ 'ROK' => 'Roku OS',
119
+ 'RSO' => 'Rosa',
120
+ 'REM' => 'Remix OS',
121
+ 'REX' => 'REX',
122
+ 'RZD' => 'RazoDroiD',
123
+ 'SAB' => 'Sabayon',
124
+ 'SSE' => 'SUSE',
125
+ 'SAF' => 'Sailfish OS',
126
+ 'SEE' => 'SeewoOS',
127
+ 'SLW' => 'Slackware',
128
+ 'SOS' => 'Solaris',
129
+ 'SYL' => 'Syllable',
130
+ 'SYM' => 'Symbian',
131
+ 'SYS' => 'Symbian OS',
132
+ 'S40' => 'Symbian OS Series 40',
133
+ 'S60' => 'Symbian OS Series 60',
134
+ 'SY3' => 'Symbian^3',
135
+ 'TDX' => 'ThreadX',
136
+ 'TIZ' => 'Tizen',
137
+ 'TOS' => 'TmaxOS',
138
+ 'UBT' => 'Ubuntu',
139
+ 'WAS' => 'watchOS',
140
+ 'WTV' => 'WebTV',
141
+ 'WHS' => 'Whale OS',
142
+ 'WIN' => 'Windows',
143
+ 'WCE' => 'Windows CE',
144
+ 'WIO' => 'Windows IoT',
145
+ 'WMO' => 'Windows Mobile',
146
+ 'WPH' => 'Windows Phone',
147
+ 'WRT' => 'Windows RT',
148
+ 'XBX' => 'Xbox',
149
+ 'XBT' => 'Xubuntu',
150
+ 'YNS' => 'YunOS',
151
+ 'IOS' => 'iOS',
152
+ 'POS' => 'palmOS',
153
+ 'WOS' => 'webOS'
154
+ }.freeze
155
+
156
+ DOWNCASED_OPERATING_SYSTEMS = OPERATING_SYSTEMS.each_with_object({}) do |(short, long), h|
157
+ h[long.downcase] = short
158
+ end.freeze
128
159
 
129
160
  OS_FAMILIES = {
130
- 'Android' => ['AND', 'CYN', 'FIR', 'REM', 'RZD', 'MLD', 'MCD', 'YNS'],
131
- 'AmigaOS' => ['AMG', 'MOR'],
132
- 'Apple TV' => ['ATV'],
133
- 'BlackBerry' => ['BLB', 'QNX'],
134
- 'Brew' => ['BMP'],
135
- 'BeOS' => ['BEO', 'HAI'],
136
- 'Chrome OS' => ['COS'],
137
- 'Firefox OS' => ['FOS', 'KOS'],
138
- 'Gaming Console' => ['WII', 'PS3'],
139
- 'Google TV' => ['GTV'],
140
- 'IBM' => ['OS2'],
141
- 'iOS' => ['IOS'],
142
- 'RISC OS' => ['ROS'],
143
- 'GNU/Linux' => ['LIN', 'ARL', 'DEB', 'KNO', 'MIN', 'UBT', 'KBT', 'XBT', 'LBT', 'FED', 'RHT', 'VLN', 'MDR', 'GNT', 'SAB', 'SLW', 'SSE', 'CES', 'BTR', 'SAF'],
144
- 'Mac' => ['MAC'],
145
- 'Mobile Gaming Console' => ['PSP', 'NDS', 'XBX'],
146
- 'Real-time OS' => ['MTK', 'TDX'],
147
- 'Other Mobile' => ['WOS', 'POS', 'SBA', 'TIZ', 'SMG', 'MAE'],
148
- 'Symbian' => ['SYM', 'SYS', 'SY3', 'S60', 'S40'],
149
- 'Unix' => ['SOS', 'AIX', 'HPX', 'BSD', 'NBS', 'OBS', 'DFB', 'SYL', 'IRI', 'T64', 'INF'],
150
- 'WebTV' => ['WTV'],
151
- 'Windows' => ['WIN'],
152
- 'Windows Mobile' => ['WPH', 'WMO', 'WCE', 'WRT', 'WIO']
153
- }
154
-
155
- FAMILY_TO_OS = OS_FAMILIES.each_with_object({}) do |(family,oss),h|
156
- oss.each{|os| h[os] = family}
157
- end
161
+ 'Android' => %w[AND CYN FIR REM RZD MLD MCD YNS GRI HAR],
162
+ 'AmigaOS' => %w[AMG MOR],
163
+ 'BlackBerry' => %w[BLB QNX],
164
+ 'Brew' => ['BMP'],
165
+ 'BeOS' => %w[BEO HAI],
166
+ 'Chrome OS' => %w[COS FYD SEE],
167
+ 'Firefox OS' => %w[FOS KOS],
168
+ 'Gaming Console' => %w[WII PS3],
169
+ 'Google TV' => ['GTV'],
170
+ 'IBM' => ['OS2'],
171
+ 'iOS' => %w[IOS ATV WAS IPA],
172
+ 'RISC OS' => ['ROS'],
173
+ 'GNU/Linux' => %w[
174
+ LIN ARL DEB KNO MIN UBT KBT XBT LBT FED
175
+ RHT VLN MDR GNT SAB SLW SSE CES BTR SAF
176
+ ORD TOS RSO DEE FRE MAG FEN CAI PCL HAS
177
+ LOS DVK ROK OWR
178
+ ],
179
+ 'Mac' => ['MAC'],
180
+ 'Mobile Gaming Console' => %w[PSP NDS XBX],
181
+ 'Real-time OS' => %w[MTK TDX MRE JME REX],
182
+ 'Other Mobile' => %w[WOS POS SBA TIZ SMG MAE],
183
+ 'Symbian' => %w[SYM SYS SY3 S60 S40],
184
+ 'Unix' => %w[SOS AIX HPX BSD NBS OBS DFB SYL IRI T64 INF],
185
+ 'WebTV' => ['WTV'],
186
+ 'Windows' => ['WIN'],
187
+ 'Windows Mobile' => %w[WPH WMO WCE WRT WIO],
188
+ 'Other Smart TV' => ['WHS']
189
+ }.freeze
190
+
191
+ FAMILY_TO_OS = OS_FAMILIES.each_with_object({}) do |(family, oss), h|
192
+ oss.each { |os| h[os] = family }
193
+ end.freeze
158
194
 
159
195
  def filenames
160
196
  ['oss.yml']
161
197
  end
162
-
163
198
  end
164
-
165
199
  end
@@ -1,7 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class DeviceDetector
2
- class Parser < Struct.new(:user_agent)
4
+ class Parser
5
+ ROOT = File.expand_path('../..', __dir__)
6
+
7
+ REGEX_CACHE = ::DeviceDetector::MemoryCache.new({})
8
+ private_constant :REGEX_CACHE
9
+
10
+ def initialize(user_agent)
11
+ @user_agent = user_agent
12
+ end
3
13
 
4
- ROOT = File.expand_path('../../..', __FILE__)
14
+ attr_reader :user_agent
5
15
 
6
16
  def name
7
17
  from_cache(['name', self.class.name, user_agent]) do
@@ -32,17 +42,17 @@ class DeviceDetector
32
42
  end
33
43
 
34
44
  def filenames
35
- fail NotImplementedError
45
+ raise NotImplementedError
36
46
  end
37
47
 
38
48
  def filepaths
39
49
  filenames.map do |filename|
40
- [ filename.to_sym, File.join(ROOT, 'regexes', filename) ]
50
+ [filename.to_sym, File.join(ROOT, 'regexes', filename)]
41
51
  end
42
52
  end
43
53
 
44
54
  def regexes_for(file_paths)
45
- from_cache(['regexes', self.class]) do
55
+ REGEX_CACHE.get_or_set(file_paths) do
46
56
  load_regexes(file_paths).flat_map { |path, regex| parse_regexes(path, regex) }
47
57
  end
48
58
  end
@@ -54,16 +64,20 @@ class DeviceDetector
54
64
  def symbolize_keys!(object)
55
65
  case object
56
66
  when Array
57
- object.map!{ |v| symbolize_keys!(v) }
67
+ object.map! { |v| symbolize_keys!(v) }
58
68
  when Hash
59
- object.keys.each{ |k| object[k.to_sym] = symbolize_keys!(object.delete(k)) if k.is_a?(String) }
69
+ keys = object.keys
70
+ keys.each do |k|
71
+ object[k.to_sym] = symbolize_keys!(object.delete(k)) if k.is_a?(String)
72
+ end
60
73
  end
61
74
  object
62
75
  end
63
76
 
64
77
  def parse_regexes(path, raw_regexes)
65
78
  raw_regexes.map do |meta|
66
- fail "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String
79
+ raise "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String
80
+
67
81
  meta[:regex] = build_regex(meta[:regex])
68
82
  meta[:path] = path
69
83
  meta
@@ -71,12 +85,11 @@ class DeviceDetector
71
85
  end
72
86
 
73
87
  def build_regex(src)
74
- Regexp.new('(?:^|[^A-Z0-9\-_]|[^A-Z0-9\-]_|sprd-)(?:' + src + ')', Regexp::IGNORECASE)
88
+ Regexp.new('(?:^|[^A-Z0-9\-_]|[^A-Z0-9\-]_|sprd-|MZ-)(?:' + src + ')', Regexp::IGNORECASE)
75
89
  end
76
90
 
77
91
  def from_cache(key)
78
92
  DeviceDetector.cache.get_or_set(key) { yield }
79
93
  end
80
-
81
94
  end
82
95
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class DeviceDetector
4
- VERSION = '1.0.3'
4
+ VERSION = '1.0.7'
5
5
  end
@@ -1,12 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class DeviceDetector
2
4
  class VersionExtractor < MetadataExtractor
5
+ MAJOR_VERSION_2 = Gem::Version.new('2.0')
6
+ MAJOR_VERSION_3 = Gem::Version.new('3.0')
7
+ MAJOR_VERSION_4 = Gem::Version.new('4.0')
8
+ MAJOR_VERSION_8 = Gem::Version.new('8.0')
9
+
10
+ def call
11
+ simple_version = super&.chomp('.')
12
+
13
+ return simple_version unless simple_version&.empty?
14
+
15
+ os_version_by_regexes
16
+ end
3
17
 
4
18
  private
5
19
 
20
+ def os_version_by_regexes
21
+ version_matches = regex_meta[:versions]
22
+ return '' unless version_matches
23
+
24
+ version_matches.detect do |matcher|
25
+ user_agent.match(matcher[:regex]) do |match_data|
26
+ return matcher[:version].gsub(/\$(\d)/) do
27
+ match_data[Regexp.last_match(1).to_i].to_s
28
+ end.strip
29
+ end
30
+ end
31
+
32
+ ''
33
+ end
34
+
6
35
  def metadata_string
7
36
  String(regex_meta[:version])
8
37
  end
9
-
10
38
  end
11
39
  end
12
-