user_agent_info 0.1.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/.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
|