wurfl_device 0.0.10 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,7 +29,7 @@ module WurflDevice
29
29
  method_option :yaml, :type => :boolean, :banner => "show the dump in yaml format", :aliases => "-y"
30
30
  def dump(device_id)
31
31
  device = WurflDevice.get_device_from_id(device_id)
32
- device = WurflDevice.get_device_from_ua(device_id, use_cache) if device.nil?
32
+ device = WurflDevice.get_device_from_ua(device_id) if device.nil?
33
33
 
34
34
  if options.json?
35
35
  WurflDevice.ui.info device.capabilities.to_json
@@ -103,6 +103,17 @@ module WurflDevice
103
103
  WurflDevice.ui.info " " + commify(devices.length) + " device id's"
104
104
  WurflDevice.ui.info " " + commify(user_agents.length) + " exact user agents" + user_agents_message
105
105
  WurflDevice.ui.info " " + commify(WurflDevice.get_user_agents_in_cache.length) + " user agents found in cache"
106
+ indexes = Array.new
107
+ WurflDevice.get_indexes.each do |index|
108
+ index.gsub!(WurflDevice::Constants::WURFL_DEVICES_INDEX, '')
109
+ indexes << "#{index}(" + commify(WurflDevice.get_user_agents_in_index(index).length) + ")"
110
+ end
111
+ indexes.sort!
112
+ WurflDevice.ui.info "wurfl user agent indexes:"
113
+ while !indexes.empty?
114
+ sub = indexes.slice!(0, 7)
115
+ WurflDevice.ui.info " " + sub.join(', ')
116
+ end
106
117
  WurflDevice.ui.info ""
107
118
  end
108
119
  map %w(stats stat info) => :status
@@ -7,6 +7,8 @@ module WurflDevice
7
7
 
8
8
  DB_INDEX = "7".freeze
9
9
  GENERIC = 'generic'
10
+ GENERIC_XHTML = 'generic_xhtml'
11
+ GENERIC_WEB_BROWSER = 'generic_web_browser'
10
12
  WURFL = "wurfl:"
11
13
  WURFL_INFO = "wurfl:info"
12
14
  WURFL_DEVICES = "wurfl:devices:"
@@ -16,14 +18,6 @@ module WurflDevice
16
18
  WURFL_USER_AGENTS = "wurfl:user_agents"
17
19
  WURFL_USER_AGENTS_CACHED = "wurfl:user_agents_cached"
18
20
 
19
- USER_AGENT_MATCHERS =
20
- [
21
- "Alcatel", "Android", "AOL", "Apple", "BenQ", "BlackBerry", "Bot", "CatchAll", "Chrome", "DoCoMo",
22
- "Firefox", "Grundig", "HTC", "Kddi", "Konqueror", "Kyocera", "LG", "Mitsubishi", "Motorola", "MSIE",
23
- "Nec", "Nintendo", "Nokia", "Opera", "OperaMini", "Panasonic", "Pantech", "Philips", "Portalmmm", "Qtek",
24
- "Safari", "Sagem", "Samsung", "Sanyo", "Sharp", "Siemens", "SonyEricsson", "SPV", "Toshiba", "Vodafone", "WindowsCE"
25
- ]
26
-
27
21
  MOBILE_BROWSERS = [
28
22
  'cldc', 'symbian', 'midp', 'j2me', 'mobile', 'wireless', 'palm', 'phone', 'pocket pc', 'pocketpc', 'netfront',
29
23
  'bolt', 'iris', 'brew', 'openwave', 'windows ce', 'wap2.', 'android', 'opera mini', 'opera mobi', 'maemo', 'fennec',
@@ -12,6 +12,7 @@ module WurflDevice
12
12
  else
13
13
  @capabilities = build_device(device_id)
14
14
  end
15
+ @capabilities['actual_device_root'] ||= ((@capabilities['user_agent'] !~ /^DO_NOT_MATCH/i) ? true : false)
15
16
  end
16
17
 
17
18
  def is_valid?
@@ -32,7 +33,7 @@ module WurflDevice
32
33
 
33
34
  capabilities['fall_back_tree'] ||= Array.new
34
35
 
35
- if !device['fall_back'].nil? && !device['fall_back'].empty? && device['id'] != WurflDevice::Constants::GENERIC
36
+ if !device['fall_back'].nil? && !device['fall_back'].empty? && device['fall_back'] != 'root'
36
37
  fall_back = build_device(device['fall_back'])
37
38
  unless fall_back.nil?
38
39
  capabilities['fall_back_tree'].unshift(fall_back['id'])
@@ -0,0 +1,139 @@
1
+ module WurflDevice
2
+ class UserAgent < String
3
+ def is_desktop_browser?
4
+ ua = self.downcase
5
+ WurflDevice::Constants::DESKTOP_BROWSERS.each do |sig|
6
+ return true if ua.index(sig)
7
+ end
8
+ return false
9
+ end
10
+
11
+ def is_mobile_browser?
12
+ ua = self.downcase
13
+ return false if self.is_desktop_browser?
14
+ return true if ua =~ /[^\d]\d{3}x\d{3}/
15
+ WurflDevice::Constants::DESKTOP_BROWSERS.each do |sig|
16
+ return true if ua.index(sig)
17
+ end
18
+ return false
19
+ end
20
+
21
+ def is_robot?
22
+ ua = self.downcase
23
+ WurflDevice::Constants::ROBOTS.each do |sig|
24
+ return true if ua.index(sig)
25
+ end
26
+ return false
27
+ end
28
+
29
+ def first_slash
30
+ pos = self.index('/')
31
+ return self.length if pos.nil?
32
+ return pos
33
+ end
34
+
35
+ def second_slash
36
+ first = self.index('/')
37
+ return self.length if first.nil?
38
+ second = self.index('/', first + 1)
39
+ return self.length if second.nil?
40
+ return second
41
+ end
42
+
43
+ def first_space
44
+ pos = self.index(' ')
45
+ return self.length if pos.nil?
46
+ return pos
47
+ end
48
+
49
+ def first_open_paren
50
+ pos = self.index('(')
51
+ return self.length if pos.nil?
52
+ return pos
53
+ end
54
+
55
+ def contains(find, ignore_case=false)
56
+ user_agent = self.downcase if ignore_case
57
+ user_agent = self unless ignore_case
58
+ if find.kind_of?(Array)
59
+ find.map do |needle|
60
+ needle = needle.downcase if ignore_case
61
+ return true unless user_agent.index(needle).nil?
62
+ end
63
+ return false
64
+ else
65
+ find = find.downcase if ignore_case
66
+ return true unless user_agent.index(find).nil?
67
+ return false
68
+ end
69
+ end
70
+
71
+ def starts_with(find, ignore_case=false)
72
+ user_agent = self.downcase if ignore_case
73
+ user_agent = self unless ignore_case
74
+ if find.kind_of?(Array)
75
+ find.map do |needle|
76
+ needle = needle.downcase if ignore_case
77
+ return true if user_agent.index(needle) == 0
78
+ end
79
+ return false
80
+ else
81
+ find = find.downcase if ignore_case
82
+ return true if user_agent.index(find) == 0
83
+ return false
84
+ end
85
+ end
86
+
87
+ def index_of_or_length(target, starting_index=nil)
88
+ length = self.length
89
+ return length if starting_index.nil?
90
+ if target.kind_of?(Array)
91
+ target.map do |needle|
92
+ next if needle.nil?
93
+ pos = self.index(needle, starting_index)
94
+ return pos unless pos.nil?
95
+ end
96
+ return length
97
+ else
98
+ pos = self.index(target, starting_index)
99
+ return length if pos.nil?
100
+ return pos unless pos.nil?
101
+ end
102
+ end
103
+
104
+ def ordinal_index_of(needle, ordinal)
105
+ return -1 if self.nil? || self.empty? || ordinal.is_a?(Integer)
106
+ found = 0
107
+ index = -1
108
+ begin
109
+ index = self.index(needle, index + 1)
110
+ index = index.is_a?(Integer) ? index : -1
111
+ return index if index < 0
112
+ found = found + 1
113
+ end while found < ordinal
114
+ return index
115
+ end
116
+
117
+ def cleaned
118
+ user_agent = self.dup
119
+ user_agent.sub!('UP.Link', '')
120
+ user_agent.replace($1) if user_agent =~ /^(.+)NOKIA-MSISDN\:\ (.+)$/i
121
+ user_agent.sub!("'M', 'Y' 'P', 'H', 'O', 'N', 'E'", "MyPhone")
122
+ user_agent.sub!('(null)', '')
123
+
124
+ # remove serial numbers
125
+ user_agent.sub!(/\/SN\d{15}/, '/SNXXXXXXXXXXXXXXX')
126
+ user_agent.sub!(/\[(ST|TF|NT)\d+\]/, '')
127
+
128
+ # remove locale identifiers
129
+ user_agent.sub!(/([ ;])[a-zA-Z]{2}-[a-zA-Z]{2}([ ;\)])/, '\1xx-xx\2')
130
+
131
+ pos = self.index('BlackBerry')
132
+ user_agent.replace(self.slice(pos, user_agent.length-pos)) unless pos.nil?
133
+
134
+ user_agent.sub!(/(Android \d\.\d)([^; \/\)]+)/, '\1')
135
+ user_agent.strip!
136
+ user_agent
137
+ end
138
+ end
139
+ end
@@ -2,53 +2,39 @@ require 'text'
2
2
 
