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
@@ -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,159 @@ 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
+ 'ORD' => 'Ordissimo',
112
+ 'PCL' => 'PCLinuxOS',
113
+ 'PSP' => 'PlayStation Portable',
114
+ 'PS3' => 'PlayStation',
115
+ 'RHT' => 'Red Hat',
116
+ 'ROS' => 'RISC OS',
117
+ 'RSO' => 'Rosa',
118
+ 'REM' => 'Remix OS',
119
+ 'REX' => 'REX',
120
+ 'RZD' => 'RazoDroiD',
121
+ 'SAB' => 'Sabayon',
122
+ 'SSE' => 'SUSE',
123
+ 'SAF' => 'Sailfish OS',
124
+ 'SEE' => 'SeewoOS',
125
+ 'SLW' => 'Slackware',
126
+ 'SOS' => 'Solaris',
127
+ 'SYL' => 'Syllable',
128
+ 'SYM' => 'Symbian',
129
+ 'SYS' => 'Symbian OS',
130
+ 'S40' => 'Symbian OS Series 40',
131
+ 'S60' => 'Symbian OS Series 60',
132
+ 'SY3' => 'Symbian^3',
133
+ 'TDX' => 'ThreadX',
134
+ 'TIZ' => 'Tizen',
135
+ 'TOS' => 'TmaxOS',
136
+ 'UBT' => 'Ubuntu',
137
+ 'WAS' => 'watchOS',
138
+ 'WTV' => 'WebTV',
139
+ 'WHS' => 'Whale OS',
140
+ 'WIN' => 'Windows',
141
+ 'WCE' => 'Windows CE',
142
+ 'WIO' => 'Windows IoT',
143
+ 'WMO' => 'Windows Mobile',
144
+ 'WPH' => 'Windows Phone',
145
+ 'WRT' => 'Windows RT',
146
+ 'XBX' => 'Xbox',
147
+ 'XBT' => 'Xubuntu',
148
+ 'YNS' => 'YunOs',
149
+ 'IOS' => 'iOS',
150
+ 'POS' => 'palmOS',
151
+ 'WOS' => 'webOS'
152
+ }.freeze
153
+
154
+ DOWNCASED_OPERATING_SYSTEMS = OPERATING_SYSTEMS.each_with_object({}) do |(short, long), h|
155
+ h[long.downcase] = short
156
+ end.freeze
128
157
 
129
158
  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
159
+ 'Android' => %w[AND CYN FIR REM RZD MLD MCD YNS GRI HAR],
160
+ 'AmigaOS' => %w[AMG MOR],
161
+ 'BlackBerry' => %w[BLB QNX],
162
+ 'Brew' => ['BMP'],
163
+ 'BeOS' => %w[BEO HAI],
164
+ 'Chrome OS' => %w[COS FYD SEE],
165
+ 'Firefox OS' => %w[FOS KOS],
166
+ 'Gaming Console' => %w[WII PS3],
167
+ 'Google TV' => ['GTV'],
168
+ 'IBM' => ['OS2'],
169
+ 'iOS' => %w[IOS ATV WAS IPA],
170
+ 'RISC OS' => ['ROS'],
171
+ 'GNU/Linux' => %w[
172
+ LIN ARL DEB KNO MIN UBT KBT XBT LBT FED
173
+ RHT VLN MDR GNT SAB SLW SSE CES BTR SAF
174
+ ORD TOS RSO DEE FRE MAG FEN CAI PCL HAS
175
+ LOS DVK
176
+ ],
177
+ 'Mac' => ['MAC'],
178
+ 'Mobile Gaming Console' => %w[PSP NDS XBX],
179
+ 'Real-time OS' => %w[MTK TDX MRE JME REX],
180
+ 'Other Mobile' => %w[WOS POS SBA TIZ SMG MAE],
181
+ 'Symbian' => %w[SYM SYS SY3 S60 S40],
182
+ 'Unix' => %w[SOS AIX HPX BSD NBS OBS DFB SYL IRI T64 INF],
183
+ 'WebTV' => ['WTV'],
184
+ 'Windows' => ['WIN'],
185
+ 'Windows Mobile' => %w[WPH WMO WCE WRT WIO],
186
+ 'Other Smart TV' => ['WHS']
187
+ }.freeze
188
+
189
+ FAMILY_TO_OS = OS_FAMILIES.each_with_object({}) do |(family, oss), h|
190
+ oss.each { |os| h[os] = family }
191
+ end.freeze
158
192
 
159
193
  def filenames
160
194
  ['oss.yml']
161
195
  end
162
-
163
196
  end
164
-
165
197
  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
@@ -77,6 +91,5 @@ class DeviceDetector
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.2'
4
+ VERSION = '1.0.6'
5
5
  end
@@ -1,12 +1,20 @@
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
+ super&.chomp('.')
12
+ end
3
13
 
4
14
  private
5
15
 
6
16
  def metadata_string
7
17
  String(regex_meta[:version])
8
18
  end
9
-
10
19
  end
11
20
  end
12
-