fivepointssolutions-uaid 0.0.1 → 0.1.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/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 1
2
+ :patch: 0
3
3
  :major: 0
4
- :minor: 0
4
+ :minor: 1
@@ -0,0 +1,115 @@
1
+ module Uaid
2
+ def Uaid.extractor
3
+ @extractor ||= Extractor.new
4
+ end
5
+
6
+ def Uaid.extractor=(e)
7
+ @extractor = e
8
+ end
9
+
10
+ class Extractor
11
+ def engines
12
+ @engines ||= %w(ie webkit gecko)
13
+ end
14
+
15
+ def products
16
+ @products ||= product_extractions.collect {|product,| product}
17
+ end
18
+
19
+ def extract(agent)
20
+ product = extract_product(agent)
21
+ engine = extract_engine(agent, product)
22
+ version = extract_version(agent, product, engine)
23
+ [engine, product, version]
24
+ end
25
+
26
+ protected
27
+ def extract_product(agent)
28
+ find_match_in_extractions(agent, product_extractions) || 'unknown'
29
+ end
30
+
31
+ def extract_engine(agent, product)
32
+ case extractions = engine_extractions(product)
33
+ when String: extractions
34
+ when Array: find_match_in_extractions(agent, extractions) || 'unknown'
35
+ when nil: 'unknown'
36
+ end
37
+ end
38
+
39
+ def extract_version(agent, product, engine)
40
+ case extractions = version_extractions(product)
41
+ when Array
42
+ match = extractions.detect {|version, regexp| agent =~ regexp}
43
+ match ? match[0] : 'x'
44
+ when nil: 'x'
45
+ end
46
+ end
47
+
48
+ def product_extractions
49
+ @product_extractions ||= [
50
+ ['ie', [/MSIE/]],
51
+ ['mobilesafari', [/iPhone.*?Version.*?Safari/]],
52
+ ['safari', [/Version.*?Safari/]],
53
+ ['chrome', [/Chrome.*?Safari/]],
54
+ ['firefox', [/Firefox|BonEcho|Shiretoko/]],
55
+ ['android', [/Android/]],
56
+ ['bot', [/googlebot|msnbot|ia_archiver/i]],
57
+ ['noagent', [/^$/]],
58
+ ]
59
+ end
60
+
61
+ def engine_extractions(product)
62
+ @engine_extractions ||= {
63
+ 'ie' => 'ie',
64
+ 'safari' => 'webkit',
65
+ 'mobilesafari' => 'webkit',
66
+ 'chrome' => 'webkit',
67
+ 'firefox' => 'gecko',
68
+ 'android' => 'webkit',
69
+ }
70
+ @engine_extractions[product]
71
+ end
72
+
73
+ def version_extractions(product)
74
+ @version_extractions ||= {
75
+ 'ie' => [
76
+ ['7', /MSIE 7/],
77
+ ['8', /MSIE 8/],
78
+ ['6', /MSIE 6/],
79
+ ],
80
+ 'firefox' => [
81
+ ['3', /Firefox\/3|Shiretoko/],
82
+ ['2', /Firefox\/2|BonEcho\/2/],
83
+ ],
84
+ 'safari' => [
85
+ ['3', /Version\/3/],
86
+ ['4', /Version\/4/],
87
+ ],
88
+ 'mobilesafari' => [
89
+ ['3', /Version\/3/],
90
+ ],
91
+ 'chrome' => [
92
+ ['1', /Chrome\/[01]\./],
93
+ ],
94
+ 'android' => [
95
+ ['0', /Android 0\./],
96
+ ]
97
+ }
98
+ @version_extractions[product]
99
+ end
100
+
101
+ # Answers the first matching extraction. Keep this in mind when adding
102
+ # patterns!
103
+ #
104
+ def find_match_in_extractions(agent, extractions)
105
+ match = nil
106
+ extractions.each do |answer, patterns|
107
+ matches = patterns.inject(true) {|m,pattern| m && agent =~ pattern}
108
+ next unless matches
109
+ match = answer
110
+ break
111
+ end
112
+ match
113
+ end
114
+ end
115
+ end
@@ -1,49 +1,62 @@
1
1
  module Uaid
