device_detector 0.9.1 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +49 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +5 -9
  5. data/CHANGELOG.md +16 -3
  6. data/README.md +7 -9
  7. data/Rakefile +19 -13
  8. data/device_detector.gemspec +1 -0
  9. data/lib/device_detector.rb +32 -28
  10. data/lib/device_detector/bot.rb +2 -2
  11. data/lib/device_detector/client.rb +3 -2
  12. data/lib/device_detector/device.rb +44 -21
  13. data/lib/device_detector/memory_cache.rb +26 -19
  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 +121 -111
  18. data/lib/device_detector/parser.rb +22 -9
  19. data/lib/device_detector/version.rb +3 -1
  20. data/lib/device_detector/version_extractor.rb +2 -3
  21. data/regexes/bots.yml +840 -20
  22. data/regexes/client/browser_engine.yml +11 -2
  23. data/regexes/client/browsers.yml +909 -108
  24. data/regexes/client/feed_readers.yml +38 -2
  25. data/regexes/client/libraries.yml +76 -2
  26. data/regexes/client/mediaplayers.yml +25 -5
  27. data/regexes/client/mobile_apps.yml +167 -2
  28. data/regexes/client/pim.yml +10 -1
  29. data/regexes/device/cameras.yml +1 -1
  30. data/regexes/device/car_browsers.yml +7 -3
  31. data/regexes/device/consoles.yml +3 -3
  32. data/regexes/device/mobiles.yml +10123 -465
  33. data/regexes/device/portable_media_player.yml +4 -6
  34. data/regexes/device/televisions.yml +18 -4
  35. data/regexes/oss.yml +115 -21
  36. data/regexes/vendorfragments.yml +6 -2
  37. data/spec/device_detector/concrete_user_agent_spec.rb +16 -17
  38. data/spec/device_detector/detector_fixtures_spec.rb +51 -11
  39. data/spec/device_detector/device_spec.rb +28 -48
  40. data/spec/device_detector/memory_cache_spec.rb +60 -28
  41. data/spec/device_detector/model_extractor_spec.rb +3 -3
  42. data/spec/device_detector/version_extractor_spec.rb +5 -6
  43. data/spec/device_detector_spec.rb +60 -69
  44. data/spec/fixtures/client/browser.yml +1785 -262
  45. data/spec/fixtures/client/feed_reader.yml +47 -35
  46. data/spec/fixtures/client/library.yml +112 -3
  47. data/spec/fixtures/client/mediaplayer.yml +32 -37
  48. data/spec/fixtures/client/mobile_app.yml +193 -6
  49. data/spec/fixtures/client/pim.yml +37 -18
  50. data/spec/fixtures/detector/bots.yml +1426 -118
  51. data/spec/fixtures/detector/camera.yml +36 -10
  52. data/spec/fixtures/detector/car_browser.yml +64 -3
  53. data/spec/fixtures/detector/console.yml +80 -26
  54. data/spec/fixtures/detector/desktop.yml +2222 -1589
  55. data/spec/fixtures/detector/feature_phone.yml +151 -42
  56. data/spec/fixtures/detector/feed_reader.yml +186 -121
  57. data/spec/fixtures/detector/mediaplayer.yml +113 -39
  58. data/spec/fixtures/detector/mobile_apps.yml +366 -21
  59. data/spec/fixtures/detector/phablet.yml +2597 -570
  60. data/spec/fixtures/detector/portable_media_player.yml +41 -16
  61. data/spec/fixtures/detector/smart_display.yml +8 -5
  62. data/spec/fixtures/detector/smart_speaker.yml +55 -0
  63. data/spec/fixtures/detector/smartphone-1.yml +5468 -5010
  64. data/spec/fixtures/detector/smartphone-10.yml +9977 -0
  65. data/spec/fixtures/detector/smartphone-11.yml +9891 -0
  66. data/spec/fixtures/detector/smartphone-12.yml +9906 -0
  67. data/spec/fixtures/detector/smartphone-13.yml +9920 -0
  68. data/spec/fixtures/detector/smartphone-14.yml +2662 -0
  69. data/spec/fixtures/detector/smartphone-2.yml +5213 -4635
  70. data/spec/fixtures/detector/smartphone-3.yml +5082 -4533
  71. data/spec/fixtures/detector/smartphone-4.yml +6806 -2625
  72. data/spec/fixtures/detector/smartphone-5.yml +9914 -0
  73. data/spec/fixtures/detector/smartphone-6.yml +9962 -0
  74. data/spec/fixtures/detector/smartphone-7.yml +9899 -0
  75. data/spec/fixtures/detector/smartphone-8.yml +9931 -0
  76. data/spec/fixtures/detector/smartphone-9.yml +9899 -0
  77. data/spec/fixtures/detector/smartphone.yml +5225 -4652
  78. data/spec/fixtures/detector/tablet-1.yml +4691 -4191
  79. data/spec/fixtures/detector/tablet-2.yml +9800 -71
  80. data/spec/fixtures/detector/tablet-3.yml +9959 -0
  81. data/spec/fixtures/detector/tablet-4.yml +4528 -0
  82. data/spec/fixtures/detector/tablet.yml +4664 -4177
  83. data/spec/fixtures/detector/tv.yml +3399 -1048
  84. data/spec/fixtures/detector/unknown.yml +1017 -977
  85. data/spec/fixtures/detector/wearable.yml +61 -0
  86. data/spec/fixtures/device/camera.yml +4 -3
  87. data/spec/fixtures/device/car_browser.yml +9 -2
  88. data/spec/fixtures/device/console.yml +15 -14
  89. data/spec/fixtures/parser/oss.yml +284 -2
  90. data/spec/fixtures/parser/vendorfragments.yml +8 -2
  91. metadata +50 -7