3
3
  module WurflDevice
4
4
  class UserAgentMatcher
5
- attr_accessor :user_agent, :user_agent_cleaned, :device
5
+ attr_accessor :user_agent, :device
6
6
 
7
7
  def match(user_agent)
8
- @user_agent = user_agent
9
- @user_agent_cleaned = UserAgentMatcher.clean_user_agent(user_agent)
10
- @device = nil
8
+ @user_agent = UserAgent.new(user_agent)
11
9
 
12
10
  # exact match
13
11
  @device = WurflDevice.get_device_from_ua_cache(@user_agent)
14
- @device = WurflDevice.get_device_from_ua_cache(@user_agent_cleaned) if @device.nil?
12
+ @device = WurflDevice.get_device_from_ua_cache(@user_agent.cleaned) if @device.nil?
15
13
 
16
14
  # already in cache so return immediately
17
15
  return self if !@device.nil? && @device.is_valid?
18
16
 
19
17
  # ris match
18
+ user_agent = @user_agent.cleaned
20
19
  if @device.nil?
21
- user_agent = @user_agent
22
- user_agent_list = WurflDevice.get_user_agents_in_index(UserAgentMatcher.get_index(user_agent)).sort { |a, b| a[0] <=> b[0] }
23
- tolerance = UserAgentMatcher.first_slash(user_agent)-1
24
- curlen = user_agent.length
25
- while curlen >= tolerance
26
- user_agent_list.map do |ua, device_id|
27
- if ua.index(user_agent) == 0
28
- @device = Device.new(device_id)
29
- break
30
- end
20
+ index_matcher = get_index(user_agent)
21
+ matcher = "matcher_#{index_matcher.downcase}"
22
+ if self.respond_to?(matcher)
23
+ self.send(matcher, user_agent)
24
+ else
25
+ if user_agent =~ /^Mozilla/i
26
+ tolerance = 5
27
+ @device = ld_match(user_agent, tolerance)
28
+ else
29
+ tolerance = user_agent.first_slash
30
+ @device = ris_match(user_agent, tolerance)
31
31
  end
32
- break unless @device.nil?
33
- user_agent = user_agent.slice(0, curlen-1)
34
- curlen = user_agent.length
35
32
  end
36
33
  end
37
34
 
38
35
  # last attempts
39
36
  if @device.nil?
40
- user_agent = @user_agent
41
- device_id = WurflDevice::Constants::GENERIC
42
- device_id = 'opwv_v7_generic' if user_agent.index('UP.Browser/7')
43
- device_id = 'opwv_v6_generic' if user_agent.index('UP.Browser/6')
44
- device_id = 'upgui_generic' if user_agent.index('UP.Browser/5')
45
- device_id = 'uptext_generic' if user_agent.index('UP.Browser/4')
46
- device_id = 'uptext_generic' if user_agent.index('UP.Browser/3')
47
- device_id = 'nokia_generic_series60' if user_agent.index('Series60')
48
- device_id = 'generic_web_browser' if user_agent.index('Mozilla/4.0')
49
- device_id = 'generic_web_browser' if user_agent.index('Mozilla/5.0')
50
- device_id = 'generic_web_browser' if user_agent.index('Mozilla/6.0')
51
- @device = WurflDevice.get_device_from_id(device_id)
37
+ last_attempts(user_agent)
52
38
  end
53
39
 
54
40
  WurflDevice.save_device_in_ua_cache(@user_agent, @device)
@@ -56,101 +42,589 @@ module WurflDevice
56
42
  return self
57
43
  end
58
44
 
59
- class << self
60
- def get_index(user_agent)
61
- # create device index
62
- matcher = 'Generic'
63
- WurflDevice::Constants::USER_AGENT_MATCHERS.each do |m|
64
- if Regexp.new(m, Regexp::IGNORECASE) =~ user_agent
65
- matcher = m
45
+ def ris_match(user_agent, tolerance)
46
+ device = nil
47
+ user_agent_list = WurflDevice.get_user_agents_in_index(get_index(user_agent))
48
+ curlen = user_agent.length
49
+ while curlen >= tolerance
50
+ user_agent_list.each do |ua|
51
+ next if ua.length < curlen
52
+ if ua.index(user_agent) == 0
53
+ device = WurflDevice.get_device_from_ua_cache(ua, true)
66
54
  break
