Skip to content

Commit

Permalink
Platform (software) and device (hardware) are now detected separately.
Browse files Browse the repository at this point in the history
  • Loading branch information
fnando committed Jan 2, 2016
1 parent 810e743 commit 9f5bd86
Show file tree
Hide file tree
Showing 70 changed files with 1,622 additions and 841 deletions.
42 changes: 22 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,39 +23,41 @@ browser.name # readable browser name
browser.version # major version number
browser.full_version
browser.safari?
browser.ios?
browser.device.ios?
browser.app? # request performed by ios' app webview
browser.opera?
browser.chrome?
browser.chrome_os?
browser.platform.chrome_os?
browser.mobile?
browser.tablet?
browser.device.tablet?
browser.console?
browser.firefox?
browser.ie?
browser.ie?(6) # detect specific IE version
browser.edge? # Newest MS browser
browser.modern? # Webkit, Firefox 17+, IE 9+ and Opera 12+
browser.platform # return :mac, :windows, :linux or :other
browser.ios? # detect iOS
browser.ios?(9) # detect specific iOS version
browser.mac?
browser.windows?
browser.windows_x64?
browser.linux?
browser.blackberry?
browser.blackberry?(10) # detect specific BlackBerry version
browser.ie?(6) # detect specific IE version
browser.edge? # Newest MS browser
browser.modern? # Webkit, Firefox 17+, IE 9+ and Opera 12+
browser.platform # Information about the platform
browser.platform.id # e.g. :linux, :mac, :ios, :android
browser.platform.version # e.g. 9 (for iOS9)
browser.platform.ios? # detect iOS
browser.platform.ios?(9) # detect specific iOS version
browser.platform.mac?
browser.platform.windows?
browser.platform.windows_x64?
browser.platform.linux?
browser.platform.blackberry?
browser.platform.blackberry?(10) # detect specific BlackBerry version
browser.bot?
browser.search_engine?
browser.phantom_js?
browser.quicktime?
browser.core_media?
browser.silk?
browser.android?
browser.android?(4.2) # detect Android Jelly Bean 4.2
browser.known? # has the browser been successfully detected?
browser.meta # an array with several attributes
browser.to_s # the meta info joined by space
browser.platform.android?
browser.platform.android?(4.2) # detect Android Jelly Bean 4.2
browser.known? # has the browser been successfully detected?
browser.meta # an array with several attributes
browser.to_s # the meta info joined by space
```

See the [tests](https://github.com/fnando/browser/blob/master/test/browser_test.rb) and [implementation](https://github.com/fnando/browser/blob/master/lib/browser.rb) for more examples.
Expand Down
110 changes: 77 additions & 33 deletions lib/browser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,44 @@
require "browser/middleware/context"
require "browser/rails" if defined?(::Rails)

require "browser/platform"
require "browser/platform/base"
require "browser/platform/ios"
require "browser/platform/linux"
require "browser/platform/windows"
require "browser/platform/mac"
require "browser/platform/windows_phone"
require "browser/platform/windows_mobile"
require "browser/platform/firefox_os"
require "browser/platform/blackberry"
require "browser/platform/android"
require "browser/platform/other"
require "browser/platform/chrome_os"
require "browser/platform/adobe_air"

require "browser/device"
require "browser/device/base"
require "browser/device/unknown"
require "browser/device/ipad"
require "browser/device/ipod_touch"
require "browser/device/iphone"
require "browser/device/playstation3"
require "browser/device/playstation4"
require "browser/device/psp"
require "browser/device/psvita"
require "browser/device/kindle"
require "browser/device/kindle_fire"
require "browser/device/wii"
require "browser/device/wiiu"
require "browser/device/blackberry_playbook"
require "browser/device/surface"
require "browser/device/tv"
require "browser/device/xbox_one"
require "browser/device/xbox_360"

require "browser/methods/ie"
require "browser/methods/blackberry"
require "browser/methods/platform"
require "browser/methods/mobile"
require "browser/methods/devices"
require "browser/methods/consoles"
require "browser/methods/language"
require "browser/methods/bots"
require "browser/methods/tv"
require "browser/methods/proxy"

require "browser/meta/base"
Expand All @@ -28,17 +57,13 @@
require "browser/meta/proxy"
require "browser/meta/safari"
require "browser/meta/webkit"
require "browser/meta/tablet"
require "browser/meta/device"

class Browser
include IE
include BlackBerry
include Platform
include Mobile
include Devices
include Consoles
include Language
include Bots
include Tv
include Proxy

# Set browser's UA string.
Expand All @@ -52,21 +77,11 @@ class Browser
chrome: "Chrome", # Must come before android
firefox: "Firefox", # Must come before android
uc_browser: "UC Browser", # Must come before android
android: "Android",
blackberry_running_safari: "Safari",
blackberry: "BlackBerry",
core_media: "Apple CoreMedia",
ipad: "iPad", # Must come before safari
iphone: "iPhone", # Must come before safari
ipod: "iPod Touch", # Must come before safari
nintendo: "Nintendo",
opera: "Opera",
safari: "Safari",
phantom_js: "PhantomJS",
psp: "PlayStation Portable",
playstation: "PlayStation",
quicktime: "QuickTime",
safari: "Safari",
xbox: "Xbox",
nokia: "Nokia S40 Ovi Browser",

# This must be last item, since Ruby 1.9+ has ordered keys.
Expand All @@ -76,11 +91,15 @@ class Browser
VERSIONS = {
edge: %r[Edge/([\d.]+)],
chrome: %r[(?:Chrome|CriOS)/([\d.]+)],
default: %r[(?:Version|MSIE|Firefox|QuickTime|BlackBerry[^/]+|CoreMedia v|PhantomJS|AdobeAIR)[/ ]?([a-z0-9.]+)]i,
default: %r[(?:Version|MSIE|Firefox|QuickTime|CoreMedia v|PhantomJS)[/ ]?([a-z0-9.]+)]i,
opera: %r[(?:Opera/.*? Version/([\d.]+)|Chrome/.*?OPR/([\d.]+))],
ie: %r[(?:MSIE |Trident/.*?; rv:)([\d.]+)]
}

def self.root
@root ||= Pathname.new(File.expand_path("../..", __FILE__))
end

# Define the rules which define a modern browser.
# A rule must be a proc/lambda or any object that implements the method
# === and accepts the browser object.
Expand All @@ -101,7 +120,7 @@ def self.modern_rules
rules << -> b { b.ie? && b.version.to_i >= 9 && !b.compatibility_view? }
rules << -> b { b.edge? && !b.compatibility_view? }
rules << -> b { b.opera? && b.version.to_i >= 12 }
rules << -> b { b.firefox? && b.tablet? && b.android? && b.version.to_i >= 14 }
rules << -> b { b.firefox? && b.device.tablet? && b.platform.android? && b.version.to_i >= 14 }
end

# Create a new browser instance and set
Expand All @@ -126,8 +145,8 @@ def name

# Get the browser identifier.
def id
NAMES.keys
.find {|id| respond_to?("#{id}?", true) ? send("#{id}?") : id }
@id ||= NAMES.keys
.find {|id| respond_to?("#{id}?", true) ? send("#{id}?") : id }
end

# Return major version.
Expand All @@ -143,6 +162,8 @@ def version
def full_version
if ie?
ie_full_version
elsif alternative_version?
webkit_full_version || "0.0"
else
_, *v = *ua.match(VERSIONS.fetch(id, VERSIONS[:default]))
v.compact.first || "0.0"
Expand Down Expand Up @@ -176,7 +197,7 @@ def phantom_js?

# Detect if browser is Safari.
def safari?
!!((ua =~ /Safari/) && ua !~ /Android|Chrome|CriOS|PhantomJS/)
!!(ua =~ /Safari/ && ua !~ /Chrome|CriOS|PhantomJS/)
end

def safari_webapp_mode?
Expand All @@ -198,11 +219,6 @@ def opera?
!!(ua =~ /(Opera|OPR)/)
end

# Detect if browser is Silk.
def silk?
!!(ua =~ /Silk/)
end

# Detect if browser is Yandex.
def yandex?
!!(ua =~ /YaBrowser/)
Expand All @@ -213,10 +229,34 @@ def uc_browser?
!!(ua =~ /UCBrowser/)
end

# Detect if browser is Nokia S40 Ovi Browser.
def nokia?
!!(ua =~ /S40OviBrowser/)
end

# Detect if browser is Opera Mini.
def opera_mini?
!!(ua =~ /Opera Mini/)
end

def webkit_full_version
ua[%r[AppleWebKit/([\d.]+)], 1] || "0.0"
end

def known?
id != :other
end

# Return the platform.
def platform
@platform ||= Browser::Platform.new(ua)
end

# Return the device info.
def device
@device ||= Browser::Device.new(ua)
end

# Return a meta info about this browser.
def meta
Meta.constants.each_with_object(Set.new) do |meta_name, meta|
Expand All @@ -234,6 +274,10 @@ def to_s

private

def alternative_version?
platform.blackberry? || device.playbook? || platform.adobe_air?
end

def detect_version?(actual_version, expected_version)
return true unless expected_version
actual_version.to_s.start_with?(expected_version.to_s)
Expand Down
Loading

0 comments on commit 9f5bd86

Please sign in to comment.