divining_rod 0.2.0 → 0.3.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
@@ -1,13 +1,6 @@
1
1
  # Divining Rod
2
2
 
3
- A tool to help format your sites mobile pages. The goal is to have the ability to do things in your
4
- views like this
5
-
6
- <%- if request.dv_profile.youtube_capable? %>
7
- <%= link_to "YouTube Video", @link.youtube_url %>
8
- <%- else %>
9
- Sorry, you have a shitty phone.
10
- <% end %>
3
+ A tool to help format your sites mobile pages.
11
4
 
12
5
  ## Installation
13
6
 
@@ -15,35 +8,56 @@ views like this
15
8
 
16
9
  ## Usage
17
10
 
18
- require 'divining_rod'
11
+ _initializers/divining\_rod.rb_
19
12
 
20
13
  DiviningRod::Matchers.define do |map|
14
+ # map.ua /user_agent_regex/, :format, :tags => []
21
15
  map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube_capable]
22
- map.ua /Android/, :webkit, :tags => [:youtube_capable, :google_gears]
23
- map.default :unknown
16
+ map.ua /Android/, :webkit, :tags => [:android, :youtube_capable, :google_gears]
17
+ map.subdomain /wap/, :wap, :tags => [:crappy_old_phone]
18
+
19
+ # Enable this to forces a default format if unmatched
20
+ # otherwise it will return the request.format
21
+ # map.default :html
24
22
  end
23
+
24
+ _initializers/mime\_types.rb_
25
25
 
26
- profile = DiviningRod::Profile(request) #profile and incoming iphone request
27
- profile.format #=> :webkit
28
- profile.iphone? #=> true
26
+ Mime::Type.register_alias "text/html", :webkit
27
+
28
+ _app/controllers/mobile\_controller.rb_
29
+
30
+ class MobileController < ApplicationController
31
+ before_filter :detect_mobile_type
32
+
33
+ ....
34
+
35
+ private
36
+
37
+ def detect_mobile_type
38
+ # If the profile isn't matched it defaults to request.format
39
+ @profile = DiviningRod::Profile.new(request).format
40
+ end
41
+
42
+ end
43
+
44
+ _app/views/mobile/show.webkit.html_
45
+
46
+ <%- if @profile.iphone? %>
47
+ <%= link_to "Install our iPhone App in the AppStore", @iPhone_appstore_url %>
48
+ <%- elsif @profile.android? %>
49
+ <%= link_to "Direct download", @android_app_url %>
50
+ <% end %>
51
+
29
52
 
30
53
  ## Note on the development
31
54
 
32
- This is still very much in beta, but we are using in extensively in production. We plan
33
- to keep the API the same.
55
+ This is still very much in beta, but we are using it in production. As such we plan
56
+ to do our best to keep the API the same.
34
57
 
35
58
  The user agent definitions will be updated here later this week.
36
59
 
37
-
38
- ### Note on Patches/Pull Requests
39
-
40
- * Fork the project.
41
- * Make your feature addition or bug fix.
42
- * Add tests for it. This is important so I don't break it in a
43
- future version unintentionally.
44
- * Commit, do not mess with rakefile, version, or history.
45
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
46
- * Send me a pull request. Bonus points for topic branches.
60
+ ## Todo
47
61
 
48
62
  ### Copyright
49
63
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.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.2.0"
8
+ s.version = "0.3.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-17}
12
+ s.date = %q{2010-02-18}
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 = [
data/lib/divining_rod.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  require 'yaml'
2
2
 
3
3
  module DiviningRod
4
-
4
+
5
5
  class Profile
6
-
6
+
7
7
  attr_reader :match
8
-
8
+
9
9
  def initialize(request)
10
+ @request = request
10
11
  matchers.each do |matcher|
11
12
  @match = matcher if matcher.matches?(request)
12
13
  break if @match
@@ -15,43 +16,51 @@ module DiviningRod
15
16
  end
16
17
 
17
18
  def group
18
- @match.group
19
+ if @match
20
+ @match.group
21
+ else
22
+ @request.format
23
+ end
19
24
  end
20
25
  alias_method :format, :group
21
-
26
+
22
27
  def recognized?
23
28
  !!@match
24
29
  end
25
-
30
+
26
31
  def method_missing(meth)
27
32
  if meth.to_s.match(/(.+)\?$/)
28
33
  tag = $1
29
- @match.tags.include?(tag.to_s) || @match.tags.include?(tag.to_sym) || @match.tags == tag
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
30
39
  else
31
40
  super
32
41
  end
33
42
  end
34
-
43
+
35
44
  def matchers
36
45
  DiviningRod::Matchers.definitions || []
37
46
  end
38
-
47
+
39
48
  end
40
-
49
+
41
50
  class Matchers
42
-
51
+
43
52
  class << self
44
-
53
+
45
54
  attr_accessor :definitions
46
-
55
+
47
56
  def define
48
57
  yield(self)
49
58
  end
50
-
59
+
51
60
  def clear_definitions
52
61
  @definitions = []
53
62
  end
54
-
63
+
55
64
  def ua(pattern, group, opts={})
56
65
  @definitions ||= []
57
66
  @definitions << Definition.new(group, opts) { |request|
@@ -61,29 +70,38 @@ module DiviningRod
61
70
  }
62
71
  end
63
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
+
64
82
  def default(group, opts = {})
65
83
  @definitions ||= []
66
84
  @definitions << Definition.new(group, opts) { |request| true }
67
85
  end
68
-
86
+
69
87
  end
70
-
88
+
71
89
  end
72
-
90
+
73
91
  class Definition
74
-
92
+
75
93
  attr_accessor :prc, :tags, :group
76
-
94
+
77
95
  def initialize(group, opts={}, &blk)
78
96
  @group = group
79
97
  @tags = opts[:tags] || []
80
98
  @prc = blk
81
99
  end
82
-
100
+
83
101
  def matches?(request)
84
102
  !!@prc.call(request)
85
103
  end
86
-
104
+
87
105
  end
88
-
89
- end
106
+
107
+ end
data/spec/basic_spec.rb CHANGED
@@ -1,86 +1,151 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DiviningRod do
4
-
4
+
5
5
  before :each do
6
6
  @request = mock("rails_request", :user_agent => 'My iPhone')
7
7
  DiviningRod::Matchers.clear_definitions
8
8
  DiviningRod::Matchers.define do |map|
9
- map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube, :geolocate]
10
- map.default(:unknown)
9
+ map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube, :geolocate]
11
10
  end