67
55
  end
68
56
  end
69
- return matcher
57
+ break unless device.nil?
58
+ user_agent = user_agent.slice(0, curlen-1)
59
+ curlen = user_agent.length
60
+ end
61
+ return device
62
+ end
63
+
64
+ def ld_match(user_agent, tolerance=nil)
65
+ tolerance = 7 if tolerance.nil?
66
+ device = nil
67
+ user_agent_list = WurflDevice.get_user_agents_in_index(get_index(user_agent))
68
+
69
+ length = user_agent.length
70
+ best = tolerance
71
+ current = 0
72
+ match = nil
73
+ user_agent_list.select do |ua|
74
+ next if !ua.length.between?(length - tolerance, length + tolerance)
75
+ current = Text::Levenshtein.distance(ua, user_agent)
76
+ if current <= best
77
+ best = current
78
+ match = ua
79
+ end
80
+ puts "#{current}: #{ua}"
70
81
  end
71
82
 
72
- def clean_user_agent(user_agent)
73
- user_agent = remove_up_link_from_ua(user_agent)
83
+ device = WurflDevice.get_device_from_ua_cache(match, true)
84
+ return device
85
+ end
74
86
 
75
- # remove nokia-msisdn header
76
- user_agent = remove_nokia_msisdn(user_agent)
87
+ def get_index(user_agent)
88
+ ua = UserAgent.new(user_agent)
89
+ # Process MOBILE user agents
90
+ unless ua.is_desktop_browser?
91
+ return 'Nokia' if ua.contains('Nokia')
92
+ return 'Samsung' if ua.contains(['Samsung/SGH', 'SAMSUNG-SGH']) || ua.starts_with(['SEC-', 'Samsung', 'SAMSUNG', 'SPH', 'SGH', 'SCH']) || ua.starts_with('samsung', true)
93
+ return 'BlackBerry' if ua.contains('blackberry', true)
94
+ return 'SonyEricsson' if ua.contains('Sony')
95
+ return 'Motorola' if ua.starts_with(['Mot-', 'MOT-', 'MOTO', 'moto']) || ua.contains('Motorola')
77
96
 
78
- # clean up myphone id's
79
- user_agent = user_agent.sub("'M', 'Y' 'P', 'H', 'O', 'N', 'E'", "MyPhone")
80
-
81
- # remove serial numbers
82
- user_agent = user_agent.sub(/\/SN\d{15}/, '/SNXXXXXXXXXXXXXXX')
83
- user_agent = user_agent.sub(/\[(ST|TF|NT)\d+\]/, '')
97
+ return 'Alcatel' if ua.starts_with('alcatel', true)
98
+ return 'Apple' if ua.contains(['iPhone', 'iPod', 'iPad', '(iphone'])
99
+ return 'BenQ' if ua.starts_with('benq', true)
100
+ return 'DoCoMo' if ua.starts_with('DoCoMo')
101
+ return 'Grundig' if ua.starts_with('grundig', true)
102
+ return 'HTC' if ua.contains(['HTC', 'XV6875'])
103
+ return 'Kddi' if ua.contains('KDDI-')
104
+ return 'Kyocera' if ua.starts_with(['kyocera', 'QC-', 'KWC-'])
105
+ return 'LG' if ua.starts_with('lg', true)
106
+ return 'Mitsubishi' if ua.starts_with('Mitsu')
107
+ return 'Nec' if ua.starts_with(['NEC-', 'KGT'])
108
+ return 'Nintendo' if ua.contains('Nintendo') || (ua.starts_with('Mozilla/') && ua.starts_with('Nitro') && ua.starts_with('Opera'))
109
+ return 'Panasonic' if ua.contains('Panasonic')
110
+ return 'Pantech' if ua.starts_with(['Pantech', 'PT-', 'PANTECH', 'PG-'])
111
+ return 'Philips' if ua.starts_with('philips', true)
112
+ return 'Portalmmm' if ua.starts_with('portalmmm')
113
+ return 'Qtek' if ua.starts_with('Qtek')
114
+ return 'Sagem' if ua.starts_with('sagem', true)
115
+ return 'Sharp' if ua.starts_with('sharp', true)
116
+ return 'Siemens' if ua.starts_with('SIE-')
117
+ return 'SPV' if ua.starts_with('SPV')
118
+ return 'Toshiba' if ua.starts_with('Toshiba')
119
+ return 'Vodafone' if ua.starts_with('Vodafone')
84
120
 
85
- # remove locale identifiers
86
- user_agent = user_agent.sub(/([ ;])[a-zA-Z]{2}-[a-zA-Z]{2}([ ;\)])/, '\1xx-xx\2')
121
+ # mobile browsers
122
+ return 'Android' if ua.contains('Android')
123
+ return 'OperaMini' if ua.contains(['Opera Mini', 'Opera Mobi'])
124
+ return 'WindowsCE' if ua.contains('Mozilla/') && ua.contains('Windows CE')
125
+ end
87
126
 
88
- user_agent = normalize_blackberry(user_agent)
89
- user_agent = normalize_android(user_agent)
127
+ # Process Robots (Web Crawlers and the like)
128
+ return 'Bot' if ua.is_robot?
90
129
 
91
- return user_agent.strip
130
+ # Process NON-MOBILE user agents
131
+ unless ua.is_mobile_browser?
132
+ return 'MSIE' if ua.starts_with('Mozilla') && ua.contains('MSIE') && !ua.contains(['Opera', 'armv', 'MOTO', 'BREW'])
133
+ return 'Firefox' if ua.contains('Firefox') && !ua.contains(['Sony', 'Novarra', 'Opera'])
134
+ return 'Chrome' if ua.contains('Chrome')
135
+ return 'Konqueror' if ua.contains('Konqueror')
136
+ return 'Opera' if ua.contains('Opera')
137
+ return 'Safari' if ua.starts_with('Mozilla') && ua.contains('Safari')
138
+ return 'AOL' if ua.contains(['AOL', 'America Online']) || ua.contains('aol 9', true)
92
139
  end
93
140
 
