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
@@ -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
-