@@ -15,6 +15,11 @@ describe DeviceDetector do
15
15
  fail "Failed to parse #{fixture_file}, reason: #{e}"
16
16
  end
17
17
 
18
+ def str_or_nil(string)
19
+ return nil if string == ''
20
+ string
21
+ end
22
+
18
23
  fixtures.each do |f|
19
24
 
20
25
  user_agent = f["user_agent"]
@@ -24,29 +29,64 @@ describe DeviceDetector do
24
29
  describe user_agent do
25
30
  it "should be detected" do
26
31
  if detector.bot?
27
- assert_equal f["bot"]["name"], detector.bot_name, "failed bot name detection"
32
+ assert_equal str_or_nil(f["bot"]["name"]), detector.bot_name, "failed bot name detection"
28
33
  else
29
34
  if f["client"]
30
- assert_equal f["client"]["name"], detector.name, "failed client name detection"
35
+ assert_equal str_or_nil(f["client"]["name"]), detector.name, "failed client name detection"
31
36
  end
32
- if f["os_family"] != "Unknown"
33
- assert_equal f["os_family"], os.family, "failed os family detection"
34
- assert_equal f["os"]["name"], os.name, "failed os name detection"
35
- assert_equal f["os"]["short_name"], os.short_name, "failed os short name detection"
36
- assert_equal f["os"]["version"], os.full_version, "failed os version detection"
37
+
38
+ os_family = str_or_nil(f["os_family"])
39
+ if os_family != "Unknown"
40
+ if os_family.nil?
41
+ assert_nil os.family, "failed os family detection"
42
+ else
43
+ assert_equal os_family, os.family, "failed os family detection"
44
+ end
45
+
46
+ name = str_or_nil(f["os"]["name"])
47
+ if name.nil?
48
+ assert_nil os.name, "failed os name detection"
49
+ else
50
+ assert_equal name, os.name, "failed os name detection"
51
+ end
52
+
53
+ short_name = str_or_nil(f["os"]["short_name"])
54
+ if short_name.nil?
55
+ assert_nil os.short_name, "failed os short name detection"
56
+ else
57
+ assert_equal short_name, os.short_name, "failed os short name detection"
58
+ end
59
+
60
+ os_version = str_or_nil(f["os"]["version"])
61
+ if os_version.nil?
62
+ assert_nil os.full_version, "failed os version detection"
63
+ else
64
+ assert_equal os_version, os.full_version, "failed os version detection"
65
+ end
37
66
  end