94
- def first_slash(user_agent)
95
- pos = user_agent.index('/')
96
- return user_agent.length if pos.nil?
97
- return pos
141
+ return 'CatchAll'
142
+ end
143
+
144
+ private
145
+ # user agent matchers
146
+ def last_attempts(user_agent)
147
+ device_id = case
148
+ # OpenWave
149
+ when user_agent.contains('UP.Browser/7.2')
150
+ 'opwv_v72_generic'
151
+ when user_agent.contains('UP.Browser/7')
152
+ 'opwv_v7_generic'
153
+ when user_agent.contains('UP.Browser/6.2')
154
+ 'opwv_v62_generic'
155
+ when user_agent.contains('UP.Browser/6')
156
+ 'opwv_v6_generic'
157
+ when user_agent.contains('UP.Browser/5')
158
+ 'upgui_generic'
159
+ when user_agent.contains('UP.Browser/4')
160
+ 'uptext_generic'
161
+ when user_agent.contains('UP.Browser/3')
162
+ 'uptext_generic'
163
+ # Series 60
164
+ when user_agent.contains('Series60')
165
+ 'nokia_generic_series60'
166
+ when user_agent.contains('Series80')
167
+ 'nokia_generic_series80'
168
+ # Access/Net Front
169
+ when user_agent.contains(['NetFront/3.0', 'ACS-NF/3.0'])
170
+ 'generic_netfront_ver3'
171
+ when user_agent.contains(['NetFront/3.1', 'ACS-NF/3.1'])
172
+ 'generic_netfront_ver3_1'
173
+ when user_agent.contains(['NetFront/3.2', 'ACS-NF/3.2'])
174
+ 'generic_netfront_ver3_2'
175
+ when user_agent.contains(['NetFront/3.3', 'ACS-NF/3.3'])
176
+ 'generic_netfront_ver3_3'
177
+ when user_agent.contains('NetFront/3.4')
178
+ 'generic_netfront_ver3_4'
179
+ when user_agent.contains('NetFront/3.5')
180
+ 'generic_netfront_ver3_5'
181
+ # Contains Mozilla/, but not at the beginning of the UA
182
+ when user_agent.starts_with('Mozilla/') || @user_agent.contains('Mozilla/')
183
+ WurflDevice::Constants::GENERIC_XHTML
184
+ # Obigo
185
+ when user_agent.contains(['ObigoInternetBrowser/Q03C', 'AU-MIC/2', 'AU-MIC-', 'AU-OBIGO', 'Obigo/Q03', 'Obigo/Q04', 'ObigoInternetBrowser/2', 'Teleca Q03B1'])
186
+ WurflDevice::Constants::GENERIC_XHTML
187
+ # DoCoMo
188
+ when user_agent.starts_with('DoCoMo') || @user_agent.starts_with('KDDI')
189
+ 'docomo_generic_jap_ver1'
190
+ # Generic Mozilla
191
+ when user_agent.contains(['Mozilla/4.0', 'Mozilla/5.0', 'Mozilla/6.0'])
192
+ WurflDevice::Constants::GENERIC_WEB_BROWSER
193
+ else
194
+ WurflDevice::Constants::GENERIC
98
195
  end
196
+ @device = WurflDevice.get_device_from_id(device_id)
197
+ end
198
+
199
+ # mobile user agents
200
+ def match_nokia(user_agent)
201
+ tolerance = user_agent.index_of_or_length(['/', ' '], user_agent.index('Nokia'))
202
+ @device = ris_match(user_agent, tolerance)
203
+ end
99
204
 
100
- def second_slash(user_agent)
101
- first = user_agent.index('/')
102
- return user_agent.length if first.nil?
103
- first = first + 1
104
- second = user_agent.index('/', first)
105
- return user_agent.length if second.nil?
106
- return second
205
+ def matcher_samsung(user_agent)
206
+ if user_agent.starts_with('SAMSUNG') || user_agent.starts_with('SEC-') || user_agent.starts_with('SCH-')
207
+ tolerance = user_agent.first_slash
208
+ elsif user_agent.starts_with('Samsung') || user_agent.starts_with('SPH') || user_agent.starts_with('SGH')
209
+ tolerance = user_agent.first_space
210
+ else
211
+ tolerance = user_agent.second_slash
212
+ end
213
+ @device = ris_match(user_agent, tolerance)
214
+ if @device.nil?
215
+ if user_agent.starts_with('SAMSUNG')
216
+ tolerance = 8
217
+ @device = ld_match(user_agent, tolerance)
218
+ else
219
+ tolerance = user_agent.index_of_or_length('/', user_agent.index('Samsung'))
220
+ @device = ris_match(user_agent, tolerance)
221
+ end
222
+ end
223
+ end
224
+
225
+ def matcher_blackberry(user_agent)
226
+ if user_agent.starts_with('BlackBerry')
227
+ tolerance = user_agent.ordinal_index_of(';', 3)
228
+ else
229
+ tolerance = user_agent.first_slash
230
+ end
231
+ @device = ris_match(user_agent, tolerance)
232
+ if @device.nil?
233
+ if user_agent =~ /\#Black[Bb]erry[^\/\s]+\/(\d.\d)\#/
234
+ versions = {
235
+ '2.' => 'blackberry_generic_ver2',
236
+ '3.2' => 'blackberry_generic_ver3_sub2',
237
+ '3.3' => 'blackberry_generic_ver3_sub30',
238
+ '3.5' => 'blackberry_generic_ver3_sub50',
239
+ '3.6' => 'blackberry_generic_ver3_sub60',
240
+ '3.7' => 'blackberry_generic_ver3_sub70',
241
+ '4.1' => 'blackberry_generic_ver4_sub10',
242
+ '4.2' => 'blackberry_generic_ver4_sub20',
243
+ '4.3' => 'blackberry_generic_ver4_sub30',
244
+ '4.5' => 'blackberry_generic_ver4_sub50',
245
+ '4.6' => 'blackberry_generic_ver4_sub60',
246
+ '4.7' => 'blackberry_generic_ver4_sub70',
247
+ '4.' => 'blackberry_generic_ver4',
248
+ '5.' => 'blackberry_generic_ver5',
249
+ '6.' => 'blackberry_generic_ver6',
250
+ }.each_pair do |version, device_id|
251
+ if version.index($1)
252
+ @device = Device.new(device_id)
253
+ break
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ def matcher_sonyericsson(user_agent)
261
+ if user_agent.starts_with('SonyEricsson')
262
+ tolerance = user_agent.first_slash - 1
263
+ @device = ris_match(user_agent, tolerance)
264
+ else
265
+ tolerance = user_agent.second_slash
266
+ @device = ris_match(user_agent, tolerance)
267
+ end
268
+ if @device.nil?
269
+ tolerance = 14
270
+ @device = ris_match(user_agent, tolerance)
107
271
  end
272
+ end
108
273
 
109
- def first_space(user_agent)
110
- pos = user_agent.index(' ')
111
- return user_agent.length if pos.nil?
112
- return pos
274
+ def matcher_motorola(user_agent)
275
+ tolerance = 5
276
+ if user_agent.starts_with('Mot-') || user_agent.starts_with('MOT-') || user_agent.starts_with('Motorola')
277
+ @device = ris_match(user_agent, tolerance)
278
+ else
279
+ @device = ld_match(user_agent, tolerance)
280
+ end
281
+ if @device.nil?
282
+ @device = Device.new('mot_mib22_generic') if @user_agent.contains('MIB/2.2') || @user_agent.contains('MIB/BER2.2')
113
283
  end
