user_agent_info 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.rdoc +18 -0
- data/Rakefile +14 -0
- data/VERSION +1 -0
- data/doc/classes/ActionController.html +101 -0
- data/doc/classes/ActionController/Request.html +140 -0
- data/doc/classes/ActionController/Request.src/M000001.html +18 -0
- data/doc/classes/UserAgentInfo.html +138 -0
- data/doc/classes/UserAgentInfo/UserAgent.html +234 -0
- data/doc/classes/UserAgentInfo/UserAgent.src/M000001.html +18 -0
- data/doc/classes/UserAgentInfo/UserAgent.src/M000002.html +18 -0
- data/doc/classes/UserAgentInfo/UserAgent.src/M000003.html +18 -0
- data/doc/classes/UserAgentInfo/UserAgent.src/M000004.html +18 -0
- data/doc/classes/UserAgentInfo/UserAgent.src/M000005.html +18 -0
- data/doc/classes/UserAgentInfo/UserAgent.src/M000006.html +18 -0
- data/doc/classes/UserAgentInfo/UserAgent.src/M000007.html +48 -0
- data/doc/classes/UserAgentInfo/UserAgent.src/M000008.html +48 -0
- data/doc/created.rid +1 -0
- data/doc/files/lib/user_agent_info_rb.html +128 -0
- data/doc/fr_class_index.html +29 -0
- data/doc/fr_file_index.html +27 -0
- data/doc/fr_method_index.html +31 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/lib/user_agent_info.rb +189 -0
- data/tests/test_browsers.rb +52 -0
- data/user_agent_info.gemspec +34 -0
- metadata +81 -0
data/doc/rdoc-style.css
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
body {
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
4
|
+
font-size: 90%;
|
5
|
+
margin: 0;
|
6
|
+
margin-left: 40px;
|
7
|
+
padding: 0;
|
8
|
+
background: white;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
12
|
+
h1 { font-size: 150%; }
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
14
|
+
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
16
|
+
a:hover { background: #039; color: #eef; }
|
17
|
+
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
19
|
+
td > a {
|
20
|
+
background: transparent;
|
21
|
+
color: #039;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* and inside a section title */
|
26
|
+
.section-title > a {
|
27
|
+
background: transparent;
|
28
|
+
color: #eee;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* === Structural elements =================================== */
|
33
|
+
|
34
|
+
div#index {
|
35
|
+
margin: 0;
|
36
|
+
margin-left: -40px;
|
37
|
+
padding: 0;
|
38
|
+
font-size: 90%;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div#index a {
|
43
|
+
margin-left: 0.7em;
|
44
|
+
}
|
45
|
+
|
46
|
+
div#index .section-bar {
|
47
|
+
margin-left: 0px;
|
48
|
+
padding-left: 0.7em;
|
49
|
+
background: #ccc;
|
50
|
+
font-size: small;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
div#classHeader, div#fileHeader {
|
55
|
+
width: auto;
|
56
|
+
color: white;
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
58
|
+
margin: 0;
|
59
|
+
margin-left: -40px;
|
60
|
+
border-bottom: 3px solid #006;
|
61
|
+
}
|
62
|
+
|
63
|
+
div#classHeader a, div#fileHeader a {
|
64
|
+
background: inherit;
|
65
|
+
color: white;
|
66
|
+
}
|
67
|
+
|
68
|
+
div#classHeader td, div#fileHeader td {
|
69
|
+
background: inherit;
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
div#fileHeader {
|
75
|
+
background: #057;
|
76
|
+
}
|
77
|
+
|
78
|
+
div#classHeader {
|
79
|
+
background: #048;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
.class-name-in-header {
|
84
|
+
font-size: 180%;
|
85
|
+
font-weight: bold;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
div#bodyContent {
|
90
|
+
padding: 0 1.5em 0 1.5em;
|
91
|
+
}
|
92
|
+
|
93
|
+
div#description {
|
94
|
+
padding: 0.5em 1.5em;
|
95
|
+
background: #efefef;
|
96
|
+
border: 1px dotted #999;
|
97
|
+
}
|
98
|
+
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
100
|
+
color: #125;;
|
101
|
+
background: transparent;
|
102
|
+
}
|
103
|
+
|
104
|
+
div#validator-badges {
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
div#validator-badges img { border: 0; }
|
108
|
+
|
109
|
+
div#copyright {
|
110
|
+
color: #333;
|
111
|
+
background: #efefef;
|
112
|
+
font: 0.75em sans-serif;
|
113
|
+
margin-top: 5em;
|
114
|
+
margin-bottom: 0;
|
115
|
+
padding: 0.5em 2em;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/* === Classes =================================== */
|
120
|
+
|
121
|
+
table.header-table {
|
122
|
+
color: white;
|
123
|
+
font-size: small;
|
124
|
+
}
|
125
|
+
|
126
|
+
.type-note {
|
127
|
+
font-size: small;
|
128
|
+
color: #DEDEDE;
|
129
|
+
}
|
130
|
+
|
131
|
+
.xxsection-bar {
|
132
|
+
background: #eee;
|
133
|
+
color: #333;
|
134
|
+
padding: 3px;
|
135
|
+
}
|
136
|
+
|
137
|
+
.section-bar {
|
138
|
+
color: #333;
|
139
|
+
border-bottom: 1px solid #999;
|
140
|
+
margin-left: -20px;
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
.section-title {
|
145
|
+
background: #79a;
|
146
|
+
color: #eee;
|
147
|
+
padding: 3px;
|
148
|
+
margin-top: 2em;
|
149
|
+
margin-left: -30px;
|
150
|
+
border: 1px solid #999;
|
151
|
+
}
|
152
|
+
|
153
|
+
.top-aligned-row { vertical-align: top }
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
155
|
+
|
156
|
+
/* --- Context section classes ----------------------- */
|
157
|
+
|
158
|
+
.context-row { }
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
162
|
+
|
163
|
+
/* --- Method classes -------------------------- */
|
164
|
+
.method-detail {
|
165
|
+
background: #efefef;
|
166
|
+
padding: 0;
|
167
|
+
margin-top: 0.5em;
|
168
|
+
margin-bottom: 1em;
|
169
|
+
border: 1px dotted #ccc;
|
170
|
+
}
|
171
|
+
.method-heading {
|
172
|
+
color: black;
|
173
|
+
background: #ccc;
|
174
|
+
border-bottom: 1px solid #666;
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
176
|
+
}
|
177
|
+
.method-signature { color: black; background: inherit; }
|
178
|
+
.method-name { font-weight: bold; }
|
179
|
+
.method-args { font-style: italic; }
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
181
|
+
|
182
|
+
/* --- Source code sections -------------------- */
|
183
|
+
|
184
|
+
a.source-toggle { font-size: 90%; }
|
185
|
+
div.method-source-code {
|
186
|
+
background: #262626;
|
187
|
+
color: #ffdead;
|
188
|
+
margin: 1em;
|
189
|
+
padding: 0.5em;
|
190
|
+
border: 1px dashed #999;
|
191
|
+
overflow: hidden;
|
192
|
+
}
|
193
|
+
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
195
|
+
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
197
|
+
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
199
|
+
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
@@ -0,0 +1,189 @@
|
|
1
|
+
#
|
2
|
+
# = UserAgentInfo
|
3
|
+
#
|
4
|
+
# == simplify user-agent detection in Rails
|
5
|
+
#
|
6
|
+
# Author:: Mehmet Celik
|
7
|
+
#
|
8
|
+
# == Usage
|
9
|
+
#
|
10
|
+
# It extends ActionController::Request and parses the requests HTTP_USER_AGENT header so it can be queried.
|
11
|
+
# The supported browsers are IE, Firefox, Chrome, Opera this translates into the methods isIE?, isFirefox?, isChrome, isOpera?
|
12
|
+
# You can also supply a version like isIE?('6.0') and you can query if it is worse or/and better then a version isIE_or_worse?('6.0')
|
13
|
+
#
|
14
|
+
# === Example
|
15
|
+
#
|
16
|
+
# class UpgradeBrowserController < ApplicationController
|
17
|
+
# def index
|
18
|
+
# @upgrade = request.user_agent_info.isIE_or_worse?('6.0')
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
|
22
|
+
|
23
|
+
module UserAgentInfo
|
24
|
+
class UserAgent
|
25
|
+
attr_reader :browser_info
|
26
|
+
|
27
|
+
def initialize(r) #:nodoc:
|
28
|
+
parse_browser_info(r)
|
29
|
+
end
|
30
|
+
|
31
|
+
# query user_agent_info
|
32
|
+
#
|
33
|
+
# request.user_agent_info['header'] ==> Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4
|
34
|
+
# request.user_agent_info['platform'] ==> Macintosh
|
35
|
+
# request.user_agent_info['name'] ==> Firefox
|
36
|
+
# request.user_agent_info['name_display'] ==> Mozilla Firefox
|
37
|
+
# request.user_agent_info['cpuos'] ==> Intel Mac OS X 10.5
|
38
|
+
# request.user_agent_info['language'] ==> en-US
|
39
|
+
# request.user_agent_info['version'] ==> 3.5
|
40
|
+
# request.user_agent_info['engine'] ==> Gecko/20091016
|
41
|
+
def [](lookup)
|
42
|
+
@browser_info[lookup]
|
43
|
+
end
|
44
|
+
|
45
|
+
# check if browser is Internet Explorer
|
46
|
+
# request.user_agent_info.isIE? ==> true if browser is Internet Explorer <br />
|
47
|
+
# request.user_agent_info.isIE?('6.0') ==> true if browser is Internet Explorer version 6.0 '=='
|
48
|
+
# request.user_agent_info.isIE_or_worse?('6.0') ==> true if browser is Internet Explorer version worse or equal to 6.0 '<='
|
49
|
+
# request.user_agent_info.isIE_and_worse?('6.0') ==> true if browser is Internet Explorer version worse then 6.0 '<'
|
50
|
+
# request.user_agent_info.isIE_or_better?('6.0') ==> true if browser is Internet Explorer version better or equal to 6.0 '>='
|
51
|
+
# request.user_agent_info.isIE_and_better?('6.0') ==> true if browser is Internet Explorer version better then 6.0 '>'
|
52
|
+
def isIE?(version = nil)
|
53
|
+
browser_query('MSIE', version)
|
54
|
+
end
|
55
|
+
|
56
|
+
def isFirefox?(version = nil)
|
57
|
+
browser_query('Firefox', version)
|
58
|
+
end
|
59
|
+
|
60
|
+
def isChrome?(version = nil)
|
61
|
+
browser_query('Chrome', version)
|
62
|
+
end
|
63
|
+
|
64
|
+
def isOpera?(version = nil)
|
65
|
+
browser_query('Opera', version)
|
66
|
+
end
|
67
|
+
|
68
|
+
def method_missing(method_id, *arguments, &block) #:nodoc:
|
69
|
+
actions = ['better', 'worse']
|
70
|
+
operators = ['or', 'and']
|
71
|
+
|
72
|
+
method = method_id.to_s
|
73
|
+
method_name = "#{method.split('_')[0]}?"
|
74
|
+
|
75
|
+
operator = method.split('_')[1]
|
76
|
+
action = method.split('_')[2].chop
|
77
|
+
|
78
|
+
return false if !operators.include?(operator)
|
79
|
+
return false if !action.include?(action)
|
80
|
+
|
81
|
+
if self.send method_name.to_sym
|
82
|
+
if arguments.size != 1
|
83
|
+
raise RuntimeError, "Missing 'version' argument."
|
84
|
+
end
|
85
|
+
|
86
|
+
version = arguments[0].to_f
|
87
|
+
case
|
88
|
+
when action.eql?("better") && operator.eql?('or')
|
89
|
+
return @browser_info['version'] >= version
|
90
|
+
when action.eql?("better") && operator.eql?('and')
|
91
|
+
return @browser_info['version'] > version
|
92
|
+
when action.eql?("worse") && operator.eql?('or')
|
93
|
+
return @browser_info['version'] <= version
|
94
|
+
when action.eql?("worse") && operator.eql?('and')
|
95
|
+
return @browser_info['version'] < version
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def parse_browser_info(r)
|
104
|
+
supported_browser = %w(MSIE Firefox Chrome Opera)
|
105
|
+
browser_labels = {"MSIE" => 'Microsoft Internet Explorer',
|
106
|
+
"Firefox" => "Mozilla Firefox",
|
107
|
+
"Chrome" => "Google Chrome",
|
108
|
+
"Opera" => "Opera",
|
109
|
+
"unknown" => "unknown"}
|
110
|
+
|
111
|
+
header = platform = name = cpuos = language = engine = ''
|
112
|
+
version = 0.0
|
113
|
+
|
114
|
+
if r.nil?
|
115
|
+
raise "Couldn't determine request"
|
116
|
+
end
|
117
|
+
header = r.headers['HTTP_USER_AGENT']
|
118
|
+
|
119
|
+
case
|
120
|
+
when header.match('MSIE')
|
121
|
+
string_match = header.match('.*? \((.*?)?\)( .*)?')
|
122
|
+
browser = string_match[1].split(';').map {|e| e.strip}
|
123
|
+
|
124
|
+
platform = browser[0]
|
125
|
+
cpuos = browser[2]
|
126
|
+
name_version = browser[1].split(' ')
|
127
|
+
version = name_version[1].to_f
|
128
|
+
name = name_version[0]
|
129
|
+
language = ''
|
130
|
+
when header.match('Firefox') || header.match('Chrome') || header.match('Safari')
|
131
|
+
string_match = header.match('.*? \((.*?)?\)( .*)?')
|
132
|
+
browser = string_match[1].split(';').map {|e| e.strip}
|
133
|
+
platform = browser[0]
|
134
|
+
name = browser[1]
|
135
|
+
cpuos = browser[2]
|
136
|
+
language = browser[3]
|
137
|
+
|
138
|
+
name_version_engine = string_match[2].gsub(/\(.*?\)/,'').split(' ')
|
139
|
+
name_version = name_version_engine[1].split('/')
|
140
|
+
name = name_version[0]
|
141
|
+
version = name_version[1].to_f
|
142
|
+
engine = name_version_engine[0]
|
143
|
+
when header.match('Opera')
|
144
|
+
string_match = header.match('(.*?) \((.*?)?\)( .*)?')
|
145
|
+
browser = string_match[1].split('/').map { |e| e.strip }
|
146
|
+
name = browser[0]
|
147
|
+
version = browser[1].to_f
|
148
|
+
browser = string_match[2].split(';').map {|e| e.strip}
|
149
|
+
platform = browser[0]
|
150
|
+
cpuos = browser[1]
|
151
|
+
language = browser[3]
|
152
|
+
engine = string_match[3].strip
|
153
|
+
else
|
154
|
+
platform = name = cpuos = language = engine = 'unknown'
|
155
|
+
end
|
156
|
+
|
157
|
+
@browser_info = {'header' => header, 'platform' => platform, 'name' => name, 'name_display' => browser_labels[name],
|
158
|
+
'cpuos' => cpuos, 'language' => language, 'version' => version, 'engine' => engine}
|
159
|
+
|
160
|
+
@browser_info
|
161
|
+
end
|
162
|
+
|
163
|
+
def browser_query(browser_name, version)
|
164
|
+
response = false
|
165
|
+
if @browser_info.nil?
|
166
|
+
parse_browser_info
|
167
|
+
end
|
168
|
+
|
169
|
+
unless @browser_info.nil?
|
170
|
+
if @browser_info['name'].eql?(browser_name)
|
171
|
+
if version.nil? || version.empty?
|
172
|
+
response = true
|
173
|
+
else
|
174
|
+
response = true if (@browser_info['version'] == version.to_f)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
response
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class ActionController::Request #:nodoc: all
|
186
|
+
def user_agent_info
|
187
|
+
UserAgentInfo::UserAgent.new(self)
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
$LOAD_PATH << '../lib'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'shoulda'
|
5
|
+
|
6
|
+
require 'action_controller'
|
7
|
+
require 'user_agent_info'
|
8
|
+
|
9
|
+
|
10
|
+
class Request
|
11
|
+
attr_accessor :headers
|
12
|
+
|
13
|
+
def initialize(header)
|
14
|
+
@headers = {'HTTP_USER_AGENT' => header}
|
15
|
+
end
|
16
|
+
|
17
|
+
def user_agent_info
|
18
|
+
UserAgentInfo::UserAgent.new(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def headers
|
22
|
+
@headers
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
FIREFOX_OSX_HEADER ='Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4'
|
28
|
+
CHROME_OSX_HEADER ='Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Chrome/4.0.223.11 Safari/532.3'
|
29
|
+
OPERA_OSX_HEADER ='Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00'
|
30
|
+
IE_80_WIN_HEADER ='Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)'
|
31
|
+
IE_70_WIN_HEADER ='Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)'
|
32
|
+
FIREFOX_WIN_HEADER ='Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 (.NET CLR 3.5.30729)'
|
33
|
+
|
34
|
+
class TestBrowsers < Test::Unit::TestCase
|
35
|
+
|
36
|
+
context "All browsers user agent info" do
|
37
|
+
context "MS Internet Explorer" do
|
38
|
+
setup do
|
39
|
+
@request = Request.new(IE_80_WIN_HEADER)
|
40
|
+
@browser = "This is #{@request.user_agent_info['name_display']} #{@request.user_agent_info['version']}"
|
41
|
+
end
|
42
|
+
|
43
|
+
should 'be Internet Explorer 8.0' do
|
44
|
+
assert(@request.user_agent_info.isIE?('8.0'), @browser)
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'be Internet Explorer 6.0 or better' do
|
48
|
+
assert(@request.user_agent_info.isIE_or_better?('6.0'), @browser)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|