brauser 1.0.7 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -1
- data/Gemfile +1 -1
- data/README.md +6 -3
- data/Rakefile +1 -1
- data/brauser.gemspec +10 -8
- data/doc/Brauser.html +4 -4
- data/doc/Brauser/Browser.html +1722 -3546
- data/doc/Brauser/BrowserMethods.html +125 -0
- data/doc/Brauser/BrowserMethods/Attributes.html +484 -0
- data/doc/Brauser/BrowserMethods/General.html +134 -0
- data/doc/Brauser/BrowserMethods/General/ClassMethods.html +529 -0
- data/doc/Brauser/BrowserMethods/Parsing.html +350 -0
- data/doc/Brauser/BrowserMethods/PartialQuerying.html +629 -0
- data/doc/Brauser/BrowserMethods/Querying.html +583 -0
- data/doc/Brauser/BrowserMethods/Register.html +134 -0
- data/doc/Brauser/BrowserMethods/Register/ClassMethods.html +1081 -0
- data/doc/Brauser/Hooks.html +3 -3
- data/doc/Brauser/Hooks/RubyOnRails.html +3 -3
- data/doc/Brauser/Query.html +470 -52
- data/doc/Brauser/Version.html +5 -5
- data/doc/_index.html +102 -4
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +11 -8
- data/doc/frames.html +1 -1
- data/doc/index.html +11 -8
- data/doc/method_list.html +61 -61
- data/doc/top-level-namespace.html +3 -3
- data/lib/brauser.rb +1 -1
- data/lib/brauser/browser.rb +725 -674
- data/lib/brauser/hooks.rb +1 -1
- data/lib/brauser/query.rb +6 -4
- data/lib/brauser/version.rb +3 -3
- data/spec/brauser/browser_spec.rb +15 -38
- data/spec/brauser/hooks_spec.rb +1 -1
- data/spec/brauser/query_spec.rb +1 -1
- data/spec/brauser_spec.rb +1 -1
- data/spec/coverage_helper.rb +1 -1
- data/spec/frameworks_helper.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +25 -22
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>
|
7
7
|
Top Level Namespace
|
8
8
|
|
9
|
-
— Documentation by YARD 0.8.
|
9
|
+
— Documentation by YARD 0.8.3
|
10
10
|
|
11
11
|
</title>
|
12
12
|
|
@@ -103,9 +103,9 @@
|
|
103
103
|
</div>
|
104
104
|
|
105
105
|
<div id="footer">
|
106
|
-
Generated on
|
106
|
+
Generated on Sat Feb 2 17:47:18 2013 by
|
107
107
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
108
|
-
0.8.
|
108
|
+
0.8.3 (ruby-1.9.3).
|
109
109
|
</div>
|
110
110
|
|
111
111
|
</body>
|
data/lib/brauser.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
#
|
3
|
-
# This file is part of the brauser gem. Copyright (C)
|
3
|
+
# This file is part of the brauser gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
4
|
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
5
|
#
|
6
6
|
|
data/lib/brauser/browser.rb
CHANGED
@@ -1,678 +1,755 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
#
|
3
|
-
# This file is part of the brauser gem. Copyright (C)
|
3
|
+
# This file is part of the brauser gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
4
|
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
5
|
#
|
6
6
|
|
7
7
|
# A framework agnostic browser detection and querying helper.
|
8
8
|
module Brauser
|
9
|
-
#
|
10
|
-
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
9
|
+
# Methods of the {Browser Browser} class.
|
10
|
+
module BrowserMethods
|
11
|
+
# Methods for register recognized browsers, versions and platforms.
|
12
|
+
module Register
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
|
15
|
+
# Class methods.
|
16
|
+
module ClassMethods
|
17
|
+
# Registers the default list of browsers that can be recognized.
|
18
|
+
#
|
19
|
+
# @return [Boolean] `true` if at least one browser has been added, `false` otherwise.
|
20
|
+
def register_default_browsers
|
21
|
+
@browsers = nil
|
22
|
+
|
23
|
+
register_mobile_browsers
|
24
|
+
register_desktop_browsers
|
25
|
+
|
26
|
+
@browsers.present? ? true : false
|
27
|
+
end
|
25
28
|
|
26
|
-
|
27
|
-
|
29
|
+
# Registers the default list of platforms that can be recognized.
|
30
|
+
#
|
31
|
+
# @return [Boolean] `true` if at least one platform has been added, `false` otherwise.
|
32
|
+
def register_default_platforms
|
33
|
+
@platforms = nil
|
34
|
+
|
35
|
+
self.register_platform([
|
36
|
+
[:symbian, /s60|symb/i, "Symbian"],
|
37
|
+
[:windows_phone, /windows phone/i, "Microsoft Windows Phone"],
|
38
|
+
[:kindle, Proc.new { |name, agent| name == :kindle }, "Nokia Symbian"],
|
39
|
+
[:ios, Proc.new { |name, agent| [:iphone, :ipad, :ipod].include?(name) || agent =~ /ipad|iphone|ipod/i }, "Apple iOS"],
|
40
|
+
[:android, /android/i, "Android"],
|
41
|
+
[:blackberry, /blackberry/i, "RIM BlackBerry"],
|
42
|
+
[:psp, /psp/i, "Sony Playstation Portable"],
|
43
|
+
[:ps3, /playstation 3/i, "Sony Playstation 3"],
|
44
|
+
[:wii, /wii/i, "Nintendo Wii"],
|
45
|
+
|
46
|
+
[:linux, /linux/i, "Linux"],
|
47
|
+
[:osx, /mac|macintosh|mac os x/i, "Apple MacOS X"],
|
48
|
+
[:windows, /windows/i, "Microsoft Windows"]
|
49
|
+
])
|
50
|
+
|
51
|
+
@platforms.present? ? true : false
|
52
|
+
end
|
28
53
|
|
29
|
-
|
30
|
-
|
31
|
-
|
54
|
+
# Registers the default list of languages that can be recognized.
|
55
|
+
#
|
56
|
+
# @return [Boolean] `true` if at least one language has been added, `false` otherwise.
|
57
|
+
def register_default_languages
|
58
|
+
@languages = nil
|
59
|
+
|
60
|
+
self.register_language({
|
61
|
+
"af" => "Afrikaans",
|
62
|
+
"sq" => "Albanian",
|
63
|
+
"eu" => "Basque",
|
64
|
+
"bg" => "Bulgarian",
|
65
|
+
"be" => "Byelorussian",
|
66
|
+
"ca" => "Catalan",
|
67
|
+
"zh" => "Chinese",
|
68
|
+
"zh-cn" => "Chinese/China",
|
69
|
+
"zh-tw" => "Chinese/Taiwan",
|
70
|
+
"zh-hk" => "Chinese/Hong Kong",
|
71
|
+
"zh-sg" => "Chinese/singapore",
|
72
|
+
"hr" => "Croatian",
|
73
|
+
"cs" => "Czech",
|
74
|
+
"da" => "Danish",
|
75
|
+
"nl" => "Dutch",
|
76
|
+
"nl-nl" => "Dutch/Netherlands",
|
77
|
+
"nl-be" => "Dutch/Belgium",
|
78
|
+
"en" => "English",
|
79
|
+
"en-gb" => "English/United Kingdom",
|
80
|
+
"en-us" => "English/United States",
|
81
|
+
"en-au" => "English/Australian",
|
82
|
+
"en-ca" => "English/Canada",
|
83
|
+
"en-nz" => "English/New Zealand",
|
84
|
+
"en-ie" => "English/Ireland",
|
85
|
+
"en-za" => "English/South Africa",
|
86
|
+
"en-jm" => "English/Jamaica",
|
87
|
+
"en-bz" => "English/Belize",
|
88
|
+
"en-tt" => "English/Trinidad",
|
89
|
+
"et" => "Estonian",
|
90
|
+
"fo" => "Faeroese",
|
91
|
+
"fa" => "Farsi",
|
92
|
+
"fi" => "Finnish",
|
93
|
+
"fr" => "French",
|
94
|
+
"fr-be" => "French/Belgium",
|
95
|
+
"fr-fr" => "French/France",
|
96
|
+
"fr-ch" => "French/Switzerland",
|
97
|
+
"fr-ca" => "French/Canada",
|
98
|
+
"fr-lu" => "French/Luxembourg",
|
99
|
+
"gd" => "Gaelic",
|
100
|
+
"gl" => "Galician",
|
101
|
+
"de" => "German",
|
102
|
+
"de-at" => "German/Austria",
|
103
|
+
"de-de" => "German/Germany",
|
104
|
+
"de-ch" => "German/Switzerland",
|
105
|
+
"de-lu" => "German/Luxembourg",
|
106
|
+
"de-li" => "German/Liechtenstein",
|
107
|
+
"el" => "Greek",
|
108
|
+
"he" => "Hebrew",
|
109
|
+
"he-il" => "Hebrew/Israel",
|
110
|
+
"hi" => "Hindi",
|
111
|
+
"hu" => "Hungarian",
|
112
|
+
"ie-ee" => "Internet Explorer/Easter Egg",
|
113
|
+
"is" => "Icelandic",
|
114
|
+
"id" => "Indonesian",
|
115
|
+
"in" => "Indonesian",
|
116
|
+
"ga" => "Irish",
|
117
|
+
"it" => "Italian",
|
118
|
+
"it-ch" => "Italian/ Switzerland",
|
119
|
+
"ja" => "Japanese",
|
120
|
+
"km" => "Khmer",
|
121
|
+
"km-kh" => "Khmer/Cambodia",
|
122
|
+
"ko" => "Korean",
|
123
|
+
"lv" => "Latvian",
|
124
|
+
"lt" => "Lithuanian",
|
125
|
+
"mk" => "Macedonian",
|
126
|
+
"ms" => "Malaysian",
|
127
|
+
"mt" => "Maltese",
|
128
|
+
"no" => "Norwegian",
|
129
|
+
"pl" => "Polish",
|
130
|
+
"pt" => "Portuguese",
|
131
|
+
"pt-br" => "Portuguese/Brazil",
|
132
|
+
"rm" => "Rhaeto-Romanic",
|
133
|
+
"ro" => "Romanian",
|
134
|
+
"ro-mo" => "Romanian/Moldavia",
|
135
|
+
"ru" => "Russian",
|
136
|
+
"ru-mo" => "Russian /Moldavia",
|
137
|
+
"gd" => "Scots Gaelic",
|
138
|
+
"sr" => "Serbian",
|
139
|
+
"sk" => "Slovack",
|
140
|
+
"sl" => "Slovenian",
|
141
|
+
"sb" => "Sorbian",
|
142
|
+
"es" => "Spanish",
|
143
|
+
"es-do" => "Spanish",
|
144
|
+
"es-ar" => "Spanish/Argentina",
|
145
|
+
"es-co" => "Spanish/Colombia",
|
146
|
+
"es-mx" => "Spanish/Mexico",
|
147
|
+
"es-es" => "Spanish/Spain",
|
148
|
+
"es-gt" => "Spanish/Guatemala",
|
149
|
+
"es-cr" => "Spanish/Costa Rica",
|
150
|
+
"es-pa" => "Spanish/Panama",
|
151
|
+
"es-ve" => "Spanish/Venezuela",
|
152
|
+
"es-pe" => "Spanish/Peru",
|
153
|
+
"es-ec" => "Spanish/Ecuador",
|
154
|
+
"es-cl" => "Spanish/Chile",
|
155
|
+
"es-uy" => "Spanish/Uruguay",
|
156
|
+
"es-py" => "Spanish/Paraguay",
|
157
|
+
"es-bo" => "Spanish/Bolivia",
|
158
|
+
"es-sv" => "Spanish/El salvador",
|
159
|
+
"es-hn" => "Spanish/Honduras",
|
160
|
+
"es-ni" => "Spanish/Nicaragua",
|
161
|
+
"es-pr" => "Spanish/Puerto Rico",
|
162
|
+
"sx" => "Sutu",
|
163
|
+
"sv" => "Swedish",
|
164
|
+
"sv-se" => "Swedish/Sweden",
|
165
|
+
"sv-fi" => "Swedish/Finland",
|
166
|
+
"ts" => "Thai",
|
167
|
+
"tn" => "Tswana",
|
168
|
+
"tr" => "Turkish",
|
169
|
+
"uk" => "Ukrainian",
|
170
|
+
"ur" => "Urdu",
|
171
|
+
"vi" => "Vietnamese",
|
172
|
+
"xh" => "Xshosa",
|
173
|
+
"ji" => "Yiddish",
|
174
|
+
"zu" => "Zulu"
|
175
|
+
})
|
176
|
+
|
177
|
+
@languages.present? ? true : false
|
178
|
+
end
|
32
179
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
180
|
+
# Registers a new browser that can be recognized.
|
181
|
+
#
|
182
|
+
# @param name [Symbol|Array] The browser name or a list of browser (a list of array with `[name, name_match, version_match, label]` entries).
|
183
|
+
# @param name_match [String|Regexp|Block] The matcher for the name. If a block, it will be yield with the user agent and must return `true` if the name was recognized.
|
184
|
+
# @param version_match [String|Regexp|Block] The match for the version. If a block, it will be yield with the browser name and the user agent and must return the browser version.
|
185
|
+
# @param label [String] A human readable name of the browser.
|
186
|
+
# @return [Boolean] `true` if at least one browser has been added, `false` otherwise.
|
187
|
+
def register_browser(name, name_match = nil, version_match = nil, label = nil)
|
188
|
+
@browsers ||= []
|
189
|
+
register_entries(@browsers, (name.is_a?(Array) ? name : [[name.ensure_string, name_match, version_match, label]]))
|
190
|
+
end
|
40
191
|
|
41
|
-
|
42
|
-
|
43
|
-
|
192
|
+
# Registers a new platform that can be recognized.
|
193
|
+
#
|
194
|
+
# @param name [Symbol|Array] The platform name or a list of platforms (a list of array with `[name, matcher, label]` entries).
|
195
|
+
# @param matcher [StringRegexp|Block] The matcher for the platform. If a block, it will be yielded with the browser name and the user agent and must return `true` if the platform was recognized.
|
196
|
+
# @param label [String] A human readable name of the platform.
|
197
|
+
# @return [Boolean] `true` if at least one platform has been added, `false` otherwise.
|
198
|
+
def register_platform(name, matcher = nil, label = nil)
|
199
|
+
@platforms ||= []
|
200
|
+
register_entries(@platforms, (name.is_a?(Array) ? name : [[name.ensure_string, matcher, label]]))
|
201
|
+
end
|
44
202
|
|
45
|
-
|
46
|
-
|
203
|
+
# Registers a new language that can be recognized.
|
204
|
+
#
|
205
|
+
# @param code [String|Hash] The language code or an hash with codes as keys and label as values.
|
206
|
+
# @param label [String] The language name. Ignored if code is an Hash.
|
207
|
+
# @return [Boolean] `true` if at least one language has been added, `false` otherwise.
|
208
|
+
def register_language(code, label = nil)
|
209
|
+
@languages ||= {}
|
210
|
+
rv = false
|
211
|
+
code = {code.ensure_string => label.ensure_string} if !code.is_a?(Hash)
|
212
|
+
|
213
|
+
code.each_pair do |c, l|
|
214
|
+
if c.present? && l.present? then
|
215
|
+
@languages[c] = l
|
216
|
+
rv = true
|
217
|
+
end
|
218
|
+
end
|
47
219
|
|
48
|
-
|
49
|
-
|
50
|
-
# The keys are the platform name, values are arrays of the matcher and the label.
|
51
|
-
#
|
52
|
-
# @return [Hash] The list of platform that can be recognized.
|
53
|
-
def self.platforms
|
54
|
-
rv = ActiveSupport::OrderedHash.new
|
220
|
+
rv
|
221
|
+
end
|
55
222
|
|
56
|
-
|
57
|
-
|
58
|
-
|
223
|
+
private
|
224
|
+
# Register the most common desktop browsers.
|
225
|
+
# @return [Boolean] `true` if at least one browser has been added, `false` otherwise.
|
226
|
+
def register_desktop_browsers
|
227
|
+
self.register_browser([
|
228
|
+
[:chrome, /((chrome)|(chromium))/i, /(.+Chrom[a-z]+\/)([a-z0-9.]+)/i, "Google Chrome"],
|
229
|
+
[:netscape, /(netscape|navigator)\//i, /((Netscape|Navigator)\/)([a-z0-9.]+)/i, "Netscape Navigator"],
|
230
|
+
[:firefox, /firefox/i, /(.+Firefox\/)([a-z0-9.]+)/i, "Mozilla Firefox"],
|
231
|
+
[:safari, Proc.new{ |agent| agent =~ /safari/i && agent !~ /((chrome)|(chromium))/i }, /(.+Version\/)([a-z0-9.]+)/i, "Apple Safari"],
|
232
|
+
|
233
|
+
[:msie_compatibility, /trident/i, Proc.new { |name, agent|
|
234
|
+
version = /(.+Trident\/)([a-z0-9.]+)/i.match(agent)
|
235
|
+
|
236
|
+
if version.is_a?(::MatchData) then
|
237
|
+
v = version.to_a.last.split(".")
|
238
|
+
v[0] = v[0].to_integer + 4
|
239
|
+
version = v.join(".")
|
240
|
+
end
|
59
241
|
|
60
|
-
|
61
|
-
|
242
|
+
version
|
243
|
+
}, "Microsoft Internet Explorer (Compatibility View)"],
|
244
|
+
[:msie, Proc.new{ |agent| agent =~ /msie/i && agent !~ /opera/i }, /(.+MSIE )([a-z0-9.]+)/i, "Microsoft Internet Explorer"],
|
62
245
|
|
63
|
-
|
64
|
-
#
|
65
|
-
# The keys are the languages code, the values the labels.
|
66
|
-
#
|
67
|
-
# @return [Hash] The list of languages that can be recognized.
|
68
|
-
def self.languages
|
69
|
-
@languages
|
70
|
-
end
|
246
|
+
[:quicktime, /quicktime/i, /(.+((QuickTime\/)|(qtver=)))([a-z0-9.]+)/i, "Apple QuickTime"],
|
71
247
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
def self.register_default_browsers
|
76
|
-
@browsers = nil
|
77
|
-
|
78
|
-
self.register_browser([
|
79
|
-
[:coremedia, /coremedia/i, /.+CoreMedia v([a-z0-9.]+)/i, "Apple CoreMedia"],
|
80
|
-
|
81
|
-
[:opera_mobile, /opera mobi/i, /.+Opera Mobi.+((.+Opera )|(Version\/))([a-z0-9.]+)/i, "Opera Mobile"],
|
82
|
-
[:opera, /opera/i, Proc.new{ |name, agent|
|
83
|
-
regexp = (agent !~ /wii/i) ? /((.+Opera )|(Version\/))([a-z0-9.]+)/i : /(.+Nintendo Wii; U; ; )([a-z0-9.]+)/i
|
84
|
-
|
85
|
-
version = regexp.match(agent)
|
86
|
-
version = version.to_a.last if version.is_a?(MatchData)
|
87
|
-
version
|
88
|
-
}, "Opera"],
|
89
|
-
|
90
|
-
[:android, /android/i, /(.+Android )([a-z0-9.]+)/i, "Android"],
|
91
|
-
[:blackberry, /blackberry/i, /(.+Version\/)([a-z0-9.]+)/i, "RIM BlackBerry"],
|
92
|
-
[:kindle, /(kindle)/i, /(.+(Kindle|Silk)\/)([a-z0-9.]+)/i, "Amazon Kindle"],
|
93
|
-
[:psp, /psp/i, /(.+PlayStation Portable\); )([a-z0-9.]+)/i, "Sony Playstation Portable"],
|
94
|
-
[:ps3, /playstation 3/i, /(.+PLAYSTATION 3; )([a-z0-9.]+)/i, "Sony Playstation 3"],
|
95
|
-
[:windows_phone, /windows phone/i, /(.+IEMobile\/)([a-z0-9.]+)/i, "Microsoft Windows Phone"],
|
96
|
-
[:wii, /nintendo wii/, /(.+Nintendo Wii; U; ; )([a-z0-9.]+)/i, "Nintendo Wii"],
|
97
|
-
|
98
|
-
[:ipod, /ipod/i, /(.+Version\/)([a-z0-9.]+)/i, "Apple iPod"],
|
99
|
-
[:iphone, /iphone/i, /(.+Version\/)([a-z0-9.]+)/i, "Apple iPhone"],
|
100
|
-
[:ipad, /ipad/i, /(.+Version\/)([a-z0-9.]+)/i, "Apple iPad"],
|
101
|
-
|
102
|
-
[:mobile, /(mobile|symbian|midp|windows ce)/i, /.+\/([a-z0-9.]+)/i, "Other Mobile Browser"],
|
103
|
-
|
104
|
-
[:chrome, /((chrome)|(chromium))/i, /(.+Chrom[a-z]+\/)([a-z0-9.]+)/i, "Google Chrome"],
|
105
|
-
[:netscape, /(netscape|navigator)\//i, /((Netscape|Navigator)\/)([a-z0-9.]+)/i, "Netscape Navigator"],
|
106
|
-
[:firefox, /firefox/i, /(.+Firefox\/)([a-z0-9.]+)/i, "Mozilla Firefox"],
|
107
|
-
[:safari, Proc.new{ |agent| agent =~ /safari/i && agent !~ /((chrome)|(chromium))/i }, /(.+Version\/)([a-z0-9.]+)/i, "Apple Safari"],
|
108
|
-
|
109
|
-
[:msie_compatibility, /trident/i, Proc.new { |name, agent|
|
110
|
-
version = /(.+Trident\/)([a-z0-9.]+)/i.match(agent)
|
111
|
-
|
112
|
-
if version.is_a?(::MatchData) then
|
113
|
-
v = version.to_a.last.split(".")
|
114
|
-
v[0] = v[0].to_integer + 4
|
115
|
-
version = v.join(".")
|
248
|
+
[:webkit, /webkit/i, /(.+WebKit\/)([a-z0-9.]+)/i, "WebKit Browser"],
|
249
|
+
[:gecko, /gecko/i, /(.+rv:|Gecko\/)([a-z0-9.]+)/i, "Gecko Browser"],
|
250
|
+
])
|
116
251
|
end
|
117
252
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
253
|
+
# Register the most common mobile and console browsers.
|
254
|
+
# @return [Boolean] `true` if at least one browser has been added, `false` otherwise.
|
255
|
+
def register_mobile_browsers
|
256
|
+
self.register_browser([
|
257
|
+
[:coremedia, /coremedia/i, /.+CoreMedia v([a-z0-9.]+)/i, "Apple CoreMedia"],
|
258
|
+
|
259
|
+
[:opera_mobile, /opera mobi/i, /.+Opera Mobi.+((.+Opera )|(Version\/))([a-z0-9.]+)/i, "Opera Mobile"],
|
260
|
+
[:opera, /opera/i, Proc.new{ |name, agent|
|
261
|
+
regexp = (agent !~ /wii/i) ? /((.+Opera )|(Version\/))([a-z0-9.]+)/i : /(.+Nintendo Wii; U; ; )([a-z0-9.]+)/i
|
262
|
+
|
263
|
+
version = regexp.match(agent)
|
264
|
+
version = version.to_a.last if version.is_a?(MatchData)
|
265
|
+
version
|
266
|
+
}, "Opera"],
|
267
|
+
|
268
|
+
[:android, /android/i, /(.+Android )([a-z0-9.]+)/i, "Android"],
|
269
|
+
[:blackberry, /blackberry/i, /(.+Version\/)([a-z0-9.]+)/i, "RIM BlackBerry"],
|
270
|
+
[:kindle, /(kindle)/i, /(.+(Kindle|Silk)\/)([a-z0-9.]+)/i, "Amazon Kindle"],
|
271
|
+
[:psp, /psp/i, /(.+PlayStation Portable\); )([a-z0-9.]+)/i, "Sony Playstation Portable"],
|
272
|
+
[:ps3, /playstation 3/i, /(.+PLAYSTATION 3; )([a-z0-9.]+)/i, "Sony Playstation 3"],
|
273
|
+
[:windows_phone, /windows phone/i, /(.+IEMobile\/)([a-z0-9.]+)/i, "Microsoft Windows Phone"],
|
274
|
+
[:wii, /nintendo wii/, /(.+Nintendo Wii; U; ; )([a-z0-9.]+)/i, "Nintendo Wii"],
|
275
|
+
|
276
|
+
[:ipod, /ipod/i, /(.+Version\/)([a-z0-9.]+)/i, "Apple iPod"],
|
277
|
+
[:iphone, /iphone/i, /(.+Version\/)([a-z0-9.]+)/i, "Apple iPhone"],
|
278
|
+
[:ipad, /ipad/i, /(.+Version\/)([a-z0-9.]+)/i, "Apple iPad"],
|
279
|
+
|
280
|
+
[:mobile, /(mobile|symbian|midp|windows ce)/i, /.+\/([a-z0-9.]+)/i, "Other Mobile Browser"],
|
281
|
+
])
|
282
|
+
end
|
123
283
|
|
124
|
-
|
125
|
-
|
126
|
-
|
284
|
+
# Registers a new set of entries to a collection.
|
285
|
+
#
|
286
|
+
# @param collection [Array] The collection which add entries to.
|
287
|
+
# @param entries [Array] The entries to add.
|
288
|
+
def register_entries(collection, entries)
|
289
|
+
rv = false
|
290
|
+
|
291
|
+
entries.each do |entry|
|
292
|
+
entry[0] = entry[0].to_sym
|
293
|
+
index = collection.find_index { |item| item[0] == entry[0] }
|
294
|
+
|
295
|
+
# Replace a previous entry
|
296
|
+
if index then
|
297
|
+
collection[index] = entry
|
298
|
+
else
|
299
|
+
collection << entry
|
300
|
+
rv = true
|
301
|
+
end
|
302
|
+
end
|
127
303
|
|
128
|
-
|
304
|
+
rv
|
305
|
+
end
|
306
|
+
end
|
129
307
|
end
|
130
308
|
|
131
|
-
#
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
[:ps3, /playstation 3/i, "Sony Playstation 3"],
|
146
|
-
[:wii, /wii/i, "Nintendo Wii"],
|
147
|
-
|
148
|
-
[:linux, /linux/i, "Linux"],
|
149
|
-
[:osx, /mac|macintosh|mac os x/i, "Apple MacOS X"],
|
150
|
-
[:windows, /windows/i, "Microsoft Windows"]
|
151
|
-
])
|
152
|
-
|
153
|
-
@platforms.present? ? true : false
|
154
|
-
end
|
309
|
+
# General methods.
|
310
|
+
module General
|
311
|
+
extend ActiveSupport::Concern
|
312
|
+
|
313
|
+
# Class methods.
|
314
|
+
module ClassMethods
|
315
|
+
# Returns the list of browser that can be recognized.
|
316
|
+
#
|
317
|
+
# The keys are the browser name, the values are arrays of the name matcher, the version match and the label.
|
318
|
+
#
|
319
|
+
# @return [Hash] The list of browser that can be recognized.
|
320
|
+
def browsers
|
321
|
+
registered_to_hash(@browsers)
|
322
|
+
end
|
155
323
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
"sq" => "Albanian",
|
165
|
-
"eu" => "Basque",
|
166
|
-
"bg" => "Bulgarian",
|
167
|
-
"be" => "Byelorussian",
|
168
|
-
"ca" => "Catalan",
|
169
|
-
"zh" => "Chinese",
|
170
|
-
"zh-cn" => "Chinese/China",
|
171
|
-
"zh-tw" => "Chinese/Taiwan",
|
172
|
-
"zh-hk" => "Chinese/Hong Kong",
|
173
|
-
"zh-sg" => "Chinese/singapore",
|
174
|
-
"hr" => "Croatian",
|
175
|
-
"cs" => "Czech",
|
176
|
-
"da" => "Danish",
|
177
|
-
"nl" => "Dutch",
|
178
|
-
"nl-nl" => "Dutch/Netherlands",
|
179
|
-
"nl-be" => "Dutch/Belgium",
|
180
|
-
"en" => "English",
|
181
|
-
"en-gb" => "English/United Kingdom",
|
182
|
-
"en-us" => "English/United States",
|
183
|
-
"en-au" => "English/Australian",
|
184
|
-
"en-ca" => "English/Canada",
|
185
|
-
"en-nz" => "English/New Zealand",
|
186
|
-
"en-ie" => "English/Ireland",
|
187
|
-
"en-za" => "English/South Africa",
|
188
|
-
"en-jm" => "English/Jamaica",
|
189
|
-
"en-bz" => "English/Belize",
|
190
|
-
"en-tt" => "English/Trinidad",
|
191
|
-
"et" => "Estonian",
|
192
|
-
"fo" => "Faeroese",
|
193
|
-
"fa" => "Farsi",
|
194
|
-
"fi" => "Finnish",
|
195
|
-
"fr" => "French",
|
196
|
-
"fr-be" => "French/Belgium",
|
197
|
-
"fr-fr" => "French/France",
|
198
|
-
"fr-ch" => "French/Switzerland",
|
199
|
-
"fr-ca" => "French/Canada",
|
200
|
-
"fr-lu" => "French/Luxembourg",
|
201
|
-
"gd" => "Gaelic",
|
202
|
-
"gl" => "Galician",
|
203
|
-
"de" => "German",
|
204
|
-
"de-at" => "German/Austria",
|
205
|
-
"de-de" => "German/Germany",
|
206
|
-
"de-ch" => "German/Switzerland",
|
207
|
-
"de-lu" => "German/Luxembourg",
|
208
|
-
"de-li" => "German/Liechtenstein",
|
209
|
-
"el" => "Greek",
|
210
|
-
"he" => "Hebrew",
|
211
|
-
"he-il" => "Hebrew/Israel",
|
212
|
-
"hi" => "Hindi",
|
213
|
-
"hu" => "Hungarian",
|
214
|
-
"ie-ee" => "Internet Explorer/Easter Egg",
|
215
|
-
"is" => "Icelandic",
|
216
|
-
"id" => "Indonesian",
|
217
|
-
"in" => "Indonesian",
|
218
|
-
"ga" => "Irish",
|
219
|
-
"it" => "Italian",
|
220
|
-
"it-ch" => "Italian/ Switzerland",
|
221
|
-
"ja" => "Japanese",
|
222
|
-
"km" => "Khmer",
|
223
|
-
"km-kh" => "Khmer/Cambodia",
|
224
|
-
"ko" => "Korean",
|
225
|
-
"lv" => "Latvian",
|
226
|
-
"lt" => "Lithuanian",
|
227
|
-
"mk" => "Macedonian",
|
228
|
-
"ms" => "Malaysian",
|
229
|
-
"mt" => "Maltese",
|
230
|
-
"no" => "Norwegian",
|
231
|
-
"pl" => "Polish",
|
232
|
-
"pt" => "Portuguese",
|
233
|
-
"pt-br" => "Portuguese/Brazil",
|
234
|
-
"rm" => "Rhaeto-Romanic",
|
235
|
-
"ro" => "Romanian",
|
236
|
-
"ro-mo" => "Romanian/Moldavia",
|
237
|
-
"ru" => "Russian",
|
238
|
-
"ru-mo" => "Russian /Moldavia",
|
239
|
-
"gd" => "Scots Gaelic",
|
240
|
-
"sr" => "Serbian",
|
241
|
-
"sk" => "Slovack",
|
242
|
-
"sl" => "Slovenian",
|
243
|
-
"sb" => "Sorbian",
|
244
|
-
"es" => "Spanish",
|
245
|
-
"es-do" => "Spanish",
|
246
|
-
"es-ar" => "Spanish/Argentina",
|
247
|
-
"es-co" => "Spanish/Colombia",
|
248
|
-
"es-mx" => "Spanish/Mexico",
|
249
|
-
"es-es" => "Spanish/Spain",
|
250
|
-
"es-gt" => "Spanish/Guatemala",
|
251
|
-
"es-cr" => "Spanish/Costa Rica",
|
252
|
-
"es-pa" => "Spanish/Panama",
|
253
|
-
"es-ve" => "Spanish/Venezuela",
|
254
|
-
"es-pe" => "Spanish/Peru",
|
255
|
-
"es-ec" => "Spanish/Ecuador",
|
256
|
-
"es-cl" => "Spanish/Chile",
|
257
|
-
"es-uy" => "Spanish/Uruguay",
|
258
|
-
"es-py" => "Spanish/Paraguay",
|
259
|
-
"es-bo" => "Spanish/Bolivia",
|
260
|
-
"es-sv" => "Spanish/El salvador",
|
261
|
-
"es-hn" => "Spanish/Honduras",
|
262
|
-
"es-ni" => "Spanish/Nicaragua",
|
263
|
-
"es-pr" => "Spanish/Puerto Rico",
|
264
|
-
"sx" => "Sutu",
|
265
|
-
"sv" => "Swedish",
|
266
|
-
"sv-se" => "Swedish/Sweden",
|
267
|
-
"sv-fi" => "Swedish/Finland",
|
268
|
-
"ts" => "Thai",
|
269
|
-
"tn" => "Tswana",
|
270
|
-
"tr" => "Turkish",
|
271
|
-
"uk" => "Ukrainian",
|
272
|
-
"ur" => "Urdu",
|
273
|
-
"vi" => "Vietnamese",
|
274
|
-
"xh" => "Xshosa",
|
275
|
-
"ji" => "Yiddish",
|
276
|
-
"zu" => "Zulu"
|
277
|
-
})
|
278
|
-
|
279
|
-
@languages.present? ? true : false
|
280
|
-
end
|
324
|
+
# Returns the list of platforms that can be recognized.
|
325
|
+
#
|
326
|
+
# The keys are the platform name, values are arrays of the matcher and the label.
|
327
|
+
#
|
328
|
+
# @return [Hash] The list of platform that can be recognized.
|
329
|
+
def platforms
|
330
|
+
registered_to_hash(@platforms)
|
331
|
+
end
|
281
332
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
333
|
+
# Returns the list of languages that can be recognized.
|
334
|
+
#
|
335
|
+
# The keys are the languages code, the values the labels.
|
336
|
+
#
|
337
|
+
# @return [Hash] The list of languages that can be recognized.
|
338
|
+
def languages
|
339
|
+
@languages
|
340
|
+
end
|
341
|
+
|
342
|
+
# Compares two versions.
|
343
|
+
#
|
344
|
+
# @param v1 [String] The first versions to compare.
|
345
|
+
# @param operator [Symbol] The operator to use for comparison, can be one of `[:lt, :lte, :eq, :gte, :gt]`.
|
346
|
+
# @param v2 [Symbol] The second version to compare.
|
347
|
+
# @return [Boolean] true if comparison is valid, `false` otherwise.
|
348
|
+
def compare_versions(v1 = "", operator = :eq, v2 = "")
|
349
|
+
valid_results = {lt: [-1], lte: [-1, 0], eq: [0], gte: [0, 1], gt: [1]}.fetch(operator, [])
|
350
|
+
|
351
|
+
if valid_results.present? && v1.ensure_string.present? then
|
352
|
+
p1, p2 = find_relevant_tokens(v1.ensure_string.strip, v2.ensure_string.strip)
|
353
|
+
p1, p2 = normalize_tokens(p1, p2)
|
354
|
+
valid_results.include?(p1 <=> p2)
|
355
|
+
else
|
356
|
+
false
|
357
|
+
end
|
358
|
+
end
|
294
359
|
|
295
|
-
|
296
|
-
|
360
|
+
private
|
361
|
+
# Find relevant tokens (that is, the first two which are not equals) in a string for comparison.
|
362
|
+
#
|
363
|
+
# @param v1 [String] The first versions to compare.
|
364
|
+
# @param v2 [String] The second version to compare.
|
365
|
+
# @return [Array] The tokens to compare.
|
366
|
+
def find_relevant_tokens(v1, v2)
|
367
|
+
v1 = v1.split(".")
|
368
|
+
v2 = v2.split(".")
|
369
|
+
|
370
|
+
p1 = nil
|
371
|
+
p2 = nil
|
372
|
+
[v1.length, v2.length].max.times do |i|
|
373
|
+
p1 = v1[i]
|
374
|
+
p2 = v2[i]
|
375
|
+
break if !p1 && !p2 || p1 != p2
|
376
|
+
end
|
297
377
|
|
298
|
-
|
299
|
-
|
378
|
+
[p1 || "0", p2 || "0"]
|
379
|
+
end
|
300
380
|
|
301
|
-
|
302
|
-
|
303
|
-
|
381
|
+
# Normalizes token for comparison.
|
382
|
+
#
|
383
|
+
# @param p1 [String] The first token to normalize.
|
384
|
+
# @param p2 [String] The second token to normalize.
|
385
|
+
# @return [Array] The tokens to compare.
|
386
|
+
def normalize_tokens(p1, p2)
|
387
|
+
if !p1.is_integer? then
|
388
|
+
ll = p1.length
|
389
|
+
p1 = p2 + p1
|
390
|
+
p2 = p2 + ("z" * ll)
|
391
|
+
end
|
304
392
|
|
305
|
-
|
306
|
-
|
307
|
-
@browsers[index] = browser
|
308
|
-
else
|
309
|
-
@browsers << browser
|
310
|
-
@browsers_indexes[browser[0]] = @browsers.length - 1
|
311
|
-
end
|
393
|
+
[p1, p2]
|
394
|
+
end
|
312
395
|
|
313
|
-
|
396
|
+
# Converts a list of register entries to an ordered hash.
|
397
|
+
#
|
398
|
+
# @param entries [Array] The array to convert.
|
399
|
+
# @return [OrderedHash] An ordered hash.
|
400
|
+
def registered_to_hash(entries)
|
401
|
+
entries.inject(ActiveSupport::OrderedHash.new) do |rv, entry|
|
402
|
+
rv[entry[0]] = entry[1, entry.length]
|
403
|
+
rv
|
404
|
+
end
|
405
|
+
end
|
314
406
|
end
|
315
|
-
|
316
|
-
rv
|
317
407
|
end
|
318
408
|
|
319
|
-
#
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
@platforms = []
|
328
|
-
@platforms_indexes = {}
|
409
|
+
# Methods to handle attributes
|
410
|
+
module Attributes
|
411
|
+
# Gets a human-readable browser name.
|
412
|
+
#
|
413
|
+
# @return [String] A human-readable browser name.
|
414
|
+
def readable_name
|
415
|
+
self.parse_agent(@agent) if !@name
|
416
|
+
::Brauser::Browser.browsers.fetch(@name, ["Unknown Browser"]).last.ensure_string
|
329
417
|
end
|
330
418
|
|
419
|
+
# Gets a human-readable platform name.
|
420
|
+
#
|
421
|
+
# @return [String] A readable platform name.
|
422
|
+
def platform_name
|
423
|
+
self.parse_agent(@agent) if !@platform
|
424
|
+
::Brauser::Browser.platforms.fetch(@platform, ["Unknown Platform"]).last.ensure_string
|
425
|
+
end
|
331
426
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
427
|
+
# Returns an array of information about the browser. Information are strings which are suitable to use as CSS classes.
|
428
|
+
#
|
429
|
+
# For version, it will be included a class for every token of the version. For example, version `7.0.1.2` will return this:
|
430
|
+
#
|
431
|
+
# ```ruby
|
432
|
+
# ["version-7", "version-7_0", "version-7_0_1", "version-7_0_1_2"]
|
433
|
+
# ```
|
434
|
+
#
|
435
|
+
# If you provide a block (with accepts name, version and platform as arguments), it will be used for translating the name.
|
436
|
+
#
|
437
|
+
# @param join [String|NilClass] If non falsy, the separator to use to join information. If falsy, informations will be returned as array.
|
438
|
+
# @param name [Boolean] If non falsy, the string to prepend to the name. If falsy, the name information will not be included.
|
439
|
+
# @param version [String|NilClass] If non falsy, the string to prepend to the version. If falsy, the version information will not be included.
|
440
|
+
# @param platform [String|NilClass] If non falsy, the string to prepend to the platform. If falsy, the platform information will not be included.
|
441
|
+
# @param block [Proc] A block to translate browser name.
|
442
|
+
# @return [String|Array] CSS ready information of the current browser.
|
443
|
+
def classes(join = " ", name = "", version = "version-", platform = "platform-", &block)
|
444
|
+
platform = "platform-" if platform == true
|
445
|
+
rv = [stringify_name(name, &block), stringify_version(version), !platform ? nil : (platform + @platform.to_s)].compact.flatten
|
446
|
+
join ? rv.join(join) : rv
|
447
|
+
end
|
448
|
+
alias :meta :classes
|
449
|
+
|
450
|
+
private
|
451
|
+
# Stringifies a browser name.
|
452
|
+
#
|
453
|
+
# @param name [Boolean] If non falsy, the string to prepend to the name. If falsy, the name information will not be included.
|
454
|
+
# @param block [Proc] A block to translate browser name.
|
455
|
+
# @return [String|nil] The browser name or `nil`, if it was set to be skipped
|
456
|
+
def stringify_name(name, &block)
|
457
|
+
name = "" if name == true
|
458
|
+
!name ? nil : "#{name}#{block_given? ? yield(@name, @version, @platform) : (@name || self.parse_agent(@agent))}"
|
340
459
|
end
|
341
460
|
|
342
|
-
#
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
461
|
+
# Stringifies a browser version.
|
462
|
+
#
|
463
|
+
# @param version [String|NilClass] If non falsy, the string to prepend to the version. If falsy, the version information will not be included.
|
464
|
+
# @return [Array] The version strings or `nil`, if it was set to be skipped
|
465
|
+
def stringify_version(version)
|
466
|
+
version = "version-" if version == true
|
467
|
+
others = @version.split(".")
|
468
|
+
major = others.shift
|
469
|
+
!version ? nil : others.inject([version + major]) {|prev, current| prev + [prev.last + "_" + current] }.flatten
|
348
470
|
end
|
349
|
-
|
350
|
-
rv = true
|
351
|
-
end
|
352
|
-
|
353
|
-
rv
|
354
471
|
end
|
355
472
|
|
356
|
-
#
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
rv = false
|
364
|
-
code = {code.ensure_string => label.ensure_string} if !code.is_a?(Hash)
|
365
|
-
|
366
|
-
code.each_pair do |c, l|
|
367
|
-
if c.present? && l.present? then
|
368
|
-
@languages[c] = l
|
369
|
-
rv = true
|
370
|
-
end
|
371
|
-
end
|
473
|
+
# Methods to parse the user agent.
|
474
|
+
module Parsing
|
475
|
+
# Parses the User-Agent header.
|
476
|
+
# @param agent [String] The User-Agent header.
|
477
|
+
# @return [Boolean] `true` if the browser was detected, `false` otherwise.
|
478
|
+
def parse_agent(agent = nil)
|
479
|
+
agent = agent.ensure_string
|
372
480
|
|
373
|
-
|
374
|
-
|
481
|
+
@name, version = match_name_and_version(agent)
|
482
|
+
@version = adjust_version(@version)
|
483
|
+
@platform = match_platform(agent)
|
375
484
|
|
376
|
-
|
377
|
-
|
378
|
-
# @param v1 [String] The first versions to compare.
|
379
|
-
# @param operator [Symbol] The operator to use for comparison, can be one of `[:lt, :lte, :eq, :gte, :gt]`.
|
380
|
-
# @param v2 [Symbol] The second version to compare.
|
381
|
-
# @return [Boolean] true if comparison is valid, `false` otherwise.
|
382
|
-
def self.compare_versions(v1 = "", operator = :eq, v2 = "")
|
383
|
-
rv = true
|
384
|
-
|
385
|
-
if [:lt, :lte, :eq, :gte, :gt].include?(operator) && v1.ensure_string.present? then
|
386
|
-
# At first, split versions
|
387
|
-
vv1 = v1.ensure_string.split(".").reverse
|
388
|
-
vv2 = v2.ensure_string.split(".").reverse
|
389
|
-
|
390
|
-
left = vv1.pop
|
391
|
-
right = vv2.pop
|
392
|
-
|
393
|
-
# Start comparison, picking from length
|
394
|
-
rv = catch(:result) do
|
395
|
-
while true do
|
396
|
-
left = (left || "0").ensure_string
|
397
|
-
right = (right || "0").ensure_string
|
398
|
-
|
399
|
-
# Adjust for alpha, beta, etc
|
400
|
-
if !left.is_integer? then
|
401
|
-
ll = left.length
|
402
|
-
left = right + left
|
403
|
-
right = right + ("z" * ll)
|
404
|
-
end
|
485
|
+
(@name != :unknown) ? true : false
|
486
|
+
end
|
405
487
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
left = vv1.pop
|
414
|
-
right = vv2.pop
|
415
|
-
|
416
|
-
# We end the left version, so until now all tokens were equal. Check what to do.
|
417
|
-
if left.blank? then
|
418
|
-
case operator
|
419
|
-
when :lt then throw(:result, right.present? && right.to_integer > 0) # The comparison is true if there is at least another right version number greater than 0.
|
420
|
-
when :lte then throw(:result, right.blank? || right.is_integer?) # The comparison is true if there is no other right version or that is a integer (so it means no alpha, beta etc).
|
421
|
-
when :eq then throw(:result, right.blank? || ([right] + vv2).uniq.first == "0") # The comparison is true if also right version ends or only zero are left.
|
422
|
-
when :gte then throw(:result, right.blank? || !right.is_integer?) # The comparison is true if there is no other right version or that is not a integer (so it means alpha, beta etc).
|
423
|
-
when :gt then throw(:result, right.present? && !right.is_integer?) # The comparison is true if there is at least another right version not a integer (so it means alpha, beta etc).
|
424
|
-
end
|
425
|
-
end
|
488
|
+
# Parses the Accept-Language header.
|
489
|
+
#
|
490
|
+
# @param accept_language [String] The Accept-Language header.
|
491
|
+
# @return [Array] The list of accepted languages.
|
492
|
+
def parse_accept_language(accept_language = nil)
|
493
|
+
accept_language.ensure_string.gsub(/;q=[\d.]+/, "").split(",").collect {|l| l.downcase.strip }.select{|l| l.present? }
|
494
|
+
end
|
426
495
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
496
|
+
private
|
497
|
+
# Matches a browser name and version.
|
498
|
+
#
|
499
|
+
# @param agent [String] The User-Agent header.
|
500
|
+
# @return [String|Symbol] The browser name or `:unknown`, if no match was found.
|
501
|
+
def match_name_and_version(agent)
|
502
|
+
catch(:name) do
|
503
|
+
::Brauser::Browser.browsers.each do |name, definitions|
|
504
|
+
matched = match_definition(definitions[0], agent)
|
505
|
+
|
506
|
+
if matched then
|
507
|
+
@version = match_definition(definitions[1], name, agent)
|
508
|
+
throw(:name, name)
|
433
509
|
end
|
434
510
|
end
|
511
|
+
|
512
|
+
:unknown
|
435
513
|
end
|
436
514
|
end
|
437
|
-
else
|
438
|
-
rv = false
|
439
|
-
end
|
440
|
-
|
441
|
-
rv
|
442
|
-
end
|
443
|
-
|
444
|
-
# Creates a new browser.
|
445
|
-
#
|
446
|
-
# @param agent [String] The User-Agent HTTP header.
|
447
|
-
# @param accept_language [String] The Accept-Language HTTP header.
|
448
|
-
def initialize(agent = "", accept_language = "")
|
449
|
-
self.class.register_default_browsers
|
450
|
-
self.class.register_default_platforms
|
451
|
-
self.class.register_default_languages
|
452
515
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
# Parses the User-Agent header.
|
461
|
-
# @param agent [String] The User-Agent header.
|
462
|
-
# @return [Boolean] `true` if the browser was detected, `false` otherwise.
|
463
|
-
def parse_agent(agent = nil)
|
464
|
-
agent = agent.ensure_string
|
465
|
-
|
466
|
-
# At first, detect name and version. Tries order is important to avoid false positives.
|
467
|
-
@name = catch(:name) do
|
468
|
-
self.class.browsers.each do |name, definitions|
|
469
|
-
matched = false
|
470
|
-
|
471
|
-
if definitions[0].is_a?(::Regexp) then
|
472
|
-
matched = definitions[0].match(agent) ? true : false
|
473
|
-
elsif definitions[0].respond_to?(:call) then
|
474
|
-
matched = (definitions[0].call(agent) ? true : false)
|
516
|
+
# Adjusts a browser version.
|
517
|
+
def adjust_version(version)
|
518
|
+
# Adjust version
|
519
|
+
if version.blank? then
|
520
|
+
version = "0.0"
|
521
|
+
elsif version.is_a?(::MatchData) then
|
522
|
+
version = version.to_a.last
|
475
523
|
else
|
476
|
-
|
524
|
+
version
|
477
525
|
end
|
526
|
+
end
|
478
527
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
528
|
+
# Matches a browser platform.
|
529
|
+
#
|
530
|
+
# @param agent [String] The User-Agent header.
|
531
|
+
# @return [String|Symbol] The browser platform or `:unknown`, if no match was found.
|
532
|
+
def match_platform(agent)
|
533
|
+
catch(:platform) do
|
534
|
+
::Brauser::Browser.platforms.each do |platform, definitions|
|
535
|
+
matched = match_definition(definitions[0], @name, agent)
|
536
|
+
throw(:platform, platform) if matched
|
487
537
|
end
|
488
|
-
end
|
489
538
|
|
490
|
-
|
539
|
+
:unknown
|
540
|
+
end
|
491
541
|
end
|
492
542
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
if definitions[0].is_a?(::Regexp) then
|
503
|
-
matched = definitions[0].match(agent) ? true : false
|
504
|
-
elsif definitions[0].respond_to?(:call) then
|
505
|
-
matched = (definitions[0].call(@name, agent) ? true : false)
|
543
|
+
# Matches a subject against a definition
|
544
|
+
#
|
545
|
+
# @param subject [Array] The subject to match.
|
546
|
+
# @param definition [StringRegexp|Block] The definition. If a block, it will be yielded with the subject must return `true` if the subject was recognized.
|
547
|
+
def match_definition(definition, *subject)
|
548
|
+
if definition.is_a?(::Regexp) then
|
549
|
+
definition.match(subject.last)
|
550
|
+
elsif definition.respond_to?(:call) then
|
551
|
+
definition.call(*subject)
|
506
552
|
else
|
507
|
-
|
553
|
+
subject.last == definition.ensure_string ? subject.last : nil
|
508
554
|
end
|
509
|
-
|
510
|
-
throw(:platform, platform) if matched
|
511
555
|
end
|
512
|
-
|
513
|
-
:unknown
|
514
|
-
end
|
515
|
-
|
516
|
-
(@name != :unknown) ? true : false
|
517
556
|
end
|
518
557
|
|
519
|
-
#
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
558
|
+
# Methods to query with chaining.
|
559
|
+
module PartialQuerying
|
560
|
+
# Checks if the browser is a specific name and optionally of a specific version and platform.
|
561
|
+
#
|
562
|
+
# @see #v?
|
563
|
+
# @see #on?
|
564
|
+
#
|
565
|
+
# @param names [Symbol|Array] A list of specific names to match. Also, this meta-names are supported: `:capable` and `:tablet`.
|
566
|
+
# @param versions [String|Hash] A string in the form `operator version && ...` (example: `>= 7 && < 4`) or an hash with specific version to match against, in form `{:operator => version}`, where operator is one of `:lt, :lte, :eq, :gt, :gte`.
|
567
|
+
# @param platforms [Symbol|Array] A list of specific platform to match. Valid values are all those possible for the platform attribute.
|
568
|
+
# @return [Query] A query which can evaluated for concatenation or result.
|
569
|
+
def is(names = [], versions = {}, platforms = [])
|
570
|
+
self.parse_agent(@agent) if !@name
|
571
|
+
|
572
|
+
names = adjust_names(names)
|
573
|
+
versions = parse_versions_query(versions)
|
574
|
+
platforms = platforms.ensure_array
|
575
|
+
|
576
|
+
::Brauser::Query.new(self,
|
577
|
+
(names.blank? || (names.include?(@name) && check_capable(names))) &&
|
578
|
+
(versions.blank? || self.v?(versions)) &&
|
579
|
+
(platforms.blank? || self.on?(platforms))
|
580
|
+
)
|
581
|
+
end
|
526
582
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
583
|
+
# Checks if the brower is a specific version.
|
584
|
+
#
|
585
|
+
# @param versions [String|Hash] A string in the form `operator version && ...` (example: `>= 7 && < 4`) or an hash with specific version to match against, in form `{:operator => version}`, where operator is one of `:lt, :lte, :eq, :gt, :gte`.
|
586
|
+
# @return [Query] A query which can evaluated for concatenation or result.
|
587
|
+
def v(versions = {})
|
588
|
+
self.parse_agent(@agent) if !@version
|
589
|
+
rv = true
|
534
590
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
591
|
+
versions = if versions.is_a?(String) then
|
592
|
+
parse_versions_query(versions)
|
593
|
+
elsif !versions.is_a?(::Hash) then
|
594
|
+
{}
|
595
|
+
else
|
596
|
+
versions
|
597
|
+
end
|
542
598
|
|
543
|
-
|
544
|
-
#
|
545
|
-
# @see #v?
|
546
|
-
# @see #on?
|
547
|
-
#
|
548
|
-
# @param names [Symbol|Array] A list of specific names to match. Also, this meta-names are supported: `:capable` and `:tablet`.
|
549
|
-
# @param versions [Hash] An hash with specific version to match against. Need to be in form `{:operator => version}`, where operator is one of `:lt, :lte, :eq, :gt, :gte`.
|
550
|
-
# @param platforms [Symbol|Array] A list of specific platform to match. Valid values are all those possible for the platform attribute.
|
551
|
-
# @return [Query] A query which can evaluated for concatenation or result.
|
552
|
-
def is(names = [], versions = {}, platforms = [])
|
553
|
-
self.parse_agent(@agent) if !@name
|
554
|
-
versions = {} if !versions.is_a?(::Hash)
|
555
|
-
platforms = platforms.ensure_array
|
556
|
-
|
557
|
-
# Adjust names
|
558
|
-
names = names.ensure_array.uniq.compact.collect {|n| n.ensure_string.to_sym }
|
559
|
-
names << [:msie] if names.include?(:ie)
|
560
|
-
names << [:chromium] if names.include?(:chrome)
|
561
|
-
|
562
|
-
if names.delete(:capable) then
|
563
|
-
names += [:chrome, :firefox, :safari, :opera, :msie]
|
564
|
-
|
565
|
-
# Add version 9 as minimum for IE if capable is specified
|
566
|
-
versions[:gte] = 9 if @name == :msie
|
599
|
+
::Brauser::Query.new(self, versions.all? { |operator, value| Brauser::Browser.compare_versions(@version, operator, value) })
|
567
600
|
end
|
568
601
|
|
569
|
-
|
570
|
-
|
602
|
+
# Check if the browser is on a specific platform.
|
603
|
+
#
|
604
|
+
# @param platforms [Symbol|Array] A list of specific platform to match.
|
605
|
+
# @return [Query] A query which can evaluated for concatenation or result.
|
606
|
+
def on(platforms = [])
|
607
|
+
self.parse_agent(@agent) if !@platform
|
608
|
+
::Brauser::Query.new(self, platforms.blank? || platforms.ensure_array.uniq.compact.collect {|p| p.ensure_string.to_sym }.include?(@platform))
|
609
|
+
end
|
571
610
|
|
572
|
-
|
611
|
+
# Check if the browser accepts the specified languages.
|
612
|
+
#
|
613
|
+
# @param langs [String|Array] A list of languages to match against.
|
614
|
+
# @return [Query] A query which can evaluated for concatenation or result.
|
615
|
+
def accepts(langs = [])
|
616
|
+
self.parse_accept_language(@accept_language) if !@languages
|
617
|
+
::Brauser::Query.new(self, (@languages & langs.ensure_array.uniq.compact.collect {|l| l.to_s }).present?)
|
618
|
+
end
|
573
619
|
|
574
|
-
|
575
|
-
|
620
|
+
private
|
621
|
+
# Adjusts names for correct matching.
|
622
|
+
#
|
623
|
+
# @param names [Array] A list of names.
|
624
|
+
# @return [Array] The adjusted list of names.
|
625
|
+
def adjust_names(names)
|
626
|
+
# Adjust names
|
627
|
+
names = names.ensure_array.compact.collect {|n| n.ensure_string.to_sym }
|
628
|
+
names << [:msie] if names.include?(:ie)
|
629
|
+
names << [:chromium] if names.include?(:chrome)
|
630
|
+
names << [:chrome, :firefox, :safari, :opera, :msie] if names.include?(:capable)
|
631
|
+
names << [:ipad, :android, :kindle] if names.include?(:tablet)
|
632
|
+
names.flatten.compact.uniq
|
633
|
+
end
|
576
634
|
|
577
|
-
|
578
|
-
|
635
|
+
# Checks if the browser is capable.
|
636
|
+
#
|
637
|
+
# @param names [Array] A list of names.
|
638
|
+
# @return [Boolean] `true` if the browser is capable, `false` otherwise.
|
639
|
+
def check_capable(names)
|
640
|
+
!names.include?(:capable) || @name != :msie || Brauser::Browser.compare_versions(@version, :gte, 9)
|
641
|
+
end
|
579
642
|
|
580
|
-
|
581
|
-
|
643
|
+
# Parses a version query.
|
644
|
+
#
|
645
|
+
# @param versions [String|Hash] A string in the form `operator version && ...` (example: `>= 7 && < 4`) or an hash with specific version to match against, in form `{:operator => version}`, where operator is one of `:lt, :lte, :eq, :gt, :gte`.
|
646
|
+
# @return [Hash] The hash representation of the query.
|
647
|
+
def parse_versions_query(versions)
|
648
|
+
versions.is_a?(::Hash) ? versions : versions.ensure_string.split(/\s*&&\s*/).inject({}) do |prev, token|
|
649
|
+
operator, version = parse_versions_query_component(token)
|
650
|
+
prev[operator] = version if operator.present? && version.present?
|
651
|
+
prev
|
652
|
+
end
|
653
|
+
end
|
582
654
|
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
# @return [Boolean] `true` if current browser matches, `false` otherwise.
|
592
|
-
def is?(names = [], versions = {}, platforms = [])
|
593
|
-
self.is(names, versions, platforms).result
|
655
|
+
# Parses a token of a version query.
|
656
|
+
#
|
657
|
+
# @param token [String] The token to parse.
|
658
|
+
# @return [Array] An operator and an argument.
|
659
|
+
def parse_versions_query_component(token)
|
660
|
+
operator, version = token.strip.split(/\s+/, 2).collect(&:strip)
|
661
|
+
[{"<" => :lt, "<=" => :lte, "=" => :eq, "==" => :eq, ">" => :gt, ">=" => :gte}.fetch(operator, nil), version]
|
662
|
+
end
|
594
663
|
end
|
595
664
|
|
596
|
-
#
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
tokens = token.strip.split(/\s+/).collect {|t| t.strip}
|
611
|
-
operator = case tokens[0]
|
612
|
-
when "<" then :lt
|
613
|
-
when "<=" then :lte
|
614
|
-
when "=" then :eq
|
615
|
-
when "==" then :eq
|
616
|
-
when ">=" then :gte
|
617
|
-
when ">" then :gt
|
618
|
-
else tokens[0].downcase.to_sym
|
619
|
-
end
|
665
|
+
# Methods to end querying.
|
666
|
+
module Querying
|
667
|
+
# Checks if the browser is a specific name and optionally of a specific version and platform.
|
668
|
+
#
|
669
|
+
# @see #v?
|
670
|
+
# @see #on?
|
671
|
+
#
|
672
|
+
# @param names [Symbol|Array] A list of specific names to match. Also, this meta-names are supported: `:capable` and `:tablet`.
|
673
|
+
# @param versions [Hash] An hash with specific version to match against. Need to be in form `{:operator => version}`, where operator is one of `:lt, :lte, :eq, :gt, :gte`.
|
674
|
+
# @param platforms [Symbol|Array] A list of specific platform to match. Valid values are all those possible for the platform attribute.
|
675
|
+
# @return [Boolean] `true` if current browser matches, `false` otherwise.
|
676
|
+
def is?(names = [], versions = {}, platforms = [])
|
677
|
+
self.is(names, versions, platforms).result
|
678
|
+
end
|
620
679
|
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
680
|
+
# Checks if the brower is a specific version.
|
681
|
+
#
|
682
|
+
# @param versions [String|Hash] A string in the form `operator version && ...` (example: `>= 7 && < 4`) or an hash with specific version to match against, in form `{:operator => version}`, where operator is one of `:lt, :lte, :eq, :gt, :gte`.
|
683
|
+
# @return [Boolean] `true` if current browser matches, `false` otherwise.
|
684
|
+
def v?(versions = {})
|
685
|
+
self.v(versions).result
|
625
686
|
end
|
626
687
|
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
688
|
+
# Check if the browser is on a specific platform.
|
689
|
+
#
|
690
|
+
# @param platforms [Symbol|Array] A list of specific platform to match.
|
691
|
+
# @return [Boolean] `true` if current browser matches, `false` otherwise.
|
692
|
+
def on?(platforms = [])
|
693
|
+
self.on(platforms).result
|
631
694
|
end
|
632
695
|
|
633
|
-
|
696
|
+
# Check if the browser accepts the specified languages.
|
697
|
+
#
|
698
|
+
# @param langs [String|Array] A list of languages to match against.
|
699
|
+
# @return [Boolean] `true` if current browser matches, `false` otherwise.
|
700
|
+
def accepts?(langs = [])
|
701
|
+
self.accepts(langs).result
|
702
|
+
end
|
634
703
|
end
|
704
|
+
end
|
635
705
|
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
706
|
+
# This class represents a detection of the current user browser.
|
707
|
+
#
|
708
|
+
# @attribute agent
|
709
|
+
# @return [String] The raw User-Agent HTTP header.
|
710
|
+
# @attribute accept_language
|
711
|
+
# @return [String] The raw Accept-Language HTTP header.
|
712
|
+
# @attribute languages
|
713
|
+
# @return [Array] The accepted languages.
|
714
|
+
# @attribute name
|
715
|
+
# @return [String] The current browser name.
|
716
|
+
# @attribute version
|
717
|
+
# @return [String] The current browser version.
|
718
|
+
# @attribute platform
|
719
|
+
# @return [String] The current browser platform.
|
720
|
+
class Browser
|
721
|
+
attr_accessor :agent
|
722
|
+
attr_accessor :accept_language
|
723
|
+
attr_accessor :languages
|
724
|
+
attr_accessor :name
|
725
|
+
attr_accessor :version
|
726
|
+
attr_accessor :platform
|
643
727
|
|
644
|
-
#
|
645
|
-
|
646
|
-
|
647
|
-
# @return [Query] A query which can evaluated for concatenation or result.
|
648
|
-
def on(platforms = [])
|
649
|
-
self.parse_agent(@agent) if !@platform
|
650
|
-
::Brauser::Query.new(self, platforms.blank? || platforms.ensure_array.uniq.compact.collect {|p| p.ensure_string.to_sym }.include?(@platform))
|
651
|
-
end
|
728
|
+
# Aliases
|
729
|
+
alias :ua :agent
|
730
|
+
alias :ua= :agent=
|
652
731
|
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
end
|
732
|
+
include ::Brauser::BrowserMethods::General
|
733
|
+
include ::Brauser::BrowserMethods::Attributes
|
734
|
+
include ::Brauser::BrowserMethods::Register
|
735
|
+
include ::Brauser::BrowserMethods::Parsing
|
736
|
+
include ::Brauser::BrowserMethods::PartialQuerying
|
737
|
+
include ::Brauser::BrowserMethods::Querying
|
660
738
|
|
661
|
-
#
|
739
|
+
# Creates a new browser.
|
662
740
|
#
|
663
|
-
# @param
|
664
|
-
# @
|
665
|
-
def
|
666
|
-
|
667
|
-
::Brauser::
|
668
|
-
|
741
|
+
# @param agent [String] The User-Agent HTTP header.
|
742
|
+
# @param accept_language [String] The Accept-Language HTTP header.
|
743
|
+
def initialize(agent = "", accept_language = "")
|
744
|
+
::Brauser::Browser.register_default_browsers
|
745
|
+
::Brauser::Browser.register_default_platforms
|
746
|
+
::Brauser::Browser.register_default_languages
|
669
747
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
self.accepts(langs).result
|
748
|
+
@agent = agent
|
749
|
+
@accept_language = accept_language
|
750
|
+
|
751
|
+
@languages = self.parse_accept_language(@accept_language) if @accept_language
|
752
|
+
self.parse_agent(@agent) if @agent
|
676
753
|
end
|
677
754
|
|
678
755
|
# This method enables the use of dynamic queries in just one method.
|
@@ -693,102 +770,76 @@ module Brauser
|
|
693
770
|
# @param block [Proc] A block to pass to the method. Unused from the query.
|
694
771
|
# @return [Boolean|Query|nil] A query or a boolean value (if `method` ends with `?`). If the query is not valid, `NoMethodError` will be raised.
|
695
772
|
def method_missing(query, *arguments, &block)
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
# See if return a boolean in case of valid query
|
703
|
-
as_result = query =~ /\?$/
|
704
|
-
query = query.gsub(/\?$/, "")
|
705
|
-
|
706
|
-
# Parse the query
|
707
|
-
query.ensure_string.split("__").each do |parts|
|
708
|
-
tokens = parts.split("_")
|
709
|
-
method = tokens[0]
|
710
|
-
arguments = tokens[1, tokens.length].join("_")
|
711
|
-
|
712
|
-
if method == "v" then
|
713
|
-
arguments.gsub("_", ".")
|
714
|
-
end
|
715
|
-
|
716
|
-
if ["is", "v", "on"].include?(method) then
|
717
|
-
if method == "v" then
|
718
|
-
arguments = arguments.gsub(/_?eq_?/, " == ") # Parse ==
|
719
|
-
arguments = arguments.gsub(/_?lte_?/, " <= ").gsub(/_?gte_?/, " >= ") # Parse <= and >=
|
720
|
-
arguments = arguments.gsub(/_?lt_?/, " < ").gsub(/_?gt_?/, " > ") # Parse < and >
|
721
|
-
arguments = arguments.gsub(/_?and_?/, " && ") # Parse &&
|
722
|
-
arguments = arguments.gsub("_", ".").gsub(/\s+/, " ").strip # Replace _ and spaces, then strip
|
723
|
-
end
|
724
|
-
|
725
|
-
rv = Brauser::Query.new(self, true) if !rv
|
726
|
-
rv = rv.send(method, *arguments)
|
727
|
-
|
728
|
-
break if rv.result == false
|
729
|
-
else # Invalid finder
|
730
|
-
rv = nil
|
731
|
-
break
|
732
|
-
end
|
773
|
+
begin
|
774
|
+
parsed_query = parse_query(query.ensure_string)
|
775
|
+
rv = execute_query(parsed_query) || Brauser::Query.new(self, false)
|
776
|
+
query.ensure_string =~ /\?$/ ? rv.result : rv
|
777
|
+
rescue NoMethodError
|
778
|
+
super(query, *arguments, &block)
|
733
779
|
end
|
734
|
-
|
735
|
-
rv = rv.result if !rv.nil? && as_result
|
736
|
-
!rv.nil? ? rv : super(oq, *oa, &block)
|
737
780
|
end
|
738
781
|
|
739
|
-
# Returns
|
740
|
-
#
|
741
|
-
# For version, it will be included a class for every token of the version. For example, version `7.0.1.2` will return this:
|
742
|
-
#
|
743
|
-
# ```ruby
|
744
|
-
# ["version-7", "version-7_0", "version-7_0_1", "version-7_0_1_2"]
|
745
|
-
# ```
|
782
|
+
# Returns the current browser as a string.
|
746
783
|
#
|
747
|
-
#
|
784
|
+
# @see #classes
|
748
785
|
#
|
749
|
-
# @
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
if name then
|
763
|
-
final_name = block_given? ? yield(@name, @version, @platform) : @name
|
764
|
-
rv << name + final_name.ensure_string
|
786
|
+
# @return [String] A string representation of the current browser.
|
787
|
+
def to_s
|
788
|
+
self.classes
|
789
|
+
end
|
790
|
+
|
791
|
+
private
|
792
|
+
# Parse query, getting all arguments.
|
793
|
+
# @param query [String] The query to issue. Use `__` to separate query and `_` in place of `.` in the version.
|
794
|
+
# @return [Array] And array of `[method, arguments]` entries.
|
795
|
+
def parse_query(query)
|
796
|
+
query.gsub(/\?$/, "").split("__").collect do |part|
|
797
|
+
parse_query_part(part)
|
798
|
+
end
|
765
799
|
end
|
766
800
|
|
767
|
-
#
|
768
|
-
|
769
|
-
|
770
|
-
|
801
|
+
# Handles a part of a query.
|
802
|
+
#
|
803
|
+
# @param part [String] A part of a query.
|
804
|
+
# @return [Boolean|Query|nil] A query or a boolean value (if `method` ends with `?`). If the query is not valid, `NoMethodError` will be raised.
|
805
|
+
def parse_query_part(part)
|
806
|
+
method, arguments = part.split("_", 2)
|
771
807
|
|
772
|
-
|
773
|
-
|
774
|
-
|
808
|
+
if method == "v" then
|
809
|
+
arguments = parse_query_version(arguments)
|
810
|
+
elsif !["is", "on"].include?(method)
|
811
|
+
raise NoMethodError
|
775
812
|
end
|
776
|
-
end
|
777
813
|
|
778
|
-
|
814
|
+
[method, arguments]
|
815
|
+
end
|
779
816
|
|
780
|
-
#
|
781
|
-
|
782
|
-
|
783
|
-
|
817
|
+
# Parses the version for a query.
|
818
|
+
#
|
819
|
+
# @param version [String] The version to parse.
|
820
|
+
# @return [String] The parsed version.
|
821
|
+
def parse_query_version(version)
|
822
|
+
[
|
823
|
+
[/_?eq_?/, " == "], # Parse ==
|
824
|
+
[/_?lte_?/, " <= "], # Parse <=
|
825
|
+
[/_?gte_?/, " >= "], # Parse >=
|
826
|
+
[/_?lt_?/, " < "], # Parse <
|
827
|
+
[/_?gt_?/, " > "], # Parse >
|
828
|
+
[/_?and_?/, " && "], # Parse &&
|
829
|
+
["_", "."], # Dot notation
|
830
|
+
[/\s+/, " "]
|
831
|
+
].inject(version) { |current, parse| current.gsub(parse[0], parse[1])}.strip
|
832
|
+
end
|
784
833
|
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
834
|
+
# Executes a parsed query
|
835
|
+
#
|
836
|
+
# @param query [Array] And array of `[method, arguments]` entries.
|
837
|
+
# @return [Brauser::Query] The result of the query.
|
838
|
+
def execute_query(query)
|
839
|
+
query.inject(Brauser::Query.new(self, true)) { |rv, call|
|
840
|
+
break if !rv.result
|
841
|
+
rv.send(call[0], *call[1])
|
842
|
+
}
|
843
|
+
end
|
793
844
|
end
|
794
845
|
end
|