38
67
  if f["device"]
39
- expected_type = f["device"]["type"]
68
+ expected_type = str_or_nil(f["device"]["type"])
40
69
  actual_type = detector.device_type
70
+
41
71
  if expected_type != actual_type
42
72
  # puts "\n", f.inspect, expected_type, actual_type, detector.device_name, regex_meta.inspect
43
73
  # debugger
44
74
  # detector.device_type
45
75
  end
46
- assert_equal expected_type, actual_type, "failed device type detection"
47
- model = f["device"]["model"]
76
+ if expected_type.nil?
77
+ assert_nil actual_type, "failed device type detection"
78
+ else
79
+ assert_equal expected_type, actual_type, "failed device type detection"
80
+ end
81
+
82
+ model = str_or_nil(f["device"]["model"])
48
83
  model = model.to_s unless model.nil?
49
- assert_equal model, detector.device_name, "failed device name detection"
84
+
85
+ if model.nil?
86
+ assert_nil detector.device_name, "failed device name detection"
87
+ else
88
+ assert_equal model, detector.device_name, "failed device name detection"
89
+ end
50
90
  end
51
91
  end
52
92
  end
@@ -1,18 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../spec_helper'
2
4
 
3
5
  describe DeviceDetector::Device do
4
-
5
6
  subject { DeviceDetector::Device.new(user_agent) }
6
7
 
7
- alias :device :subject
8
+ alias_method :device, :subject
8
9
 
9
10
  describe '#name' do
10
-
11
11
  describe 'when models are nested' do
