brauser 1.0.7 → 2.0.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/.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
|