284
+ end
114
285
 
115
- def first_open_paren(user_agent)
116
- pos = user_agent.index('(')
117
- return user_agent.length if pos.nil?
118
- return pos
286
+ def matcher_alcatel(user_agent)
287
+ tolerance = user_agent.first_slash
288
+ @device = ris_match(user_agent, tolerance)
289
+ end
290
+
291
+ def matcher_apple(user_agent)
292
+ if user_agent.starts_with('Apple')
293
+ tolerance = user_agent.ordinal_index_of(' ')
294
+ tolerance = user_agent.length if tolerance == -1
295
+ else
296
+ tolerance = user_agent.ordinal_index_of(';')
297
+ end
298
+ @device = ris_match(user_agent, tolerance)
299
+ if @device.nil?
300
+ device_id = case
301
+ when user_agent.contains('iPod')
302
+ 'apple_ipod_touch_ver1'
303
+ when user_agent.contains('iPad')
304
+ 'apple_ipad_ver1'
305
+ when user_agent.contains('iPhone')
306
+ 'apple_iphone_ver1'
307
+ else
308
+ WurfDevice::Contants::GENERIC
309
+ end
310
+ @device = Device.new(device_id)
119
311
  end
312
+ end
313
+
314
+ def matcher_benq(user_agent)
315
+ tolerance = user_agent.first_slash
316
+ @device = ris_match(user_agent, tolerance)
317
+ end
120
318
 
121
- def remove_nokia_msisdn(user_agent)
122
- if user_agent =~ /^(.+)NOKIA-MSISDN\:\ (.+)$/i
123
- user_agent = $1
319
+ def matcher_docomo(user_agent)
320
+ if user_agent.num_slashes >= 2
321
+ tolerance = user_agent.second_slash
322
+ else
323
+ tolerance = user_agent.first_open_paren
324
+ end
325
+ @device = ris_match(user_agent, tolerance)
326
+ if @device.nil?
327
+ version_index = 7
328
+ device_id = case
329
+ when user_agent[version_index] == '2'
330
+ 'docomo_generic_jap_ver2'
331
+ else
332
+ 'docomo_generic_jap_ver1'
124
333
  end
125
- return user_agent
334
+ @device = Device.new(device_id)
126
335
  end
336
+ end
337
+
338
+ def matcher_grundig(user_agent)
339
+ tolerance = user_agent.first_slash
340
+ @device = ris_match(user_agent, tolerance)
341
+ end
127
342
 
128
- def remove_up_link_from_ua(user_agent)
129
- pos = user_agent.index('UP.Link')
130
- return user_agent unless pos
131
- return user_agent.slice(0..(pos-1))
343
+ def matcher_htc(user_agent)
344
+ tolerance = user_agent.first_slash
345
+ @device = ris_match(user_agent, tolerance)
346
+ if @device.nil?
347
+ tolerance = 6
348
+ @device = ris_match(user_agent, tolerance)
132
349
  end
350
+ end
133
351
 
134
- def normalize_blackberry(user_agent)
135
- pos = user_agent.index('BlackBerry')
136
- return user_agent if pos.nil?
137
- return user_agent.slice(pos, user_agent.length - pos)
352
+ def matcher_kddi(user_agent)
353
+ if user_agent.starts_with('KDDI/')
354
+ tolerance = user_agent.second_slash
355
+ @device = ris_match(user_agent, tolerance)
356
+ else
357
+ tolerance = user_agent.first_slash
358
+ @device = ris_match(user_agent, tolerance)
359
+ end
360
+ if @device.nil?
361
+ @device = Device.new('opwv_v62_generic')
138
362
  end
363
+ end
139
364
 
140
- def normalize_android(user_agent)
141
- return user_agent.sub(/(Android \d\.\d)([^; \/\)]+)/, '\1')
365
+ def matcher_kyocera(user_agent)
366
+ tolerance = user_agent.first_slash
367
+ @device = ris_match(user_agent, tolerance)
368
+ end
369
+
370
+ def matcher_lg(user_agent)
371
+ tolerance = user_agent.index_of_or_length('/', user_agent.index('LG'))
372
+ @device = ris_match(user_agent, tolerance)
373
+ if @device.nil?
374
+ tolerance = 7
375
+ @device = ris_match(user_agent, tolerance)
142
376
  end
377
+ end
143
378
 
144
- def parse(user_agent)
145
- # grab all Agent/version strings as 'agents'
146
- agents = Array.new
147
- user_agent.split(/\s+/).each do |string|
148
- if string =~ /\//
149
- agents << string
150
- end
379
+ def matcher_mitsubishi(user_agent)
380
+ tolerance = user_agent.first_slash
381
+ @device = ris_match(user_agent, tolerance)
382
+ end
383
+
384
+ def matcher_nec(user_agent)
385
+ tolerance = user_agent.first_slash
386
+ @device = ris_match(user_agent, tolerance)
387
+ if @device.nil?
388
+ tolerance = 2
389
+ @device = ris_match(user_agent, tolerance)
390
+ end
391
+ end
392
+
393
+ def matcher_nintendo(user_agent)
394
+ @device = ld_match(user_agent, tolerance)
395
+ if @device.nil?
396
+ device_id = case
397
+ when user_agent.contains('Nintendo Wii')
398
+ 'nintendo_wii_browser'
399
+ when user_agent.contains('Nintendo DSi')
400
+ 'nintendo_dsi_ver1'
401
+ when user_agent.starts_with('Mozilla/') && user_agent.contains('Nitro') && user_agent.contains('Opera')
402
+ 'nintendo_ds_ver1'
403
+ else
404
+ 'nintendo_wii_browser'
151
405
  end
152
- return agents
406
+ @device = Device.new(device_id)
153
407
  end
154
408
  end
