divining_rod 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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