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.
@@ -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