12
12
  let(:user_agent) { 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B466 [FBDV/iPhone7,2]' }
13
13
 
14
14
  it 'finds an Apple iPhone 6' do
15
- device.name.must_equal 'iPhone 6'
15
+ value(device.name).must_equal 'iPhone 6'
16
16
  end
17
17
  end
18
18
 
@@ -20,7 +20,7 @@ describe DeviceDetector::Device do
20
20
  let(:user_agent) { 'AIRNESS-AIR99/REV 2.2.1/Teleca Q03B1' }
21
21
 
22
22
  it 'finds an Airness AIR99' do
23
- device.name.must_equal 'AIR99'
23
+ value(device.name).must_equal 'AIR99'
24
24
  end
25
25
  end
26
26
 
@@ -28,19 +28,17 @@ describe DeviceDetector::Device do
28
28
  let(:user_agent) { 'UNKNOWN MODEL NAME' }
29
29
 
30
30
  it 'returns nil' do
31
- device.name.must_be_nil
31
+ value(device.name).must_be_nil
32
32
  end
33
33
  end
34
-
35
34
  end
36
35
 
37
36
  describe '#type' do
38
-
39
37
  describe 'when models are nested' do
40
38
  let(:user_agent) { 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B466 [FBDV/iPhone7,2]' }
41
39
 
42
40
  it 'finds device of Apple iPhone 6' do
43
- device.type.must_equal 'smartphone'
41
+ value(device.type).must_equal 'smartphone'
44
42
  end
45
43
  end
46
44
 
@@ -48,7 +46,7 @@ describe DeviceDetector::Device do
48
46
  let(:user_agent) { 'AIRNESS-AIR99/REV 2.2.1/Teleca Q03B1' }
49
47
 
50
48
  it 'finds the device of Airness AIR99' do
51
- device.type.must_equal 'feature phone'
49
+ value(device.type).must_equal 'feature phone'
52
50
  end
53
51
  end
54
52
 
@@ -56,96 +54,78 @@ describe DeviceDetector::Device do
56
54
  let(:user_agent) { 'UNKNOWN MODEL TYPE' }
57
55
 
58
56
  it 'returns nil' do
59
- device.type.must_be_nil
57
+ value(device.type).must_be_nil
60
58
  end
61
-
62
59
  end
63
60
 
64
61
  describe 'device not specified in nested block' do
65
-
66
62
  let(:user_agent) { 'Mozilla/5.0 (Linux; Android 4.4.2; es-us; SAMSUNG SM-G900F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko)' }
67
63
 
68
64
  it 'falls back to top-level device' do
69
- device.type.must_equal 'smartphone'
65
+ value(device.type).must_equal 'smartphone'
70
66
  end
71
-
72
67
  end
73
-
74
68
  end
75
69
 
76
70
  describe 'concrete device types' do
77
-
78
71
  describe 'mobiles' do
79
-
80
72
  let(:user_agent) { 'Mozilla/5.0 (Linux; Android 4.4.2; es-us; SAMSUNG SM-G900F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko)' }
81
73
 
82
74
  it 'identifies the device' do
83
- device.name.must_equal 'GALAXY S5'
84
- device.type.must_equal 'smartphone'
85
- device.brand.must_equal 'Samsung'
75
+ value(device.name).must_equal 'GALAXY S5'
76
+ value(device.type).must_equal 'smartphone'
77
+ value(device.brand).must_equal 'Samsung'
86
78
  end
87
-
88
79
  end
89
80
 
90
81
  describe 'cameras' do
91
-
92
82
  let(:user_agent) { 'Mozilla/5.0 (Linux; U; Android 4.0; xx-xx; EK-GC100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' }
93
83
 
94
84
  it 'identifies the device' do
95
- device.name.must_equal 'GALAXY Camera'
96
- device.type.must_equal 'camera'
97
- device.brand.must_equal 'Samsung'
85
+ value(device.name).must_equal 'GALAXY Camera'
86
+ value(device.type).must_equal 'camera'
87
+ value(device.brand).must_equal 'Samsung'
98
88
  end
99
-
100
89
  end
101
90
 
102
91
  describe 'car browsers' do
103
-
104
92
  let(:user_agent) { 'Mozilla/5.0 (X11; Linux) AppleWebKit/534.34 (KHTML, like Gecko) QtCarBrowser Safari/534.34' }
105
93
 
106
94
  it 'identifies the device' do
107
- device.name.must_equal 'Model S'
108
- device.type.must_equal 'car browser'
109
- device.brand.must_be_nil
95
+ value(device.name).must_equal 'Model S'
96
+ value(device.type).must_equal 'car browser'
97
+ value(device.brand).must_equal 'Tesla'
110
98
  end
111
-
112
99
  end
113
100
 
114
101
  describe '(gaming) consoles' do
115
-
116
102
  let(:user_agent) { 'Opera/9.30 (Nintendo Wii; U; ; 2047-7;en)' }
117
103
 
118
104
  it 'identifies the device' do
119
- device.name.must_equal 'Wii'
120
- device.type.must_equal 'console'
121
- device.brand.must_be_nil
105
+ value(device.name).must_equal 'Wii'
106
+ value(device.type).must_equal 'console'
107
+ value(device.brand).must_be_nil
122
108
  end
123
-
124
109
  end
125
110
 
126
111
  describe 'portable media players' do
127
-
128
112
  let(:user_agent) { 'Mozilla/5.0 (iPod touch; CPU iPhone OS 7_0_6 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B651 Safari/9537.53' }
129
113
 
130
114
  it 'identifies the device' do
131
- device.name.must_equal 'iPod Touch'
132
- device.type.must_equal 'portable media player'
133
- device.brand.must_equal 'Apple'
115
+ value(device.name).must_equal 'iPod Touch'
116
+ value(device.type).must_equal 'portable media player'
117
+ value(device.brand).must_equal 'Apple'
134
118
  end
135
-
136
119
  end
137
120
 
138
121
  describe 'televisions' do
139
-
140
122
  let(:user_agent) { 'Mozilla/5.0 (Unknown; Linux armv7l) AppleWebKit/537.1+ (KHTML, like Gecko) Safari/537.1+ HbbTV/1.1.1 ( ;LGE ;NetCast 4.0 ;03.10.81 ;1.0M ;)' }
141
123
 
142
124
  it 'identifies the device' do
143
- device.name.must_equal 'NetCast 4.0'
144
- device.type.must_equal 'tv'
145
- device.brand.must_equal 'LG'
125
+ value(device.name).must_equal 'NetCast 4.0'
126
+ value(device.type).must_equal 'tv'
127
+ value(device.brand).must_equal 'LG'
146
128
  end
147
-
148
129
  end
149
130
  end
150
-
151
131
  end
@@ -1,73 +1,103 @@
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
16
15
  subject.set(key, 'value')
17
16
 
18
- subject.data[key].must_equal 'value'
17
+ value(subject.data[key]).must_equal 'value'
19
18
  end
20
19
 
20
+ it 'returns the value' do
21
+ value(subject.set(key, 'value')).must_equal 'value'
22
+ value(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
- subject.data[String(key)].must_equal 'value'
33
+ value(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
+ value(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
+ value(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
+ value(subject.data[String(key)]).must_equal false
63
+ value(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
+ value(subject.data[String(key)]).must_equal false
70
+ value(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
44
80
  subject.data[key] = 'value'
45
81
 
46
- subject.get(key).must_equal 'value'
82
+ value(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
- subject.get(key).must_equal 'value'
92
+ value(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
 
@@ -76,30 +106,34 @@ describe DeviceDetector::MemoryCache do
76
106
  block_called = true
77
107
  end
78
108
 
79
- value.must_equal 'value'
80
- block_called.must_equal false
109
+ value(value).must_equal 'value'
110
+ value(block_called).must_equal false
81
111
  end
82
112
 
113
+ it 'returns the value' do
114
+ subject.data[key] = 'value2'
115
+ value(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
90
123
  block_called = true
91
124
  end
92
125
 
93
- block_called.must_equal true
94
- subject.data[key].must_equal true
126
+ value(block_called).must_equal true
127
+ value(subject.data[key]).must_equal true
95
128
  end
96
129
 
130
+ it 'returns the value' do
131
+ value(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
@@ -108,9 +142,7 @@ describe DeviceDetector::MemoryCache do
108
142
  subject.set('3', 'baz')
109
143
  subject.set('4', 'boz')
110
144
 
111
- subject.data.keys.size.must_equal 3
145
+ value(subject.data.keys.size).must_equal 3
112
146
  end
113
-
114
147
  end
115
-
116
148
  end
@@ -23,7 +23,7 @@ describe DeviceDetector::ModelExtractor do
23
23
  let(:device_name) { 'iPhone' }
24
24
 
25
25
  it 'returns the textual portion without trailing whitespace' do
26
- extractor.call.must_equal device_name
26
+ value(extractor.call).must_equal device_name
27
27
  end
28
28
 
29
29
  end
@@ -33,7 +33,7 @@ describe DeviceDetector::ModelExtractor do
33
33
  let(:device_name) { 'iPhone 5S' }
34
34
 
35
35
  it 'returns the full device name' do
36
- extractor.call.must_equal device_name
36
+ value(extractor.call).must_equal device_name
37
37
  end
38
38
 
39
39
  end
@@ -53,7 +53,7 @@ describe DeviceDetector::ModelExtractor do
53
53
  end
54
54
 
55
55
  it 'returns the model name' do
56
- extractor.call.must_equal device_name
56
+ value(extractor.call).must_equal device_name
57
57
  end
58
58
 
59
59
  end