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 +40 -26
- data/VERSION +1 -1
- data/divining_rod.gemspec +2 -2
- data/lib/divining_rod.rb +42 -24
- data/spec/basic_spec.rb +89 -24
- metadata +2 -2
data/README.markdown
CHANGED
@@ -1,13 +1,6 @@
|
|
1
1
|
# Divining Rod
|
2
2
|
|
3
|
-
A tool to help format your sites mobile pages.
|
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
|
-
|
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.
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
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.
|
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.
|
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-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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-
|
12
|
+
date: 2010-02-18 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|