409
+
410
+ def matcher_panasonic(user_agent)
411
+ tolerance = user_agent.first_slash
412
+ @device = ris_match(user_agent, tolerance)
413
+ end
414
+
415
+ def matcher_pantech(user_agent)
416
+ if user_agent.starts_with('Pantech')
417
+ tolerance = 5
418
+ @device = ld_match(user_agent, tolerance)
419
+ else
420
+ tolerance = user_agent.first_slash
421
+ @device = ris_match(user_agent, tolerance)
422
+ end
423
+ end
424
+
425
+ def matcher_philips(user_agent)
426
+ tolerance = user_agent.first_slash
427
+ @device = ris_match(user_agent, tolerance)
428
+ end
429
+
430
+ def matcher_portalmmm(user_agent)
431
+ @device = Device.new(WurflDevice::Constants::GENERIC)
432
+ end
433
+
434
+ def matcher_qtek(user_agent)
435
+ tolerance = user_agent.first_slash
436
+ @device = ris_match(user_agent, tolerance)
437
+ end
438
+
439
+ def matcher_sagem(user_agent)
440
+ tolerance = user_agent.first_slash
441
+ @device = ris_match(user_agent, tolerance)
442
+ end
443
+
444
+ def matcher_sharp(user_agent)
445
+ tolerance = user_agent.first_slash
446
+ @device = ris_match(user_agent, tolerance)
447
+ end
448
+
449
+ def matcher_siemens(user_agent)
450
+ tolerance = user_agent.first_slash
451
+ @device = ris_match(user_agent, tolerance)
452
+ end
453
+
454
+ def matcher_spv(user_agent)
455
+ pos = user_agent.index(';')
456
+ tolerance = pos || user_agent.index('SPV')
457
+ @device = ris_match(user_agent, tolerance)
458
+ end
459
+
460
+ def matcher_toshiba(user_agent)
461
+ tolerance = user_agent.first_slash
462
+ @device = ris_match(user_agent, tolerance)
463
+ end
464
+
465
+ def matcher_vodafone(user_agent)
466
+ tolerance = user_agent.first_slash
467
+ @device = ris_match(user_agent, tolerance)
468
+ if @device.nil?
469
+ @device = ld_match(user_agent)
470
+ end
471
+ end
472
+
473
+ # mobile browsers
474
+ def matcher_android(user_agent)
475
+ device_id = 'generic_android'
476
+ if user_agent.contains('Froyo')
477
+ device_id = Device.new('generic_android_ver2_2')
478
+ elsif user_agent =~ /#Android[\s\/](\d).(\d)#/
479
+ version = "generic_android_ver#{$1}_#{$2}"
480
+ version = 'generic_android_ver2' if version == 'generic_android_ver2_0'
481
+ device_id = version if [
482
+ 'generic_android',
483
+ 'generic_android_ver1_5',
484
+ 'generic_android_ver1_6',
485
+ 'generic_android_ver2',
486
+ 'generic_android_ver2_1',
487
+ 'generic_android_ver2_2',
488
+ ].include?(version)
489
+ end
490
+ @device = Device.new(device_id)
491
+ end
492
+
493
+ def matcher_operamini(user_agent)
494
+ tolerance = user_agent.first_slash
495
+ @device = ris_match(user_agent, tolerance)
496
+ if @device.nil?
497
+ device_id = 'browser_opera_mini_release1';
498
+ if user_agent =~ /#Opera Mini\/([1-5])#/
499
+ device_id = "browser_opera_mini_release#{$1}"
500
+ elsif user_agent.contains('Opera Mobi')
501
+ device_id = 'browser_opera_mini_release4'
502
+ end
503
+ @device = Device.new(device_id)
504
+ end
505
+ end
506
+
507
+ def matcher_windowsce(user_agent)
508
+ tolerance = 3
509
+ @device = ld_match(user_agent, tolerance)
510
+ if @device.nil?
511
+ @device = Device.new('generic_ms_mobile_browser_ver1')
512
+ end
513
+ end
514
+
515
+ # robots
516
+ def matcher_bot(user_agent)
517
+ tolerance = user_agent.first_slash
518
+ @device = ris_match(user_agent, tolerance)
519
+ if @device.nil?
520
+ @device = Device.new(WurflDevice::Constants::GENERIC_WEB_BROWSER)
521
+ end
522
+ end
523
+
524
+ # desktop browsers
525
+ def matcher_msie(user_agent)
526
+ if user_agent =~ /^Mozilla\/4\.0 \(compatible; MSIE (\d)\.(\d);/
527
+ version = $1.to_i
528
+ version_sub = $2.to_i
529
+ device_id = case
530
+ when version == 7
531
+ 'msie_7'
532
+ when version == 8
533
+ 'msie_8'
534
+ when version == 6
535
+ 'msie_6'
536
+ when version == 4
537
+ 'msie_4'
538
+ when version == 5
539
+ version_sub == 5 ? 'msie_5_5' : 'msie_5'
540
+ else
541
+ 'msie'
542
+ end
543
+ @device = Device.new(device_id)
544
+ end
545
+ user_agent.sub!(/( \.NET CLR [\d\.]+;?| Media Center PC [\d\.]+;?| OfficeLive[a-zA-Z0-9\.\d]+;?| InfoPath[\.\d]+;?)/, '')
546
+ tolerance = user_agent.first_slash
547
+ @device = ris_match(user_agent, tolerance)
548
+ if @device.nil?
549
+ if user_agent.contains(['SLCC1', 'Media Center PC', '.NET CLR', 'OfficeLiveConnector'])
550
+ @device = Device.new(WurfDevice::Constants::GENERIC_WEB_BROWSER)
551
+ else
552
+ @device = Device.new(WurfDevice::Constants::GENERIC)
553
+ end
554
+ end
555
+ end
556
+
557
+ def matcher_firefox(user_agent)
558
+ if user_agent =~ /Firefox\/(\d)\.(\d)/
559
+ version = $1.to_i
560
+ version_sub = $2.to_i
561
+ device_id = case
562
+ when version == 3
563
+ version_sub == 5 ? 'firefox_3_5' : 'firefox_3'
564
+ when version == 2
565
+ 'firefox_2'
566
+ when version == 1
567
+ version_sub == 5 ? 'firefox_1_5' : 'firefox_1'
568
+ else
569
+ nil
570
+ end
571
+ @device = Device.new(device_id) unless device_id.nil?
572
+ else
573
+ tolerance = 5
574
+ @device = ld_match(user_agent, tolerance)
575
+ end
576
+ end
577
+
578
+ def matcher_chrome(user_agent)
579
+ tolerance = user_agent.index_of_or_length('/', user_agent.index('Chrome'))
580
+ @device = ris_match(user_agent, tolerance)
581
+ if @device.nil?
582
+ @device = Device.new('google_chrome')
583
+ end
584
+ end
585
+
586
+ def matcher_konqueror(user_agent)
587
+ tolerance = user_agent.first_slash
588
+ @device = ris_match(user_agent, tolerance)
589
+ end
590
+
591
+ def matcher_opera(user_agent)
592
+ device_id = case
593
+ when user_agent.contains('Opera/10')
594
+ 'opera_10'
595
+ when user_agent.contains('Opera/9')
596
+ 'opera_9'
597
+ when user_agent.contains('Opera/8')
598
+ 'opera_8'
599
+ when user_agent.contains('Opera/7')
600
+ 'opera_7'
601
+ else
602
+ nil
603
+ end
604
+ @device = Device.new(device_id) unless device_id.nil?
605
+ if @device.nil?
606
+ tolerance = 5
607
+ @device = ld_match(user_agent, tolerance)
608
+ end
609
+ @device = Device.new('opera') if @device.nil?
610
+ end
611
+
612
+ def matcher_safari(user_agent)
613
+ tolerance = user_agent.first_slash
614
+ @device = ris_match(user_agent, tolerance)
615
+ if @device.nil?
616
+ device_id = case
617
+ when user_agent.contains('Macintosh') || user_agent.contains('Windows')
618
+ WurflDevice::Constants::GENERIC_WEB_BROWSER
619
+ else
620
+ WurflDevice::Constants::GENERIC
621
+ end
622
+ @device = Device.new(device_id)
623
+ end
624
+ end
625
+
626
+ def matcher_aol(user_agent)
627
+ @device = Device.new(WurflDevice::Constants::GENERIC_WEB_BROWSER)
628
+ end
155
629
  end
156
630
  end
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  module WurflDevice
4
- VERSION = "0.0.10".freeze
4
+ VERSION = "0.1".freeze
5
5
  end
data/lib/wurfl_device.rb CHANGED
@@ -10,6 +10,7 @@ module WurflDevice
10
10
  autoload :Handset, 'wurfl_device/handset'
11
11
  autoload :UI, 'wurfl_device/ui'
12
12
  autoload :CLI, 'wurfl_device/cli'
13
+ autoload :UserAgent, 'wurfl_device/user_agent'
13
14
  autoload :UserAgentMatcher, 'wurfl_device/user_agent_matcher'
14
15
  autoload :XmlLoader, 'wurfl_device/xml_loader'
15
16
 
@@ -62,9 +63,11 @@ module WurflDevice
62
63
  return matcher.device
63
64
  end
64
65
 
65
- def get_device_from_ua_cache(user_agent)
66
- cached_device = db.hget(Constants::WURFL_USER_AGENTS_CACHED, user_agent)
67
- return Marshal::load(cached_device) unless cached_device.nil?
66
+ def get_device_from_ua_cache(user_agent, bypass_main_cache=false)
67
+ unless bypass_main_cache
68
+ cached_device = db.hget(Constants::WURFL_USER_AGENTS_CACHED, user_agent)
69
+ return Marshal::load(cached_device) unless cached_device.nil?
70
+ end
68
71
  cached_device = db.hget(Constants::WURFL_USER_AGENTS, user_agent)
69
72
  return Marshal::load(cached_device) unless cached_device.nil?
70
73
  return nil
@@ -89,8 +92,8 @@ module WurflDevice
89
92
 
90
93
  def clear_devices
91
94
  db.keys("#{Constants::WURFL_DEVICES}*").each { |k| db.del k }
92
- db.del(Contants::WURFL_INITIALIZED)
93
- db.del(Contants::WURFL_INFO)
95
+ db.del(Constants::WURFL_INITIALIZED)
96
+ db.del(Constants::WURFL_INFO)
94
97
  end
95
98
 
96
99
  def get_user_agents
@@ -102,7 +105,7 @@ module WurflDevice
102
105
  end
103
106
 
104
107
  def get_user_agents_in_index(matcher)
105
- db.hgetall("#{Constants::WURFL_DEVICES_INDEX}#{matcher}")
108
+ db.hkeys("#{Constants::WURFL_DEVICES_INDEX}#{matcher}")
106
109
  end
107
110
 
108
111
  def get_actual_device_raw(device_id)
@@ -119,9 +122,8 @@ module WurflDevice
119
122
 
120
123
  def rebuild_user_agent_cache
121
124
  # update the cache's
122
- get_indexes.each { |k| db.del k }
123
125
  db.del(Constants::WURFL_USER_AGENTS)
124
- db.del(Constants::WURFL_DEVICES_INDEX)
126
+ get_indexes.each { |k| db.del(k) }
125
127
 
126
128
  get_devices.each do |device_id|
127
129
  device_id.gsub!(Constants::WURFL_DEVICES, '')
@@ -131,7 +133,8 @@ module WurflDevice
131
133
  next if user_agent.nil? || user_agent.empty?
132
134
  db.hset(Constants::WURFL_USER_AGENTS, user_agent, Marshal::dump(Device.new(device_id)))
133
135
 
134
- matcher = UserAgentMatcher.get_index(user_agent)
136
+ next if user_agent =~ /^DO_NOT_MATCH/i
137
+ matcher = UserAgentMatcher.new.get_index(user_agent)
135
138
  db.hset("#{Constants::WURFL_DEVICES_INDEX}#{matcher}", user_agent, device_id)
136
139
  end
137
140
 
@@ -155,35 +158,42 @@ module WurflDevice
155
158
  db.set(Constants::WURFL_INITIALIZED, false)
156
159
 
157
160
  # download & parse the wurfl xml
158
- (devices, version, last_updated) = XmlLoader.load_xml_file(download_wurfl_xml_file) do |capabilities|
159
- device_id = capabilities.delete('id')
160
- next if device_id.nil? || device_id.empty?
161
- db.del("#{Constants::WURFL_DEVICES}#{device_id}")
162
- user_agent = capabilities.delete('user_agent')
163
- fall_back = capabilities.delete('fall_back')
164
-
165
- device_id.strip! unless device_id.nil?
166
- user_agent.strip! unless user_agent.nil?
167
- fall_back.strip! unless fall_back.nil?
168
-
169
- db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "id", device_id)
170
- db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "user_agent", user_agent)
171
- db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "fall_back", fall_back)
172
-
173
- capabilities.each_pair do |key, value|
174
- if value.is_a?(Hash)
175
- value.each_pair do |k, v|
176
- db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "#{key.to_s}:#{k.to_s}", v)
161
+ xml_list = Array.new
162
+ xml_list << download_wurfl_xml_file
163
+ xml_list << download_wurfl_web_patch_xml_file
164
+
165
+ xml_list.each do |xml_file|
166
+ (devices, version, last_updated) = XmlLoader.load_xml_file(xml_file) do |capabilities|
167
+ device_id = capabilities.delete('id')
168
+ next if device_id.nil? || device_id.empty?
169
+ db.del("#{Constants::WURFL_DEVICES}#{device_id}")
170
+ user_agent = capabilities.delete('user_agent')
171
+ fall_back = capabilities.delete('fall_back')
172
+
173
+ device_id.strip! unless device_id.nil?
174
+ user_agent.strip! unless user_agent.nil?
175
+ fall_back.strip! unless fall_back.nil?
176
+
177
+ db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "id", device_id)
178
+ db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "user_agent", user_agent)
179
+ db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "fall_back", fall_back)
180
+
181
+ capabilities.each_pair do |key, value|
182
+ if value.is_a?(Hash)
183
+ value.each_pair do |k, v|
184
+ db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "#{key.to_s}:#{k.to_s}", v)
185
+ end
186
+ else
187
+ db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "#{key.to_s}", value)
177
188
  end
