device_detector 1.0.1 → 1.0.2
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.
- 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
|