divining_rod 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -5,20 +5,43 @@ A tool to help format your sites mobile pages.
5
5
  ## Installation
6
6
 
7
7
  gem install divining_rod
8
+
9
+ ## Example
10
+
11
+ Using the example configuration (found in [example_config.rb](http://github.com/markpercival/divining_rod/blob/master/example_config.rb)])
12
+
13
+ # For a request with the user agent
14
+ # "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"
15
+
16
+ profile = DiviningRod::Profile.new(request)
17
+ profile.iphone? #=> true
18
+ profile.name #=> 'iPhone'
19
+ profile.youtube_capable? #=> true
20
+ profile.format #=> :webkit
21
+
8
22
 
9
23
  ## Usage
10
24
 
11
25
  _initializers/divining\_rod.rb_
12
26
 
13
- DiviningRod::Matchers.define do |map|
14
- # map.ua /user_agent_regex/, :format, :tags => []
15
- map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube_capable]
16
- map.ua /Android/, :webkit, :tags => [:android, :youtube_capable, :google_gears]
17
- map.subdomain /wap/, :wap, :tags => [:crappy_old_phone]
27
+ DiviningRod::Mappings.define do |map|
28
+ # Android based phones
29
+ map.ua /Android/, :format => :webkit, :name => 'Android', :tags => [:android, :youtube_capable, :google_gears]
30
+
31
+ # Apple iPhone OS
32
+ map.ua /Apple.*Mobile.*Safari/, :format => :webkit, :tags => [:apple, :iphone_os, :youtube_capable] do |iphone|
33
+ iphone.ua /iPad/, :tags => :ipad, :name => 'iPad'
34
+ iphone.ua /iPod/, :tags => :ipod, :name => 'iPod Touch'
35
+ iphone.ua /iPhone/, :tags => [:iphone], :name => 'iPhone'
36
+ end
37
+
38
+ #Blackberry, needs more detail here
39
+ map.ua /BlackBerry/, :tags => :blackberry, :name => 'BlackBerry'
40
+ map.subdomain /wap/, :format => :wap, :tags => [:crappy_old_phone]
18
41
 
19
42
  # Enable this to forces a default format if unmatched
20
43
  # otherwise it will return the request.format
21
- # map.default :html
44
+ # map.default :format => :html
22
45
  end
23
46
 
24
47
  _initializers/mime\_types.rb_
@@ -53,10 +76,10 @@ _app/views/mobile/show.webkit.html_
53
76
 
54
77
  ## Note on the development
55
78
 
56
- This is still very much in beta, but we are using it in production. As such we plan
57
- to do our best to keep the API the same.
79
+ Tags always merge, while all other hash keys get overridden. Tags also will always allow you to call them as
80
+ booleans. Ex @profile.iphone?
58
81
 
59
- The user agent definitions will be updated here later this week.
82
+ If the :format key isn't available we default to request.format.
60
83
 
61
84
  ## Todo
62
85
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
data/divining_rod.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{divining_rod}
8
- s.version = "0.3.1"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Mark Percival"]
12
- s.date = %q{2010-02-18}
12
+ s.date = %q{2010-02-23}
13
13
  s.description = %q{A mobile phone web request profiler using definitions that look like rails routes}
14
14
  s.email = %q{mark@mpercival.com}
15
15
  s.extra_rdoc_files = [
@@ -24,8 +24,19 @@ Gem::Specification.new do |s|
24
24
  "Rakefile",
25
25
  "VERSION",
26
26
  "divining_rod.gemspec",
27
+ "example_config.rb",
27
28
  "lib/divining_rod.rb",
28
- "spec/basic_spec.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
+ "spec/definition_spec.rb",
36
+ "spec/example_mapping_spec.rb",
37
+ "spec/mapper_spec.rb",
38
+ "spec/mapping_spec.rb",
39
+ "spec/profile_spec.rb",
29
40
  "spec/spec_helper.rb"
30
41
  ]
31
42
  s.homepage = %q{http://github.com/markpercival/divining_rod}
@@ -34,7 +45,11 @@ Gem::Specification.new do |s|
34
45
  s.rubygems_version = %q{1.3.5}
35
46
  s.summary = %q{A mobile phone web request profiler}
36
47
  s.test_files = [
37
- "spec/basic_spec.rb",
48
+ "spec/definition_spec.rb",
49
+ "spec/example_mapping_spec.rb",
50
+ "spec/mapper_spec.rb",
51
+ "spec/mapping_spec.rb",
52
+ "spec/profile_spec.rb",
38
53
  "spec/spec_helper.rb"
39
54
  ]
40
55
 
data/example_config.rb ADDED
@@ -0,0 +1,31 @@
1
+ DiviningRod::Mappings.define do |map|
2
+ # Android based phones
3
+ map.ua /Android/, :format => :webkit, :name => 'Android', :tags => [:android, :youtube_capable, :google_gears]
4
+
5
+ # Apple iPhone OS
6
+ map.ua /Apple.*Mobile.*Safari/, :format => :webkit, :tags => [:apple, :iphone_os, :youtube_capable] do |iphone|
7
+ iphone.ua /iPad/, :tags => :ipad, :name => 'iPad'
8
+ iphone.ua /iPod/, :tags => :ipod, :name => 'iPod Touch'
9
+ iphone.ua /iPhone/, :tags => [:iphone], :name => 'iPhone'
10
+ end
11
+
12
+ #Blackberry, needs more detail here
13
+ map.ua /BlackBerry/, :tags => :blackberry, :name => 'BlackBerry'
14
+
15
+ # The desktop browsers, we don't set a format on these to let it pass through
16
+ map.with_options :tags => :desktop do |desktop|
17
+ desktop.ua /Chrome/, :tags => :chrome, :name => 'Chrome'
18
+ desktop.ua /Firefox/, :tags => :firefox, :name => 'Firefox'
19
+ desktop.ua /Safari/, :tags => :safari, :name => 'Safari'
20
+ desktop.ua /Opera/, :tags => :opera, :name => 'Opera'
21
+ desktop.ua /MSIE/, :tags => :ie, :name => 'Internet Explorer' do |msie|
22
+ msie.ua /MSIE 6/, :version => 6
23
+ msie.ua /MSIE 7/, :version => 7
24
+ msie.ua /MSIE 8/, :version => 8
25
+ end
26
+ end
27
+
28
+ # Enable this to forces a default format if unmatched
29
+ # otherwise it will return the request.format
30
+ # map.default :format => :html
31
+ end
data/lib/divining_rod.rb CHANGED
@@ -1,107 +1,8 @@
1
- require 'yaml'
2
-
3
- module DiviningRod
4
-
5
- class Profile
6
-
7
- attr_reader :match
8
-
9
- def initialize(request)
10
- @request = request.clone #Lets not mess with the real one
11
- matchers.each do |matcher|
12
- @match = matcher if matcher.matches?(request)
13
- break if @match
14
- end
15
- nil
16
- end
17
-
18
- def group
19
- if @match
20
- @match.group
21
- else
22
- @request.format
23
- end
24
- end
25
- alias_method :format, :group
26
-
27
- def recognized?
28
- !!@match
29
- end
30
-
31
- def method_missing(meth)
32
- if meth.to_s.match(/(.+)\?$/)
33
- tag = $1
34
- if @match
35
- @match.tags.include?(tag.to_s) || @match.tags.include?(tag.to_sym) || @match.tags == tag
36
- else
37
- false
38
- end
39
- else
40
- super
41
- end
42
- end
43
-
44
- def matchers
45
- DiviningRod::Matchers.definitions || []
46
- end
47
-
48
- end
49
-
50
- class Matchers
51
-
52
- class << self
53
-
54
- attr_accessor :definitions
55
-
56
- def define
57
- yield(self)
58
- end
59
-
60
- def clear_definitions
61
- @definitions = []
62
- end
63
-
64
- def ua(pattern, group, opts={})
65
- @definitions ||= []
66
- @definitions << Definition.new(group, opts) { |request|
67
- if pattern.match(request.user_agent)
68
- true
69
- end
70
- }
71
- end
72
-
73
- def subdomain(pattern, group, opts={})
74
- @definitions ||= []
75
- @definitions << Definition.new(group, opts) { |request|
76
- if pattern.match(request.subdomains[0])
77
- true
78
- end
79
- }
80
- end
81
-
82
- def default(group, opts = {})
83
- @definitions ||= []
84
- @definitions << Definition.new(group, opts) { |request| true }
85
- end
86
-
87
- end
88
-
89
- end
90
-
91
- class Definition
92
-
93
- attr_accessor :prc, :tags, :group
94
-
95
- def initialize(group, opts={}, &blk)
96
- @group = group
97
- @tags = opts[:tags] || []
98
- @prc = blk
99
- end
100
-
101
- def matches?(request)
102
- !!@prc.call(request)
103
- end
104
-
105
- end
106
-
107
- end
1
+ module DiviningRod; end
2
+
3
+ require 'divining_rod/profile'
4
+ require 'divining_rod/murge'
5
+ require 'divining_rod/definition'
6
+ require 'divining_rod/mappings'
7
+ require 'divining_rod/mapper'
8
+ require 'divining_rod/matchers'
@@ -0,0 +1,53 @@
1
+ module DiviningRod
2
+ class Definition
3
+ include Murge
4
+
5
+ attr_accessor :prc, :group, :opts, :parent
6
+ attr_writer :children
7
+
8
+ def initialize(opts={}, &blk)
9
+ @prc = blk
10
+ @opts = opts
11
+ end
12
+
13
+ def evaluate(request)
14
+ result = nil
15
+ child_result = nil
16
+ if @prc.call(request)
17
+ result = self
18
+ unless self.children.empty?
19
+ self.children.each do |child|
20
+ child_result = child.evaluate(request)
21
+ break if child_result
22
+ end
23
+ end
24
+ end
25
+ child_result || result
26
+ end
27
+
28
+ def tags
29
+ opts[:tags] || []
30
+ end
31
+
32
+ def opts
33
+ if parent
34
+ @murged_opts ||= murge(parent.opts, @opts)
35
+ else
36
+ @opts
37
+ end
38
+ end
39
+
40
+ def format
41
+ opts[:format]
42
+ end
43
+
44
+ def children
45
+ @children ||= []
46
+ @children.each do |child|
47
+ child.parent ||= self
48
+ end
49
+ @children
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,55 @@
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
@@ -0,0 +1,20 @@
1
+ module DiviningRod
2
+ class Mappings
3
+
4
+ class << self
5
+
6
+ attr_accessor :root_definition
7
+
8
+ def define(opts = {})
9
+ @root_definition = Definition.new { true }
10
+ yield Mapper.new(@root_definition, opts)
11
+ end
12
+
13
+ def evaluate(obj)
14
+ @root_definition.evaluate(obj)
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ module DiviningRod
2
+ class Matchers
3
+ class << self
4
+
5
+ def ua(pattern, opts = {})
6
+ Definition.new(opts) { |request|
7
+ if pattern.match(request.user_agent)
8
+ true
9
+ end
10
+ }
11
+ end
12
+
13
+ def subdomain(pattern, opts={})
14
+ Definition.new(opts) { |request|
15
+ if pattern.match(request.subdomains[0])
16
+ true
17
+ end
18
+ }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ module DiviningRod
2
+ module Murge
3
+
4
+ # This is tacky, but I'm preserving tags in the option hash
5
+ # and only want to have to write this once
6
+ #
7
+ def murge(old_opts, new_opts)
8
+ old_opts = old_opts || {}
9
+ tags = Array(old_opts[:tags]) | Array(new_opts[:tags])
10
+ opts = old_opts.merge(new_opts)
11
+ opts[:tags] = tags
12
+ opts
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ module DiviningRod
2
+ class Profile
3
+
4
+ attr_reader :match
5
+
6
+ def initialize(request)
7
+ @request = request.clone #Lets not mess with the real one
8
+ @match = DiviningRod::Mappings.evaluate(request)
9
+ end
10
+
11
+ def format
12
+ if @match && @match.format
13
+ @match.format
14
+ else
15
+ @request.format
16
+ end
17
+ end
18
+
19
+ def recognized?
20
+ @match != DiviningRod::Mappings.root_definition
21
+ end
22
+
23
+ def method_missing(meth)
24
+ if meth.to_s.match(/(.+)\?$/)
25
+ tag = $1
26
+ if @match
27
+ @match.tags.include?(tag.to_s) || @match.tags.include?(tag.to_sym) || @match.tags == tag
28
+ else
29
+ false
30
+ end
31
+ elsif @match.opts.include?(meth.to_sym)
32
+ @match.opts[meth]
33
+ else
34
+ super
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,40 @@
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
@@ -0,0 +1,65 @@
1
+ require 'spec/spec_helper'
2
+ require 'example_config'
3
+
4
+
5
+ def request_mock(ua, subdomain = [])
6
+ mock('RailsRequest', :user_agent => ua, :subdomain => subdomain)
7
+ end
8
+
9
+ def profile_ua(ua)
10
+ DiviningRod::Profile.new(request_mock(ua))
11
+ end
12
+
13
+
14
+ describe 'the example config' do
15
+
16
+ describe "recognizing Apple devices" do
17
+
18
+ it "should recognize an iPad" do
19
+ 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")
20
+ profile.ipad?.should be_true
21
+ end
22
+
23
+ it "should recognize an iPod touch 2.2.1" do
24
+ 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")
25
+ profile.ipod?.should be_true
26
+ end
27
+
28
+ it "should recognize an iPod touch 3.1.2" do
29
+ 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")
30
+ profile.ipod?.should be_true
31
+ end
32
+
33
+ it "should recognize an iPhone 3.1.2" do
34
+ 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")
35
+ profile.iphone?.should be_true
36
+ end
37
+
38
+ it "should recognize an iPhone 2.1.2" do
39
+ 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")
40
+ profile.iphone?.should be_true
41
+ end
42
+
43
+ end
44
+
45
+ describe "recognizing Android devices" do
46
+
47
+ it "should recognize a basic android" do
48
+ 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")
49
+ profile.android?.should be_true
50
+ end
51
+
52
+ end
53
+
54
+ describe "recognizing desktop browsers" do
55
+
56
+ it "should recognize Internet Explorer 7" do
57
+ profile = profile_ua("Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)")
58
+ profile.desktop?.should be_true
59
+ profile.version.should eql(7)
60
+ end
61
+
62
+ end
63
+
64
+
65
+ end
@@ -0,0 +1,21 @@
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 = mock("rails_request", :user_agent => 'Apple Mobile Safari', :format => :html)
17
+ result = @root_definition.evaluate(request)
18
+ result.tags.should include(:fuck)
19
+ end
20
+
21
+ end
@@ -0,0 +1,78 @@
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 = mock("rails_request", :user_agent => '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 = mock("rails_request", :user_agent => '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 = mock("rails_request", :user_agent => '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 = mock("rails_request", :user_agent => '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 = mock("rails_request", :user_agent => '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 = mock("rails_request", :user_agent => '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
@@ -3,10 +3,12 @@ require 'spec_helper'
3
3
  describe DiviningRod do
4
4
 
5
5
  before :each do
6
- @request = mock("rails_request", :user_agent => 'My iPhone')
7
- DiviningRod::Matchers.clear_definitions
8
- DiviningRod::Matchers.define do |map|
9
- map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube, :geolocate]
6
+ @request = mock("rails_request", :user_agent => '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
10
12
  end
11
13
  end
12
14
 
@@ -17,7 +19,7 @@ describe DiviningRod do
17
19
 
18
20
  it "should know if it belongs to a category tag" do
19
21
  profile = DiviningRod::Profile.new(@request)
20
- profile.geolocate?.should be_true
22
+ profile.ipad?.should be_true
21
23
  end
22
24
 
23
25
  it "should know if it does not belongs to a category" do
@@ -29,9 +31,9 @@ describe DiviningRod do
29
31
 
30
32
  before :each do
31
33
  @request = mock("rails_request", :user_agent => 'My Foo Fone', :format => :html)
32
- DiviningRod::Matchers.clear_definitions
33
- DiviningRod::Matchers.define do |map|
34
- map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube, :geolocate]
34
+
35
+ DiviningRod::Mappings.define do |map|
36
+ map.ua /iPhone/, :format => :webkit, :tags => [:iphone, :youtube, :geolocate]
35
37
  end
36
38
  end
37
39
 
@@ -48,10 +50,10 @@ describe DiviningRod do
48
50
 
49
51
  before :each do
50
52
  @request = mock("rails_request", :user_agent => 'My Foo Fone')
51
- DiviningRod::Matchers.clear_definitions
52
- DiviningRod::Matchers.define do |map|
53
- map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube, :geolocate]
54
- map.default :html
53
+
54
+ DiviningRod::Mappings.define do |map|
55
+ map.ua /iPhone/, :format => :webkit, :tags => [:iphone, :youtube, :geolocate]
56
+ map.default :format => :html
55
57
  end
56
58
  end
57
59
 
@@ -67,9 +69,9 @@ describe DiviningRod do
67
69
 
68
70
  before :each do
69
71
  @request = mock("rails_request", :user_agent => 'Foo Fone', :format => :html)
70
- DiviningRod::Matchers.clear_definitions
71
- DiviningRod::Matchers.define do |map|
72
- map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube, :geolocate]
72
+
73
+ DiviningRod::Mappings.define do |map|
74
+ map.ua /iPhone/, :format => :webkit, :tags => [:iphone, :youtube, :geolocate]
73
75
  end
74
76
  end
75
77
 
@@ -83,9 +85,9 @@ describe DiviningRod do
83
85
 
84
86
  before :each do
85
87
  @request = mock("rails_request", :user_agent => 'Foo Fone', :subdomains => ['wap'])
86
- DiviningRod::Matchers.clear_definitions
87
- DiviningRod::Matchers.define do |map|
88
- map.subdomain /wap/, :wap, :tags => [:shitty]
88
+
89
+ DiviningRod::Mappings.define do |map|
90
+ map.subdomain /wap/, :format => :wap, :tags => [:shitty]
89
91
  end
90
92
  end
91
93
 
@@ -101,9 +103,9 @@ describe DiviningRod do
101
103
 
102
104
  before :each do
103
105
  @request = mock("rails_request", :user_agent => nil, :subdomains => [])
104
- DiviningRod::Matchers.clear_definitions
105
- DiviningRod::Matchers.define do |map|
106
- map.ua /iPhone/, :wap, :tags => [:shitty]
106
+
107
+ DiviningRod::Mappings.define do |map|
108
+ map.ua /iPhone/, :format => :wap, :tags => [:shitty]
107
109
  end
108
110
  end
109
111
 
@@ -114,38 +116,3 @@ describe DiviningRod do
114
116
  end
115
117
 
116
118
  end
117
-
118
-
119
- describe DiviningRod::Matchers do
120
-
121
- before :each do
122
- @request = mock("rails_request", :user_agent => 'iPhone Foo')
123
- DiviningRod::Matchers.clear_definitions
124
- DiviningRod::Matchers.define do |map|
125
- map.ua /iPhone/, :iphone, :tags => [:iphone, :youtube]
126
- end
127
- end
128
-
129
- it "should recognize an iPhone" do
130
- DiviningRod::Matchers.definitions.first.matches?(@request).should be_true
131
- DiviningRod::Matchers.definitions.first.group.should eql(:iphone)
132
- end
133
-
134
- describe "defining a default definition" do
135
-
136
- before :each do
137
- @request = mock("rails_request", :user_agent => 'Foo Fone')
138
- DiviningRod::Matchers.clear_definitions
139
- DiviningRod::Matchers.define do |map|
140
- map.default :unknown, :tags => [:html]
141
- end
142
- end
143
-
144
- it "should use the default route if no other match is found" do
145
- DiviningRod::Matchers.definitions.first.matches?(@request).should be_true
146
- DiviningRod::Matchers.definitions.first.group.should eql(:unknown)
147
- end
148
-
149
- end
150
-
151
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: divining_rod
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Percival
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-18 00:00:00 -05:00
12
+ date: 2010-02-23 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -39,8 +39,19 @@ files:
39
39
  - Rakefile
40
40
  - VERSION
41
41
  - divining_rod.gemspec
42
+ - example_config.rb
42
43
  - lib/divining_rod.rb
43
- - spec/basic_spec.rb
44
+ - lib/divining_rod/definition.rb
45
+ - lib/divining_rod/mapper.rb
46
+ - lib/divining_rod/mappings.rb
47
+ - lib/divining_rod/matchers.rb
48
+ - lib/divining_rod/murge.rb
49
+ - lib/divining_rod/profile.rb
50
+ - spec/definition_spec.rb
51
+ - spec/example_mapping_spec.rb
52
+ - spec/mapper_spec.rb
53
+ - spec/mapping_spec.rb
54
+ - spec/profile_spec.rb
44
55
  - spec/spec_helper.rb
45
56
  has_rdoc: true
46
57
  homepage: http://github.com/markpercival/divining_rod
@@ -71,5 +82,9 @@ signing_key:
71
82
  specification_version: 3
72
83
  summary: A mobile phone web request profiler
73
84
  test_files:
74
- - spec/basic_spec.rb
85
+ - spec/definition_spec.rb
86
+ - spec/example_mapping_spec.rb
87
+ - spec/mapper_spec.rb
88
+ - spec/mapping_spec.rb
89
+ - spec/profile_spec.rb
75
90
  - spec/spec_helper.rb