178
- else
179
- db.hset("#{Constants::WURFL_DEVICES}#{device_id}", "#{key.to_s}", value)
180
189
  end
181
190
  end
182
- end
183
191
 
184
- db.set(Constants::WURFL_INITIALIZED, true)
185
- db.hset(Constants::WURFL_INFO, "version", version)
186
- db.hset(Constants::WURFL_INFO, "last_updated", Time.now)
192
+ next if version.nil?
193
+ db.set(Constants::WURFL_INITIALIZED, true)
194
+ db.hset(Constants::WURFL_INFO, "version", version)
195
+ db.hset(Constants::WURFL_INFO, "last_updated", Time.now)
196
+ end
187
197
  end
188
198
  end
189
199
 
@@ -215,6 +225,17 @@ module WurflDevice
215
225
  wurfl_xml_file_extracted
216
226
  end
217
227
 
228
+ def download_wurfl_web_patch_xml_file
229
+ wurfl_web_patch_xml_source = 'http://sourceforge.net/projects/wurfl/files/WURFL/2.2/web_browsers_patch.xml'
230
+ `wget --timeout=60 -qN -- #{wurfl_web_patch_xml_source} > /dev/null`
231
+ raise "Failed to download wurfl-latest.xml.gz" unless $? == 0
232
+
233
+ wurfl_web_patch_xml = File.join(WurflDevice.tmp_dir, 'web_browsers_patch.xml')
234
+ raise "web_browsers_patch.xml does not exists!" unless File.exists?(wurfl_web_patch_xml)
235
+
236
+ wurfl_web_patch_xml
237
+ end
238
+
218
239
  def lock_the_cache_for_initializing