12
11
  end
13
-
12
+
14
13
  it "should recognize an iPhone" do
15
14
  profile = DiviningRod::Profile.new(@request)
16
15
  profile.format.should eql(:webkit)
17
16
  end
18
-
17
+
19
18
  it "should know if it belongs to a category tag" do
20
19
  profile = DiviningRod::Profile.new(@request)
21
20
  profile.geolocate?.should be_true
22
21
  end
23
-
22
+
24
23
  it "should know if it does not belongs to a category" do
25
24
  profile = DiviningRod::Profile.new(@request)
26
25
  profile.wap?.should be_false
27
26
  end
28
27
 
29
- it "should use the default group for unknown phones" do
30
- @request = mock("rails_request", :user_agent => 'My Foo Phone')
31
- profile = DiviningRod::Profile.new(@request)
32
- profile.wap?.should be_false
28
+ describe "without a default route" do
29
+
30
+ before :each do
31
+ @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]
35
+ end
36
+ end
37
+
38
+ it "should use the default group for unknown phones" do
39
+ profile = DiviningRod::Profile.new(@request)
40
+ profile.wap?.should be_false
41
+ profile.format.should eql(:html)
42
+ end
43
+
33
44
  end
34
45
 
35
- describe "without a default definition" do
46
+
47
+ describe "with a default route" do
36
48
 
49
+ before :each do
50
+ @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
55
+ end
56
+ end
57
+
58
+ it "should use the default group for unknown phones" do
59
+ profile = DiviningRod::Profile.new(@request)
60
+ profile.wap?.should be_false
61
+ profile.format.should eql(:html)
62
+ end
63
+
64
+ end
65
+
66
+ describe "without a default definition" do
67
+
37
68
  before :each do
38
69
  @request = mock("rails_request", :user_agent => 'Foo Fone')
39
70
  DiviningRod::Matchers.clear_definitions
40
71
  DiviningRod::Matchers.define do |map|
41
- map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube, :geolocate]
72
+ map.ua /iPhone/, :webkit, :tags => [:iphone, :youtube, :geolocate]
42
73
  end
43
74
  end
44
-
75
+
45
76
  it "should not find a match" do
46
77
  DiviningRod::Profile.new(@request).recognized?.should be_false
47
78
  end
48
-
79
+
49
80
  end
50
81
 
82
+ describe "matching a subdomain" do
83
+
84
+ before :each do
85
+ @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]
89
+ end
90
+ end
91
+
92
+ it "should not find a match" do
93
+ DiviningRod::Profile.new(@request).recognized?.should be_true
94
+ profile = DiviningRod::Profile.new(@request)
95
+ profile.wap?
96
+ end
97
+
98
+ end
99
+
100
+ describe "matching the weird requests(no user_agent passed)" do
101
+
102
+ before :each do
103
+ @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]
107
+ end
108
+ end
109
+
110
+ it "should not find a match" do
111
+ DiviningRod::Profile.new(@request).recognized?.should be_false
112
+ end
113
+
114
+ end
115
+
51
116
  end
52
117
 
53
118
 
54
119
  describe DiviningRod::Matchers do
55
-
120
+
56
121
  before :each do
57
122
  @request = mock("rails_request", :user_agent => 'iPhone Foo')
58
123
  DiviningRod::Matchers.clear_definitions
59
124
  DiviningRod::Matchers.define do |map|
60
- map.ua /iPhone/, :iphone, :tags => [:iphone, :youtube]
125
+ map.ua /iPhone/, :iphone, :tags => [:iphone, :youtube]
61
126
  end
62
127
  end
63
-
128
+
64
129
  it "should recognize an iPhone" do
65
130
  DiviningRod::Matchers.definitions.first.matches?(@request).should be_true
66
131
  DiviningRod::Matchers.definitions.first.group.should eql(:iphone)
67
132
  end
68
-
133
+
69
134
  describe "defining a default definition" do
70
-
135
+
71
136
  before :each do
72
137
  @request = mock("rails_request", :user_agent => 'Foo Fone')
73
138
  DiviningRod::Matchers.clear_definitions
74
139
  DiviningRod::Matchers.define do |map|
75
- map.default :unknown, :tags => [:html]
140
+ map.default :unknown, :tags => [:html]
76
141
  end
77
142
  end
78
-
143
+
79
144
  it "should use the default route if no other match is found" do
80
145
  DiviningRod::Matchers.definitions.first.matches?(@request).should be_true
81
146
  DiviningRod::Matchers.definitions.first.group.should eql(:unknown)
82
147
  end
83
-
148
+
84
149
  end
85
-
86
- 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.2.0
4
+ version: 0.3.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-17 00:00:00 -05:00
12
+ date: 2010-02-18 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency