browserino 3.0.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,290 @@
1
+ # frozen_string_literal: true
2
+ Browserino.config.define do
3
+ # a set of global matchers that will use formatted properties found earlier
4
+ # they will also be applied to every matcher unless that matcher has it's own
5
+ # property set for the defined smart matcher
6
+ smart_match :version, with: ':name/([\d\._]+)', flags: [:i]
7
+ smart_match :engine_version, with: ':engine/([\d\._]+)', flags: [:i]
8
+
9
+ # a simple set of global matchers that will be merged
10
+ # with an identity the final client object is created
11
+ match do
12
+ locale %r{(?<!nintendo)[;\s](\w{2}(?:\-\w{2})?)[;)]}i
13
+ architecture %r{((?:(?:x|x86_|amd|wow|win)64)|i[36]86)}i
14
+ mobile %r{(bolt|nokia|samsung(?!b)|mobi(?:le)?|i?p(?:[ao]d|hone)
15
+ |android|bb\d+|blackberry|iemobile|fennec|bada|meego
16
+ |tizen|vodafone|t\-mobile|opera\sm(?:ob|in)i)}xi
17
+ platform %r{.*(xbox|wii|nintendo\sds|playstation|windows(?:\sphone)?
18
+ |macintosh|mac\sos\sx|android|tizen|ip(?:[ao]d|hone)
19
+ |blackberry|linux|ubuntu|x11|bsd|s(?:unos|olaris)
20
+ |w(?:eb)?os)}xi
21
+ platform_version %r{(?:windows(?:\sphone(?:\sos)?)?|nt|mac\sos\sx|android
22
+ |(?:cpu\s|ip(?:[ao]d|hone)\s)os|blackberry|bb
23
+ |s(?:unos|olaris)/?|w(?:eb)?os/|tizen)\s?([\d\._]+)}xi
24
+ end
25
+
26
+ # automatically set type to :browser for each defined matcher
27
+ browsers do
28
+ # a single matcher that will create an Identity for a specific match
29
+ # identities are added in an array in order of definition - higher is better
30
+ # aliasses are prepended to the list instead of appended (e.g. like blocks)
31
+ # this ensures that aliasses will be matched before any regular matcher
32
+ match %r{maxthon}i do
33
+ # define properties by calling a method with the desired name and:
34
+ # -- value # => will create a static method that returns that value
35
+ # -- /(pat)/ # => will create a method that scans the UA and
36
+ # saves the first capture group
37
+ # -- { blk } # => will create a dynamic method that returns the result
38
+ # of the block, it will be executed within an
39
+ # instantiated Client object
40
+ name :maxthon
41
+
42
+ version %r{maxthon[/\s]([\d\.]+)}i
43
+ engine %r{(webkit|presto|gecko|trident)}i
44
+ engine_version %r{(?:webkit|presto|gecko|trident)/([\d\.]+)}i
45
+ end
46
+
47
+ match %r{retawq}i do
48
+ name :retawq
49
+ locale %r{\[(\w{2}(?:\-\w{2})?)\]}i
50
+ end
51
+
52
+ match %r{lynx}i do
53
+ name :lynx
54
+ end
55
+
56
+ match %r{ucbrowser}i do
57
+ name :ucbrowser
58
+
59
+ version %r{ucbrowser/?([\d\.]+)}i
60
+ engine %r{(trident|gecko|webkit|presto)}i
61
+ engine_version %r{(?:trident|gecko|webkit|presto)/([\d\.]+)}i
62
+ end
63
+
64
+ match %r{edge}i do
65
+ name :edge
66
+ engine :edge
67
+ modern? true
68
+ end
69
+
70
+ match %r{ope?ra?\smini}i do
71
+ name :opera_mini
72
+
73
+ version %r{ope?ra?\smini/([\d\.]+)}i
74
+ engine %r{(presto|webkit)}i
75
+ engine_version %r{(?:presto|webkit)/([\d\.]+)}i
76
+ end
77
+
78
+ match %r{opera[^\w]}i do
79
+ name :opera
80
+
81
+ version %r{(?:opera[\s/]|version/)([\d\.]+)}i
82
+ engine %r{(presto|webkit)}i
83
+ engine_version %r{(?:presto|webkit)/([\d\.]+)}i
84
+ end
85
+
86
+ match %r{msie|trident}i do
87
+ name :ie
88
+ engine :trident
89
+
90
+ version %r{(?:(?:ms)?ie\s|rv:)([\d\.]+)}i
91
+ modern? { version >= 10 }
92
+ end
93
+
94
+ match %r{chrome(?:ium)?}i do
95
+ name :chrome
96
+
97
+ version %r{chrome(?:ium)?/([\d\.]+)}i
98
+ engine %r{(webkit|blink)}i
99
+ engine_version %r{(?:webkit|blink)/([\d\.]+)}i
100
+ modern? { version >= 50 }
101
+ end
102
+
103
+ match %r{firefox}i do
104
+ name :firefox
105
+
106
+ engine %r{(gecko|servo)}i
107
+ engine_version %r{(?:rv:\s?|servo/)([\d\.]+)}i
108
+ modern? { version >= 50 }
109
+ end
110
+
111
+ match %r{konqueror}i do
112
+ name :konqueror
113
+ end
114
+
115
+ match %r{midori}i do
116
+ name :midori
117
+ engine :webkit
118
+ end
119
+
120
+ match %r{safari}i do
121
+ name :safari
122
+ engine :webkit
123
+
124
+ version %r{(?:safari|version)/([\d\.]+)}i
125
+ modern? { version >= 9 }
126
+ end
127
+ end
128
+
129
+ # automatically set type to :bot for each defined matcher
130
+ bots do
131
+ match %r{googlebot}i, name: :googlebot
132
+ match %r{yahoo\!\sslurp}i, name: :yahoo_slurp
133
+ match %r{msnbot}i, name: :msnbot
134
+ match %r{bingbot}i, name: :bingbot
135
+ match %r{baiduspider}i, name: :baiduspider
136
+ match %r{yandexbot}i, name: :yandexbot
137
+ match %r{sosospider}i, name: :sosospider
138
+ match %r{exabot}i, name: :exabot
139
+ match %r{sogou\s?spider}i, name: :sogou_spider
140
+ match %r{nutch}i, name: :nutch
141
+ match %r{scrapy}i, name: :scrapy
142
+ match %r{dataparksearch}i, name: :dataparksearch
143
+ match %r{holmes}i, name: :holmes
144
+ match %r{(?:ask)\sjeeves}i, name: :ask
145
+ match %r{duckduckgo}i, name: :duckduckgo
146
+ match %r{beslistbot}i, name: :beslistbot
147
+ match %r{twitterbot}i, name: :twitterbot
148
+ match %r{linkedinbot}i, name: :linkedin
149
+ match %r{instagram}i, name: :instagram
150
+ match %r{pinterest}i, name: :pinterest
151
+ match %r{tumblr}i, name: :tumblr
152
+ match %r{ia_archiver}i, name: :alexa
153
+ match %r{4anything}i, name: :four_anything
154
+ match %r{autoemailspider}i, name: :auto_email_spider
155
+ match %r{boston[_ ]project}i, name: :boston_project
156
+ match %r{atomz}i, name: :atomz
157
+ match %r{atomic_email_hunter}i, name: :atomic_email_hunter
158
+ match %r{altavista}i, name: :altavista
159
+ match %r{alkaline}i, name: :alkalinebot
160
+ match %r{acoi}i, name: :acoi
161
+ match %r{acoon}i, name: :acoon
162
+ match %r{accoona}i, name: :accoona
163
+ match %r{face(?:bookexternalhit|bot)}i, name: :facebook
164
+ match %r{linkdexbot}i, name: :linkdexbot
165
+ match %r{aitcsrobot}i, name: :aitcsrobot
166
+ match %r{alexibot}i, name: :alexibot
167
+ match %r{aqua_products}i, name: :aqua_products
168
+ match %r{arachnophilia}i, name: :arachnophilia
169
+ match %r{aspider}i, name: :aspider
170
+ match %r{asterias}i, name: :asterias
171
+ match %r{auresys}i, name: :auresys
172
+ match %r{b2w}i, name: :b2w
173
+ match %r{backdoorbot}i, name: :backdoorbot
174
+ match %r{backrub}i, name: :backrub
175
+ match %r{big\sbrother}i, name: :big_brother
176
+ match %r{bizbot}i, name: :bizbot
177
+ match %r{black\shole}i, name: :black_hole
178
+ match %r{blackwidow}i, name: :blackwidow
179
+ match %r{blexbot}i, name: :blexbot
180
+ match %r{bspider}i, name: :bspider
181
+ match %r{bullseye}i, name: :bullseye
182
+ match %r{emailcollector}i, name: :emailcollector
183
+ match %r{emailsiphon}i, name: :emailsiphon
184
+ match %r{emailwolf}i, name: :emailwolf
185
+ match %r{ecatch}i, name: :ecatch
186
+ match %r{flaming\sattackbot}i, name: :flaming_attackbot
187
+ match %r{getright}i, name: :getright
188
+ match %r{harvest}i, name: :harvest
189
+ match %r{huaweisymantecspider}i, name: :huaweisymantecspider
190
+
191
+ match %r{mass\sdownloader}i, name: :mass_downloader,
192
+ version: %r{mass\sdownloader/([\d\.]+)}i
193
+ match %r{safetynet\srobot}i, name: :safetynet_robot,
194
+ version: %r{safetynet\srobot\s([\d\.]+)}i
195
+ match %r{internet\sninja}i, name: :internet_ninja,
196
+ version: %r{internet\sninja\s([\d\.]+)}i
197
+ match %r{go\!zilla}i, name: :gozilla,
198
+ version: %r{go\!zilla\s([\d\.]+)}i
199
+ match %r{larbin}i, name: :larbin,
200
+ version: %r{larbin_([\d\.]+)}i
201
+ match %r{download\sdemon}i, name: :download_demon,
202
+ version: %r{download\sdemon/([\d\.]+)}i
203
+ end
204
+
205
+ # automatically set type to :library for each defined matcher
206
+ validators do
207
+ match %r{cse\shtml\svalidator}i, name: :cse_html_validator
208
+ match %r{csscheck}i, name: :csscheck
209
+ match %r{htmlparser}i, name: :htmlparser
210
+ match %r{p3p\svalidator}i, name: :p3p_validator
211
+ match %r{wdg_validator}i, name: :wdg_validator
212
+ match %r{w3c_validator}i, name: :w3c_validator
213
+
214
+ match %r{cynthia}i, name: :cynthia,
215
+ version: %r{cynthia\s([\d\.]+)}i
216
+
217
+ match %r{w3c_css_validator}i,
218
+ name: :w3c_css_validator,
219
+ version: %r{w3c_css_validator_jfouffa/([\d\.]+)}i
220
+ end
221
+
222
+ # automatically set type to :library for each defined matcher
223
+ libraries do
224
+ match %r{php}i, name: :php
225
+ match %r{python}i, name: :python, version: %r{-urllib/([\d\.]+)}i
226
+ match %r{perl}i, name: :perl
227
+ match %r{java}i, name: :java
228
+ match %r{pycurl}i, name: :pycurl
229
+ match %r{curl}i, name: :curl
230
+ end
231
+
232
+ # inherit properties a standard set of properties by the name of a
233
+ # previously defined matcher, overwritten by properties added within matchers
234
+ # inherit properties from Identity where name == :chrome
235
+ like :chrome do
236
+ match %r{brave}i, name: :brave, version: %r{brave/([\d\.]+)}i
237
+ match %r{vivaldi}i, name: :vivaldi, version: %r{vivaldi/([\d\.]+)}i
238
+ match %r{colibri}i, name: :colibri, version: %r{colibri/([\d\.]+)}i
239
+ match %r{rockmelt}i, name: :rockmelt, version: %r{rockmelt/([\d\.]+)}i
240
+ match %r{flock}i, name: :flock, version: %r{flock/([\d\.]+)}i
241
+
242
+ match %r{comodo_dragon}i, name: :comodo_dragon,
243
+ version: %r{comodo_dragon/([\d\.]+)}i
244
+ end
245
+
246
+ # inherit properties from Identity where name == :safari
247
+ like :safari do
248
+ match %r{bolt}i, name: :bolt, version: %r{bolt/([\d\.]+)}i
249
+
250
+ match %r{stainless}i, name: :stainless,
251
+ version: %r{stainless/([\d\.]+)}i
252
+ match %r{samsungbrowser}i, name: :samsungbrowser,
253
+ version: %r{samsungbrowser/([\d\.]+)}i
254
+ match %r{omniweb}i, name: :omniweb,
255
+ version: %r{omniweb/v([\d\.]+)}i
256
+
257
+ match %r{webos|wosbrowser}i,
258
+ name: :webosbrowser,
259
+ version: %r{(?:version|w(?:eb)?osbrowser)/([\d\.]+)}i
260
+ end
261
+
262
+ # inherit properties from Identity where name == :firefox
263
+ like :firefox do
264
+ match %r{prism}i, name: :prism, version: %r{prism/([\d\.]+)}i
265
+ match %r{waterfox}i, name: :waterfox, version: %r{waterfox/([\d\.]+)}i
266
+ match %r{firebird}i, name: :firebird, version: %r{firebird/([\d\.]+)}i
267
+ match %r{netscape}i, name: :netscape, version: %r{netscape/([\d\.]+)}i
268
+ match %r{icecat}i, name: :icecat, version: %r{icecat/([\d\.]+)}i
269
+ match %r{iceweasel}i, name: :iceweasel, version: %r{iceweasel/([\d\.]+)}i
270
+ match %r{seamonkey}i, name: :seamonkey, version: %r{seamonkey/([\d\.]+)}i
271
+ match %r{superswan}i, name: :superswan, version: %r{superswan/([\d\.]+)}i
272
+ match %r{lunascape}i, name: :lunascape, version: %r{lunascape/([\d\.]+)}i
273
+ match %r{camino}i, name: :camino, version: %r{camino/([\d\.]+)}i,
274
+ locale: %r{\s(\w{2}(?:\-\w{2})?),}i
275
+ end
276
+
277
+ # never thought a browser would want to be like IE...
278
+ like :ie do
279
+ # version does not have to be supplied because we simply want to use
280
+ # the version supplied by the MSIE token instead (there is no version on
281
+ # the avant browser or slimbrowser UA itself)
282
+ match %r{avant\sbrowser}i, name: :avant_browser
283
+ match %r{slimbrowser}i, name: :slimbrowser
284
+
285
+ match %r{sleipnir}i, name: :sleipnir,
286
+ version: %r{sleipnir/([\d\.]+)}i
287
+ match %r{deepnet\sexplorer}i, name: :deepnet_explorer,
288
+ version: %r{deepnet\sexplorer ([\d\.]+)}i
289
+ end
290
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ module Browserino
3
+ class Identity
4
+ attr_reader :pattern, :properties
5
+
6
+ SETTINGS = { name: nil, type: :unknown }.freeze
7
+
8
+ def initialize(pattern = //, opts = {}, **additional, &block)
9
+ opts = pattern if pattern.is_a?(Hash) && opts.empty?
10
+ @properties = SETTINGS.merge(opts.merge(additional))
11
+ @pattern = pattern
12
+
13
+ instance_eval(&block) if block
14
+ end
15
+
16
+ def matches?(user_agent)
17
+ pattern =~ user_agent if pattern.is_a? Regexp
18
+ end
19
+
20
+ def ===(other)
21
+ return false if properties[:name].nil?
22
+
23
+ case other
24
+ when Regexp then other =~ properties[:name]
25
+ when String then other.to_sym == properties[:name]
26
+ when Symbol then other == properties[:name]
27
+ when Identity then other.properties[:name] == properties[:name]
28
+ else false
29
+ end
30
+ end
31
+
32
+ def to_str
33
+ properties[:name].to_s
34
+ end
35
+
36
+ def =~(other)
37
+ self === other
38
+ end
39
+
40
+ def ==(other)
41
+ self === other
42
+ end
43
+
44
+ def method_missing(sym, *args, &block)
45
+ return @properties[sym] = block if block
46
+ return @properties[sym] = args.shift if args.any?
47
+
48
+ @properties[sym]
49
+ end
50
+
51
+ def respond_to_missing?(_, *__, &___)
52
+ true
53
+ end
54
+ end
55
+ end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'action_controller/railtie'
2
4
 
3
5
  module Browserino
4
6
  class ActionController
5
7
  module Base
6
- def agent
7
- @agent ||= Browserino.parse(request.headers['User-Agent'])
8
+ def client
9
+ @client ||= Browserino.parse request.headers['User-Agent']
8
10
  end
9
11
  end
10
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails/railtie'
2
4
  require_relative 'action_controller'
3
5
 
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+ module Browserino
3
+ def self.analyze(user_agent, identity = nil)
4
+ props = [*config.global_identities, identity].compact.map(&:properties)
5
+ .reduce(&:merge)
6
+ like = props.delete :like if props.key? :like
7
+ props = collect(props, user_agent)
8
+ props = normalize props
9
+ props = with_smart_matchers props
10
+ left = props.select { |_, val| val.is_a? Regexp }
11
+ props = props.merge normalize(collect(left, user_agent)) if left.any?
12
+ props = with_labels props
13
+
14
+ if like
15
+ repl = user_agent =~ %r{#{like}}i && '' || like.to_s
16
+ like = parse user_agent.gsub identity.pattern, repl
17
+ end
18
+
19
+ Client.new props, like
20
+ end
21
+
22
+ def self.config
23
+ @config ||= Config.new({ before_parse: [],
24
+ global_identities: [],
25
+ properties: [],
26
+ types: [:unknown],
27
+ names: [],
28
+ smart_matchers: {},
29
+ identities: [],
30
+ labels: Hash.new { |h, k| h[k] = [] },
31
+ filters: Hash.new { |h, k| h[k] = [] },
32
+ aliasses: Hash.new { |h, k| h[k] = [] } })
33
+ end
34
+
35
+ def self.label_for(target_name, version = nil)
36
+ return unless config.labels.key?(target_name) && version
37
+ version = Version.new version unless version.is_a? Version
38
+ return unless version > 0
39
+ config.labels[target_name].each do |candidate|
40
+ min = Version.new candidate[:range].min
41
+ max = Version.new candidate[:range].max
42
+
43
+ return candidate[:name] if version >= min && version <= max
44
+ end
45
+ nil
46
+ end
47
+
48
+ def self.with_labels(properties)
49
+ [:name, :engine, :platform].each do |prop|
50
+ lbl_prop = (prop == :name) && :label || "#{prop}_label".to_sym
51
+ ver_prop = (prop == :name) && :version || "#{prop}_version".to_sym
52
+ properties[lbl_prop] ||= label_for properties[prop], properties[ver_prop]
53
+ end
54
+
55
+ properties
56
+ end
57
+
58
+ def self.with_smart_matchers(properties)
59
+ config.smart_matchers.each_with_object properties do |(prop, detector), props|
60
+ props[prop] ||= parse_detector detector, properties
61
+ end
62
+ end
63
+
64
+ def self.parse_detector(detect, properties)
65
+ pat = properties.each_with_object(detect[:with].dup) do |(key, val), str|
66
+ replacement = val.to_s.strip
67
+ str.gsub! ":#{key}", replacement unless replacement.empty?
68
+ end
69
+
70
+ Regexp.new pat, get_flags(*detect[:flags].to_a)
71
+ end
72
+
73
+ def self.collect(properties, ua)
74
+ properties.each_with_object({}) do |(prop, value), res|
75
+ res[prop] = case value
76
+ when Regexp then value.match(ua).to_a[1]
77
+ else value
78
+ end
79
+ end
80
+ end
81
+
82
+ def self.normalize(properties)
83
+ properties.each_with_object({}) do |(prop, value), store|
84
+ store[prop] = convert value, format: prop
85
+ end
86
+ end
87
+
88
+ def self.convert(val, **opts)
89
+ filters = config.filters[:global] + config.filters[opts[:format]]
90
+ filters.compact.each do |fmt|
91
+ val = fmt.call val
92
+ end
93
+
94
+ val
95
+ end
96
+
97
+ def self.get_flags(*flags)
98
+ val = 0
99
+
100
+ flags.each do |flag|
101
+ case flag.to_sym
102
+ when :m then val |= Regexp::MULTILINE
103
+ when :i then val |= Regexp::IGNORECASE
104
+ when :x then val |= Regexp::EXTENDED
105
+ end
106
+ end
107
+
108
+ val
109
+ end
110
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ module Browserino
3
+ class Options
4
+ def initialize(options = {})
5
+ @options = options
6
+ end
7
+
8
+ def method_missing(sym, *args, &block)
9
+ return @options[opt(sym)] == args.first if args.any?
10
+ @options[opt(sym)]
11
+ end
12
+
13
+ def respond_to_missing?(sym, *args, &block)
14
+ option? sym
15
+ end
16
+
17
+ def merge(other)
18
+ @options.merge! other
19
+ self
20
+ end
21
+
22
+ def to_hash
23
+ @options
24
+ end
25
+
26
+ def to_a
27
+ @options.to_a
28
+ end
29
+
30
+ def to_s
31
+ @options.to_s
32
+ end
33
+
34
+ private
35
+
36
+ def opt(sym)
37
+ sym.to_s.tr('?', '').to_sym
38
+ end
39
+
40
+ def option?(sym)
41
+ @options.keys.include? opt(sym)
42
+ end
43
+ end
44
+ end
@@ -1,3 +1,74 @@
1
+ # frozen_string_literal: true
1
2
  module Browserino
2
- VERSION = '3.0.1'.freeze
3
+ VERSION = '4.0.0'.freeze
4
+
5
+ def self.version
6
+ @verion ||= Version.new VERSION.dup
7
+ end
8
+
9
+ # This class makes versions easily comparable using logical operators
10
+ # it makes it convenient to check versions in a natural way
11
+ class Version < Array
12
+ attr_reader :major, :minor, :patch
13
+
14
+ def initialize(val, *rest)
15
+ super parse_params(val, *rest)
16
+ @major = fetch 0, 0
17
+ @minor = fetch 1, 0
18
+ @patch = fetch 2, 0
19
+ end
20
+
21
+ def full
22
+ to_s
23
+ end
24
+
25
+ def to_s
26
+ @str ||= join '.'
27
+ end
28
+
29
+ def <(other)
30
+ compare :<, other
31
+ end
32
+
33
+ def <=(other)
34
+ compare :<=, other
35
+ end
36
+
37
+ def >(other)
38
+ compare :>, other
39
+ end
40
+
41
+ def >=(other)
42
+ compare :>=, other
43
+ end
44
+
45
+ def ==(other)
46
+ compare :==, other
47
+ end
48
+
49
+ def !=(other)
50
+ compare :!=, other
51
+ end
52
+
53
+ private
54
+
55
+ def parse_params(val, *rest)
56
+ case val
57
+ when Float then val.to_s.split '.'
58
+ when Integer then [val, *rest]
59
+ when String then val.tr('_', '.').split '.'
60
+ when Array then val
61
+ when Hash then [val[:major], val[:minor], val[:patch]]
62
+ when Symbol then []
63
+ else val.to_a
64
+ end.map(&:to_i)
65
+ end
66
+
67
+ def compare(op, other)
68
+ other = Version.new other unless other.is_a? Version
69
+ subsize = [size, other.size].min
70
+
71
+ (self[0...subsize] <=> other[0...subsize]).send op, 0
72
+ end
73
+ end
3
74
  end
data/lib/browserino.rb CHANGED
@@ -1,67 +1,25 @@
1
- require_relative 'browserino/core/mapping'
2
- require_relative 'browserino/core/patterns'
3
- require_relative 'browserino/core/supported'
4
- require_relative 'browserino/core/questions'
5
- require_relative 'browserino/core/helpers'
6
- require_relative 'browserino/core/lies'
7
- require_relative 'browserino/core/alias'
8
-
1
+ # frozen_string_literal: true
9
2
  require_relative 'browserino/integrate/rails' if defined?(::Rails)
10
3
 
11
- require_relative 'browserino/unknown'
12
- require_relative 'browserino/agent'
13
-
4
+ require_relative 'browserino/options'
5
+ require_relative 'browserino/config'
6
+ require_relative 'browserino/methods'
7
+ require_relative 'browserino/client'
14
8
  require_relative 'browserino/version'
15
- require_relative 'browserino/browser'
16
- require_relative 'browserino/engine'
17
- require_relative 'browserino/operating_system'
18
- require_relative 'browserino/console'
19
-
20
- module Browserino
21
- module_function
22
-
23
- def parse(ua)
24
- name = Browser.name(ua)
25
- info = fetch_info(strip_lies(ua), name)
26
- tmp = info[:name].to_s.tr('_', ' ')
27
- info[:name] = tmp.strip == '' ? nil : tmp
28
-
29
- Agent.new check_for_aliases(info), ua
30
- end
9
+ require_relative 'browserino/identity'
31
10
 
32
- def fetch_info(ua, name)
33
- { name: name,
34
- browser_version: Browser.version(ua, name),
35
- engine_name: Engine.name(ua),
36
- engine_version: Engine.version(ua),
37
- system_name: OperatingSystem.name(ua),
38
- system_version: OperatingSystem.version(ua),
39
- system_architecture: OperatingSystem.architecture(ua),
40
- console_name: Console.name(ua),
41
- locale: OperatingSystem.locale(ua) }
42
- end
43
-
44
- def strip_lies(ua)
45
- Core::LIES.inject(ua) do |s, arr|
46
- s = s.gsub(arr[0], '') if arr[1] == true || s =~ arr[1]
47
- s
48
- end
49
- end
11
+ require_relative 'browserino/definitions/matchers'
12
+ require_relative 'browserino/definitions/aliasses'
13
+ require_relative 'browserino/definitions/filters'
14
+ require_relative 'browserino/definitions/labels'
50
15
 
51
- def check_for_aliases(h)
52
- Core::ALIAS.each do |k, v|
53
- h[k] = v.select { |n, re| n if h[k] =~ re }.keys.first || h[k]
16
+ module Browserino
17
+ def self.parse(ua)
18
+ config.before_parse.each { |b| ua = b.call ua } if config.before_parse.any?
19
+ config.identities.each do |identity|
20
+ return analyze ua, identity if identity.matches? ua
54
21
  end
55
- h
56
- end
57
22
 
58
- def extract_match(match, sym)
59
- if match && match.names.include?(sym.to_s)
60
- m = match[sym].to_s.downcase.strip
61
- m = yield(m) if block_given?
62
- m
63
- else
64
- UNKNOWN
65
- end
23
+ analyze ua
66
24
  end
67
25
  end