mobvious 0.1.0.pre
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/.gitignore +5 -0
- data/.yardopts +1 -0
- data/Gemfile +13 -0
- data/Guardfile +5 -0
- data/Rakefile +1 -0
- data/lib/mobvious.rb +21 -0
- data/lib/mobvious/config.rb +26 -0
- data/lib/mobvious/manager.rb +57 -0
- data/lib/mobvious/strategies/cookie.rb +55 -0
- data/lib/mobvious/strategies/mobileesp.rb +43 -0
- data/lib/mobvious/strategies/url.rb +30 -0
- data/lib/mobvious/version.rb +3 -0
- data/mobvious.gemspec +42 -0
- data/spec/mobvious/manager_spec.rb +91 -0
- data/spec/mobvious/strategies/cookie_spec.rb +83 -0
- data/spec/mobvious/strategies/mobileesp_spec.rb +56 -0
- data/spec/mobvious/strategies/url_spec.rb +31 -0
- data/spec/spec_helper.rb +34 -0
- metadata +189 -0
data/.gitignore
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-m markdown
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
|
6
|
+
gem 'mobileesp', git: 'git://github.com/jistr/mobileesp'
|
7
|
+
|
8
|
+
# == SPECIAL DEVELOPMENT DEPS HANDLING ==
|
9
|
+
|
10
|
+
# temporarily switched for this fork, because the current version of guard-minitest has broken notifications
|
11
|
+
gem 'guard-minitest', git: 'git://github.com/aspiers/guard-minitest', ref: '4b660261d35'
|
12
|
+
gem 'mocha', require: false
|
13
|
+
gem 'turn', require: false
|
data/Guardfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/mobvious.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "mobvious/version"
|
2
|
+
|
3
|
+
require "mobvious/config"
|
4
|
+
require "mobvious/manager"
|
5
|
+
|
6
|
+
# A library (Rack middleware) to detect device types (mobile, tablet, desktop etc.)
|
7
|
+
# from requests.
|
8
|
+
#
|
9
|
+
# See {Mobvious::Manager} for the actual Rack middleware.
|
10
|
+
#
|
11
|
+
# See {Mobvious::Config} for configuration options (and set them via calling
|
12
|
+
# {Mobvious.config Mobvious.config}).
|
13
|
+
#
|
14
|
+
# See {Mobvious::Strategies} for predefined strategies or roll out your own.
|
15
|
+
module Mobvious
|
16
|
+
# An accessor for the global Mobvious configuration object.
|
17
|
+
# See {Config} for configuration options.
|
18
|
+
def self.config
|
19
|
+
@config ||= Mobvious::Config.new
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Mobvious
|
2
|
+
# Class encapsulating Mobvious configuration.
|
3
|
+
#
|
4
|
+
# Set configuration options them via calling {Mobvious.config Mobvious.config}.
|
5
|
+
class Config
|
6
|
+
# Creates a new configuration with no strategies and default device type `:desktop`.
|
7
|
+
def initialize()
|
8
|
+
self.clear
|
9
|
+
end
|
10
|
+
|
11
|
+
# Resets a configuration to no strategies and default device type `:desktop`.
|
12
|
+
def clear
|
13
|
+
@strategies = []
|
14
|
+
@default_device_type = :desktop
|
15
|
+
end
|
16
|
+
|
17
|
+
# Strategies used to determine device type from a request. They are evaluated
|
18
|
+
# in the order they are inserted. Result of the first successful strategy
|
19
|
+
# (returning something else than nil) is used.
|
20
|
+
attr_accessor :strategies
|
21
|
+
|
22
|
+
# Default device type is used when no strategy was successful (all return nil
|
23
|
+
# or none is present).
|
24
|
+
attr_accessor :default_device_type
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Mobvious
|
4
|
+
# Rack middleware that enables device type detection for requests.
|
5
|
+
#
|
6
|
+
# Use `Mobvious.config` to set which strategies to use.
|
7
|
+
#
|
8
|
+
# Look into `Mobvious::Strategies` for predefined strategies or write your own.
|
9
|
+
class Manager
|
10
|
+
# Create a new instance of this rack middleware.
|
11
|
+
#
|
12
|
+
# @param app Rack application that can be called.
|
13
|
+
def initialize(app)
|
14
|
+
@app = app
|
15
|
+
end
|
16
|
+
|
17
|
+
# Perform the device type detection and call the inner Rack application.
|
18
|
+
#
|
19
|
+
# @param env Rack environment.
|
20
|
+
# @return rack response `[status, headers, body]`
|
21
|
+
def call(env)
|
22
|
+
request = Rack::Request.new(env)
|
23
|
+
assign_device_type(request)
|
24
|
+
|
25
|
+
status, headers, body = @app.call(env)
|
26
|
+
|
27
|
+
response = Rack::Response.new(body, status, headers)
|
28
|
+
response_callback(request, response)
|
29
|
+
|
30
|
+
[status, headers, body]
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def assign_device_type(request)
|
35
|
+
request.env['mobvious.device_type'] =
|
36
|
+
get_device_type_using_strategies(request) || config.default_device_type
|
37
|
+
end
|
38
|
+
|
39
|
+
def response_callback(request, response)
|
40
|
+
config.strategies.each do |strategy|
|
41
|
+
strategy.response_callback(request, response) if strategy.respond_to? :response_callback
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_device_type_using_strategies(request)
|
46
|
+
config.strategies.each do |strategy|
|
47
|
+
result = strategy.get_device_type(request)
|
48
|
+
return result.to_sym if result
|
49
|
+
end
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def config
|
54
|
+
Mobvious.config
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Mobvious
|
2
|
+
module Strategies
|
3
|
+
# Mobvious device detection strategy that saves and loads a cookie that precisely
|
4
|
+
# specifies which device type should be used for current client.
|
5
|
+
#
|
6
|
+
# Usually, you will want to set the device type via cookie only when you are absolutely
|
7
|
+
# sure that user wants it this way (e.g. after manual switch between mobile/desktop
|
8
|
+
# interface versions performed by user). Also make sure to use this strategy with high
|
9
|
+
# priority, (e.g. put it before user-agent based detection) so it does not get overriden.
|
10
|
+
#
|
11
|
+
# Use `set_device_type_cookie` method to set the device type and the strategy will then
|
12
|
+
# recognize it on subsequent requests.
|
13
|
+
class Cookie
|
14
|
+
# Creates a new Cookie strategy instance.
|
15
|
+
#
|
16
|
+
# @param cookie_expires [Integer]
|
17
|
+
# Amount of seconds to hold device type cookie. Defaults to one year (365*24*60*60).
|
18
|
+
def initialize(cookie_expires = (365*24*60*60))
|
19
|
+
@cookie_expires = cookie_expires
|
20
|
+
end
|
21
|
+
|
22
|
+
# Gets device type using a pre-set cookie. Returns nil if the cookie is not set.
|
23
|
+
#
|
24
|
+
# @param request [Rack::Request]
|
25
|
+
# @return [Symbol] device type or nil
|
26
|
+
def get_device_type(request)
|
27
|
+
request.cookies['mobvious.device_type'].to_sym if request.cookies['mobvious.device_type']
|
28
|
+
end
|
29
|
+
|
30
|
+
# Automatically sets the device type cookie again to prolong its expiration date.
|
31
|
+
#
|
32
|
+
# @param request [Rack::Request]
|
33
|
+
# @param response [Rack::Response]
|
34
|
+
def response_callback(request, response)
|
35
|
+
response_cookie_already_set = !!response.headers["Set-Cookie"] &&
|
36
|
+
!!response.headers["Set-Cookie"]["mobvious.device_type"]
|
37
|
+
request_cookie = request.cookies['mobvious.device_type']
|
38
|
+
|
39
|
+
# re-set the cookie to renew the expiration date
|
40
|
+
if request_cookie && !response_cookie_already_set
|
41
|
+
set_device_type_cookie(response, request_cookie)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Sets the device type cookie.
|
46
|
+
#
|
47
|
+
# @param response [Rack::Response]
|
48
|
+
# @param device_type [Symbol] A device type symbol (or string).
|
49
|
+
def set_device_type_cookie(response, device_type)
|
50
|
+
response.set_cookie('mobvious.device_type',
|
51
|
+
{ value: device_type.to_s, path: '/', expires: Time.now + @cookie_expires })
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'mobileesp'
|
2
|
+
|
3
|
+
module Mobvious
|
4
|
+
module Strategies
|
5
|
+
# Mobvious device detection strategy that uses user-agent sniffing provided by
|
6
|
+
# the MobileESP library.
|
7
|
+
class Mobileesp
|
8
|
+
# Detection procedure that classifies mobile phones as `:mobile` and anything
|
9
|
+
# else as `:desktop`.
|
10
|
+
DEVICE_TYPES_MOBILE_DESKTOP = lambda {|mobileesp|
|
11
|
+
return :mobile if mobileesp.is_tier_generic_mobile || mobileesp.is_tier_iphone
|
12
|
+
return :desktop
|
13
|
+
}
|
14
|
+
|
15
|
+
# Detection procedure that classifies mobile phones as `:mobile`, tablets as
|
16
|
+
# `:tablet` and anything else as `:desktop`.
|
17
|
+
DEVICE_TYPES_MOBILE_TABLET_DESKTOP = lambda {|mobileesp|
|
18
|
+
return :mobile if mobileesp.is_tier_generic_mobile || mobileesp.is_tier_iphone
|
19
|
+
return :tablet if mobileesp.is_tier_tablet
|
20
|
+
return :desktop
|
21
|
+
}
|
22
|
+
|
23
|
+
# Creates a new instance of MobileESP strategy.
|
24
|
+
#
|
25
|
+
# @param detection_procedure
|
26
|
+
# A lambda function that gets one parameter (`MobileESP::UserAgentInfo` instance)
|
27
|
+
# and returns device type symbol or nil.
|
28
|
+
def initialize(detection_procedure = DEVICE_TYPES_MOBILE_DESKTOP)
|
29
|
+
@detection_procedure = detection_procedure
|
30
|
+
end
|
31
|
+
|
32
|
+
# Gets device type using user-agent sniffing. Can return nil if the used
|
33
|
+
# detection procedure does so.
|
34
|
+
#
|
35
|
+
# @param request [Rack::Request]
|
36
|
+
# @return [Symbol] device type or nil
|
37
|
+
def get_device_type(request)
|
38
|
+
mobileesp = MobileESP::UserAgentInfo.new(request.user_agent, request.accept)
|
39
|
+
@detection_procedure.call(mobileesp)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Mobvious
|
2
|
+
module Strategies
|
3
|
+
# Mobvious device detection strategy that uses URL pattern matching.
|
4
|
+
class URL
|
5
|
+
# Rule set with only one rule for domains that begin with `m.` matching as `:mobile`.
|
6
|
+
MOBILE_PATH_RULES = { /^\w+:\/\/m\./ => :mobile }
|
7
|
+
|
8
|
+
# Creates a new URL strategy instance.
|
9
|
+
#
|
10
|
+
# @param rules
|
11
|
+
# A hash containing regular expressions mapped to symbols. The regular expression
|
12
|
+
# is evaluated against the whole URL of the request (including `http://`). If matching,
|
13
|
+
# the corresponding symbol is returned as the device type.
|
14
|
+
def initialize(rules = MOBILE_PATH_RULE)
|
15
|
+
@rules = rules
|
16
|
+
end
|
17
|
+
|
18
|
+
# Gets device type using URL pattern matching. Returns nil if no match found.
|
19
|
+
#
|
20
|
+
# @param request [Rack::Request]
|
21
|
+
# @return [Symbol] device type or nil
|
22
|
+
def get_device_type(request)
|
23
|
+
@rules.each do |regex, device_type|
|
24
|
+
return device_type if request.url =~ regex
|
25
|
+
end
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/mobvious.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "mobvious/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "mobvious"
|
7
|
+
s.version = Mobvious::VERSION
|
8
|
+
s.authors = ["Jiří Stránský"]
|
9
|
+
s.email = ["jistr@jistr.com"]
|
10
|
+
s.homepage = "http://github.com/jistr/mobvious"
|
11
|
+
s.summary = %q{Rack middleware for choosing a version of an interface to render for given request}
|
12
|
+
s.description = %q{Rack middleware for choosing a version of an interface to render for given request}
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_runtime_dependency "rack", ">= 1.2.0"
|
20
|
+
s.add_runtime_dependency "mobileesp"
|
21
|
+
|
22
|
+
|
23
|
+
# == DEVELOPMENT DEPENDENCIES ==
|
24
|
+
# Smart irb
|
25
|
+
s.add_development_dependency 'pry'
|
26
|
+
|
27
|
+
# Specs
|
28
|
+
s.add_development_dependency 'minitest'
|
29
|
+
s.add_development_dependency 'mocha'
|
30
|
+
s.add_development_dependency 'rack-test'
|
31
|
+
|
32
|
+
# Running tests during development
|
33
|
+
s.add_development_dependency 'guard'
|
34
|
+
s.add_development_dependency 'guard-minitest'
|
35
|
+
# Linux Guard watching
|
36
|
+
s.add_development_dependency 'rb-inotify'
|
37
|
+
# Linux Guard notifications
|
38
|
+
s.add_development_dependency 'libnotify'
|
39
|
+
|
40
|
+
# Pretty printed test output
|
41
|
+
s.add_development_dependency 'turn'
|
42
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Mobvious
|
4
|
+
class ManagerSpec < MiniTest::Spec
|
5
|
+
describe Manager do
|
6
|
+
before do
|
7
|
+
@app = mock 'app'
|
8
|
+
@env = mock 'env'
|
9
|
+
@manager = Mobvious::Manager.new(@app)
|
10
|
+
@return_value = [200, ['My-Header'], ['body_part_1']]
|
11
|
+
|
12
|
+
@app.stubs(:call).with(@env).returns(@return_value)
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
Mobvious.config.clear
|
17
|
+
end
|
18
|
+
|
19
|
+
it "calls the app and returns what app returns" do
|
20
|
+
@env.stub_everything
|
21
|
+
@app.expects(:call).with(@env).returns(@return_value)
|
22
|
+
@manager.call(@env).must_equal @return_value
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "having strategies" do
|
26
|
+
before do
|
27
|
+
@strategy1 = mock 'strategy1'
|
28
|
+
@strategy2 = mock 'strategy2'
|
29
|
+
@strategy3 = mock 'strategy3'
|
30
|
+
Mobvious.config.strategies << @strategy1
|
31
|
+
Mobvious.config.strategies << @strategy2
|
32
|
+
Mobvious.config.strategies << @strategy3
|
33
|
+
end
|
34
|
+
|
35
|
+
it "uses the result of the first successful strategy" do
|
36
|
+
@app.stub_everything
|
37
|
+
@app.expects(:call).with(@env).returns(@return_value)
|
38
|
+
@strategy1.expects(:get_device_type).returns(nil)
|
39
|
+
@strategy2.expects(:get_device_type).returns(:strategy_2_result)
|
40
|
+
@env.expects('[]=').with('mobvious.device_type', :strategy_2_result)
|
41
|
+
@manager.call(@env)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "calls strategies with a request object" do
|
45
|
+
@app.stub_everything
|
46
|
+
@env.stub_everything
|
47
|
+
@strategy1.expects(:get_device_type).returns(:result).with() {|param|
|
48
|
+
param.must_be_instance_of Rack::Request
|
49
|
+
(param.env == @env).must_equal true
|
50
|
+
}
|
51
|
+
@manager.call(@env)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "uses default value if no strategy is successful" do
|
55
|
+
@app.stub_everything
|
56
|
+
@strategy1.stub_everything
|
57
|
+
@strategy2.stub_everything
|
58
|
+
@strategy3.stub_everything
|
59
|
+
Mobvious.config.default_device_type = :test_default_type
|
60
|
+
@env.expects('[]=').with('mobvious.device_type', :test_default_type)
|
61
|
+
@manager.call(@env)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "calls the response callback on strategies that have it defined" do
|
65
|
+
@env.stub_everything
|
66
|
+
@strategy1.stubs(:get_device_type)
|
67
|
+
@strategy1.stubs(:respond_to?).with(:response_callback).returns(true)
|
68
|
+
@strategy1.expects(:response_callback).with() {|request, response|
|
69
|
+
request.must_be_instance_of Rack::Request
|
70
|
+
(request.env == @env).must_equal true
|
71
|
+
response.must_be_instance_of Rack::Response
|
72
|
+
response.body.must_equal @return_value[2]
|
73
|
+
}
|
74
|
+
|
75
|
+
@strategy2.stub_everything
|
76
|
+
@strategy3.stub_everything
|
77
|
+
@manager.call(@env)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "not having strategies" do
|
82
|
+
it "uses default value" do
|
83
|
+
@app.stub_everything
|
84
|
+
Mobvious.config.default_device_type = :test_default_type
|
85
|
+
@env.expects('[]=').with('mobvious.device_type', :test_default_type)
|
86
|
+
@manager.call(@env)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mobvious/strategies/cookie'
|
3
|
+
|
4
|
+
module Mobvious::Strategies
|
5
|
+
class CookieSpec < MiniTest::Spec
|
6
|
+
describe Cookie do
|
7
|
+
before do
|
8
|
+
@strategy = Cookie.new
|
9
|
+
@app = mock 'app'
|
10
|
+
@uri = URI("http://foo.com/")
|
11
|
+
|
12
|
+
@env = Rack::MockRequest::DEFAULT_ENV
|
13
|
+
@request = Rack::Request.new(@env)
|
14
|
+
@response = Rack::Response.new(['body'], 200, {})
|
15
|
+
|
16
|
+
@mock_session = Rack::MockSession.new(@app)
|
17
|
+
@mock_session.after_request do
|
18
|
+
@strategy.response_callback(@request, @response)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "with no device type cookie set" do
|
23
|
+
it "returns nil as device type" do
|
24
|
+
@strategy.get_device_type(@request).must_equal nil
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "when device type set during the app execution" do
|
28
|
+
it "sets the cookie on response" do
|
29
|
+
@app.expects(:call).returns([@response.status, @response.headers, @response.body])
|
30
|
+
.with do |env|
|
31
|
+
@strategy.set_device_type_cookie(@response, :tablet)
|
32
|
+
true
|
33
|
+
end
|
34
|
+
@mock_session.request @uri, @env
|
35
|
+
cookies = Mobvious::CookieParser.new(@response.headers['Set-Cookie'])
|
36
|
+
cookies['mobvious.device_type']['value'].must_equal 'tablet'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "with set device type cookie" do
|
42
|
+
before do
|
43
|
+
@request = Rack::Request.new(@env)
|
44
|
+
@request.cookies['mobvious.device_type'] = 'tablet'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "gets device type from cookie" do
|
48
|
+
@app.expects(:call).returns([@response.status, @response.headers, @response.body])
|
49
|
+
.with do |env|
|
50
|
+
@strategy.get_device_type(@request).must_equal :tablet
|
51
|
+
true
|
52
|
+
end
|
53
|
+
mock_response = @mock_session.request @uri, @env
|
54
|
+
end
|
55
|
+
|
56
|
+
it "refreshes the cookie expiration date with every request" do
|
57
|
+
@app.expects(:call).returns([@response.status, @response.headers, @response.body])
|
58
|
+
mock_response = @mock_session.request @uri, @env
|
59
|
+
cookies = Mobvious::CookieParser.new(@response.headers['Set-Cookie'])
|
60
|
+
cookies['mobvious.device_type'].wont_be_nil
|
61
|
+
cookies['mobvious.device_type']['value'].must_equal 'tablet'
|
62
|
+
cookies['mobvious.device_type']['expires'].wont_be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "when device type set during the app execution" do
|
66
|
+
it "sets the response cookie to the new value, not the old one" do
|
67
|
+
@app.expects(:call).returns([@response.status, @response.headers, @response.body])
|
68
|
+
.with do |env|
|
69
|
+
@strategy.set_device_type_cookie(@response, :mobile)
|
70
|
+
true
|
71
|
+
end
|
72
|
+
@mock_session.request @uri, @env
|
73
|
+
cookies = Mobvious::CookieParser.new(@response.headers['Set-Cookie'])
|
74
|
+
cookies['mobvious.device_type'].wont_be_nil
|
75
|
+
cookies['mobvious.device_type']['value'].must_equal 'mobile'
|
76
|
+
cookies['mobvious.device_type']['expires'].wont_be_nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mobvious/strategies/mobileesp'
|
3
|
+
|
4
|
+
module Mobvious::Strategies
|
5
|
+
class MobileespSpec < MiniTest::Spec
|
6
|
+
describe Mobileesp do
|
7
|
+
describe "using mobile_desktop strategy" do
|
8
|
+
before do
|
9
|
+
@strategy = Mobvious::Strategies::Mobileesp.new
|
10
|
+
@request = mock 'request'
|
11
|
+
@request.stubs(:accept).returns('text/html')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "categorizes iPhone as :mobile" do
|
15
|
+
@request.stubs(:user_agent).returns("Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7")
|
16
|
+
@strategy.get_device_type(@request).must_equal :mobile
|
17
|
+
end
|
18
|
+
|
19
|
+
it "categorizes Android tablet as :desktop" do
|
20
|
+
@request.stubs(:user_agent).returns("Mozilla/5.0 (Linux; U; Android 3.0; xx-xx; Xoom Build/HRI39) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2")
|
21
|
+
@strategy.get_device_type(@request).must_equal :desktop
|
22
|
+
end
|
23
|
+
|
24
|
+
it "categorizes Chrome on Linux as :desktop" do
|
25
|
+
@request.stubs(:user_agent).returns("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.46 Safari/535.11")
|
26
|
+
@strategy.get_device_type(@request).must_equal :desktop
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "using mobile_tablet_desktop strategy" do
|
31
|
+
before do
|
32
|
+
@strategy = Mobvious::Strategies::Mobileesp.new(
|
33
|
+
Mobvious::Strategies::Mobileesp::DEVICE_TYPES_MOBILE_TABLET_DESKTOP)
|
34
|
+
@request = mock 'request'
|
35
|
+
@request.stubs(:accept).returns('text/html')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "categorizes iPhone as :mobile" do
|
39
|
+
@request.stubs(:user_agent).returns("Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7")
|
40
|
+
@strategy.get_device_type(@request).must_equal :mobile
|
41
|
+
end
|
42
|
+
|
43
|
+
it "categorizes Android tablet as :tablet" do
|
44
|
+
@request.stubs(:user_agent).returns("Mozilla/5.0 (Linux; U; Android 3.0; xx-xx; Xoom Build/HRI39) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2")
|
45
|
+
@strategy.get_device_type(@request).must_equal :tablet
|
46
|
+
end
|
47
|
+
|
48
|
+
it "categorizes Chrome on Linux as :desktop" do
|
49
|
+
@request.stubs(:user_agent).returns("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.46 Safari/535.11")
|
50
|
+
@strategy.get_device_type(@request).must_equal :desktop
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mobvious/strategies/url'
|
3
|
+
|
4
|
+
module Mobvious::Strategies
|
5
|
+
class URLSpec < MiniTest::Spec
|
6
|
+
describe URL do
|
7
|
+
before do
|
8
|
+
@env = Rack::MockRequest::DEFAULT_ENV
|
9
|
+
@env.merge!({
|
10
|
+
'rack.url_scheme' => 'http',
|
11
|
+
'HTTP_HOST' => 'm.foo.com',
|
12
|
+
'SERVER_PORT' => 80,
|
13
|
+
'SCRIPT_NAME' => '',
|
14
|
+
'PATH_INFO' => '/some_path'
|
15
|
+
})
|
16
|
+
@request = Rack::Request.new(@env)
|
17
|
+
@strategy = URL.new(URL::MOBILE_PATH_RULES)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns the right device type when matching rule found" do
|
21
|
+
puts @request.url
|
22
|
+
@strategy.get_device_type(@request).must_equal :mobile
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns nil if no matching rule found" do
|
26
|
+
@env['HTTP_HOST'] = 'www.foo.com'
|
27
|
+
@strategy.get_device_type(@request).must_equal nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
begin; require 'turn'; rescue LoadError; end
|
4
|
+
require 'mocha'
|
5
|
+
require 'rack/test'
|
6
|
+
require 'mobvious'
|
7
|
+
|
8
|
+
module Mobvious
|
9
|
+
class CookieParser
|
10
|
+
attr_reader :cookies
|
11
|
+
|
12
|
+
def initialize(cookie_header_content)
|
13
|
+
@cookies = {}
|
14
|
+
return unless cookie_header_content
|
15
|
+
|
16
|
+
cookie_header_content.split("\n").each do |cookie_string|
|
17
|
+
cookie_parts = cookie_string.split(';')
|
18
|
+
|
19
|
+
name, cookie_value = cookie_parts.first.split('=')
|
20
|
+
cookie = { 'value' => cookie_value }
|
21
|
+
|
22
|
+
cookie_parts[1..-1].each do |cookie_part|
|
23
|
+
key, value = cookie_part.split('=')
|
24
|
+
cookie[key.strip] = value
|
25
|
+
end
|
26
|
+
@cookies[name.strip] = cookie
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def [](*args)
|
31
|
+
@cookies[*args]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mobvious
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.pre
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jiří Stránský
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rack
|
16
|
+
requirement: &12623500 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.2.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *12623500
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: mobileesp
|
27
|
+
requirement: &12623000 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *12623000
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: pry
|
38
|
+
requirement: &12622080 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *12622080
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: minitest
|
49
|
+
requirement: &12621480 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *12621480
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: mocha
|
60
|
+
requirement: &12620840 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *12620840
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rack-test
|
71
|
+
requirement: &12619900 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *12619900
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: guard
|
82
|
+
requirement: &12619220 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *12619220
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: guard-minitest
|
93
|
+
requirement: &12618320 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *12618320
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: rb-inotify
|
104
|
+
requirement: &12617600 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *12617600
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: libnotify
|
115
|
+
requirement: &12616840 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *12616840
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: turn
|
126
|
+
requirement: &12616080 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *12616080
|
135
|
+
description: Rack middleware for choosing a version of an interface to render for
|
136
|
+
given request
|
137
|
+
email:
|
138
|
+
- jistr@jistr.com
|
139
|
+
executables: []
|
140
|
+
extensions: []
|
141
|
+
extra_rdoc_files: []
|
142
|
+
files:
|
143
|
+
- .gitignore
|
144
|
+
- .yardopts
|
145
|
+
- Gemfile
|
146
|
+
- Guardfile
|
147
|
+
- Rakefile
|
148
|
+
- lib/mobvious.rb
|
149
|
+
- lib/mobvious/config.rb
|
150
|
+
- lib/mobvious/manager.rb
|
151
|
+
- lib/mobvious/strategies/cookie.rb
|
152
|
+
- lib/mobvious/strategies/mobileesp.rb
|
153
|
+
- lib/mobvious/strategies/url.rb
|
154
|
+
- lib/mobvious/version.rb
|
155
|
+
- mobvious.gemspec
|
156
|
+
- spec/mobvious/manager_spec.rb
|
157
|
+
- spec/mobvious/strategies/cookie_spec.rb
|
158
|
+
- spec/mobvious/strategies/mobileesp_spec.rb
|
159
|
+
- spec/mobvious/strategies/url_spec.rb
|
160
|
+
- spec/spec_helper.rb
|
161
|
+
homepage: http://github.com/jistr/mobvious
|
162
|
+
licenses: []
|
163
|
+
post_install_message:
|
164
|
+
rdoc_options: []
|
165
|
+
require_paths:
|
166
|
+
- lib
|
167
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
168
|
+
none: false
|
169
|
+
requirements:
|
170
|
+
- - ! '>='
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
segments:
|
174
|
+
- 0
|
175
|
+
hash: 816301950663841186
|
176
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ! '>'
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: 1.3.1
|
182
|
+
requirements: []
|
183
|
+
rubyforge_project:
|
184
|
+
rubygems_version: 1.8.11
|
185
|
+
signing_key:
|
186
|
+
specification_version: 3
|
187
|
+
summary: Rack middleware for choosing a version of an interface to render for given
|
188
|
+
request
|
189
|
+
test_files: []
|