browserino 3.0.1 → 4.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -0
- data/.travis.yml +6 -7
- data/bin/browserino +20 -52
- data/bin/console +5 -8
- data/browserino.gemspec +2 -6
- data/lib/browserino/client.rb +216 -0
- data/lib/browserino/config.rb +90 -0
- data/lib/browserino/definitions/aliasses.rb +12 -0
- data/lib/browserino/definitions/filters.rb +67 -0
- data/lib/browserino/definitions/labels.rb +45 -0
- data/lib/browserino/definitions/matchers.rb +290 -0
- data/lib/browserino/identity.rb +55 -0
- data/lib/browserino/integrate/action_controller.rb +4 -2
- data/lib/browserino/integrate/rails.rb +2 -0
- data/lib/browserino/methods.rb +110 -0
- data/lib/browserino/options.rb +44 -0
- data/lib/browserino/version.rb +72 -1
- data/lib/browserino.rb +16 -58
- metadata +15 -61
- data/lib/browserino/agent.rb +0 -116
- data/lib/browserino/browser.rb +0 -28
- data/lib/browserino/console.rb +0 -10
- data/lib/browserino/core/alias.rb +0 -23
- data/lib/browserino/core/helpers.rb +0 -141
- data/lib/browserino/core/lies.rb +0 -14
- data/lib/browserino/core/mapping.rb +0 -78
- data/lib/browserino/core/patterns.rb +0 -142
- data/lib/browserino/core/questions.rb +0 -88
- data/lib/browserino/core/supported.rb +0 -31
- data/lib/browserino/engine.rb +0 -16
- data/lib/browserino/operating_system.rb +0 -33
- data/lib/browserino/unknown.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bdd2af440a3b1476900a3cdd36d2905660053c6
|
4
|
+
data.tar.gz: 0c7a2151e6ec79341ba5dda81eceddef2e8128ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb4d367fb7cfd3bd9cf637998de4a41549e18f20aaa0f14e007cb28883aff70b66e4beb75f757d99fe299b61a77db0c4322b90da74691e30677c524428a1c3eb
|
7
|
+
data.tar.gz: c13adf9ce004e08c5504b07367c5f362446ca06dbc6abe372872f703cca9694e8b3dd6f8fd7900970dea265a917e5d37ca9e951aef94176f241afaa4eba3f82c
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
language: ruby
|
2
|
-
cache: bundler
|
3
2
|
rvm:
|
4
|
-
- 2.3.1
|
5
|
-
- 2.3.0
|
6
|
-
- 2.2.1
|
7
|
-
- 2.1.0
|
8
3
|
- 2.0.0
|
9
|
-
|
10
|
-
|
4
|
+
- 2.1.0
|
5
|
+
- 2.2.0
|
6
|
+
- 2.3.0
|
7
|
+
- 2.4.0
|
8
|
+
before_install: gem install bundler
|
9
|
+
script: bundle exec rspec spec
|
data/bin/browserino
CHANGED
@@ -1,60 +1,28 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
require 'bundler/setup'
|
3
|
+
require 'pry'
|
4
4
|
require_relative '../lib/browserino'
|
5
5
|
|
6
|
-
|
6
|
+
props = Browserino.parse(ARGV[0].dup).properties
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
puts Browserino.parse(ARGV[1]).to_console_s
|
12
|
-
else
|
13
|
-
puts ' Usage: browserino parse [ua]'
|
14
|
-
puts ' * ua: the user agent string you want to parse'
|
15
|
-
end
|
16
|
-
when 'list', '-l'
|
17
|
-
ARGV[1] ||= 'info'
|
18
|
-
type = (ARGV[1].to_s.gsub(/[\s\-]/, '_')).to_sym
|
19
|
-
if type == :info
|
20
|
-
puts ' Usage: browserino list [subject]'
|
21
|
-
puts ' * subject: the type you want to display'
|
22
|
-
puts ' * all - list everything that is supported'
|
23
|
-
puts ' * bots - list supported bots'
|
24
|
-
puts ' * browsers - list supported browsers'
|
25
|
-
puts ' * social-media - list supported social media'
|
26
|
-
puts ' * search-engines - list supported search engines'
|
27
|
-
puts ' * consoles - list supported consoles'
|
28
|
-
puts ' * libraries - list supported libraries'
|
29
|
-
puts ' * operating-systems - list supported operating systems'
|
30
|
-
else
|
31
|
-
res = {}
|
32
|
-
res[:bots] = Browserino::Core::SUPPORTED[:bots] - aliasses if type == :all || type == :bots
|
33
|
-
res[:browsers] = Browserino::Core::SUPPORTED[:browsers] - aliasses if type == :all || type == :browsers
|
34
|
-
res[:consoles] = Browserino::Core::SUPPORTED[:consoles] - aliasses if type == :all || type == :consoles
|
35
|
-
res[:libraries] = Browserino::Core::SUPPORTED[:libraries] - aliasses if type == :all || type == :libraries
|
36
|
-
res[:social_media] = Browserino::Core::SUPPORTED[:social_media] - aliasses if type == :all || type == :social_media
|
37
|
-
res[:search_engines] = Browserino::Core::SUPPORTED[:search_engines] - aliasses if type == :all || type == :search_engines
|
38
|
-
res[:operating_systems] = Browserino::Core::SUPPORTED[:operating_systems] - aliasses if type == :all || type == :operating_systems
|
8
|
+
parsed = props.each_with_object({}) do |(prop, val), store|
|
9
|
+
store[prop] = val.to_s
|
10
|
+
end
|
39
11
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
puts out
|
45
|
-
end
|
46
|
-
when 'console', '-c'
|
47
|
-
require 'pry'
|
48
|
-
puts "Starting Browserino #{Browserino::VERSION} on Ruby #{RUBY_VERSION}"
|
49
|
-
Pry.start
|
12
|
+
max_key_len = parsed.keys.map(&:size).max
|
13
|
+
max_val_len = parsed.values.map(&:size).max
|
14
|
+
spacing = 2
|
15
|
+
spacer = ' ' * spacing
|
50
16
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
puts "\n"
|
57
|
-
puts ' * parse or -p - parse a user agent'
|
58
|
-
puts ' * list or -l - list supported entities'
|
59
|
-
puts ' * console or -c - enter a console'
|
17
|
+
out = parsed.map do |pair|
|
18
|
+
key = [spacer, pair[0], spacer].join.ljust(max_key_len + (spacing * 2))
|
19
|
+
val = [spacer, pair[1], spacer].join.ljust(max_val_len + (spacing * 2))
|
20
|
+
tmp = [key, val].join '|'
|
21
|
+
"|#{tmp}|\n"
|
60
22
|
end
|
23
|
+
|
24
|
+
row = '+' * (out.map(&:size).max - 1) + "\n"
|
25
|
+
|
26
|
+
out[0] = "#{row}#{out[0]}"
|
27
|
+
out[-1] = "#{out[-1]}#{row}"
|
28
|
+
puts out.join("#{row}")
|
data/bin/console
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
|
-
require 'browserino'
|
5
4
|
require 'pry'
|
5
|
+
require 'browserino'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
puts "> You can create a fresh object by using\n"
|
12
|
-
puts "> Browserino.parse([string] ua)\n\n"
|
13
|
-
puts "> ua - The user agent you'd actually want to parse as a string"
|
7
|
+
@client = Browserino.parse ARGV[0].dup || 'Mozilla/5.0 (Macintosh; Intel Mac\
|
8
|
+
OS X 10_11_2) AppleWebKit/601.3.9\
|
9
|
+
(KHTML, l ike Gecko) Version/9.0.\
|
10
|
+
2 Safari/601.3.9'
|
14
11
|
|
15
12
|
Pry.start
|
data/browserino.gemspec
CHANGED
@@ -8,7 +8,6 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Browserino::VERSION
|
9
9
|
spec.authors = ["Sidney Liebrand"]
|
10
10
|
spec.email = ["sidneyliebrand@gmail.com"]
|
11
|
-
|
12
11
|
spec.summary = %q{A browser identification gem with command line and Rails (>= 3.2.0) integration}
|
13
12
|
spec.homepage = "https://sidofc.github.io/projects/browserino/"
|
14
13
|
spec.license = "MIT"
|
@@ -18,12 +17,9 @@ Gem::Specification.new do |spec|
|
|
18
17
|
spec.executables = ['browserino']
|
19
18
|
spec.require_paths = ["lib"]
|
20
19
|
|
21
|
-
spec.add_development_dependency "
|
22
|
-
spec.add_development_dependency "
|
23
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
-
spec.add_development_dependency "term-ansicolor"
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
21
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
25
22
|
spec.add_development_dependency "rspec"
|
26
|
-
spec.add_development_dependency "tins"
|
27
23
|
spec.add_development_dependency "coveralls"
|
28
24
|
spec.add_development_dependency "pry"
|
29
25
|
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Browserino
|
3
|
+
class Client
|
4
|
+
attr_reader :property_names
|
5
|
+
|
6
|
+
def initialize(props = {}, like = nil)
|
7
|
+
@property_names = props.is_a?(Hash) && props.keys || []
|
8
|
+
@like = like if like
|
9
|
+
# properties are added as methods that will each be defined in a specific
|
10
|
+
# order below. First, seperate static value methods from procs,
|
11
|
+
# procs will be able to call methods in this instances' context
|
12
|
+
# therefore we need to define static methods before procs
|
13
|
+
|
14
|
+
# for each static property:
|
15
|
+
# -- define a method that returns it's property value
|
16
|
+
# -- define a question method that returns it's property value or
|
17
|
+
# checks version against supplied value if truthy
|
18
|
+
define_simple_methods! props
|
19
|
+
|
20
|
+
# for each proc property:
|
21
|
+
# -- define a method that returns it's instance evalled block value
|
22
|
+
# -- define a question method that returns it's instance evalled block
|
23
|
+
# value or checks version against supplied value if truthy
|
24
|
+
define_proc_methods! props
|
25
|
+
|
26
|
+
# for each of #name, #engine and #platform, use their results as
|
27
|
+
# methods names, this will create a method #firefox? for the output
|
28
|
+
# of a #name # => :firefox for example.
|
29
|
+
define_name_result_methods!
|
30
|
+
|
31
|
+
# finally, add labels and their aliasses into the mix
|
32
|
+
# none of these methods should override an existing method
|
33
|
+
# therefore we check it's existence using defined?
|
34
|
+
define_label_methods!
|
35
|
+
end
|
36
|
+
|
37
|
+
def properties
|
38
|
+
@properties ||= @property_names.each_with_object({}) do |prop, result|
|
39
|
+
result[prop] = send prop
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def like
|
44
|
+
@like ||= self
|
45
|
+
end
|
46
|
+
|
47
|
+
def like?(sym = nil, opts = {})
|
48
|
+
opts = sym if sym.is_a? Hash
|
49
|
+
must = []
|
50
|
+
must << like.is?(sym) if sym
|
51
|
+
must << like.version?(opts[:version]) if opts[:version]
|
52
|
+
|
53
|
+
must.any? && must.all?
|
54
|
+
end
|
55
|
+
|
56
|
+
def x64?
|
57
|
+
@x64_cache ||= architecture == :x64
|
58
|
+
end
|
59
|
+
|
60
|
+
def x32?
|
61
|
+
@x32_cache ||= architecture == :x32
|
62
|
+
end
|
63
|
+
|
64
|
+
# check the type of a Client
|
65
|
+
def type?(sym)
|
66
|
+
return type == sym if sym.is_a? Symbol
|
67
|
+
type == sym.to_sym
|
68
|
+
end
|
69
|
+
|
70
|
+
# the catch all method, anything it can ask as question will respond
|
71
|
+
# otherwise nil is returned, this is also true when supplying a version
|
72
|
+
def is?(sym, opts = {})
|
73
|
+
return send "#{sym}?", opts[:version] if opts[:version]
|
74
|
+
send "#{sym}?"
|
75
|
+
end
|
76
|
+
|
77
|
+
def ===(other)
|
78
|
+
return false unless name
|
79
|
+
|
80
|
+
case other
|
81
|
+
when Regexp then other =~ name
|
82
|
+
when String then other.to_sym == name
|
83
|
+
when Symbol, Browserino::Client then other == name
|
84
|
+
else false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def ==(other)
|
89
|
+
self === other
|
90
|
+
end
|
91
|
+
|
92
|
+
def =~(other)
|
93
|
+
self === other
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_str
|
97
|
+
to_s
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_json(*args)
|
101
|
+
@json_cache ||= properties.map do |prop, val|
|
102
|
+
final = val.is_a?(Version) && val.full || val
|
103
|
+
[prop, final]
|
104
|
+
end.to_h.to_json(*args)
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_s
|
108
|
+
@str_cache ||= [:name, :engine, :platform].map do |prop|
|
109
|
+
name = send prop
|
110
|
+
ver = version if prop == :name
|
111
|
+
ver = send "#{prop}_version" if ver.nil?
|
112
|
+
|
113
|
+
[[name], [name, (ver.major if ver > '0.0.0')].compact.join.to_sym]
|
114
|
+
end.flatten.uniq.join(' ').gsub(/\s{2,}/, ' ').strip
|
115
|
+
end
|
116
|
+
|
117
|
+
def to_hash
|
118
|
+
properties
|
119
|
+
end
|
120
|
+
|
121
|
+
def to_h
|
122
|
+
properties
|
123
|
+
end
|
124
|
+
|
125
|
+
def to_a
|
126
|
+
properties.to_a
|
127
|
+
end
|
128
|
+
|
129
|
+
# scary, I know, but a falsy value is all we need to return if some
|
130
|
+
# property isn't known or true as any property can be defined on the Client
|
131
|
+
def method_missing(_, *__, &___)
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
|
135
|
+
# always respond to missing, read method_missing comment
|
136
|
+
def respond_to_missing?(_, *__, &___)
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def define_simple_methods!(props)
|
143
|
+
props.reject { |val| val.respond_to? :call }.each do |name, value|
|
144
|
+
define_singleton_method(name) { value }
|
145
|
+
define_singleton_method("#{name}?") do |val = nil, **opts|
|
146
|
+
values = [value, *Browserino.config.aliasses[value]]
|
147
|
+
return values.include? val if val && !opts[:version]
|
148
|
+
if val && opts[:version]
|
149
|
+
ver_res = send(name == :name ? :version : "#{name}_version")
|
150
|
+
return (ver_res == opts[:version]) && values.include?(val)
|
151
|
+
end
|
152
|
+
return value > 0 if value.is_a? Version
|
153
|
+
value && true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def define_proc_methods!(props)
|
159
|
+
props.select { |_, val| val.respond_to? :call }.each do |name, value|
|
160
|
+
result = instance_eval(&value)
|
161
|
+
define_singleton_method(name) { result }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def define_name_result_methods!
|
166
|
+
[:name, :engine, :platform].each do |prop|
|
167
|
+
result = send prop
|
168
|
+
ver_res = version if prop == :name
|
169
|
+
ver_res = send("#{prop}_version") if ver_res.nil?
|
170
|
+
|
171
|
+
# for each of the props:
|
172
|
+
# -- define a question method using the value of prop
|
173
|
+
# (ex: name # => firefox # => "firefox?")
|
174
|
+
# -- when supplied with a value, check it against {prop_res}_version
|
175
|
+
# -- when called without argument, return result
|
176
|
+
define_singleton_method("#{result}?") do |value = nil|
|
177
|
+
return ver_res == value if value
|
178
|
+
result && true
|
179
|
+
end
|
180
|
+
|
181
|
+
# for each of the aliasses found:
|
182
|
+
# -- define a question method using the current alias
|
183
|
+
# -- when supplied with a value, check it against {prop_res}_version
|
184
|
+
# -- when called without argument, return result
|
185
|
+
Browserino.config.aliasses[result].each do |alt|
|
186
|
+
define_singleton_method("#{alt}?") do |value = nil|
|
187
|
+
return ver_res == value if value
|
188
|
+
result && true
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def define_label_methods!
|
195
|
+
property_names.select { |name| name =~ /label/i }.each do |prop|
|
196
|
+
next unless (result = send(prop))
|
197
|
+
|
198
|
+
ver_type = prop.to_s.gsub /_?label/, ''
|
199
|
+
ver_res = version if ver_type.empty?
|
200
|
+
ver_res = send("#{ver_type}_version") unless prop == :label
|
201
|
+
|
202
|
+
define_singleton_method("#{result}?") do |value = nil|
|
203
|
+
return ver_res == value if value
|
204
|
+
result && true
|
205
|
+
end
|
206
|
+
|
207
|
+
Browserino.config.aliasses[result].each do |alt|
|
208
|
+
define_singleton_method("#{alt}?") do |value = nil|
|
209
|
+
return ver_res == value if value
|
210
|
+
result && true
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Browserino
|
3
|
+
class Config < Options
|
4
|
+
def define(&block)
|
5
|
+
instance_eval(&block)
|
6
|
+
return unless identities.any? && identities.all?
|
7
|
+
|
8
|
+
identities.each do |identity|
|
9
|
+
properties << identity.properties.keys
|
10
|
+
types << identity.type
|
11
|
+
names << identity.name
|
12
|
+
end
|
13
|
+
|
14
|
+
properties.flatten!.uniq!
|
15
|
+
types.uniq!
|
16
|
+
names.uniq!
|
17
|
+
end
|
18
|
+
|
19
|
+
def label(name, **opts)
|
20
|
+
return false unless opts[:for]
|
21
|
+
opts[:name] ||= name
|
22
|
+
labels[opts[:for]] << opts
|
23
|
+
end
|
24
|
+
|
25
|
+
def filter(*props, &block)
|
26
|
+
props << :global unless props.any?
|
27
|
+
props.each { |prop| filters[prop] << block }
|
28
|
+
end
|
29
|
+
|
30
|
+
def smart_match(prop, **options)
|
31
|
+
smart_matchers[prop] = options if options[:with]
|
32
|
+
end
|
33
|
+
|
34
|
+
def match(rgxp = nil, **opts, &block)
|
35
|
+
rgxp, opts = [nil, rgxp] if rgxp.is_a? Hash
|
36
|
+
opts = @tmp_defaults.merge opts if @tmp_defaults.is_a? Hash
|
37
|
+
|
38
|
+
if rgxp && opts[:like]
|
39
|
+
identities.unshift with_alias(rgxp, opts, &block)
|
40
|
+
elsif rgxp
|
41
|
+
identities << Identity.new(rgxp, opts, &block)
|
42
|
+
else
|
43
|
+
global_identities.unshift Identity.new(&block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def alias_for(name, *names)
|
48
|
+
aliasses[name] += names
|
49
|
+
end
|
50
|
+
|
51
|
+
def before_parse(&block)
|
52
|
+
@options[:before_parse] << block if block
|
53
|
+
@options[:before_parse]
|
54
|
+
end
|
55
|
+
|
56
|
+
def preset(props, &block)
|
57
|
+
@tmp_defaults = props
|
58
|
+
instance_eval(&block)
|
59
|
+
@tmp_defaults = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def like(tmp, &block)
|
63
|
+
preset like: tmp.to_sym, &block
|
64
|
+
end
|
65
|
+
|
66
|
+
def validators(&block)
|
67
|
+
preset type: :validator, &block
|
68
|
+
end
|
69
|
+
|
70
|
+
def browsers(&block)
|
71
|
+
preset type: :browser, &block
|
72
|
+
end
|
73
|
+
|
74
|
+
def bots(&block)
|
75
|
+
preset type: :bot, &block
|
76
|
+
end
|
77
|
+
|
78
|
+
def libraries(&block)
|
79
|
+
preset type: :library, &block
|
80
|
+
end
|
81
|
+
|
82
|
+
def with_alias(pattern, **opts, &block)
|
83
|
+
id = identities.select { |id| id == opts[:like] }.first
|
84
|
+
|
85
|
+
raise "No alias found for: #{opts[:like] || 'nil'}" unless id
|
86
|
+
|
87
|
+
Identity.new pattern, id.properties.merge(opts), &block
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
Browserino.config.define do
|
3
|
+
# aliasses will be defined after a Client has been initialized
|
4
|
+
# only the aliasses matching the Client will be defined
|
5
|
+
alias_for :firefox, :ff
|
6
|
+
alias_for :windows, :win
|
7
|
+
alias_for :macintosh, :mac, :osx, :macos
|
8
|
+
alias_for :blackberry, :bb
|
9
|
+
alias_for :ie, :internet_explorer
|
10
|
+
alias_for :facebook, :fb
|
11
|
+
alias_for :duckduckgo, :ddg
|
12
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
Browserino.config.define do
|
3
|
+
# executes before parsing the user agent, 's' in this case is the actual
|
4
|
+
# user agent string in full glory. Do manipulations as you wish, I'm
|
5
|
+
# using it to successfully strip lies from the user agent and to sometimes
|
6
|
+
# simplify a word e.g. 'AppleWebKit' => 'webkit'
|
7
|
+
|
8
|
+
# the returned result will be used as the user agent to parse so make
|
9
|
+
# sure to return the final ua at the end
|
10
|
+
before_parse do |ua|
|
11
|
+
ua = ua.gsub(%r{applewebkit}i, 'webkit').gsub %r{(Mozilla/[\d\.]+)}i, ''
|
12
|
+
ua = ua.gsub(%r{chrome|safari}i, '').gsub('OPR', 'opera') if ua =~ %r{OPR}
|
13
|
+
ua = ua.gsub %r{9\.80}, '' if ua =~ %r{opera}i
|
14
|
+
ua = ua.gsub %r{webkit/}i, '' if ua =~ %r{presto}i
|
15
|
+
ua = ua.gsub %r{(?:ms)?ie}i, '' if ua =~ %r{rv:}i
|
16
|
+
ua = ua.gsub %r{android|linux}i, '' if ua =~ %r{tizen}i
|
17
|
+
ua = ua.gsub %r{linux}i, '' if ua =~ %r{android|s(unos|olaris)|w(eb)?os}i
|
18
|
+
ua = ua.gsub %r{x11}i, '' if ua =~ %r{bsd|s(unos|olaris)}i
|
19
|
+
ua = ua.gsub %r{windows\snt}i, '' if ua =~ %r{windows\sphone}i
|
20
|
+
ua = ua.gsub %r{rv:}i, '' if ua =~ %r{servo}i
|
21
|
+
ua = ua.gsub %r{mac\sos\sx}i, '' if ua =~ %r{ip(?:[ao]d|hone)}i
|
22
|
+
ua = ua.gsub %r{msie}i, '' if ua =~ %r{huaweisymantecspider}i
|
23
|
+
ua
|
24
|
+
end
|
25
|
+
|
26
|
+
# after an identity is found, it's values are filtered in two stages
|
27
|
+
# first, filters will parse all statically defined values (e.g.) no regexp
|
28
|
+
# or block within matchers, after that, smart matcher patterns will be
|
29
|
+
# conditionally added and parsed with the previously collected values and
|
30
|
+
# then also filtered
|
31
|
+
|
32
|
+
# this is a global filter, multiple can be defined and they will all run
|
33
|
+
# before any named filters
|
34
|
+
filter do |value|
|
35
|
+
case value
|
36
|
+
when TrueClass, FalseClass, NilClass, Proc then value
|
37
|
+
when %r{\A[\d_\.]+\z}i then value.to_s.strip.tr('_', '.')
|
38
|
+
else value.to_s.downcase.strip.gsub(%r{[\s-]+}i, '_').to_sym
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# this is a named filter, it defines the same filter for 3 properties
|
43
|
+
# multiple name filters for the same property can be created, they will be
|
44
|
+
# executed in order of addition
|
45
|
+
filter :version, :engine_version, :platform_version do |value|
|
46
|
+
Browserino::Version.new value
|
47
|
+
end
|
48
|
+
|
49
|
+
filter :platform do |value|
|
50
|
+
value = :ios if value =~ %r{ip(?:[ao]d|hone)}i
|
51
|
+
value = :webos if value =~ %r{w(?:eb)?os}i
|
52
|
+
value = :linux if value =~ %r{ubuntu|x11}i
|
53
|
+
value = :solaris if value =~ %r{s(?:unos|olaris)}i
|
54
|
+
value = :macintosh if value =~ %r{mac_os_x}i
|
55
|
+
value
|
56
|
+
end
|
57
|
+
|
58
|
+
filter :architecture do |value|
|
59
|
+
value = :x64 if value && value =~ %r{(?:x86_|amd|wow)?64|i686}i
|
60
|
+
value = :x32 if value && value != :x64
|
61
|
+
value
|
62
|
+
end
|
63
|
+
|
64
|
+
filter :mobile do |value|
|
65
|
+
!value.to_s.strip.empty?
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
Browserino.config.define do
|
3
|
+
# labels will be defined before a client has been initialized
|
4
|
+
# they will not be filtered before being injected into the Client
|
5
|
+
|
6
|
+
# labels will be matched against values of #name, #engine and #platform and
|
7
|
+
# will create #label, #engine_label and #platform_label properties
|
8
|
+
# respectively. These enjoy all the features that regular defined properties
|
9
|
+
# in for instance methods enjoy, such as automatic question methods like
|
10
|
+
# client.platform_label? :mavericks
|
11
|
+
label :android, for: :android, range: '1'..'1.4.9'
|
12
|
+
label :cupcake, for: :android, range: '1.5'..'1.9.9'
|
13
|
+
label :eclair, for: :android, range: '2'..'2.1'
|
14
|
+
label :froyo, for: :android, range: '2.2'..'2.2.3'
|
15
|
+
label :gingerbread, for: :android, range: '2.2.4'..'2.3.7'
|
16
|
+
label :honeycomb, for: :android, range: '3'..'3.2.6'
|
17
|
+
label :ice_cream_sandwich, for: :android, range: '4'..'4.0.4'
|
18
|
+
label :jelly_bean, for: :android, range: '4.1'..'4.3.1'
|
19
|
+
label :kitkat, for: :android, range: '4.4'..'4.4.4'
|
20
|
+
label :lollipop, for: :android, range: '5'..'5.1.1'
|
21
|
+
label :marshmallow, for: :android, range: '6'..'6.1.1'
|
22
|
+
label :nougat, for: :android, range: '7'..'7.1.1'
|
23
|
+
|
24
|
+
label :cheetah, for: :macintosh, range: '10.0'..'10.0.9'
|
25
|
+
label :puma, for: :macintosh, range: '10.1'..'10.1.9'
|
26
|
+
label :jaguar, for: :macintosh, range: '10.2'..'10.2.9'
|
27
|
+
label :panther, for: :macintosh, range: '10.3'..'10.3.9'
|
28
|
+
label :tiger, for: :macintosh, range: '10.4'..'10.4.9'
|
29
|
+
label :leopard, for: :macintosh, range: '10.5'..'10.5.9'
|
30
|
+
label :snow_leopard, for: :macintosh, range: '10.6'..'10.6.9'
|
31
|
+
label :lion, for: :macintosh, range: '10.7'..'10.7.9'
|
32
|
+
label :mountain_lion, for: :macintosh, range: '10.8'..'10.8.9'
|
33
|
+
label :mavericks, for: :macintosh, range: '10.9'..'10.9.9'
|
34
|
+
label :yosemite, for: :macintosh, range: '10.10'..'10.10.9'
|
35
|
+
label :el_capitan, for: :macintosh, range: '10.11'..'10.11.9'
|
36
|
+
label :sierra, for: :macintosh, range: '10.12'..'10.12.9'
|
37
|
+
|
38
|
+
label :windows_dos, for: :windows, range: '3.1'..'4.0'
|
39
|
+
label :windows_2000, for: :windows, range: '5.0'..'5.0.9'
|
40
|
+
label :windows_xp, for: :windows, range: '5.1'..'5.2.9'
|
41
|
+
label :windows_vista, for: :windows, range: '6.0'..'6.0.9'
|
42
|
+
label :windows_7, for: :windows, range: '6.1'..'6.1.9'
|
43
|
+
label :windows_8, for: :windows, range: '6.2'..'6.3'
|
44
|
+
label :windows_10, for: :windows, range: '10.0'..'10.0.9'
|
45
|
+
end
|