divining_rod 0.5.0 → 0.6.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/Gemfile +4 -0
- data/Gemfile.lock +14 -0
- data/LICENSE +2 -1
- data/Rakefile +1 -43
- data/divining_rod.gemspec +15 -68
- data/example_config.rb +8 -7
- data/lib/divining_rod.rb +1 -2
- data/lib/divining_rod/definition.rb +6 -20
- data/lib/divining_rod/mappings.rb +55 -6
- data/lib/divining_rod/mash.rb +17 -0
- data/lib/divining_rod/matchers.rb +1 -1
- data/lib/divining_rod/murge.rb +4 -3
- data/lib/divining_rod/profile.rb +17 -8
- data/lib/divining_rod/utilities.rb +3 -3
- data/lib/divining_rod/version.rb +3 -0
- data/test/test_definition.rb +41 -0
- data/test/test_example_config.rb +71 -0
- data/{spec/spec_helper.rb → test/test_helper.rb} +9 -4
- data/test/test_mash.rb +25 -0
- metadata +28 -52
- data/VERSION +0 -1
- data/lib/divining_rod/mapper.rb +0 -55
- data/spec/definition_spec.rb +0 -40
- data/spec/example_mapping_spec.rb +0 -60
- data/spec/mapper_spec.rb +0 -21
- data/spec/mapping_spec.rb +0 -78
- data/spec/profile_spec.rb +0 -118
- data/spec/rack_spec.rb +0 -27
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE
CHANGED
data/Rakefile
CHANGED
@@ -1,53 +1,11 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
3
|
|
4
|
-
begin
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "divining_rod"
|
8
|
-
gem.summary = %Q{A mobile phone web request profiler}
|
9
|
-
gem.description = %Q{A mobile phone web request profiler using definitions that look like rails routes}
|
10
|
-
gem.email = "mark@mpercival.com"
|
11
|
-
gem.homepage = "http://github.com/markpercival/divining_rod"
|
12
|
-
gem.authors = ["Mark Percival"]
|
13
|
-
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
-
end
|
16
|
-
Jeweler::GemcutterTasks.new
|
17
|
-
rescue LoadError
|
18
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
-
end
|
20
|
-
|
21
4
|
require 'rake/testtask'
|
22
5
|
Rake::TestTask.new(:test) do |test|
|
23
|
-
test.libs << 'lib' << 'test'
|
6
|
+
test.libs << 'lib' << 'test' << '.'
|
24
7
|
test.pattern = 'test/**/test_*.rb'
|
25
8
|
test.verbose = true
|
26
9
|
end
|
27
10
|
|
28
|
-
begin
|
29
|
-
require 'rcov/rcovtask'
|
30
|
-
Rcov::RcovTask.new do |test|
|
31
|
-
test.libs << 'test'
|
32
|
-
test.pattern = 'test/**/test_*.rb'
|
33
|
-
test.verbose = true
|
34
|
-
end
|
35
|
-
rescue LoadError
|
36
|
-
task :rcov do
|
37
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
task :test => :check_dependencies
|
42
|
-
|
43
11
|
task :default => :test
|
44
|
-
|
45
|
-
require 'rake/rdoctask'
|
46
|
-
Rake::RDocTask.new do |rdoc|
|
47
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
-
|
49
|
-
rdoc.rdoc_dir = 'rdoc'
|
50
|
-
rdoc.title = "divining_rod #{version}"
|
51
|
-
rdoc.rdoc_files.include('README*')
|
52
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
-
end
|
data/divining_rod.gemspec
CHANGED
@@ -1,74 +1,21 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "divining_rod/version"
|
5
4
|
|
6
5
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
6
|
+
s.name = "divining_rod"
|
7
|
+
s.version = DiviningRod::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Mark Percival"]
|
10
|
+
s.email = ["mark@markpercival.us"]
|
11
|
+
s.homepage = "http://github.com/mdp/divining_rod"
|
12
|
+
s.summary = %q{An opinionated ruby encryption library}
|
13
|
+
s.description = %q{Supports OpenSSL compatible AES, HMAC, and RSA encryption}
|
9
14
|
|
10
|
-
s.
|
11
|
-
s.authors = ["Mark Percival"]
|
12
|
-
s.date = %q{2010-08-30}
|
13
|
-
s.description = %q{A mobile phone web request profiler using definitions that look like rails routes}
|
14
|
-
s.email = %q{mark@mpercival.com}
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"LICENSE",
|
17
|
-
"README.markdown"
|
18
|
-
]
|
19
|
-
s.files = [
|
20
|
-
".document",
|
21
|
-
".gitignore",
|
22
|
-
"LICENSE",
|
23
|
-
"README.markdown",
|
24
|
-
"Rakefile",
|
25
|
-
"VERSION",
|
26
|
-
"divining_rod.gemspec",
|
27
|
-
"example_config.rb",
|
28
|
-
"lib/divining_rod.rb",
|
29
|
-
"lib/divining_rod/definition.rb",
|
30
|
-
"lib/divining_rod/mapper.rb",
|
31
|
-
"lib/divining_rod/mappings.rb",
|
32
|
-
"lib/divining_rod/matchers.rb",
|
33
|
-
"lib/divining_rod/murge.rb",
|
34
|
-
"lib/divining_rod/profile.rb",
|
35
|
-
"lib/divining_rod/rack.rb",
|
36
|
-
"lib/divining_rod/rack/divining_rack.rb",
|
37
|
-
"lib/divining_rod/utilities.rb",
|
38
|
-
"spec/definition_spec.rb",
|
39
|
-
"spec/example_mapping_spec.rb",
|
40
|
-
"spec/mapper_spec.rb",
|
41
|
-
"spec/mapping_spec.rb",
|
42
|
-
"spec/profile_spec.rb",
|
43
|
-
"spec/rack_spec.rb",
|
44
|
-
"spec/spec_helper.rb"
|
45
|
-
]
|
46
|
-
s.homepage = %q{http://github.com/markpercival/divining_rod}
|
47
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
-
s.require_paths = ["lib"]
|
49
|
-
s.rubygems_version = %q{1.3.6}
|
50
|
-
s.summary = %q{A mobile phone web request profiler}
|
51
|
-
s.test_files = [
|
52
|
-
"spec/definition_spec.rb",
|
53
|
-
"spec/example_mapping_spec.rb",
|
54
|
-
"spec/mapper_spec.rb",
|
55
|
-
"spec/mapping_spec.rb",
|
56
|
-
"spec/profile_spec.rb",
|
57
|
-
"spec/rack_spec.rb",
|
58
|
-
"spec/spec_helper.rb"
|
59
|
-
]
|
60
|
-
|
61
|
-
if s.respond_to? :specification_version then
|
62
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
63
|
-
s.specification_version = 3
|
15
|
+
s.rubyforge_project = "divining_rod"
|
64
16
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
else
|
71
|
-
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
72
|
-
end
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
73
21
|
end
|
74
|
-
|
data/example_config.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
DiviningRod::Mappings.define do |map|
|
1
|
+
DiviningRod::Mappings.define(:format => :html) do |map|
|
2
2
|
# Android based phones
|
3
3
|
map.ua /Android/, :format => :webkit, :name => 'Android', :tags => [:android, :youtube_capable, :google_gears]
|
4
|
-
|
4
|
+
|
5
5
|
# Apple iPhone OS
|
6
6
|
map.ua /Apple.*Mobile.*Safari/, :format => :webkit, :tags => [:apple, :iphone_os, :youtube_capable] do |iphone|
|
7
7
|
iphone.ua /iPad/, :tags => :ipad, :name => 'iPad'
|
8
8
|
iphone.ua /iPod/, :tags => :ipod, :name => 'iPod Touch'
|
9
9
|
iphone.ua /iPhone/, :tags => [:iphone], :name => 'iPhone'
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
#Blackberry, needs more detail here
|
13
13
|
map.ua /BlackBerry/, :tags => :blackberry, :name => 'BlackBerry'
|
14
|
-
|
14
|
+
|
15
15
|
# The desktop browsers, we don't set a format on these to let it pass through
|
16
16
|
map.with_options :tags => :desktop do |desktop|
|
17
17
|
desktop.ua /Chrome/, :tags => :chrome, :name => 'Chrome'
|
@@ -22,10 +22,11 @@ DiviningRod::Mappings.define do |map|
|
|
22
22
|
msie.ua /MSIE 6/, :version => 6
|
23
23
|
msie.ua /MSIE 7/, :version => 7
|
24
24
|
msie.ua /MSIE 8/, :version => 8
|
25
|
+
msie.ua /MSIE 10/, :version => 10, :tags => :html5
|
25
26
|
end
|
26
27
|
end
|
27
|
-
|
28
|
+
|
28
29
|
# Enable this to forces a default format if unmatched
|
29
30
|
# otherwise it will return the request.format
|
30
|
-
|
31
|
-
end
|
31
|
+
map.default :name => "Unknown"
|
32
|
+
end
|
data/lib/divining_rod.rb
CHANGED
@@ -2,8 +2,7 @@ module DiviningRod; end
|
|
2
2
|
|
3
3
|
require 'divining_rod/profile'
|
4
4
|
require 'divining_rod/utilities'
|
5
|
-
require 'divining_rod/
|
5
|
+
require 'divining_rod/mash'
|
6
6
|
require 'divining_rod/definition'
|
7
7
|
require 'divining_rod/mappings'
|
8
|
-
require 'divining_rod/mapper'
|
9
8
|
require 'divining_rod/matchers'
|
@@ -1,13 +1,11 @@
|
|
1
1
|
module DiviningRod
|
2
2
|
class Definition
|
3
|
-
include Murge
|
4
3
|
|
5
4
|
attr_accessor :prc, :group, :opts, :parent
|
6
|
-
attr_writer :children
|
7
5
|
|
8
6
|
def initialize(opts={}, &blk)
|
9
7
|
@prc = blk
|
10
|
-
@opts = opts
|
8
|
+
@opts = Mash.new(opts)
|
11
9
|
end
|
12
10
|
|
13
11
|
def evaluate(request)
|
@@ -26,28 +24,16 @@ module DiviningRod
|
|
26
24
|
end
|
27
25
|
|
28
26
|
def tags
|
29
|
-
opts[:tags] || []
|
27
|
+
@tags ||= opts[:tags] || []
|
30
28
|
end
|
31
|
-
|
32
|
-
def
|
33
|
-
|
34
|
-
@murged_opts ||= murge(parent.opts, @opts)
|
35
|
-
else
|
36
|
-
@opts
|
37
|
-
end
|
29
|
+
|
30
|
+
def children
|
31
|
+
@children ||= []
|
38
32
|
end
|
39
|
-
|
33
|
+
|
40
34
|
def format
|
41
35
|
opts[:format]
|
42
36
|
end
|
43
|
-
|
44
|
-
def children
|
45
|
-
@children ||= []
|
46
|
-
@children.each do |child|
|
47
|
-
child.parent ||= self
|
48
|
-
end
|
49
|
-
@children
|
50
|
-
end
|
51
37
|
|
52
38
|
end
|
53
39
|
end
|
@@ -4,18 +4,67 @@ module DiviningRod
|
|
4
4
|
class << self
|
5
5
|
|
6
6
|
attr_accessor :root_definition
|
7
|
-
|
7
|
+
|
8
8
|
def define(opts = {})
|
9
|
-
@root_definition = Definition.new { true }
|
10
|
-
yield
|
11
|
-
@root_definition
|
9
|
+
@root_definition = Definition.new(opts) { true }
|
10
|
+
yield Mappings.new(@root_definition)
|
11
|
+
@root_definition
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def evaluate(obj)
|
15
15
|
@root_definition.evaluate(obj)
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :default_opts, :parent
|
21
|
+
|
22
|
+
def initialize(parent, default_opts = {})
|
23
|
+
@parent = parent
|
24
|
+
@default_opts = Mash.new(default_opts)
|
25
|
+
end
|
26
|
+
|
27
|
+
def pattern(type, pattern, opts = {})
|
28
|
+
definition = Matchers.send(type.to_sym, pattern, merged_opts(opts))
|
29
|
+
append_to_parent(definition)
|
30
|
+
if block_given?
|
31
|
+
yield self.class.new(definition)
|
32
|
+
end
|
33
|
+
definition
|
34
|
+
end
|
35
|
+
|
36
|
+
def default(opts = {})
|
37
|
+
definition = Definition.new(merged_opts(opts)) { true }
|
38
|
+
append_to_parent(definition)
|
39
|
+
definition
|
40
|
+
end
|
41
|
+
|
42
|
+
def with_options(opts)
|
43
|
+
yield self.class.new(parent, opts)
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_missing(meth, *args, &blk)
|
47
|
+
# Lets us use map.ua instead of map.pattern :ua
|
48
|
+
if Matchers.respond_to?(meth.to_sym)
|
49
|
+
self.pattern(meth, args[0], args[1,], &blk)
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
18
53
|
end
|
19
54
|
|
55
|
+
private
|
56
|
+
|
57
|
+
def merged_opts(opts)
|
58
|
+
opts = parent.opts.merge(opts)
|
59
|
+
opts = default_opts.merge(opts)
|
60
|
+
opts
|
61
|
+
end
|
62
|
+
|
63
|
+
def append_to_parent(definition)
|
64
|
+
parent.children << definition
|
65
|
+
definition
|
66
|
+
end
|
67
|
+
|
68
|
+
|
20
69
|
end
|
21
70
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DiviningRod
|
2
|
+
class Mash < Hash
|
3
|
+
|
4
|
+
def initialize(hsh = {})
|
5
|
+
self.replace(hsh || {})
|
6
|
+
end
|
7
|
+
|
8
|
+
def merge(opts = {})
|
9
|
+
if self[:tags] || opts[:tags]
|
10
|
+
tags = Array(self[:tags]) | Array(opts[:tags])
|
11
|
+
opts[:tags] = tags
|
12
|
+
end
|
13
|
+
super(opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
data/lib/divining_rod/murge.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
module DiviningRod
|
2
2
|
module Murge
|
3
|
-
|
3
|
+
|
4
4
|
# This is tacky, but I'm preserving tags in the option hash
|
5
5
|
# and only want to have to write this once
|
6
6
|
#
|
7
7
|
def murge(old_opts, new_opts)
|
8
8
|
old_opts = old_opts || {}
|
9
|
+
new_opts = new_opts || {}
|
9
10
|
tags = Array(old_opts[:tags]) | Array(new_opts[:tags])
|
10
11
|
opts = old_opts.merge(new_opts)
|
11
12
|
opts[:tags] = tags
|
12
13
|
opts
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
end
|
16
|
-
end
|
17
|
+
end
|
data/lib/divining_rod/profile.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module DiviningRod
|
2
|
-
|
2
|
+
module Profiler
|
3
3
|
|
4
4
|
def initialize(request)
|
5
|
-
@request = request
|
5
|
+
@request = request
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def match
|
9
9
|
@match ||= DiviningRod::Mappings.evaluate(@request)
|
10
10
|
end
|
@@ -21,14 +21,18 @@ module DiviningRod
|
|
21
21
|
match != DiviningRod::Mappings.root_definition
|
22
22
|
end
|
23
23
|
|
24
|
+
def tagged?(tag)
|
25
|
+
if match
|
26
|
+
Array(match.tags).include?(tag.to_sym)
|
27
|
+
else
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
24
32
|
def method_missing(meth)
|
25
33
|
if meth.to_s.match(/(.+)\?$/)
|
26
34
|
tag = $1
|
27
|
-
|
28
|
-
match.tags.include?(tag.to_s) || match.tags.include?(tag.to_sym) || match.tags == tag
|
29
|
-
else
|
30
|
-
false
|
31
|
-
end
|
35
|
+
tagged?(tag)
|
32
36
|
elsif match.opts.include?(meth.to_sym)
|
33
37
|
match.opts[meth]
|
34
38
|
else
|
@@ -37,4 +41,9 @@ module DiviningRod
|
|
37
41
|
end
|
38
42
|
|
39
43
|
end
|
44
|
+
|
45
|
+
class Profile
|
46
|
+
include Profiler
|
47
|
+
end
|
40
48
|
end
|
49
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DefinitionTest < Test::Unit::TestCase
|
4
|
+
context DiviningRod::Definition do
|
5
|
+
|
6
|
+
should "work with no children not match" do
|
7
|
+
definition = DiviningRod::Definition.new(:format => :iphone, :tags => [:overpriced, :easy_to_break]) { |request|
|
8
|
+
request == 'iphone'
|
9
|
+
}
|
10
|
+
assert_equal definition.evaluate('foo'), nil
|
11
|
+
end
|
12
|
+
|
13
|
+
should "work with no children and match" do
|
14
|
+
definition = DiviningRod::Definition.new(:format => :iphone, :tags => [:overpriced, :easy_to_break]) { |request|
|
15
|
+
request == 'iphone'
|
16
|
+
}
|
17
|
+
assert_equal definition, definition.evaluate('iphone')
|
18
|
+
end
|
19
|
+
|
20
|
+
context "with children" do
|
21
|
+
|
22
|
+
should "work with children that match" do
|
23
|
+
definition = DiviningRod::Definition.new(:format => :iphone, :tags => [:overpriced, :easy_to_break]) { |request|
|
24
|
+
request.match(/iphone/)
|
25
|
+
}
|
26
|
+
definition.children << DiviningRod::Definition.new(:format => :ipod, :tags => [:small, :lacks_a_camera]) { |request|
|
27
|
+
request.match(/ipod/)
|
28
|
+
}
|
29
|
+
definition.children << DiviningRod::Definition.new(:format => :ipad, :tags => [:big, :lacks_a_camera]) { |request|
|
30
|
+
request.match(/ipad/)
|
31
|
+
}
|
32
|
+
result = definition.evaluate('iphone ipad')
|
33
|
+
assert_equal :ipad, result.format
|
34
|
+
assert result.tags.include?(:big)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'example_config'
|
3
|
+
|
4
|
+
def profile_ua(ua)
|
5
|
+
DiviningRod::Profile.new(request_mock(:ua => ua))
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
class ExampleConfigTest < Test::Unit::TestCase
|
10
|
+
context 'the example config' do
|
11
|
+
|
12
|
+
context "recognizing Apple devices" do
|
13
|
+
|
14
|
+
should "recognize an iPad" do
|
15
|
+
profile = profile_ua("Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10")
|
16
|
+
assert profile.ipad?
|
17
|
+
end
|
18
|
+
|
19
|
+
should "recognize an iPod touch 2.2.1" do
|
20
|
+
profile = profile_ua("Mozilla/5.0 (iPod; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11 Safari/525.20")
|
21
|
+
assert profile.ipod?
|
22
|
+
end
|
23
|
+
|
24
|
+
should "recognize an iPod touch 3.1.2" do
|
25
|
+
profile = profile_ua("Mozilla/5.0 (iPod; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16")
|
26
|
+
assert profile.ipod?
|
27
|
+
end
|
28
|
+
|
29
|
+
should "recognize an iPhone 3.1.2" do
|
30
|
+
profile = profile_ua("Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16")
|
31
|
+
assert profile.iphone?
|
32
|
+
end
|
33
|
+
|
34
|
+
should "recognize an iPhone 2.1.2" do
|
35
|
+
profile = profile_ua("Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11 Safari/525.20")
|
36
|
+
assert profile.iphone?
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
context "recognizing Android devices" do
|
42
|
+
|
43
|
+
should "recognize a basic android" do
|
44
|
+
profile = profile_ua("Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2")
|
45
|
+
assert profile.android?
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
context "recognizing desktop browsers" do
|
51
|
+
|
52
|
+
should "recognize Internet Explorer 10" do
|
53
|
+
profile = profile_ua("Mozilla/4.0 (compatible; MSIE 10.0; Windows NT 7.0)")
|
54
|
+
assert profile.desktop?
|
55
|
+
assert_equal profile.version, 10
|
56
|
+
assert profile.html5?
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
context "with root definition options" do
|
62
|
+
should "carry through" do
|
63
|
+
profile = profile_ua("Unknown phone")
|
64
|
+
assert_equal "Unknown", profile.name
|
65
|
+
assert_equal :html, profile.format
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -1,12 +1,17 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'spec'
|
3
2
|
require 'rack'
|
4
|
-
require
|
3
|
+
require 'test/unit'
|
4
|
+
require 'shoulda'
|
5
|
+
require 'mocha'
|
6
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
7
|
+
require 'divining_rod'
|
8
|
+
|
9
|
+
include Mocha::API
|
5
10
|
|
6
11
|
def request_mock(opts)
|
7
12
|
opts = {
|
8
13
|
:host => 'example.com'
|
9
14
|
}.merge(opts)
|
10
15
|
env = {'HTTP_USER_AGENT' => opts[:ua], 'SERVER_NAME' => opts[:host], 'X_WAP_PROFILE' => opts[:wap_profile]}
|
11
|
-
|
12
|
-
end
|
16
|
+
stub(:env => env, :format => opts[:format])
|
17
|
+
end
|
data/test/test_mash.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module DiviningRod
|
4
|
+
class MashTest < Test::Unit::TestCase
|
5
|
+
context 'Mash is like Hash' do
|
6
|
+
should "work that way" do
|
7
|
+
mash = Mash.new({:a_key => "and a value"})
|
8
|
+
and_mash = Mash.new({:my_key => "and my value"})
|
9
|
+
assert_equal ({:a_key => "and a value", :my_key => "and my value"}), mash.merge(and_mash)
|
10
|
+
end
|
11
|
+
|
12
|
+
should "also mash tags" do
|
13
|
+
mash = Mash.new({:tags => :foo})
|
14
|
+
and_mash = Mash.new({:tags => [:bar, :baz]})
|
15
|
+
assert_equal mash.merge(and_mash), {:tags => [:foo, :bar, :baz]}
|
16
|
+
end
|
17
|
+
|
18
|
+
should "accept nil happily" do
|
19
|
+
mash = Mash.new(nil)
|
20
|
+
assert_equal({}, mash)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: divining_rod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 5
|
8
|
-
- 0
|
9
|
-
version: 0.5.0
|
4
|
+
prerelease:
|
5
|
+
version: 0.6.0
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Mark Percival
|
@@ -14,91 +10,71 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date:
|
13
|
+
date: 2011-04-25 00:00:00 +00:00
|
18
14
|
default_executable:
|
19
|
-
dependencies:
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
requirements:
|
25
|
-
- - ">="
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
segments:
|
28
|
-
- 0
|
29
|
-
version: "0"
|
30
|
-
type: :development
|
31
|
-
version_requirements: *id001
|
32
|
-
description: A mobile phone web request profiler using definitions that look like rails routes
|
33
|
-
email: mark@mpercival.com
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: Supports OpenSSL compatible AES, HMAC, and RSA encryption
|
18
|
+
email:
|
19
|
+
- mark@markpercival.us
|
34
20
|
executables: []
|
35
21
|
|
36
22
|
extensions: []
|
37
23
|
|
38
|
-
extra_rdoc_files:
|
39
|
-
|
40
|
-
- README.markdown
|
24
|
+
extra_rdoc_files: []
|
25
|
+
|
41
26
|
files:
|
42
27
|
- .document
|
43
28
|
- .gitignore
|
29
|
+
- Gemfile
|
30
|
+
- Gemfile.lock
|
44
31
|
- LICENSE
|
45
32
|
- README.markdown
|
46
33
|
- Rakefile
|
47
|
-
- VERSION
|
48
34
|
- divining_rod.gemspec
|
49
35
|
- example_config.rb
|
50
36
|
- lib/divining_rod.rb
|
51
37
|
- lib/divining_rod/definition.rb
|
52
|
-
- lib/divining_rod/mapper.rb
|
53
38
|
- lib/divining_rod/mappings.rb
|
39
|
+
- lib/divining_rod/mash.rb
|
54
40
|
- lib/divining_rod/matchers.rb
|
55
41
|
- lib/divining_rod/murge.rb
|
56
42
|
- lib/divining_rod/profile.rb
|
57
43
|
- lib/divining_rod/rack.rb
|
58
44
|
- lib/divining_rod/rack/divining_rack.rb
|
59
45
|
- lib/divining_rod/utilities.rb
|
60
|
-
-
|
61
|
-
-
|
62
|
-
-
|
63
|
-
-
|
64
|
-
-
|
65
|
-
- spec/rack_spec.rb
|
66
|
-
- spec/spec_helper.rb
|
46
|
+
- lib/divining_rod/version.rb
|
47
|
+
- test/test_definition.rb
|
48
|
+
- test/test_example_config.rb
|
49
|
+
- test/test_helper.rb
|
50
|
+
- test/test_mash.rb
|
67
51
|
has_rdoc: true
|
68
|
-
homepage: http://github.com/
|
52
|
+
homepage: http://github.com/mdp/divining_rod
|
69
53
|
licenses: []
|
70
54
|
|
71
55
|
post_install_message:
|
72
|
-
rdoc_options:
|
73
|
-
|
56
|
+
rdoc_options: []
|
57
|
+
|
74
58
|
require_paths:
|
75
59
|
- lib
|
76
60
|
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
77
62
|
requirements:
|
78
63
|
- - ">="
|
79
64
|
- !ruby/object:Gem::Version
|
80
|
-
segments:
|
81
|
-
- 0
|
82
65
|
version: "0"
|
83
66
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
84
68
|
requirements:
|
85
69
|
- - ">="
|
86
70
|
- !ruby/object:Gem::Version
|
87
|
-
segments:
|
88
|
-
- 0
|
89
71
|
version: "0"
|
90
72
|
requirements: []
|
91
73
|
|
92
|
-
rubyforge_project:
|
93
|
-
rubygems_version: 1.
|
74
|
+
rubyforge_project: divining_rod
|
75
|
+
rubygems_version: 1.6.2
|
94
76
|
signing_key:
|
95
77
|
specification_version: 3
|
96
|
-
summary:
|
97
|
-
test_files:
|
98
|
-
|
99
|
-
- spec/example_mapping_spec.rb
|
100
|
-
- spec/mapper_spec.rb
|
101
|
-
- spec/mapping_spec.rb
|
102
|
-
- spec/profile_spec.rb
|
103
|
-
- spec/rack_spec.rb
|
104
|
-
- spec/spec_helper.rb
|
78
|
+
summary: An opinionated ruby encryption library
|
79
|
+
test_files: []
|
80
|
+
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.5.0
|
data/lib/divining_rod/mapper.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
module DiviningRod
|
2
|
-
class Mapper
|
3
|
-
include Murge
|
4
|
-
|
5
|
-
def initialize(parent, default_opts = {})
|
6
|
-
@parent = parent
|
7
|
-
@default_opts = default_opts
|
8
|
-
end
|
9
|
-
|
10
|
-
def pattern(type, pattern, opts = {})
|
11
|
-
opts = murge(default_options, opts)
|
12
|
-
definition = Matchers.send(type.to_sym, pattern, opts)
|
13
|
-
append_to_parent(definition)
|
14
|
-
if block_given?
|
15
|
-
yield self.class.new(definition)
|
16
|
-
end
|
17
|
-
definition
|
18
|
-
end
|
19
|
-
|
20
|
-
def with_options(opts)
|
21
|
-
yield self.class.new(@parent, opts)
|
22
|
-
end
|
23
|
-
|
24
|
-
def default(opts = {})
|
25
|
-
definition = Definition.new(opts) { true }
|
26
|
-
append_to_parent(definition)
|
27
|
-
definition
|
28
|
-
end
|
29
|
-
|
30
|
-
def method_missing(meth, *args, &blk)
|
31
|
-
# Lets us use map.ua instead of map.pattern :ua
|
32
|
-
if Matchers.respond_to?(meth.to_sym)
|
33
|
-
self.pattern(meth, args[0], args[1,], &blk)
|
34
|
-
else
|
35
|
-
super
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def default_options
|
42
|
-
@default_opts || {}
|
43
|
-
end
|
44
|
-
|
45
|
-
def append_to_parent(definition)
|
46
|
-
if @parent
|
47
|
-
@parent.children << definition
|
48
|
-
end
|
49
|
-
definition
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
end
|
data/spec/definition_spec.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe DiviningRod::Definition do
|
4
|
-
|
5
|
-
it "should work with no children not match" do
|
6
|
-
definition = DiviningRod::Definition.new(:format => :iphone, :tags => [:overpriced, :easy_to_break]) { |request|
|
7
|
-
request == 'iphone'
|
8
|
-
}
|
9
|
-
definition.evaluate('foo').should be_nil
|
10
|
-
end
|
11
|
-
|
12
|
-
it "should work with no children and match" do
|
13
|
-
definition = DiviningRod::Definition.new(:format => :iphone, :tags => [:overpriced, :easy_to_break]) { |request|
|
14
|
-
request == 'iphone'
|
15
|
-
}
|
16
|
-
definition.evaluate('iphone').should eql(definition)
|
17
|
-
end
|
18
|
-
|
19
|
-
describe "with children" do
|
20
|
-
|
21
|
-
it "should work with children that match" do
|
22
|
-
definition = DiviningRod::Definition.new(:format => :iphone, :tags => [:overpriced, :easy_to_break]) { |request|
|
23
|
-
request.match(/iphone/)
|
24
|
-
}
|
25
|
-
definition.children << DiviningRod::Definition.new(:format => :ipod, :tags => [:big, :lacks_a_camera]) { |request|
|
26
|
-
request.match(/ipod/)
|
27
|
-
}
|
28
|
-
definition.children << DiviningRod::Definition.new(:format => :ipad, :tags => [:big, :lacks_a_camera]) { |request|
|
29
|
-
request.match(/ipad/)
|
30
|
-
}
|
31
|
-
result = definition.evaluate('iphone ipad')
|
32
|
-
result.should_not eql(definition)
|
33
|
-
result.format.should eql(:ipad)
|
34
|
-
result.tags.should include(:overpriced)
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'spec/spec_helper'
|
2
|
-
require 'example_config'
|
3
|
-
|
4
|
-
def profile_ua(ua)
|
5
|
-
DiviningRod::Profile.new(request_mock(:ua => ua))
|
6
|
-
end
|
7
|
-
|
8
|
-
|
9
|
-
describe 'the example config' do
|
10
|
-
|
11
|
-
describe "recognizing Apple devices" do
|
12
|
-
|
13
|
-
it "should recognize an iPad" do
|
14
|
-
profile = profile_ua("Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10")
|
15
|
-
profile.ipad?.should be_true
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should recognize an iPod touch 2.2.1" do
|
19
|
-
profile = profile_ua("Mozilla/5.0 (iPod; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11 Safari/525.20")
|
20
|
-
profile.ipod?.should be_true
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should recognize an iPod touch 3.1.2" do
|
24
|
-
profile = profile_ua("Mozilla/5.0 (iPod; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16")
|
25
|
-
profile.ipod?.should be_true
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should recognize an iPhone 3.1.2" do
|
29
|
-
profile = profile_ua("Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16")
|
30
|
-
profile.iphone?.should be_true
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should recognize an iPhone 2.1.2" do
|
34
|
-
profile = profile_ua("Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11 Safari/525.20")
|
35
|
-
profile.iphone?.should be_true
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "recognizing Android devices" do
|
41
|
-
|
42
|
-
it "should recognize a basic android" do
|
43
|
-
profile = profile_ua("Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2")
|
44
|
-
profile.android?.should be_true
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
describe "recognizing desktop browsers" do
|
50
|
-
|
51
|
-
it "should recognize Internet Explorer 7" do
|
52
|
-
profile = profile_ua("Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)")
|
53
|
-
profile.desktop?.should be_true
|
54
|
-
profile.version.should eql(7)
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
end
|
data/spec/mapper_spec.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe DiviningRod::Mapper do
|
4
|
-
|
5
|
-
before :each do
|
6
|
-
@root_definition = DiviningRod::Definition.new { true }
|
7
|
-
mapper = DiviningRod::Mapper.new(@root_definition, {:tags => [:fuck], :foo => true})
|
8
|
-
mapper.ua /Safari/, :tags => [:baz] do |map|
|
9
|
-
map.with_options :tags => :awsome do |awesome|
|
10
|
-
awesome.ua /Apple/, :tags => [:foo]
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should map a definition" do
|
16
|
-
request = request_mock(:ua => 'Apple Mobile Safari', :format => :html)
|
17
|
-
result = @root_definition.evaluate(request)
|
18
|
-
result.tags.should include(:fuck)
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
data/spec/mapping_spec.rb
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe DiviningRod::Mappings do
|
4
|
-
|
5
|
-
before :each do
|
6
|
-
DiviningRod::Mappings.define(:tags => :mobile) do |map|
|
7
|
-
map.ua /Apple/, :format => :webkit, :tags => [:apple] do |apple|
|
8
|
-
|
9
|
-
# iPod, iPhone, and iPad
|
10
|
-
apple.with_options :tags => [:youtube, :geolocate, :iphone] do |advanced|
|
11
|
-
advanced.ua /iPad/, :tags => :ipad do |ipad|
|
12
|
-
ipad.ua /OS\s4/, :tags => :version4
|
13
|
-
ipad.ua /OS\s3/, :tags => :version3 do |v3|
|
14
|
-
v3.ua /Unicorns/, :tags => :omg_unicorns do |unicorns|
|
15
|
-
unicorns.ua /eat kittens/, :tags => [:omg_they_eat_kittens]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
ipad.ua /OS\s2/, :tags => :version2
|
19
|
-
end
|
20
|
-
advanced.ua /iPod/, :tags => [:ipod, :ipod_touch]
|
21
|
-
end
|
22
|
-
|
23
|
-
# Also an apple but actualy a newton
|
24
|
-
apple.ua /Newton/, :tags => [:apple] do |newton|
|
25
|
-
newton.ua /OS 8/, :tags => :os8
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should match a top level user agent" do
|
32
|
-
request = request_mock(:ua => 'Apple Mobile Safari', :format => :html)
|
33
|
-
result = DiviningRod::Mappings.root_definition.evaluate(request)
|
34
|
-
result.should_not be_nil
|
35
|
-
result.tags.should include(:apple)
|
36
|
-
result.tags.should_not include(:ipad)
|
37
|
-
result.tags.should include(:mobile)
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should match a child definition" do
|
41
|
-
ipad_request = request_mock(:ua => 'Apple iPad', :format => :html)
|
42
|
-
result = DiviningRod::Mappings.evaluate(ipad_request)
|
43
|
-
result.tags.should include(:ipad)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should match a sub child definition" do
|
47
|
-
ipad_request = request_mock(:ua => 'Apple iPad - now powered by Unicorns - OS 3.3', :format => :html)
|
48
|
-
result = DiviningRod::Mappings.evaluate(ipad_request)
|
49
|
-
result.tags.should include(:ipad)
|
50
|
-
result.tags.should include(:omg_unicorns)
|
51
|
-
result.tags.should include(:version3)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should match a really really deep child definition" do
|
55
|
-
ipad_request = request_mock(:ua => 'Apple iPad - now powered by Unicorns who eat kittens - OS 3.3', :format => :html)
|
56
|
-
result = DiviningRod::Mappings.evaluate(ipad_request)
|
57
|
-
result.tags.should include(:ipad, :youtube)
|
58
|
-
result.tags.should include(:omg_unicorns)
|
59
|
-
result.tags.should include(:omg_they_eat_kittens)
|
60
|
-
result.tags.should include(:version3)
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should match a in order defined" do
|
64
|
-
ipad_request = request_mock(:ua => 'Apple iPad - now powered by Unicorns who eat kittens - OS 2', :format => :html)
|
65
|
-
result = DiviningRod::Mappings.evaluate(ipad_request)
|
66
|
-
result.tags.should include(:ipad, :youtube)
|
67
|
-
result.tags.should_not include(:omg_they_eat_kittens, :omg_unicorns)
|
68
|
-
result.tags.should include(:version2)
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should match a in order defined" do
|
72
|
-
ipad_request = request_mock(:ua => 'Apple Newton - OS 8', :format => :html)
|
73
|
-
result = DiviningRod::Mappings.evaluate(ipad_request)
|
74
|
-
result.tags.should_not include(:omg_they_eat_kittens, :omg_unicorns)
|
75
|
-
result.tags.should include(:os8)
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
data/spec/profile_spec.rb
DELETED
@@ -1,118 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe DiviningRod do
|
4
|
-
|
5
|
-
before :each do
|
6
|
-
@request = request_mock(:ua => 'My iPhone which is actually an iPad')
|
7
|
-
|
8
|
-
DiviningRod::Mappings.define do |map|
|
9
|
-
map.ua /iPhone/, :format => :webkit, :tags => [:iphone, :youtube, :geolocate] do |iphone|
|
10
|
-
iphone.ua /iPad/, :tags => [:ipad]
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should recognize an iPhone" do
|
16
|
-
profile = DiviningRod::Profile.new(@request)
|
17
|
-
profile.format.should eql(:webkit)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should know if it belongs to a category tag" do
|
21
|
-
profile = DiviningRod::Profile.new(@request)
|
22
|
-
profile.ipad?.should be_true
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should know if it does not belongs to a category" do
|
26
|
-
profile = DiviningRod::Profile.new(@request)
|
27
|
-
profile.wap?.should be_false
|
28
|
-
end
|
29
|
-
|
30
|
-
describe "without a default route" do
|
31
|
-
|
32
|
-
before :each do
|
33
|
-
@request = request_mock(:ua => 'My Foo Fone', :format => :html)
|
34
|
-
|
35
|
-
DiviningRod::Mappings.define do |map|
|
36
|
-
map.ua /iPhone/, :format => :webkit, :tags => [:iphone, :youtube, :geolocate]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should use the default group for unknown phones" do
|
41
|
-
profile = DiviningRod::Profile.new(@request)
|
42
|
-
profile.wap?.should be_false
|
43
|
-
profile.format.should eql(:html)
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
describe "with a default route" do
|
50
|
-
|
51
|
-
before :each do
|
52
|
-
@request = request_mock(:ua => 'My Foo Fone')
|
53
|
-
|
54
|
-
DiviningRod::Mappings.define do |map|
|
55
|
-
map.ua /iPhone/, :format => :webkit, :tags => [:iphone, :youtube, :geolocate]
|
56
|
-
map.default :format => :html
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
it "should use the default group for unknown phones" do
|
61
|
-
profile = DiviningRod::Profile.new(@request)
|
62
|
-
profile.wap?.should be_false
|
63
|
-
profile.format.should eql(:html)
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
describe "without a default definition" do
|
69
|
-
|
70
|
-
before :each do
|
71
|
-
@request = request_mock(:ua => 'Foo Fone', :format => :html)
|
72
|
-
|
73
|
-
DiviningRod::Mappings.define do |map|
|
74
|
-
map.ua /iPhone/, :format => :webkit, :tags => [:iphone, :youtube, :geolocate]
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should not find a match" do
|
79
|
-
DiviningRod::Profile.new(@request).recognized?.should be_false
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
describe "matching a subdomain" do
|
85
|
-
|
86
|
-
before :each do
|
87
|
-
@request = request_mock(:ua => 'Foo Fone', :host => 'wap.example.com')
|
88
|
-
|
89
|
-
DiviningRod::Mappings.define do |map|
|
90
|
-
map.subdomain /wap/, :format => :wap, :tags => [:shitty]
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
it "should not find a match" do
|
95
|
-
DiviningRod::Profile.new(@request).recognized?.should be_true
|
96
|
-
profile = DiviningRod::Profile.new(@request)
|
97
|
-
profile.wap?
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
describe "matching the weird requests(no user_agent passed)" do
|
103
|
-
|
104
|
-
before :each do
|
105
|
-
@request = request_mock(:ua => nil, :subdomains => [])
|
106
|
-
|
107
|
-
DiviningRod::Mappings.define do |map|
|
108
|
-
map.ua /iPhone/, :format => :wap, :tags => [:shitty]
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
it "should not find a match" do
|
113
|
-
DiviningRod::Profile.new(@request).recognized?.should be_false
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
end
|
data/spec/rack_spec.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require "divining_rod/rack"
|
3
|
-
require "rack/test"
|
4
|
-
|
5
|
-
describe DiviningRod do
|
6
|
-
include Rack::Test::Methods
|
7
|
-
|
8
|
-
def app
|
9
|
-
DiviningRod::Rack.new(app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['foo']] })
|
10
|
-
end
|
11
|
-
|
12
|
-
before :each do
|
13
|
-
DiviningRod::Mappings.define do |map|
|
14
|
-
map.ua /iPhone/, :format => :webkit, :tags => [:iphone, :youtube, :geolocate] do |iphone|
|
15
|
-
iphone.ua /iPad/, :tags => [:ipad]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should profile an incoming request" do
|
21
|
-
header 'User-Agent', "iPhone Safari"
|
22
|
-
get "/"
|
23
|
-
last_request.env['divining_rod.profile'].should be_an_instance_of(DiviningRod::Profile)
|
24
|
-
last_request.env['divining_rod.profile'].iphone?.should be_true
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|