219
240
  start_at = Time.now
220
241
  success = false
@@ -13,9 +13,25 @@ describe WurflDevice do
13
13
  end
14
14
 
15
15
  it "check for user agent matcher" do
16
- user_agent = 'Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 Nokia6120c/6.01; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413'
17
- device = WurflDevice.get_device_from_ua(user_agent)
18
- device.id.should == 'nokia_6120c_ver1_sub601'
16
+ {
17
+ 'nokia_x3_02_ver1' => 'NokiaX3-02/5.0 (05.60) Profile/MIDP-2.1 Configuration/CLDC-1.1',
18
+ 'nokia_n90_ver1_sub2052414' => 'NokiaN90-1/3.0541.5.2 Series60/2.8 Profile/MIDP-2.0 Configuration/CLDC-1.1',
19
+
20
+ #'opwv_v6_generic' => 'SAMSUNG-B5712C/1.0 RTK-E/1.0 DF/1.0 Release/08.17.2007 Browser/Openwave6.2.3.3.c.1.101 Profile/MIDP-2.0 Configuration/CLDC-1.1/*MzU3ODEwMDIwNzc5ODgx UP.Browser/6.',
21
+ 'samsung_a707_ver1_subshpvppr5' => 'SAMSUNG-SGH-A707/1.0 SHP/VPP/R5 NetFront/3.3 SMM-MMS/1.2.0 profile/MIDP-2.0 configuration/CLDC-1.1',
22
+ 'samsung_u700_ver1_subua' => 'SAMSUNG-SGH-U700/1.0 SHP/VPP/R5 NetFront/3.4 SMM-MMS/1.2.0 profile/MIDP-2.0 configuration/CLDC-1.1',
23
+ #'generic' => 'SAMSUNG-SCH-M710/(null)ID4 (compatible; MSIE 6.0; Windows CE; PPC) Opera 9.5',
24
+
25
+ 'sonyericsson_k700i_ver1subr2ay' => 'SonyEricssonK700i/R2AC SEMC-Browser/4.0.2 Profile/MIDP-2.0 Configuration/CLDC-1.1',
26
+ 'sonyericsson_k550i_ver1_subr1jd' => 'SonyEricssonK550i/R1JD Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1',
27
+
28
+ 'blackberry8520_ver1_subos5' => 'BlackBerry8520/5.0.0.592 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/603',
29
+
30
+ 'te' => "'M', 'Y' 'P', 'H', 'O', 'N', 'E' Browser/WAP2.0 Profile/MIDP-2.0 Configuration/CLDC-1.1",
31
+ }.each_pair do |device_id, user_agent|
32
+ device = WurflDevice.get_device_from_ua(user_agent)
33
+ device.id.should == device_id
34
+ end
19
35
  end
20
36
  end
21
37
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wurfl_device
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: '0.1'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-01 00:00:00.000000000 Z
12
+ date: 2011-10-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
16
- requirement: &66803460 !ruby/object:Gem::Requirement
16
+ requirement: &255091900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *66803460
24
+ version_requirements: *255091900
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: nokogiri
27
- requirement: &66802960 !ruby/object:Gem::Requirement
27
+ requirement: &255091200 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *66802960
35
+ version_requirements: *255091200
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: redis
38
- requirement: &66802500 !ruby/object:Gem::Requirement
38
+ requirement: &255090680 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *66802500
46
+ version_requirements: *255090680
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: text
49
- requirement: &66802060 !ruby/object:Gem::Requirement
49
+ requirement: &255090220 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *66802060
57
+ version_requirements: *255090220
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: bundler
60
- requirement: &66801540 !ruby/object:Gem::Requirement
60
+ requirement: &255089020 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.0.10
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *66801540
68
+ version_requirements: *255089020
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
- requirement: &66801020 !ruby/object:Gem::Requirement
71
+ requirement: &255088420 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 0.9.2
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *66801020
79
+ version_requirements: *255088420
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec-core
82
- requirement: &66800540 !ruby/object:Gem::Requirement
82
+ requirement: &255087880 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '2.0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *66800540
90
+ version_requirements: *255087880
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rspec-expectations
93
- requirement: &66800060 !ruby/object:Gem::Requirement
93
+ requirement: &255087420 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '2.0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *66800060
101
+ version_requirements: *255087420
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rr
104
- requirement: &66799560 !ruby/object:Gem::Requirement
104
+ requirement: &255086940 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ~>
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '1.0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *66799560
112
+ version_requirements: *255086940
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: faker
115
- requirement: &66799000 !ruby/object:Gem::Requirement
115
+ requirement: &255086420 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ~>
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0.9'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *66799000
123
+ version_requirements: *255086420
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: simplecov
126
- requirement: &66798340 !ruby/object:Gem::Requirement
126
+ requirement: &255085900 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ~>
@@ -131,7 +131,7 @@ dependencies:
131
131
  version: 0.5.3
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *66798340
134
+ version_requirements: *255085900
135
135
  description: Ruby client library for mobile handset detection
136
136
  email:
137
137
  - ahutalla@gmail.com
@@ -154,6 +154,7 @@ files:
154
154
  - lib/wurfl_device/constants.rb
155
155
  - lib/wurfl_device/device.rb
156
156
  - lib/wurfl_device/ui.rb
157
+ - lib/wurfl_device/user_agent.rb
157
158
  - lib/wurfl_device/user_agent_matcher.rb
158
159
  - lib/wurfl_device/version.rb
159
160
  - lib/wurfl_device/xml_loader.rb