divining_rod 0.3.1 → 0.4.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/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