2
+ def Uaid.supported_agents
3
+ @supported ||= [
4
+ /safari [34]/,
5
+ /chrome/,
6
+ /firefox [23]/,
7
+ /ie [678]/,
8
+ /android/,
9
+ /bot/
10
+ ]
11
+ end
12
+
13
+ # Define the set of supported agents. You may also concat to the existing
14
+ # list.
15
+ #
16
+ def Uaid.supported_agents=(s)
17
+ @supported = s
18
+ end
19
+
2
20
  class UserAgent
3
- SUPPORTED, UNSUPPORTED = true, false
21
+ attr_reader :agent, :engine, :product, :version, :supported
4
22
 
5
- attr_reader :agent, :name, :version
23
+ def initialize(agent, extractor = Uaid.extractor)
24
+ @agent, @extractor = agent, extractor
25
+ @engine, @product, @version = @extractor.extract(@agent ? @agent.strip : '')
26
+ end
6
27
 
7
- def initialize(agent)
8
- @agent = agent
9
- @name, @version, @supported = extract(@agent ? @agent.strip : '')
28
+ def identifier
29
+ [engine, product, product + version].join(' ')
10
30
  end
11
31
 
12
32
  def supported?
13
- @supported
33
+ !!Uaid.supported_agents.detect do |agent_match|
34
+ case agent_match
35
+ when Array: agent_match == [engine, product, version]
36
+ when Regexp: [engine, product, version].join(' ') =~ agent_match
37
+ end
38
+ end
39
+ end
40
+
41
+ def unknown?
42
+ engine == 'unknown' || product == 'unknown' || version == 'x'
14
43
  end
15
44
 
16
45
  def unsupported?
17
46
  !supported?
18
47
  end
19
48
 
49
+ def version?(e)
50
+ version == e
51
+ end
52
+
20
53
  def method_missing(method, *args)
21
- if method.to_s =~ /^(\w+)\?$/ && EXTRACTIONS.find {|patterns, values| values.first == $1}
22
- name == $1
54
+ if method.to_s =~ /^(\w+)\?$/
55
+ return true if (engine == $1 || product == $1)
56
+ @extractor.engines.include?($1) || @extractor.products.include?($1)
23
57
  else
24
58
  super
25
59
  end
26
60
  end
27
-
28
- protected
29
- EXTRACTIONS = [
30
- [[/MSIE/, /MSIE 7/], ['ie', '7', SUPPORTED]],
31
- [[/MSIE/, /MSIE 8/], ['ie', '8', SUPPORTED]],
32
- [[/MSIE/, /MSIE 6/], ['ie', '6', UNSUPPORTED]],
33
- [[/iPhone/, /Version\/3/], ['mobilesafari', '3', SUPPORTED]],
34
- [[/Safari/, /Version\/3/], ['webkit', '3', SUPPORTED]],
35
- [[/AppleWebKit/, /525/], ['webkit', '3', SUPPORTED]],
36
- [[/AppleWebKit/, /528/], ['webkit', '4', SUPPORTED]],
37
- [[/Gecko/, /Firefox\/3/], ['gecko', '3', SUPPORTED]],
38
- [[/Gecko/, /Firefox\/2|BonEcho\/2/], ['gecko', '2', SUPPORTED]],
39
- [[/Gecko/, /Shiretoko/], ['gecko', '3.5', SUPPORTED]],
40
- [[/googlebot|msnbot|ia_archiver/i], ['bot', 'x', SUPPORTED]],
41
- [[/^$/], ['noagent', 'x', UNSUPPORTED]],
42
- [[/.*/], ['unknown', 'x', UNSUPPORTED]]
43
- ]
44
-
45
- def extract(agent)
46
- EXTRACTIONS.detect {|patterns,| patterns.inject(true) {|m,pattern| m && agent =~ pattern} }.last
47
- end
48
61
  end
49
62
  end
data/lib/uaid.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'uaid/extractor'
1
2
  require 'uaid/user_agent'
2
3
  require 'uaid/helper'
3
4
 
