woothee 0.2.0

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.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/Makefile ADDED
@@ -0,0 +1,13 @@
1
+ all: test
2
+
3
+ TIMESTAMP=$(shell date +%Y%m%d-%H%M%S)
4
+
5
+ checkyaml:
6
+ perl ../bin/dataset_checker.pl
7
+
8
+ lib/woothee/dataset.rb: ../dataset.yaml
9
+ ruby ../bin/dataset_yaml2rb.rb
10
+ sync; sync; sync
11
+
12
+ test: lib/woothee/dataset.rb
13
+ rspec specs
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake'
5
+ $:.unshift File.join(File.dirname(__FILE__), "lib")
6
+
7
+ require 'rspec/core'
8
+ require 'rspec/core/rake_task'
9
+
10
+ task :default => :spec
11
+
12
+ desc "Run all specs in spec directory"
13
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'woothee/dataset'
4
+ require 'woothee/util'
5
+
6
+ module Woothee::Appliance
7
+ extend Woothee::Util
8
+
9
+ def self.challenge_playstation(ua, result)
10
+ data = case
11
+ when ua.index('PSP (PlayStation Portable);') then Woothee::DataSet.get('PSP')
12
+ when ua.index('PlayStation Vita') then Woothee::DataSet.get('PSVita')
13
+ when ua.index('PLAYSTATION 3;') then Woothee::DataSet.get('PS3')
14
+ else nil
15
+ end
16
+ return false unless data
17
+
18
+ update_map(result, data)
19
+ true
20
+ end
21
+
22
+ def self.challenge_nintendo(ua, result)
23
+ data = case
24
+ when ua.index('Nintendo 3DS;') then Woothee::DataSet.get('Nintendo3DS')
25
+ when ua.index('Nintendo DSi;') then Woothee::DataSet.get('NintendoDSi')
26
+ when ua.index('Nintendo Wii;') then Woothee::DataSet.get('NintendoWii')
27
+ else nil
28
+ end
29
+ return false unless data
30
+
31
+ update_map(result, data)
32
+ true
33
+ end
34
+
35
+ def self.challenge_digitaltv(ua, result)
36
+ data = if ua.index('InettvBrowser/')
37
+ Woothee::DataSet.get('DigitalTV')
38
+ else
39
+ nil
40
+ end
41
+ return false unless data
42
+
43
+ update_map(result, data)
44
+ true
45
+ end
46
+ end
@@ -0,0 +1,89 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'woothee/dataset'
4
+ require 'woothee/util'
5
+
6
+ module Woothee::Browser
7
+ extend Woothee::Util
8
+
9
+ def self.challenge_msie(ua, result)
10
+ return false if ua.index("compatible; MSIE").nil?
11
+
12
+ version = if ua =~ /MSIE ([.0-9]+);/o
13
+ $1
14
+ else
15
+ Woothee::VALUE_UNKNOWN
16
+ end
17
+ update_map(result, Woothee::DataSet.get('MSIE'))
18
+ update_version(result, version)
19
+ true
20
+ end
21
+
22
+ def self.challenge_safari_chrome(ua, result)
23
+ return false if ua.index('Safari/').nil?
24
+
25
+ version = Woothee::VALUE_UNKNOWN
26
+
27
+ if ua =~ /(?:Chrome|CrMo)\/([.0-9]+)/o
28
+ # Chrome
29
+ version = $1
30
+ update_map(result, Woothee::DataSet.get('Chrome'))
31
+ update_version(result, version)
32
+ return true
33
+ end
34
+
35
+ # Safari
36
+ if ua =~ /Version\/([.0-9]+)/o
37
+ version = $1
38
+ end
39
+ update_map(result, Woothee::DataSet.get('Safari'))
40
+ update_version(result, version)
41
+ true
42
+ end
43
+
44
+ def self.challenge_firefox(ua, result)
45
+ return false if ua.index('Firefox/').nil?
46
+
47
+ version = if ua =~ /Firefox\/([.0-9]+)/o
48
+ $1
49
+ else
50
+ Woothee::VALUE_UNKNOWN
51
+ end
52
+ update_map(result, Woothee::DataSet.get('Firefox'))
53
+ update_version(result, version)
54
+ true
55
+ end
56
+
57
+ def self.challenge_opera(ua, result)
58
+ return false if ua.index('Opera').nil?
59
+
60
+ version = if ua =~ /Opera[\/ ]([.0-9]+)/o
61
+ $1
62
+ else
63
+ Woothee::VALUE_UNKNOWN
64
+ end
65
+ update_map(result, Woothee::DataSet.get('Opera'))
66
+ update_version(result, version)
67
+ true
68
+ end
69
+
70
+ def self.challenge_sleipnir(ua, result)
71
+ return false if ua.index('Sleipnir/').nil?
72
+
73
+ version = if ua =~ /Sleipnir\/([.0-9]+)/o
74
+ $1
75
+ else
76
+ Woothee::VALUE_UNKNOWN
77
+ end
78
+ update_map(result, Woothee::DataSet.get('Sleipnir'))
79
+ update_version(result, version)
80
+
81
+ # Sleipnir's user-agent doesn't contain Windows version, so put 'Windows UNKNOWN Ver'.
82
+ # Sleipnir is IE component browser, so for Windows only.
83
+ win = Woothee::DataSet.get('Win')
84
+ update_category(result, win[Woothee::KEY_CATEGORY])
85
+ update_os(result, win[Woothee::KEY_NAME])
86
+
87
+ true
88
+ end
89
+ end
@@ -0,0 +1,153 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'woothee/dataset'
4
+ require 'woothee/util'
5
+
6
+ module Woothee::Crawler
7
+ extend Woothee::Util
8
+
9
+ def self.challenge_google(ua, result)
10
+ return false if ua.index('Google').nil?
11
+
12
+ if ua.index('compatible; Googlebot')
13
+ if ua.index('compatible; Googlebot-Mobile')
14
+ update_map(result, Woothee::DataSet.get('GoogleBotMobile'))
15
+ return true
16
+ else
17
+ update_map(result, Woothee::DataSet.get('GoogleBot'))
18
+ return true
19
+ end
20
+ end
21
+ if ua.index('Googlebot-Image/')
22
+ update_map(result, Woothee::DataSet.get('GoogleBot'))
23
+ return true
24
+ end
25
+ if ua.index('Mediapartners-Google')
26
+ if ua.index('compatible; Mediapartners-Google') or ua == 'Mediapartners-Google'
27
+ update_map(result, Woothee::DataSet.get('GoogleMediaPartners'))
28
+ return true
29
+ end
30
+ end
31
+ if ua.index('Feedfetcher-Google;')
32
+ update_map(result, Woothee::DataSet.get('GoogleFeedFetcher'))
33
+ return true
34
+ end
35
+ if ua.index('AppEngine-Google')
36
+ update_map(result, Woothee::DataSet.get('GoogleAppEngine'))
37
+ return true
38
+ end
39
+ if ua.index('Google Web Preview')
40
+ update_map(result, Woothee::DataSet.get('GoogleWebPreview'))
41
+ return true
42
+ end
43
+
44
+ false
45
+ end
46
+
47
+ def self.challenge_crawlers(ua, result)
48
+ if ua.index('Yahoo') or ua.index('listing.yahoo.co.jp/support/faq/')
49
+ if ua.index('compatible; Yahoo! Slurp;')
50
+ update_map(result, Woothee::DataSet.get('YahooSlurp'))
51
+ return true
52
+ end
53
+ if ua.index('YahooFeedSeekerJp') or ua.index('YahooFeedSeekerBetaJp')
54
+ update_map(result, Woothee::DataSet.get('YahooJP'))
55
+ return true
56
+ end
57
+ if ua.index('crawler (http://listing.yahoo.co.jp/support/faq/')
58
+ update_map(result, Woothee::DataSet.get('YahooJP'))
59
+ return true
60
+ end
61
+ if ua.index('Yahoo Pipes')
62
+ update_map(result, Woothee::DataSet.get('YahooPipes'))
63
+ return true
64
+ end
65
+ end
66
+ if ua.index('msnbot')
67
+ update_map(result, Woothee::DataSet.get('msnbot'))
68
+ return true
69
+ end
70
+ if ua.index('bingbot')
71
+ if ua.index('compatible; bingbot')
72
+ update_map(result, Woothee::DataSet.get('bingbot'))
73
+ return true
74
+ end
75
+ end
76
+ if ua.index('Baidu')
77
+ if ua.index('compatible; Baiduspider') or ua.index('Baiduspider+') or ua.index('Baiduspider-image+')
78
+ update_map(result, Woothee::DataSet.get('Baiduspider'))
79
+ return true
80
+ end
81
+ end
82
+ if ua.index('Yeti')
83
+ if ua.index('http://help.naver.com/robots')
84
+ update_map(result, Woothee::DataSet.get('Yeti'))
85
+ return true
86
+ end
87
+ end
88
+ if ua.index('FeedBurner/')
89
+ update_map(result, Woothee::DataSet.get('FeedBurner'))
90
+ return true
91
+ end
92
+ if ua.index('facebookexternalhit')
93
+ update_map(result, Woothee::DataSet.get('facebook'))
94
+ return true
95
+ end
96
+ if ua.index('ichiro')
97
+ if ua.index('http://help.goo.ne.jp/door/crawler.html') or ua.index('compatible; ichiro/mobile goo;')
98
+ update_map(result, Woothee::DataSet.get('gooIchiro'))
99
+ return true
100
+ end
101
+ end
102
+ if ua.index('Apple-PubSub')
103
+ update_map(result, Woothee::DataSet.get('ApplePubSub'))
104
+ return true
105
+ end
106
+ if ua.index('livedoor FeedFetcher') or ua.index('Fastladder FeedFetcher')
107
+ update_map(result, Woothee::DataSet.get('livedoorFeedFetcher'))
108
+ return true
109
+ end
110
+ if ua.index('Hatena ')
111
+ if ua.index('Hatena Antenna') or ua.index('Hatena Pagetitle Agent') or ua.index('Hatena Diary RSS')
112
+ update_map(result, Woothee::DataSet.get('Hatena'))
113
+ return true
114
+ end
115
+ end
116
+ if ua.index('mixi-check') or ua.index('mixi-news-crawler')
117
+ update_map(result, Woothee::DataSet.get('mixi'))
118
+ return true
119
+ end
120
+ if ua.index('Indy Library')
121
+ if ua.index('compatible; Indy Library')
122
+ update_map(result, Woothee::DataSet.get('IndyLibrary'))
123
+ return true
124
+ end
125
+ end
126
+
127
+ false
128
+ end
129
+
130
+ def self.challenge_maybe_crawler(ua, result)
131
+ if ua =~ /bot(?:[-_ .\/;@()]|$)/oi
132
+ update_map(result, Woothee::DataSet.get('VariousCrawler'))
133
+ return true
134
+ end
135
+
136
+ if ua =~ /(?:Rome Client |UnwindFetchor\/|ia_archiver |Summify |PostRank\/)/o or ua.index('ASP-Ranker Feed Crawler')
137
+ update_map(result, Woothee::DataSet.get('VariousCrawler'))
138
+ return true
139
+ end
140
+
141
+ if ua =~ /(feed|web) ?parser/oi
142
+ update_map(result, Woothee::DataSet.get('VariousCrawler'))
143
+ return true
144
+ end
145
+
146
+ if ua =~ /watch ?dog/oi
147
+ update_map(result, Woothee::DataSet.get('VariousCrawler'))
148
+ return true
149
+ end
150
+
151
+ false
152
+ end
153
+ end
@@ -0,0 +1,278 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Woothee
3
+ KEY_LABEL = :label
4
+ KEY_NAME = :name
5
+ KEY_TYPE = :type
6
+ KEY_CATEGORY = :category
7
+ KEY_OS = :os
8
+ KEY_VENDOR = :vendor
9
+ KEY_VERSION = :version
10
+
11
+ TYPE_BROWSER = :browser
12
+ TYPE_OS = :os
13
+ TYPE_FULL = :full
14
+
15
+ CATEGORY_PC = :pc
16
+ CATEGORY_SMARTPHONE = :smartphone
17
+ CATEGORY_MOBILEPHONE = :mobilephone
18
+ CATEGORY_CRAWLER = :crawler
19
+ CATEGORY_APPLIANCE = :appliance
20
+ CATEGORY_MISC = :misc
21
+
22
+ ATTRIBUTE_NAME = :name
23
+ ATTRIBUTE_CATEGORY = :category
24
+ ATTRIBUTE_OS = :os
25
+ ATTRIBUTE_VENDOR = :vendor
26
+ ATTRIBUTE_VERSION = :version
27
+
28
+ VALUE_UNKNOWN = "UNKNOWN"
29
+ end
30
+
31
+ module Woothee::DataSet
32
+ DATASET = {}
33
+ # GENERATED from dataset.yaml at Tue Jun 12 12:17:48 JST 2012 by tagomoris
34
+ obj = {:label => 'MSIE', :name => 'Internet Explorer', :type => :browser}
35
+ obj[:vendor] = 'Microsoft'
36
+ DATASET[obj[:label]] = obj
37
+ obj = {:label => 'Chrome', :name => 'Chrome', :type => :browser}
38
+ obj[:vendor] = 'Google'
39
+ DATASET[obj[:label]] = obj
40
+ obj = {:label => 'Safari', :name => 'Safari', :type => :browser}
41
+ obj[:vendor] = 'Apple'
42
+ DATASET[obj[:label]] = obj
43
+ obj = {:label => 'Firefox', :name => 'Firefox', :type => :browser}
44
+ obj[:vendor] = 'Mozilla'
45
+ DATASET[obj[:label]] = obj
46
+ obj = {:label => 'Opera', :name => 'Opera', :type => :browser}
47
+ obj[:vendor] = 'Opera'
48
+ DATASET[obj[:label]] = obj
49
+ obj = {:label => 'Sleipnir', :name => 'Sleipnir', :type => :browser}
50
+ obj[:vendor] = 'Fenrir Inc.'
51
+ DATASET[obj[:label]] = obj
52
+ obj = {:label => 'Win', :name => 'Windows UNKNOWN Ver', :type => :os}
53
+ obj[:category] = :pc
54
+ DATASET[obj[:label]] = obj
55
+ obj = {:label => 'Win8', :name => 'Windows 8', :type => :os}
56
+ obj[:category] = :pc
57
+ DATASET[obj[:label]] = obj
58
+ obj = {:label => 'Win7', :name => 'Windows 7', :type => :os}
59
+ obj[:category] = :pc
60
+ DATASET[obj[:label]] = obj
61
+ obj = {:label => 'WinVista', :name => 'Windows Vista', :type => :os}
62
+ obj[:category] = :pc
63
+ DATASET[obj[:label]] = obj
64
+ obj = {:label => 'WinXP', :name => 'Windows XP', :type => :os}
65
+ obj[:category] = :pc
66
+ DATASET[obj[:label]] = obj
67
+ obj = {:label => 'Win2000', :name => 'Windows 2000', :type => :os}
68
+ obj[:category] = :pc
69
+ DATASET[obj[:label]] = obj
70
+ obj = {:label => 'WinNT4', :name => 'Windows NT 4.0', :type => :os}
71
+ obj[:category] = :pc
72
+ DATASET[obj[:label]] = obj
73
+ obj = {:label => 'WinMe', :name => 'Windows Me', :type => :os}
74
+ obj[:category] = :pc
75
+ DATASET[obj[:label]] = obj
76
+ obj = {:label => 'Win98', :name => 'Windows 98', :type => :os}
77
+ obj[:category] = :pc
78
+ DATASET[obj[:label]] = obj
79
+ obj = {:label => 'Win95', :name => 'Windows 95', :type => :os}
80
+ obj[:category] = :pc
81
+ DATASET[obj[:label]] = obj
82
+ obj = {:label => 'WinPhone', :name => 'Windows Phone OS', :type => :os}
83
+ obj[:category] = :smartphone
84
+ DATASET[obj[:label]] = obj
85
+ obj = {:label => 'WinCE', :name => 'Windows CE', :type => :os}
86
+ obj[:category] = :smartphone
87
+ DATASET[obj[:label]] = obj
88
+ obj = {:label => 'OSX', :name => 'Mac OSX', :type => :os}
89
+ obj[:category] = :pc
90
+ DATASET[obj[:label]] = obj
91
+ obj = {:label => 'MacOS', :name => 'Mac OS Classic', :type => :os}
92
+ obj[:category] = :pc
93
+ DATASET[obj[:label]] = obj
94
+ obj = {:label => 'Linux', :name => 'Linux', :type => :os}
95
+ obj[:category] = :pc
96
+ DATASET[obj[:label]] = obj
97
+ obj = {:label => 'BSD', :name => 'BSD', :type => :os}
98
+ obj[:category] = :pc
99
+ DATASET[obj[:label]] = obj
100
+ obj = {:label => 'Android', :name => 'Android', :type => :os}
101
+ obj[:category] = :smartphone
102
+ DATASET[obj[:label]] = obj
103
+ obj = {:label => 'iPhone', :name => 'iPhone', :type => :os}
104
+ obj[:category] = :smartphone
105
+ DATASET[obj[:label]] = obj
106
+ obj = {:label => 'iPad', :name => 'iPad', :type => :os}
107
+ obj[:category] = :smartphone
108
+ DATASET[obj[:label]] = obj
109
+ obj = {:label => 'iPod', :name => 'iPod', :type => :os}
110
+ obj[:category] = :smartphone
111
+ DATASET[obj[:label]] = obj
112
+ obj = {:label => 'iOS', :name => 'iOS', :type => :os}
113
+ obj[:category] = :smartphone
114
+ DATASET[obj[:label]] = obj
115
+ obj = {:label => 'BlackBerry', :name => 'BlackBerry', :type => :os}
116
+ obj[:category] = :smartphone
117
+ DATASET[obj[:label]] = obj
118
+ obj = {:label => 'docomo', :name => 'docomo', :type => :full}
119
+ obj[:vendor] = 'docomo'
120
+ obj[:category] = :mobilephone
121
+ obj[:os] = 'docomo'
122
+ DATASET[obj[:label]] = obj
123
+ obj = {:label => 'au', :name => 'au by KDDI', :type => :full}
124
+ obj[:vendor] = 'au'
125
+ obj[:category] = :mobilephone
126
+ obj[:os] = 'au'
127
+ DATASET[obj[:label]] = obj
128
+ obj = {:label => 'SoftBank', :name => 'SoftBank Mobile', :type => :full}
129
+ obj[:vendor] = 'SoftBank'
130
+ obj[:category] = :mobilephone
131
+ obj[:os] = 'SoftBank'
132
+ DATASET[obj[:label]] = obj
133
+ obj = {:label => 'willcom', :name => 'WILLCOM', :type => :full}
134
+ obj[:vendor] = 'WILLCOM'
135
+ obj[:category] = :mobilephone
136
+ obj[:os] = 'WILLCOM'
137
+ DATASET[obj[:label]] = obj
138
+ obj = {:label => 'jig', :name => 'jig browser', :type => :full}
139
+ obj[:category] = :mobilephone
140
+ obj[:os] = 'jig'
141
+ DATASET[obj[:label]] = obj
142
+ obj = {:label => 'emobile', :name => 'emobile', :type => :full}
143
+ obj[:category] = :mobilephone
144
+ obj[:os] = 'emobile'
145
+ DATASET[obj[:label]] = obj
146
+ obj = {:label => 'SymbianOS', :name => 'SymbianOS', :type => :full}
147
+ obj[:category] = :mobilephone
148
+ obj[:os] = 'SymbianOS'
149
+ DATASET[obj[:label]] = obj
150
+ obj = {:label => 'MobileTranscoder', :name => 'Mobile Transcoder', :type => :full}
151
+ obj[:category] = :mobilephone
152
+ obj[:os] = 'Mobile Transcoder'
153
+ DATASET[obj[:label]] = obj
154
+ obj = {:label => 'Nintendo3DS', :name => 'Nintendo 3DS', :type => :full}
155
+ obj[:vendor] = 'Nintendo'
156
+ obj[:category] = :appliance
157
+ obj[:os] = 'Nintendo 3DS'
158
+ DATASET[obj[:label]] = obj
159
+ obj = {:label => 'NintendoDSi', :name => 'Nintendo DSi', :type => :full}
160
+ obj[:vendor] = 'Nintendo'
161
+ obj[:category] = :appliance
162
+ obj[:os] = 'Nintendo DSi'
163
+ DATASET[obj[:label]] = obj
164
+ obj = {:label => 'NintendoWii', :name => 'Nintendo Wii', :type => :full}
165
+ obj[:vendor] = 'Nintendo'
166
+ obj[:category] = :appliance
167
+ obj[:os] = 'Nintendo Wii'
168
+ DATASET[obj[:label]] = obj
169
+ obj = {:label => 'PSP', :name => 'PlayStation Portable', :type => :full}
170
+ obj[:vendor] = 'Sony'
171
+ obj[:category] = :appliance
172
+ obj[:os] = 'PlayStation Portable'
173
+ DATASET[obj[:label]] = obj
174
+ obj = {:label => 'PSVita', :name => 'PlayStation Vita', :type => :full}
175
+ obj[:vendor] = 'Sony'
176
+ obj[:category] = :appliance
177
+ obj[:os] = 'PlayStation Vita'
178
+ DATASET[obj[:label]] = obj
179
+ obj = {:label => 'PS3', :name => 'PlayStation 3', :type => :full}
180
+ obj[:vendor] = 'Sony'
181
+ obj[:category] = :appliance
182
+ obj[:os] = 'PlayStation 3'
183
+ DATASET[obj[:label]] = obj
184
+ obj = {:label => 'DigitalTV', :name => 'InternetTVBrowser', :type => :full}
185
+ obj[:category] = :appliance
186
+ obj[:os] = 'DigitalTV'
187
+ DATASET[obj[:label]] = obj
188
+ obj = {:label => 'SafariRSSReader', :name => 'Safari RSSReader', :type => :full}
189
+ obj[:vendor] = 'Apple'
190
+ obj[:category] = :misc
191
+ DATASET[obj[:label]] = obj
192
+ obj = {:label => 'GoogleDesktop', :name => 'Google Desktop', :type => :full}
193
+ obj[:vendor] = 'Google'
194
+ obj[:category] = :misc
195
+ DATASET[obj[:label]] = obj
196
+ obj = {:label => 'WindowsRSSReader', :name => 'Windows RSSReader', :type => :full}
197
+ obj[:vendor] = 'Microsoft'
198
+ obj[:category] = :misc
199
+ DATASET[obj[:label]] = obj
200
+ obj = {:label => 'VariousRSSReader', :name => 'RSSReader', :type => :full}
201
+ obj[:category] = :misc
202
+ DATASET[obj[:label]] = obj
203
+ obj = {:label => 'HTTPLibrary', :name => 'HTTP Library', :type => :full}
204
+ obj[:category] = :misc
205
+ DATASET[obj[:label]] = obj
206
+ obj = {:label => 'GoogleBot', :name => 'Googlebot', :type => :full}
207
+ obj[:category] = :crawler
208
+ DATASET[obj[:label]] = obj
209
+ obj = {:label => 'GoogleBotMobile', :name => 'Googlebot Mobile', :type => :full}
210
+ obj[:category] = :crawler
211
+ DATASET[obj[:label]] = obj
212
+ obj = {:label => 'GoogleMediaPartners', :name => 'Google Mediapartners', :type => :full}
213
+ obj[:category] = :crawler
214
+ DATASET[obj[:label]] = obj
215
+ obj = {:label => 'GoogleFeedFetcher', :name => 'Google Feedfetcher', :type => :full}
216
+ obj[:category] = :crawler
217
+ DATASET[obj[:label]] = obj
218
+ obj = {:label => 'GoogleAppEngine', :name => 'Google AppEngine', :type => :full}
219
+ obj[:category] = :crawler
220
+ DATASET[obj[:label]] = obj
221
+ obj = {:label => 'GoogleWebPreview', :name => 'Google Web Preview', :type => :full}
222
+ obj[:category] = :crawler
223
+ DATASET[obj[:label]] = obj
224
+ obj = {:label => 'YahooSlurp', :name => 'Yahoo! Slurp', :type => :full}
225
+ obj[:category] = :crawler
226
+ DATASET[obj[:label]] = obj
227
+ obj = {:label => 'YahooJP', :name => 'Yahoo! Japan', :type => :full}
228
+ obj[:category] = :crawler
229
+ DATASET[obj[:label]] = obj
230
+ obj = {:label => 'YahooPipes', :name => 'Yahoo! Pipes', :type => :full}
231
+ obj[:category] = :crawler
232
+ DATASET[obj[:label]] = obj
233
+ obj = {:label => 'Baiduspider', :name => 'Baiduspider', :type => :full}
234
+ obj[:category] = :crawler
235
+ DATASET[obj[:label]] = obj
236
+ obj = {:label => 'msnbot', :name => 'msnbot', :type => :full}
237
+ obj[:category] = :crawler
238
+ DATASET[obj[:label]] = obj
239
+ obj = {:label => 'bingbot', :name => 'bingbot', :type => :full}
240
+ obj[:category] = :crawler
241
+ DATASET[obj[:label]] = obj
242
+ obj = {:label => 'Yeti', :name => 'Naver Yeti', :type => :full}
243
+ obj[:category] = :crawler
244
+ DATASET[obj[:label]] = obj
245
+ obj = {:label => 'FeedBurner', :name => 'Google FeedBurner', :type => :full}
246
+ obj[:category] = :crawler
247
+ DATASET[obj[:label]] = obj
248
+ obj = {:label => 'facebook', :name => 'facebook', :type => :full}
249
+ obj[:category] = :crawler
250
+ DATASET[obj[:label]] = obj
251
+ obj = {:label => 'mixi', :name => 'mixi', :type => :full}
252
+ obj[:category] = :crawler
253
+ DATASET[obj[:label]] = obj
254
+ obj = {:label => 'IndyLibrary', :name => 'Indy Library', :type => :full}
255
+ obj[:category] = :crawler
256
+ DATASET[obj[:label]] = obj
257
+ obj = {:label => 'ApplePubSub', :name => 'Apple iCloud', :type => :full}
258
+ obj[:category] = :crawler
259
+ DATASET[obj[:label]] = obj
260
+ obj = {:label => 'Hatena', :name => 'Hatena', :type => :full}
261
+ obj[:category] = :crawler
262
+ DATASET[obj[:label]] = obj
263
+ obj = {:label => 'gooIchiro', :name => 'goo', :type => :full}
264
+ obj[:category] = :crawler
265
+ DATASET[obj[:label]] = obj
266
+ obj = {:label => 'livedoorFeedFetcher', :name => 'livedoor FeedFetcher', :type => :full}
267
+ obj[:category] = :crawler
268
+ DATASET[obj[:label]] = obj
269
+ obj = {:label => 'VariousCrawler', :name => 'misc crawler', :type => :full}
270
+ obj[:category] = :crawler
271
+ DATASET[obj[:label]] = obj
272
+
273
+ DATASET.freeze
274
+
275
+ def self.get(label)
276
+ DATASET[label]
277
+ end
278
+ end
@@ -0,0 +1,67 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'woothee/dataset'
4
+ require 'woothee/util'
5
+
6
+ module Woothee::Misc
7
+ extend Woothee::Util
8
+
9
+ def self.challenge_desktoptools(ua, result)
10
+ data = case
11
+ when ua.index('AppleSyndication/') then Woothee::DataSet.get('SafariRSSReader')
12
+ when ua.index('compatible; Google Desktop/') then Woothee::DataSet.get('GoogleDesktop')
13
+ when ua.index('Windows-RSS-Platform') then Woothee::DataSet.get('WindowsRSSReader')
14
+ else nil
15
+ end
16
+ return false unless data
17
+
18
+ update_map(result, data)
19
+ true
20
+ end
21
+
22
+ def self.challenge_smartphone_patterns(ua, result)
23
+ if ua.index('CFNetwork/')
24
+ data = Woothee::DataSet.get('iOS')
25
+ update_category(result, data[Woothee::KEY_CATEGORY])
26
+ update_os(result, data[Woothee::KEY_NAME])
27
+ return true
28
+ end
29
+
30
+ false
31
+ end
32
+
33
+ def self.challenge_http_library(ua, result)
34
+ data,version = case
35
+ when ua =~ /^(?:Apache-HttpClient\/|Jakarta Commons-HttpClient\/|Java\/)/o
36
+ [Woothee::DataSet.get('HTTPLibrary'), 'Java']
37
+ when ua =~ /^Wget/o
38
+ [Woothee::DataSet.get('HTTPLibrary'), 'wget']
39
+ when ua =~ /^(?:libwww-perl|WWW-Mechanize|LWP::Simple|LWP |lwp-trivial)/o
40
+ [Woothee::DataSet.get('HTTPLibrary'), 'perl']
41
+ when ua =~ /^Python-urllib\//o
42
+ [Woothee::DataSet.get('HTTPLibrary'), 'python']
43
+ when ua =~ /^(:?PHP\/|WordPress\/|CakePHP|PukiWiki\/)/o
44
+ [Woothee::DataSet.get('HTTPLibrary'), 'php']
45
+ when ua.index('PEAR HTTP_Request class;')
46
+ [Woothee::DataSet.get('HTTPLibrary'), 'php']
47
+ else [nil,nil]
48
+ end
49
+ return false unless data
50
+
51
+ update_map(result, data)
52
+ update_version(result, version)
53
+ true
54
+ end
55
+
56
+ def self.challenge_maybe_rss_reader(ua, result)
57
+ data = if ua =~ /rss(?:reader|bar|[-_ \/;()])/oi
58
+ Woothee::DataSet.get('VariousRSSReader')
59
+ else
60
+ nil
61
+ end
62
+ return false unless data
63
+
64
+ update_map(result, data)
65
+ true
66
+ end
67
+ end
@@ -0,0 +1,94 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'woothee/dataset'
4
+ require 'woothee/util'
5
+
6
+ module Woothee::MobilePhone
7
+ extend Woothee::Util
8
+
9
+ def self.challenge_docomo(ua, result)
10
+ return false if ua.index('DoCoMo').nil? and ua.index(';FOMA;').nil?
11
+
12
+ version = if ua =~ /DoCoMo\/[.0-9]+[ \/]([^- \/;()"']+)/o
13
+ $1
14
+ elsif ua =~ /\(([^;)]+);FOMA;/o
15
+ $1
16
+ else
17
+ Woothee::VALUE_UNKNOWN
18
+ end
19
+ update_map(result, Woothee::DataSet.get('docomo'))
20
+ update_version(result, version)
21
+ true
22
+ end
23
+
24
+ def self.challenge_au(ua, result)
25
+ return false if ua.index('KDDI-').nil?
26
+
27
+ # fix Woothee::OS.challenge_mobile if you want to fix here
28
+ version = if ua =~ /KDDI-([^- \/;()"']+)/o
29
+ $1
30
+ else
31
+ Woothee::VALUE_UNKNOWN
32
+ end
33
+ update_map(result, Woothee::DataSet.get('au'))
34
+ update_version(result, version)
35
+ true
36
+ end
37
+
38
+ def self.challenge_softbank(ua, result)
39
+ return false if ua.index('SoftBank').nil? and ua.index('Vodafone').nil? and ua.index('J-PHONE').nil?
40
+
41
+ version = if ua =~ /(?:SoftBank|Vodafone|J-PHONE)\/[.0-9]+\/([^ \/;()]+)/o
42
+ $1
43
+ else
44
+ Woothee::VALUE_UNKNOWN
45
+ end
46
+ update_map(result, Woothee::DataSet.get('SoftBank'))
47
+ update_version(result, version)
48
+ true
49
+ end
50
+
51
+ def self.challenge_willcom(ua, result)
52
+ return false if ua.index('WILLCOM').nil? and ua.index('DDIPOCKET').nil?
53
+
54
+ # fix Woothee::OS.challenge_mobile if you want to fix here
55
+ version = if ua =~ /(?:WILLCOM|DDIPOCKET);[^\/]+\/([^ \/;()]+)/o
56
+ $1
57
+ else
58
+ Woothee::VALUE_UNKNOWN
59
+ end
60
+ update_map(result, Woothee::DataSet.get('willcom'))
61
+ update_version(result, version)
62
+ true
63
+ end
64
+
65
+ def self.challenge_misc(ua, result)
66
+ if ua.index('jig browser')
67
+ update_map(result, Woothee::DataSet.get('jig'))
68
+ if ua =~ /jig browser[^;]+; ([^);]+)/o
69
+ update_version(result, $1)
70
+ end
71
+ return true
72
+ end
73
+ if ua.index('emobile/') or ua.index('OpenBrowser') or ua.index('Browser/Obigo-Browser')
74
+ update_map(result, Woothee::DataSet.get('emobile'))
75
+ return true
76
+ end
77
+ if ua.index('SymbianOS')
78
+ update_map(result, Woothee::DataSet.get('SymbianOS'))
79
+ return true
80
+ end
81
+ if ua.index('Hatena-Mobile-Gateway/')
82
+ update_map(result, Woothee::DataSet.get('MobileTranscoder'))
83
+ update_version(result, 'Hatena')
84
+ return true
85
+ end
86
+ if ua.index('livedoor-Mobile-Gateway/')
87
+ update_map(result, Woothee::DataSet.get('MobileTranscoder'))
88
+ update_version(result, 'livedoor')
89
+ return true
90
+ end
91
+
92
+ false
93
+ end
94
+ end
data/lib/woothee/os.rb ADDED
@@ -0,0 +1,166 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'woothee/dataset'
4
+ require 'woothee/util'
5
+
6
+ module Woothee::OS
7
+ extend Woothee::Util
8
+
9
+ def self.challenge_windows(ua, result)
10
+ return false if ua.index("Windows").nil?
11
+
12
+ data = Woothee::DataSet.get('Win')
13
+ unless ua =~ /Windows ([ .a-zA-Z0-9]+)[;\\)]/o
14
+ # Windows, but version unknown
15
+ update_category(result, data[Woothee::KEY_CATEGORY])
16
+ update_os(result, data[Woothee::KEY_NAME])
17
+ return true
18
+ end
19
+
20
+ version = $1
21
+ data = case
22
+ when version == 'NT 6.2' then Woothee::DataSet.get('Win8')
23
+ when version == 'NT 6.1' then Woothee::DataSet.get('Win7')
24
+ when version == 'NT 6.0' then Woothee::DataSet.get('WinVista')
25
+ when version == 'NT 5.1' then Woothee::DataSet.get('WinXP')
26
+ when version =~ /^Phone OS/o then Woothee::DataSet.get('WinPhone')
27
+ when version == 'NT 5.0' then Woothee::DataSet.get('Win2000')
28
+ when version == 'NT 4.0' then Woothee::DataSet.get('WinNT4')
29
+ when version == '98' then Woothee::DataSet.get('Win98') # wow, WinMe is shown as 'Windows 98; Win9x 4.90', fxxxk
30
+ when version == '95' then Woothee::DataSet.get('Win95')
31
+ when version == 'CE' then Woothee::DataSet.get('WinCE')
32
+ else
33
+ data # windows unknown version
34
+ end
35
+ update_category(result, data[Woothee::KEY_CATEGORY])
36
+ update_os(result, data[Woothee::KEY_NAME])
37
+ true
38
+ end
39
+
40
+ def self.challenge_osx(ua, result)
41
+ return false if ua.index('Mac OS X').nil?
42
+
43
+ data = Woothee::DataSet.get('OSX')
44
+ if ua.index('like Mac OS X')
45
+ data = case
46
+ when ua.index('iPhone;') then Woothee::DataSet.get('iPhone')
47
+ when ua.index('iPad;') then Woothee::DataSet.get('iPad')
48
+ when ua.index('iPod;') then Woothee::DataSet.get('iPod')
49
+ else data
50
+ end
51
+ end
52
+ update_category(result, data[Woothee::KEY_CATEGORY])
53
+ update_os(result, data[Woothee::KEY_NAME])
54
+ true
55
+ end
56
+
57
+ def self.challenge_linux(ua, result)
58
+ return false if ua.index('Linux').nil?
59
+
60
+ data = if ua.index('Android')
61
+ Woothee::DataSet.get('Android')
62
+ else
63
+ Woothee::DataSet.get('Linux')
64
+ end
65
+ update_category(result, data[Woothee::KEY_CATEGORY])
66
+ update_os(result, data[Woothee::KEY_NAME])
67
+ true
68
+ end
69
+
70
+ def self.challenge_smartphone(ua, result)
71
+ data = case
72
+ when ua.index('iPhone') then Woothee::DataSet.get('iPhone')
73
+ when ua.index('iPad') then Woothee::DataSet.get('iPad')
74
+ when ua.index('iPod') then Woothee::DataSet.get('iPod')
75
+ when ua.index('Android') then Woothee::DataSet.get('Android')
76
+ when ua.index('CFNetwork') then Woothee::DataSet.get('iOS')
77
+ when ua.index('BlackBerry') then Woothee::DataSet.get('BlackBerry')
78
+ else nil
79
+ end
80
+ return false unless data
81
+
82
+ update_category(result, data[Woothee::KEY_CATEGORY])
83
+ update_os(result, data[Woothee::KEY_NAME])
84
+ true
85
+ end
86
+
87
+ def self.challenge_mobilephone(ua, result)
88
+ if ua.index('KDDI-')
89
+ if ua =~ /KDDI-([^- \/;()"']+)/o
90
+ term = $1
91
+ data = Woothee::DataSet.get('au')
92
+ update_category(result, data[Woothee::KEY_CATEGORY])
93
+ update_os(result, data[Woothee::KEY_OS])
94
+ update_version(result, term)
95
+ return true
96
+ end
97
+ end
98
+ if ua.index('WILLCOM') or ua.index('DDIPOCKET')
99
+ if ua =~ /(?:WILLCOM|DDIPOCKET);[^\/]+\/([^ \/;()]+)/o
100
+ term = $1
101
+ data = Woothee::DataSet.get('willcom')
102
+ update_category(result, data[Woothee::KEY_CATEGORY])
103
+ update_os(result, data[Woothee::KEY_OS])
104
+ update_version(result, term)
105
+ return true
106
+ end
107
+ end
108
+ if ua.index('SymbianOS')
109
+ data = Woothee::DataSet.get('SymbianOS')
110
+ update_category(result, data[Woothee::KEY_CATEGORY])
111
+ update_os(result, data[Woothee::KEY_OS])
112
+ return true
113
+ end
114
+ if ua.index('Google Wireless Transcoder')
115
+ update_map(result, Woothee::DataSet.get('MobileTranscoder'))
116
+ update_version(result, 'Google')
117
+ return true
118
+ end
119
+ if ua.index('Naver Transcoder')
120
+ update_map(result, Woothee::DataSet.get('MobileTranscoder'))
121
+ update_version(result, 'Naver')
122
+ return true
123
+ end
124
+
125
+ false
126
+ end
127
+
128
+ def self.challenge_appliance(ua, result)
129
+ if ua.index('Nintendo DSi;')
130
+ data = Woothee::DataSet.get('NintendoDSi')
131
+ update_category(result, data[Woothee::KEY_CATEGORY])
132
+ update_os(result, data[Woothee::KEY_OS])
133
+ return true
134
+ end
135
+ if ua.index('Nintendo Wii;')
136
+ data = Woothee::DataSet.get('NintendoWii')
137
+ update_category(result, data[Woothee::KEY_CATEGORY])
138
+ update_os(result, data[Woothee::KEY_OS])
139
+ return true
140
+ end
141
+
142
+ false
143
+ end
144
+
145
+ def self.challenge_misc(ua, result)
146
+ data = case
147
+ when ua.index('(Win98;')
148
+ Woothee::DataSet.get('Win98')
149
+ when ua.index('Macintosh; U; PPC;')
150
+ Woothee::DataSet.get('MacOS')
151
+ when ua.index('Mac_PowerPC')
152
+ Woothee::DataSet.get('MacOS')
153
+ when ua.index('X11; FreeBSD ')
154
+ Woothee::DataSet.get('BSD')
155
+ else
156
+ nil
157
+ end
158
+ if data
159
+ update_category(result, data[Woothee::KEY_CATEGORY])
160
+ update_os(result, data[Woothee::KEY_NAME])
161
+ return true
162
+ end
163
+
164
+ false
165
+ end
166
+ end
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Woothee::Util
4
+ def update_map(target, source)
5
+ source.keys.each do |key|
6
+ next if key == Woothee::KEY_LABEL or key == Woothee::KEY_TYPE
7
+ if source[key].length > 0
8
+ target[key] = source[key]
9
+ end
10
+ end
11
+ end
12
+
13
+ def update_category(target, category)
14
+ target[Woothee::ATTRIBUTE_CATEGORY] = category
15
+ end
16
+
17
+ def update_version(target, version)
18
+ target[Woothee::ATTRIBUTE_VERSION] = version
19
+ end
20
+
21
+ def update_os(target, os)
22
+ target[Woothee::ATTRIBUTE_OS] = os
23
+ end
24
+ end
data/lib/woothee.rb ADDED
@@ -0,0 +1,159 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'woothee/dataset'
4
+ require 'woothee/browser'
5
+ require 'woothee/os'
6
+ require 'woothee/mobilephone'
7
+ require 'woothee/crawler'
8
+ require 'woothee/appliance'
9
+ require 'woothee/misc'
10
+
11
+ module Woothee
12
+ def self.parse(useragent)
13
+ fill_result(exec_parse(useragent))
14
+ end
15
+
16
+ def self.is_crawler(useragent)
17
+ useragent.length > 0 and useragent != '-' and try_crawler(useragent, {})
18
+ end
19
+
20
+ def self.exec_parse(useragent)
21
+ result = {}
22
+
23
+ return result if useragent.length < 1 or useragent == '-'
24
+
25
+ if try_crawler(useragent, result)
26
+ return result
27
+ end
28
+
29
+ if try_browser(useragent, result)
30
+ if try_os(useragent, result)
31
+ return result
32
+ else
33
+ return result
34
+ end
35
+ end
36
+
37
+ if try_mobilephone(useragent, result)
38
+ return result
39
+ end
40
+
41
+ if try_appliance(useragent, result)
42
+ return result
43
+ end
44
+
45
+ if try_misc(useragent, result)
46
+ return result
47
+ end
48
+
49
+ # browser unknown. check os only
50
+ if try_os(useragent, result)
51
+ return result
52
+ end
53
+
54
+ if try_rare_cases(useragent, result)
55
+ return result
56
+ end
57
+
58
+ result
59
+ end
60
+
61
+ def self.try_crawler(useragent, result)
62
+ return true if Woothee::Crawler.challenge_google(useragent, result)
63
+
64
+ return true if Woothee::Crawler.challenge_crawlers(useragent, result)
65
+
66
+ false
67
+ end
68
+
69
+ def self.try_browser(useragent, result)
70
+ return true if Woothee::Browser.challenge_msie(useragent, result)
71
+
72
+ return true if Woothee::Browser.challenge_safari_chrome(useragent, result)
73
+
74
+ return true if Woothee::Browser.challenge_firefox(useragent, result)
75
+
76
+ return true if Woothee::Browser.challenge_opera(useragent, result)
77
+
78
+ false
79
+ end
80
+
81
+ def self.try_os(useragent, result)
82
+ return true if Woothee::OS.challenge_windows(useragent, result)
83
+
84
+ # OSX PC and iOS devices (strict check)
85
+ return true if Woothee::OS.challenge_osx(useragent, result)
86
+
87
+ # Linux PC and Android
88
+ return true if Woothee::OS.challenge_linux(useragent, result)
89
+
90
+ # all useragents matches /(iPhone|iPad|iPod|Android|BlackBerry)/
91
+ return true if Woothee::OS.challenge_smartphone(useragent, result)
92
+
93
+ # mobile phones like KDDI-.*
94
+ return true if Woothee::OS.challenge_mobilephone(useragent, result)
95
+
96
+ # Nintendo DSi/Wii with Opera
97
+ return true if Woothee::OS.challenge_appliance(useragent, result)
98
+
99
+ # Win98, BSD, classic MacOS, ...
100
+ return true if Woothee::OS.challenge_misc(useragent, result)
101
+
102
+ false
103
+ end
104
+
105
+ def self.try_mobilephone(useragent, result)
106
+ return true if Woothee::MobilePhone.challenge_docomo(useragent, result)
107
+
108
+ return true if Woothee::MobilePhone.challenge_au(useragent, result)
109
+
110
+ return true if Woothee::MobilePhone.challenge_softbank(useragent, result)
111
+
112
+ return true if Woothee::MobilePhone.challenge_willcom(useragent, result)
113
+
114
+ return true if Woothee::MobilePhone.challenge_misc(useragent, result)
115
+
116
+ false
117
+ end
118
+
119
+ def self.try_appliance(useragent, result)
120
+ return true if Woothee::Appliance.challenge_playstation(useragent, result)
121
+
122
+ return true if Woothee::Appliance.challenge_nintendo(useragent, result)
123
+
124
+ return true if Woothee::Appliance.challenge_digitaltv(useragent, result)
125
+
126
+ false
127
+ end
128
+
129
+ def self.try_misc(useragent, result)
130
+ return true if Woothee::Misc.challenge_desktoptools(useragent, result)
131
+
132
+ false
133
+ end
134
+
135
+ def self.try_rare_cases(useragent, result)
136
+ return true if Woothee::Misc.challenge_smartphone_patterns(useragent, result)
137
+
138
+ return true if Woothee::Browser.challenge_sleipnir(useragent, result)
139
+
140
+ return true if Woothee::Misc.challenge_http_library(useragent, result)
141
+
142
+ return true if Woothee::Misc.challenge_maybe_rss_reader(useragent, result)
143
+
144
+ return true if Woothee::Crawler.challenge_maybe_crawler(useragent, result)
145
+
146
+ false
147
+ end
148
+
149
+ FILLED = {
150
+ Woothee::ATTRIBUTE_NAME => Woothee::VALUE_UNKNOWN,
151
+ Woothee::ATTRIBUTE_CATEGORY => Woothee::VALUE_UNKNOWN,
152
+ Woothee::ATTRIBUTE_OS => Woothee::VALUE_UNKNOWN,
153
+ Woothee::ATTRIBUTE_VERSION => Woothee::VALUE_UNKNOWN,
154
+ Woothee::ATTRIBUTE_VENDOR => Woothee::VALUE_UNKNOWN,
155
+ }.freeze
156
+ def self.fill_result(result)
157
+ FILLED.merge(result)
158
+ end
159
+ end
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ $LOAD_PATH.push '../lib' unless $LOAD_PATH.include?('../lib')
4
+
5
+ module Woothee
6
+ end
7
+
8
+ describe Woothee do
9
+ it "should be read from each modules correctly" do
10
+ lambda { require 'woothee/dataset' }.should_not raise_error(LoadError)
11
+ lambda { require 'woothee' }.should_not raise_error(LoadError)
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ $LOAD_PATH.push '../lib' unless $LOAD_PATH.include?('../lib')
4
+
5
+ require 'woothee/dataset'
6
+
7
+ describe Woothee::DataSet do
8
+ it "contains constants" do
9
+ lambda { Woothee::ATTRIBUTE_NAME }.should_not raise_error(NameError)
10
+ Woothee::ATTRIBUTE_NAME.should eql(:name)
11
+ end
12
+
13
+ it "contains dataset" do
14
+ Woothee::DataSet.get('GoogleBot')[:name].should eql('Googlebot')
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ $LOAD_PATH.push '../lib' unless $LOAD_PATH.include?('../lib')
4
+
5
+ require 'yaml'
6
+ require 'woothee'
7
+
8
+ TESTSET_DIR = File.dirname(__FILE__) + "/../../testsets/";
9
+
10
+ TARGETS = [
11
+ ['crawler.yaml','Crawler'],['crawler_google.yaml','Crawler/Google'],
12
+ ['pc_windows.yaml','PC/Windows'],['pc_misc.yaml','PC/Misc'],
13
+ ['mobilephone_docomo.yaml','MobilePhone/docomo'],['mobilephone_au.yaml','MobilePhone/au'],
14
+ ['mobilephone_softbank.yaml','MobilePhone/softbank'],['mobilephone_willcom.yaml','MobilePhone/willcom'],
15
+ ['mobilephone_misc.yaml','MobilePhone/misc'],
16
+ ['smartphone_ios.yaml','SmartPhone/ios'],['smartphone_android.yaml','SmartPhone/android'],
17
+ ['smartphone_misc.yaml','SmartPhone/misc'],
18
+ ['appliance.yaml','Appliance'],
19
+ ['pc_lowpriority.yaml','PC/LowPriority'],
20
+ ['misc.yaml','Misc'],
21
+ ['crawler_nonmajor.yaml','Crawler/NonMajor'],
22
+ ]
23
+
24
+ describe Woothee do
25
+
26
+ TARGETS.each do |filename,groupname|
27
+ YAML.load_file(TESTSET_DIR + filename).each do |e|
28
+ r = Woothee.parse(e['target'])
29
+ [:name, :category, :os, :version, :vendor].each do |attribute|
30
+ it groupname + ("test(%s): %s" % [attribute, e['target']]) do
31
+ if [:name, :category].include?(attribute) or ([:os, :version, :vendor].include?(attribute) and e.has_key?(attribute.to_s))
32
+ r[attribute].to_s.should eql(e[attribute.to_s])
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ end
data/woothee.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ # $:.push File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "woothee"
6
+ gem.description = "Cross-language UserAgent classifier library, ruby implementation"
7
+ gem.homepage = "https://github.com/tagomoris/woothee"
8
+ gem.summary = gem.description
9
+ gem.version = "0.2.0"
10
+ gem.authors = ["TAGOMORI Satoshi"]
11
+ gem.email = "tagomoris@gmail.com"
12
+ gem.has_rdoc = false
13
+ #gem.platform = Gem::Platform::RUBY
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ gem.require_paths = ['lib']
18
+
19
+ gem.add_development_dependency "rspec", ">= 2.8.0"
20
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: woothee
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - TAGOMORI Satoshi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.8.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 2.8.0
30
+ description: Cross-language UserAgent classifier library, ruby implementation
31
+ email: tagomoris@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - Gemfile
37
+ - Makefile
38
+ - Rakefile
39
+ - lib/woothee.rb
40
+ - lib/woothee/appliance.rb
41
+ - lib/woothee/browser.rb
42
+ - lib/woothee/crawler.rb
43
+ - lib/woothee/dataset.rb
44
+ - lib/woothee/misc.rb
45
+ - lib/woothee/mobilephone.rb
46
+ - lib/woothee/os.rb
47
+ - lib/woothee/util.rb
48
+ - spec/00_valid_spec.rb
49
+ - spec/01_dataset_spec.rb
50
+ - spec/02_run_testsets_spec.rb
51
+ - woothee.gemspec
52
+ homepage: https://github.com/tagomoris/woothee
53
+ licenses: []
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project:
72
+ rubygems_version: 1.8.21
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Cross-language UserAgent classifier library, ruby implementation
76
+ test_files:
77
+ - spec/00_valid_spec.rb
78
+ - spec/01_dataset_spec.rb
79
+ - spec/02_run_testsets_spec.rb