device_detector 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -5
- data/CHANGELOG.md +3 -1
- data/README.md +5 -5
- data/Rakefile +16 -12
- data/lib/device_detector.rb +15 -0
- data/lib/device_detector/memory_cache.rb +21 -14
- data/lib/device_detector/os.rb +6 -3
- data/lib/device_detector/version.rb +3 -1
- data/regexes/bots.yml +73 -7
- data/regexes/client/browsers.yml +80 -2
- data/regexes/client/feed_readers.yml +7 -7
- data/regexes/client/libraries.yml +13 -1
- data/regexes/client/mediaplayers.yml +9 -5
- data/regexes/client/mobile_apps.yml +21 -0
- data/regexes/device/mobiles.yml +5616 -402
- data/regexes/device/televisions.yml +1 -1
- data/regexes/oss.yml +71 -13
- data/spec/device_detector/memory_cache_spec.rb +51 -19
- data/spec/device_detector_spec.rb +26 -55
- data/spec/fixtures/client/browser.yml +221 -96
- data/spec/fixtures/client/feed_reader.yml +0 -6
- data/spec/fixtures/client/library.yml +25 -1
- data/spec/fixtures/client/mediaplayer.yml +0 -12
- data/spec/fixtures/client/mobile_app.yml +24 -0
- data/spec/fixtures/detector/bots.yml +168 -3
- data/spec/fixtures/detector/desktop.yml +1422 -1422
- data/spec/fixtures/detector/feature_phone.yml +21 -1
- data/spec/fixtures/detector/feed_reader.yml +18 -5
- data/spec/fixtures/detector/mediaplayer.yml +33 -3
- data/spec/fixtures/detector/mobile_apps.yml +55 -6
- data/spec/fixtures/detector/phablet.yml +924 -164
- data/spec/fixtures/detector/smartphone-1.yml +4654 -4655
- data/spec/fixtures/detector/smartphone-10.yml +12362 -0
- data/spec/fixtures/detector/smartphone-11.yml +7639 -0
- data/spec/fixtures/detector/smartphone-2.yml +4232 -4247
- data/spec/fixtures/detector/smartphone-3.yml +4348 -4237
- data/spec/fixtures/detector/smartphone-4.yml +4110 -4103
- data/spec/fixtures/detector/smartphone-5.yml +5651 -2716
- data/spec/fixtures/detector/smartphone-6.yml +9896 -0
- data/spec/fixtures/detector/smartphone-7.yml +9899 -0
- data/spec/fixtures/detector/smartphone-8.yml +9945 -0
- data/spec/fixtures/detector/smartphone-9.yml +9916 -0
- data/spec/fixtures/detector/smartphone.yml +4114 -4013
- data/spec/fixtures/detector/tablet-1.yml +3857 -3857
- data/spec/fixtures/detector/tablet-2.yml +6681 -1787
- data/spec/fixtures/detector/tablet-3.yml +5134 -0
- data/spec/fixtures/detector/tablet.yml +3383 -3406
- data/spec/fixtures/detector/tv.yml +338 -24
- data/spec/fixtures/detector/unknown.yml +0 -120
- data/spec/fixtures/parser/oss.yml +135 -0
- metadata +17 -3
data/regexes/oss.yml
CHANGED
@@ -65,6 +65,13 @@
|
|
65
65
|
name: 'Windows IoT'
|
66
66
|
version: '10'
|
67
67
|
|
68
|
+
##########
|
69
|
+
# KaiOS
|
70
|
+
##########
|
71
|
+
- regex: 'KAIOS(?:/(\d+[\.\d]+))?'
|
72
|
+
name: 'KaiOS'
|
73
|
+
version: '$1'
|
74
|
+
|
68
75
|
##########
|
69
76
|
# Custom Android Roms
|
70
77
|
##########
|
@@ -84,10 +91,14 @@
|
|
84
91
|
name: 'MocorDroid'
|
85
92
|
version: '$1'
|
86
93
|
|
94
|
+
- regex: 'Fire OS(?:/(\d+[\.\d]*))?'
|
95
|
+
name: 'Fire OS'
|
96
|
+
version: '$1'
|
97
|
+
|
87
98
|
##########
|
88
99
|
# Android
|
89
100
|
##########
|
90
|
-
- regex: '(?:(?:Orca-)?Android|Adr)[ /](?:[a-z]+ )?(\d+[\.\d]
|
101
|
+
- regex: '(?:(?:Orca-)?Android|Adr)[ /](?:[a-z]+ )?(\d+[\.\d]*)'
|
91
102
|
name: 'Android'
|
92
103
|
version: '$1'
|
93
104
|
|
@@ -96,6 +107,10 @@
|
|
96
107
|
name: 'Android'
|
97
108
|
version: ''
|
98
109
|
|
110
|
+
- regex: '(?:TwitterAndroid).*[ /](?:[a-z]+ )?(\d+[\.\d]*)'
|
111
|
+
name: 'Android'
|
112
|
+
version: '$1'
|
113
|
+
|
99
114
|
- regex: 'BeyondPod|AntennaPod|Podkicker|DoggCatcher|Player FM|okhttp|Podcatcher Deluxe'
|
100
115
|
name: 'Android'
|
101
116
|
version: ''
|
@@ -249,12 +264,59 @@
|
|
249
264
|
- regex: 'Windows'
|
250
265
|
name: 'Windows'
|
251
266
|
version: ''
|
252
|
-
|
253
|
-
|
267
|
+
|
268
|
+
|
269
|
+
##########
|
270
|
+
# Haiku OS
|
271
|
+
##########
|
272
|
+
- regex: 'Haiku'
|
273
|
+
name: 'Haiku OS'
|
274
|
+
version: ''
|
275
|
+
|
254
276
|
|
255
277
|
##########
|
256
278
|
# iOS
|
257
279
|
##########
|
280
|
+
- regex: 'CFNetwork/889'
|
281
|
+
name: 'iOS'
|
282
|
+
version: '11.1'
|
283
|
+
|
284
|
+
- regex: 'CFNetwork/887.*(x86_64)'
|
285
|
+
name: 'Mac'
|
286
|
+
version: '10.13'
|
287
|
+
|
288
|
+
- regex: 'CFNetwork/887'
|
289
|
+
name: 'iOS'
|
290
|
+
version: '11.0'
|
291
|
+
|
292
|
+
- regex: 'CFNetwork/811.*(x86_64)'
|
293
|
+
name: 'Mac'
|
294
|
+
version: '10.12'
|
295
|
+
|
296
|
+
- regex: 'CFNetwork/811'
|
297
|
+
name: 'iOS'
|
298
|
+
version: '10.3'
|
299
|
+
|
300
|
+
- regex: 'CFNetwork/808\.3'
|
301
|
+
name: 'iOS'
|
302
|
+
version: '10.3'
|
303
|
+
|
304
|
+
- regex: 'CFNetwork/808\.2'
|
305
|
+
name: 'iOS'
|
306
|
+
version: '10.2'
|
307
|
+
|
308
|
+
- regex: 'CFNetwork/808\.1'
|
309
|
+
name: 'iOS'
|
310
|
+
version: '10.1'
|
311
|
+
|
312
|
+
- regex: 'CFNetwork/808\.0'
|
313
|
+
name: 'iOS'
|
314
|
+
version: '10.0'
|
315
|
+
|
316
|
+
- regex: 'CFNetwork/808'
|
317
|
+
name: 'iOS'
|
318
|
+
version: '10'
|
319
|
+
|
258
320
|
- regex: 'CFNetwork/758\.4\.3'
|
259
321
|
name: 'iOS'
|
260
322
|
version: '9.3.2'
|
@@ -355,7 +417,7 @@
|
|
355
417
|
name: 'iOS'
|
356
418
|
version: '$1'
|
357
419
|
|
358
|
-
- regex: 'Podcasts/(?:[\d\.]+)|Instacast(?:HD)?/(?:\d\.[\d\.abc]+)|Pocket Casts, iOS|Overcast|Castro|Podcat|i[cC]atcher'
|
420
|
+
- regex: 'Podcasts/(?:[\d\.]+)|Instacast(?:HD)?/(?:\d\.[\d\.abc]+)|Pocket Casts, iOS|Overcast|Castro|Podcat|i[cC]atcher|RSSRadio/'
|
359
421
|
name: 'iOS'
|
360
422
|
version: ''
|
361
423
|
|
@@ -368,6 +430,10 @@
|
|
368
430
|
# Mac
|
369
431
|
##########
|
370
432
|
|
433
|
+
- regex: 'CFNetwork/807'
|
434
|
+
name: 'Mac'
|
435
|
+
version: '10.12'
|
436
|
+
|
371
437
|
- regex: 'CFNetwork/760'
|
372
438
|
name: 'Mac'
|
373
439
|
version: '10.11'
|
@@ -408,7 +474,7 @@
|
|
408
474
|
name: 'Mac'
|
409
475
|
version: '10.2'
|
410
476
|
|
411
|
-
- regex: 'Mac OS X(?: (?:Version )?(\d+(?:[_\.]\d+)+))?'
|
477
|
+
- regex: 'Mac[ +]OS[ +]X(?:[ /](?:Version )?(\d+(?:[_\.]\d+)+))?'
|
412
478
|
name: 'Mac'
|
413
479
|
version: '$1'
|
414
480
|
|
@@ -458,14 +524,6 @@
|
|
458
524
|
version: ''
|
459
525
|
|
460
526
|
|
461
|
-
##########
|
462
|
-
# Haiku OS
|
463
|
-
##########
|
464
|
-
- regex: 'Haiku'
|
465
|
-
name: 'Haiku OS'
|
466
|
-
version: ''
|
467
|
-
|
468
|
-
|
469
527
|
##########
|
470
528
|
# BeOS
|
471
529
|
##########
|
@@ -1,15 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../spec_helper'
|
2
4
|
|
3
5
|
describe DeviceDetector::MemoryCache do
|
4
|
-
|
5
6
|
let(:subject) { DeviceDetector::MemoryCache.new(config) }
|
6
7
|
|
7
8
|
let(:config) { {} }
|
8
9
|
|
9
10
|
describe '#set' do
|
10
|
-
|
11
11
|
describe 'string key' do
|
12
|
-
|
13
12
|
let(:key) { 'string' }
|
14
13
|
|
15
14
|
it 'sets the value under the key' do
|
@@ -18,26 +17,63 @@ describe DeviceDetector::MemoryCache do
|
|
18
17
|
subject.data[key].must_equal 'value'
|
19
18
|
end
|
20
19
|
|
20
|
+
it 'returns the value' do
|
21
|
+
subject.set(key, 'value').must_equal 'value'
|
22
|
+
subject.set(key, false).must_equal false
|
23
|
+
assert_nil subject.set(key, nil)
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
describe 'array key' do
|
24
|
-
|
25
|
-
let(:key) { ['string1', 'string2'] }
|
28
|
+
let(:key) { %w[string1 string2] }
|
26
29
|
|
27
30
|
it 'sets the value under the key' do
|
28
31
|
subject.set(key, 'value')
|
29
32
|
|
30
33
|
subject.data[String(key)].must_equal 'value'
|
31
34
|
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'nil value' do
|
38
|
+
let(:key) { 'string' }
|
39
|
+
let(:internal_value) { DeviceDetector::MemoryCache::STORES_NIL_VALUE }
|
40
|
+
|
41
|
+
it 'sets the value under the key' do
|
42
|
+
subject.set(key, nil)
|
32
43
|
|
44
|
+
subject.data[String(key)].must_equal internal_value
|
45
|
+
assert_nil subject.get(key)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'sets the value under the key' do
|
49
|
+
subject.get_or_set(key, nil)
|
50
|
+
|
51
|
+
subject.data[String(key)].must_equal internal_value
|
52
|
+
assert_nil subject.get(key)
|
53
|
+
end
|
33
54
|
end
|
34
55
|
|
56
|
+
describe 'false value' do
|
57
|
+
let(:key) { 'string' }
|
58
|
+
|
59
|
+
it 'sets the value under the key' do
|
60
|
+
subject.set(key, false)
|
61
|
+
|
62
|
+
subject.data[String(key)].must_equal false
|
63
|
+
subject.get(key).must_equal false
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'sets the value under the key' do
|
67
|
+
subject.get_or_set(key, false)
|
68
|
+
|
69
|
+
subject.data[String(key)].must_equal false
|
70
|
+
subject.get(key).must_equal false
|
71
|
+
end
|
72
|
+
end
|
35
73
|
end
|
36
74
|
|
37
75
|
describe '#get' do
|
38
|
-
|
39
76
|
describe 'string key' do
|
40
|
-
|
41
77
|
let(:key) { 'string' }
|
42
78
|
|
43
79
|
it 'gets the value for the key' do
|
@@ -45,29 +81,23 @@ describe DeviceDetector::MemoryCache do
|
|
45
81
|
|
46
82
|
subject.get(key).must_equal 'value'
|
47
83
|
end
|
48
|
-
|
49
84
|
end
|
50
85
|
|
51
86
|
describe 'array key' do
|
52
|
-
|
53
|
-
let(:key) { ['string1', 'string2'] }
|
87
|
+
let(:key) { %w[string1 string2] }
|
54
88
|
|
55
89
|
it 'gets the value for the key' do
|
56
90
|
subject.data[String(key)] = 'value'
|
57
91
|
|
58
92
|
subject.get(key).must_equal 'value'
|
59
93
|
end
|
60
|
-
|
61
94
|
end
|
62
|
-
|
63
95
|
end
|
64
96
|
|
65
97
|
describe '#get_or_set' do
|
66
|
-
|
67
98
|
let(:key) { 'string' }
|
68
99
|
|
69
100
|
describe 'value already present' do
|
70
|
-
|
71
101
|
it 'gets the value for the key from cache' do
|
72
102
|
subject.data[key] = 'value'
|
73
103
|
|
@@ -80,10 +110,13 @@ describe DeviceDetector::MemoryCache do
|
|
80
110
|
block_called.must_equal false
|
81
111
|
end
|
82
112
|
|
113
|
+
it 'returns the value' do
|
114
|
+
subject.data[key] = 'value2'
|
115
|
+
subject.get_or_set(key, 'value').must_equal 'value2'
|
116
|
+
end
|
83
117
|
end
|
84
118
|
|
85
119
|
describe 'value not yet present' do
|
86
|
-
|
87
120
|
it 'evaluates the block and sets the result' do
|
88
121
|
block_called = false
|
89
122
|
subject.get_or_set(key) do
|
@@ -94,12 +127,13 @@ describe DeviceDetector::MemoryCache do
|
|
94
127
|
subject.data[key].must_equal true
|
95
128
|
end
|
96
129
|
|
130
|
+
it 'returns the value' do
|
131
|
+
subject.get_or_set(key, 'value').must_equal 'value'
|
132
|
+
end
|
97
133
|
end
|
98
|
-
|
99
134
|
end
|
100
135
|
|
101
136
|
describe 'cache purging' do
|
102
|
-
|
103
137
|
let(:config) { { max_cache_keys: 3 } }
|
104
138
|
|
105
139
|
it 'purges the cache when key size arrives at max' do
|
@@ -110,7 +144,5 @@ describe DeviceDetector::MemoryCache do
|
|
110
144
|
|
111
145
|
subject.data.keys.size.must_equal 3
|
112
146
|
end
|
113
|
-
|
114
147
|
end
|
115
|
-
|
116
148
|
end
|
@@ -1,218 +1,189 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'spec_helper'
|
2
4
|
|
3
5
|
describe DeviceDetector do
|
4
|
-
|
5
6
|
subject { DeviceDetector.new(user_agent) }
|
6
7
|
|
7
|
-
|
8
|
+
alias_method :client, :subject
|
8
9
|
|
9
10
|
describe 'known user agent' do
|
10
|
-
|
11
11
|
describe 'desktop chrome browser' do
|
12
|
-
|
13
12
|
let(:user_agent) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.69' }
|
14
13
|
|
15
14
|
describe '#name' do
|
16
|
-
|
17
15
|
it 'returns the name' do
|
18
16
|
client.name.must_equal 'Chrome'
|
19
17
|
end
|
20
|
-
|
21
18
|
end
|
22
19
|
|
23
20
|
describe '#full_version' do
|
24
|
-
|
25
21
|
it 'returns the full version' do
|
26
22
|
client.full_version.must_equal '30.0.1599.69'
|
27
23
|
end
|
24
|
+
end
|
28
25
|
|
26
|
+
describe '#os_family' do
|
27
|
+
it 'returns the operating system name' do
|
28
|
+
client.os_family.must_equal 'Mac'
|
29
|
+
end
|
29
30
|
end
|
30
31
|
|
31
32
|
describe '#os_name' do
|
32
|
-
|
33
33
|
it 'returns the operating system name' do
|
34
34
|
client.os_name.must_equal 'Mac'
|
35
35
|
end
|
36
|
-
|
37
36
|
end
|
38
37
|
|
39
38
|
describe '#os_full_version' do
|
40
|
-
|
41
39
|
it 'returns the operating system full version' do
|
42
40
|
client.os_full_version.must_equal '10.8.5'
|
43
41
|
end
|
44
|
-
|
45
42
|
end
|
46
43
|
|
47
44
|
describe '#known?' do
|
48
|
-
|
49
45
|
it 'returns true' do
|
50
46
|
client.known?.must_equal true
|
51
47
|
end
|
52
|
-
|
53
48
|
end
|
54
49
|
|
55
50
|
describe '#bot?' do
|
56
|
-
|
57
51
|
it 'returns false' do
|
58
52
|
client.bot?.must_equal false
|
59
53
|
end
|
60
|
-
|
61
54
|
end
|
62
55
|
|
63
56
|
describe '#bot_name' do
|
64
|
-
|
65
57
|
it 'returns nil' do
|
66
58
|
client.bot_name.must_be_nil
|
67
59
|
end
|
60
|
+
end
|
61
|
+
end
|
68
62
|
|
63
|
+
describe 'ubuntu linux' do
|
64
|
+
let(:user_agent) do
|
65
|
+
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#os_family' do
|
69
|
+
it 'returns the operating system name' do
|
70
|
+
client.os_family.must_equal 'GNU/Linux'
|
71
|
+
end
|
69
72
|
end
|
70
73
|
|
74
|
+
describe '#os_name' do
|
75
|
+
it 'returns the operating system name' do
|
76
|
+
client.os_name.must_equal 'Ubuntu'
|
77
|
+
end
|
78
|
+
end
|
71
79
|
end
|
72
80
|
|
73
81
|
describe 'firefox mobile phone' do
|
74
|
-
|
75
|
-
let(:user_agent) {'Mozilla/5.0 (Android 7.0; Mobile; rv:53.0) Gecko/53.0 Firefox/53.0'}
|
82
|
+
let(:user_agent) { 'Mozilla/5.0 (Android 7.0; Mobile; rv:53.0) Gecko/53.0 Firefox/53.0' }
|
76
83
|
|
77
84
|
it 'detects smartphone' do
|
78
85
|
client.device_type.must_equal 'smartphone'
|
79
86
|
end
|
80
|
-
|
81
87
|
end
|
82
88
|
|
83
89
|
describe 'firefox mobile tablet' do
|
84
|
-
|
85
|
-
let(:user_agent) {'Mozilla/5.0 (Android 6.0.1; Tablet; rv:47.0) Gecko/47.0 Firefox/47.0'}
|
90
|
+
let(:user_agent) { 'Mozilla/5.0 (Android 6.0.1; Tablet; rv:47.0) Gecko/47.0 Firefox/47.0' }
|
86
91
|
|
87
92
|
it 'detects tablet' do
|
88
93
|
client.device_type.must_equal 'tablet'
|
89
94
|
end
|
90
|
-
|
91
95
|
end
|
92
|
-
|
93
96
|
end
|
94
97
|
|
95
98
|
describe 'unknown user agent' do
|
96
|
-
|
97
99
|
let(:user_agent) { 'garbage123' }
|
98
100
|
|
99
101
|
describe '#name' do
|
100
|
-
|
101
102
|
it 'returns nil' do
|
102
103
|
client.name.must_be_nil
|
103
104
|
end
|
104
|
-
|
105
105
|
end
|
106
106
|
|
107
107
|
describe '#full_version' do
|
108
|
-
|
109
108
|
it 'returns nil' do
|
110
109
|
client.full_version.must_be_nil
|
111
110
|
end
|
112
|
-
|
113
111
|
end
|
114
112
|
|
115
113
|
describe '#os_name' do
|
116
|
-
|
117
114
|
it 'returns nil' do
|
118
115
|
client.os_name.must_be_nil
|
119
116
|
end
|
120
|
-
|
121
117
|
end
|
122
118
|
|
123
119
|
describe '#os_full_version' do
|
124
|
-
|
125
120
|
it 'returns nil' do
|
126
121
|
client.os_full_version.must_be_nil
|
127
122
|
end
|
128
|
-
|
129
123
|
end
|
130
124
|
|
131
125
|
describe '#known?' do
|
132
|
-
|
133
126
|
it 'returns false' do
|
134
127
|
client.known?.must_equal false
|
135
128
|
end
|
136
|
-
|
137
129
|
end
|
138
130
|
|
139
131
|
describe '#bot?' do
|
140
|
-
|
141
132
|
it 'returns false' do
|
142
133
|
client.bot?.must_equal false
|
143
134
|
end
|
144
|
-
|
145
135
|
end
|
146
136
|
|
147
137
|
describe '#bot_name' do
|
148
|
-
|
149
138
|
it 'returns nil' do
|
150
139
|
client.bot_name.must_be_nil
|
151
140
|
end
|
152
|
-
|
153
141
|
end
|
154
|
-
|
155
142
|
end
|
156
143
|
|
157
144
|
describe 'bot' do
|
158
|
-
|
159
145
|
let(:user_agent) { 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' }
|
160
146
|
|
161
147
|
describe '#name' do
|
162
|
-
|
163
148
|
it 'returns nil' do
|
164
149
|
client.name.must_be_nil
|
165
150
|
end
|
166
|
-
|
167
151
|
end
|
168
152
|
|
169
153
|
describe '#full_version' do
|
170
|
-
|
171
154
|
it 'returns nil' do
|
172
155
|
client.full_version.must_be_nil
|
173
156
|
end
|
174
|
-
|
175
157
|
end
|
176
158
|
|
177
159
|
describe '#os_name' do
|
178
|
-
|
179
160
|
it 'returns nil' do
|
180
161
|
client.os_name.must_be_nil
|
181
162
|
end
|
182
|
-
|
183
163
|
end
|
184
164
|
|
185
165
|
describe '#os_full_version' do
|
186
|
-
|
187
166
|
it 'returns nil' do
|
188
167
|
client.os_full_version.must_be_nil
|
189
168
|
end
|
190
|
-
|
191
169
|
end
|
192
170
|
|
193
171
|
describe '#known?' do
|
194
|
-
|
195
172
|
it 'returns false' do
|
196
173
|
client.known?.must_equal false
|
197
174
|
end
|
198
|
-
|
199
175
|
end
|
200
176
|
|
201
177
|
describe '#bot?' do
|
202
|
-
|
203
178
|
it 'returns true' do
|
204
179
|
client.bot?.must_equal true
|
205
180
|
end
|
206
|
-
|
207
181
|
end
|
208
182
|
|
209
183
|
describe '#bot_name' do
|
210
|
-
|
211
184
|
it 'returns the name of the bot' do
|
212
185
|
client.bot_name.must_equal 'Googlebot'
|
213
186
|
end
|
214
|
-
|
215
187
|
end
|
216
|
-
|
217
188
|
end
|
218
189
|
end
|