@@ -0,0 +1,52 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper.rb')
2
+
3
+ describe Uaid::Extractor do
4
+ before :all do
5
+ @extractor = Uaid::Extractor.new
6
+ end
7
+
8
+ {
9
+ ["unknown", "unknown", "x"] => [nil, '', ' '],
10
+ ["webkit", "safari", "3"] => [
11
+ "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/526+ (KHTML, like Gecko) Version/3.1.1 Safari/525.18",
12
+ "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.17"],
13
+ ["webkit", "chrome", "1"] => [
14
+ "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13",
15
+ "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.36 Safari/525.19"],
16
+ ["webkit", "safari", "4"] => [
17
+ "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16"],
18
+ ["gecko", "firefox", "2"] => [
19
+ "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14",
20
+ "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20060601 Firefox/2.0.0.6 (Ubuntu-edgy)",
21
+ "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.4) Gecko/20080721 BonEcho/2.0.0.4"],
22
+ ["gecko", "firefox", "3"] => [
23
+ "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1",
24
+ "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20090109 Shiretoko/3.1b3pre"],
25
+ ["ie", "ie", "8"] => [
26
+ "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0; .NET CLR 1.1.4322)"],
27
+ ["ie", "ie", "7"] => [
28
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; InfoPath.1)",
29
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"],
30
+ ["ie", "ie", "6"] => [
31
+ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"],
32
+ ["webkit", "mobilesafari", "3"] => [
33
+ "Mozilla/5.0 (iPhone; U; XXXXX like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/241 Safari/419.3"],
34
+ ["webkit", "android", "0"] => [
35
+ "Mozilla/5.0 (Linux; U; Android 0.5; en-us) AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3"],
36
+ ["unknown", "unknown", "x"] => [
37
+ "Mozilla/4.0",
38
+ "VB Project"],
39
+ ["unknown", "bot", "x"] => [
40
+ "ia_archiver",
41
+ "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
42
+ "Googlebot/2.1 (+http://www.googlebot.com/bot.html)",
43
+ "Googlebot/2.1 (+http://www.google.com/bot.html)",
44
+ "msnbot/1.0 (+http://search.msn.com/msnbot.htm)"]
45
+ }.each do |expected, agents| agents.each do |agent|
46
+
47
+ it "should identify #{agent.inspect} as #{expected.inspect}" do
48
+ @extractor.extract(agent).should == expected
49
+ end
50
+
51
+ end; end
52
+ end
data/spec/helper_spec.rb CHANGED
@@ -9,6 +9,6 @@ describe Uaid::Helper do
9
9
  it 'should provide a user_agent from the current request' do
10
10
  @request = OpenStruct.new(:headers => {'user-agent' => 'whatever'})
11
11
  user_agent.should_not be_nil
12
- user_agent.name.should == 'unknown'
12
+ user_agent.product.should == 'unknown'
13
13
  end
14
14
  end
@@ -1,57 +1,77 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper.rb')
2
2
 
3
- describe Uaid::UserAgent do
4
- {
5
- ["noagent", "x", false] => [nil, '', ' '],
6
- ["webkit", "3", true] => [
7
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/526+ (KHTML, like Gecko) Version/3.1.1 Safari/525.18",
8
- "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.17",
9
- "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13",
10
- "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.36 Safari/525.19"],
11
- ["webkit", "4", true] => [
12
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16"],
13
- ["gecko", "2", true] => [
14
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14",
15
- "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20060601 Firefox/2.0.0.6 (Ubuntu-edgy)",
16
- "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.4) Gecko/20080721 BonEcho/2.0.0.4"],
17
- ["gecko", "3", true] => [
18
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1"],
19
- ["gecko", "3.5", true] => [
20
- "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20090109 Shiretoko/3.1b3pre"],
21
- ["ie", "8", true] => [
22
- "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0; .NET CLR 1.1.4322)"],
23
- ["ie", "7", true] => [
24
- "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; InfoPath.1)",
25
- "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"],
26
- ["ie", "6", false] => [
27
- "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"],
28
- ["mobilesafari", "3", true] => [
29
- "Mozilla/5.0 (iPhone; U; XXXXX like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/241 Safari/419.3"],
30
- ["unknown", "x", false] => [
31
- "Mozilla/4.0",
32
- "VB Project"],
33
- ["bot", "x", true] => [
34
- "ia_archiver",
35
- "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
36
- "Googlebot/2.1 (+http://www.googlebot.com/bot.html)",
37
- "Googlebot/2.1 (+http://www.google.com/bot.html)",
38
- "msnbot/1.0 (+http://search.msn.com/msnbot.htm)"]
39
- }.each do |expected_name_version_supported, agents| agents.each do |agent|
40
-
41
- it "should indicate #{agent.inspect} as #{expected_name_version_supported[0..1].inspect}, #{expected_name_version_supported.last ? 'a supported' : 'an unsupported'} browser" do
42
- user_agent = Uaid::UserAgent.new(agent)
43
- user_agent.name.should == expected_name_version_supported[0]
44
- user_agent.version.should == expected_name_version_supported[1]
45
- user_agent.supported?.should == expected_name_version_supported[2]
46
- end
47
-
48
- end; end
49
- end
50
-
51
- describe Uaid::UserAgent, 'name question' do
52
- it 'should answer true when agent has name' do
53
- user_agent = Uaid::UserAgent.new('unknown')
54
- user_agent.webkit?.should be_false
55
- user_agent.unknown?.should be_true
3
+ describe Uaid::UserAgent, 'identification questions' do
4
+ before do
5
+ @user_agent = Uaid::UserAgent.new('unknown')
6
+ end
7
+
8
+ after do
9
+ Uaid.supported_agents = nil
10
+ end
11
+
12
+ [
13
+ ['unknown', 'bot', '1'],
14
+ ['webkit', 'unknown', '1'],
15
+ ['webkit', 'bot', 'x'],
16
+ ].each do |attributes|
17
+ engine, product, version = attributes
18
+ it "should answer true for unknown when unknown as #{attributes.inspect}" do
19
+ user_agent = Uaid::UserAgent.new('unknown')
20
+ stub(@user_agent).engine { engine }
21
+ stub(@user_agent).product { product }
22
+ stub(@user_agent).version { version }
23
+ @user_agent.unknown?.should be_true
24
+ end
25
+ end
26
+
27
+ it 'should answer false for unknown when all attributes are known' do
28
+ stub(@user_agent).engine { 'someengine' }
29
+ stub(@user_agent).product { 'someproduct' }
30
+ stub(@user_agent).version { '1' }
31
+ @user_agent.unknown?.should be_false
32
+ end
33
+
34
+ it 'should answer for engine' do
35
+ stub(@user_agent).engine { 'someengine' }
36
+ @user_agent.someengine?.should be_true
37
+ @user_agent.otherengine?.should be_false
38
+ end
39
+
40
+ it 'should answer for product' do
41
+ stub(@user_agent).product { 'someproduct' }
42
+ @user_agent.someproduct?.should be_true
43
+ @user_agent.otherproduct?.should be_false
44
+ end
45
+
46
+ it 'should answer for version' do
47
+ stub(@user_agent).version { '2' }
48
+ @user_agent.version?('2').should be_true
49
+ end
50
+
51
+ it 'should answer an identifier which include the engine, product and version' do
52
+ stub(@user_agent).engine { 'someengine' }
53
+ stub(@user_agent).product { 'someproduct' }
54
+ stub(@user_agent).version { '1' }
55
+ @user_agent.identifier.should == 'someengine someproduct someproduct1'
56
+ end
57
+
58
+ it 'should answer supported as true when all attributes match a supported agent' do
59
+ stub(@user_agent).engine { 'webkit' }
60
+ stub(@user_agent).product { 'safari' }
61
+ stub(@user_agent).version { '3' }
62
+ @user_agent.should be_supported
63
+ end
64
+
65
+ it 'should answer supported when an entry in the supported list is a regular expression' do
66
+ Uaid.supported_agents = [/safari [34]/]
67
+ stub(@user_agent).product { 'safari' }
68
+ stub(@user_agent).version { '3' }
69
+ @user_agent.should be_supported
70
+
71
+ stub(@user_agent).version { '4' }
72
+ @user_agent.should be_supported
73
+
74
+ stub(@user_agent).version { '2' }
75
+ @user_agent.should_not be_supported
56
76
  end
57
77
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fivepointssolutions-uaid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Williams
@@ -24,9 +24,11 @@ extra_rdoc_files: []
24
24
  files:
25
25
  - VERSION.yml
26
26
  - lib/uaid
27
+ - lib/uaid/extractor.rb
27
28
  - lib/uaid/helper.rb
28
29
  - lib/uaid/user_agent.rb
29
30
  - lib/uaid.rb
31
+ - spec/extractor_spec.rb
30
32
  - spec/helper_spec.rb
31
33
  - spec/spec.opts
32
34
  - spec/spec_helper.rb