1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
class DeviceDetector
class Parser < Struct.new(:user_agent)
ROOT = File.expand_path('../../..', __FILE__)
def name
from_cache(['name', self.class.name, user_agent]) do
NameExtractor.new(user_agent, regex_meta).call
end
end
def full_version
from_cache(['full_version', self.class.name, user_agent]) do
VersionExtractor.new(user_agent, regex_meta).call
end
end
private
def regex_meta
@regex_meta ||= matching_regex || {}
end
def matching_regex
from_cache([self.class.name, user_agent]) do
regexes.find { |r| user_agent =~ r[:regex] }
end
end
def regexes
@regexes ||= regexes_for(filepaths)
end
def filenames
fail NotImplementedError
end
def filepaths
filenames.map do |filename|
[ filename.to_sym, File.join(ROOT, 'regexes', filename) ]
end
end
def regexes_for(file_paths)
from_cache(['regexes', self.class]) do
load_regexes(file_paths).flat_map { |path, regex| parse_regexes(path, regex) }
end
end
def load_regexes(file_paths)
file_paths.map { |path, full_path| [path, symbolize_keys!(YAML.load_file(full_path))] }
end
def symbolize_keys!(object)
case object
when Array
object.map!{ |v| symbolize_keys!(v) }
when Hash
object.keys.each{ |k| object[k.to_sym] = symbolize_keys!(object.delete(k)) if k.is_a?(String) }
end
object
end
def parse_regexes(path, raw_regexes)
raw_regexes.map do |meta|
fail "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String
meta[:regex] = build_regex(meta[:regex])
meta[:path] = path
meta
end
end
def build_regex(src)
Regexp.new('(?:^|[^A-Z0-9\-_]|[^A-Z0-9\-]_|sprd-)(?:' + src + ')', Regexp::IGNORECASE)
end
def from_cache(key)
DeviceDetector.cache.get_or_set(key) { yield }
end
end
end
|