woothee 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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