lonely_coder 0.1.0 → 0.1.1
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.mdown +6 -0
- data/lib/lonely_coder/authentication.rb +2 -2
- data/lib/lonely_coder/magic_constants.rb +1 -1
- data/lib/lonely_coder/search.rb +132 -33
- data/lib/lonely_coder.rb +1 -1
- data/lonely_coder.gemspec +34 -0
- data/spec/cassettes/load_profile_from_search.yml +902 -0
- data/spec/cassettes/paginate_search_results_by_10.yml +1015 -0
- data/spec/cassettes/search_by_filters.yml +741 -1456
- data/spec/pagination_spec.rb +4 -2
- data/spec/paginator_spec.rb +44 -0
- data/spec/profile_spec.rb +7 -7
- data/spec/search_spec.rb +5 -5
- metadata +15 -11
- data/Gemfile.lock +0 -58
- data/spec/cassettes/paginate_search_results.yml +0 -879
data/README.mdown
CHANGED
@@ -40,6 +40,12 @@ How does it work?
|
|
40
40
|
-----------------------------
|
41
41
|
You'll need an OKCupid account (it's free) because most of the site is behind authentication. You can create a new connection to the site.
|
42
42
|
|
43
|
+
Install as a gem
|
44
|
+
|
45
|
+
gem install lonely_coder
|
46
|
+
|
47
|
+
Use your account
|
48
|
+
|
43
49
|
require 'lonely_coder'
|
44
50
|
okc = OKCupid.new('yourusername', 'yourpassword')
|
45
51
|
|
@@ -12,7 +12,7 @@ class OKCupid
|
|
12
12
|
username: username,
|
13
13
|
password: password
|
14
14
|
})
|
15
|
-
|
15
|
+
|
16
16
|
@success = browser.page.uri.path == '/home'
|
17
17
|
|
18
18
|
restore_default_parser(browser)
|
@@ -35,7 +35,7 @@ class OKCupid
|
|
35
35
|
# We're only using page uri to determine successful login, so
|
36
36
|
# there's not a lot of value in passing a body string to nokogiri
|
37
37
|
def initialize(uri = nil, response = nil, body = nil, code =nil)
|
38
|
-
super(uri, response,
|
38
|
+
super(uri, response, '', code)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
data/lib/lonely_coder/search.rb
CHANGED
@@ -22,23 +22,62 @@ class OKCupid
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def parse(options)
|
25
|
-
combine_ages(options)
|
26
25
|
check_for_required_options(options)
|
27
|
-
|
26
|
+
|
27
|
+
options[:age] = combine_ages(options)
|
28
|
+
|
28
29
|
|
29
30
|
@filters = []
|
31
|
+
@parameters = []
|
32
|
+
|
30
33
|
options.each do |name,value|
|
31
|
-
|
32
|
-
if OKCupid.const_defined?("#{name.to_s.camelize}Filter")
|
33
|
-
|
34
|
-
else
|
35
|
-
|
36
|
-
end
|
34
|
+
self.send("add_#{name}_option", value)
|
35
|
+
# if OKCupid.const_defined?("#{name.to_s.camelize}Filter")
|
36
|
+
# @filters << OKCupid.const_get("#{name.to_s.camelize}Filter").new(name, value)
|
37
|
+
# else
|
38
|
+
# @filters << Filter.new(name, value)
|
39
|
+
# end
|
37
40
|
end
|
38
41
|
end
|
39
42
|
|
40
|
-
def
|
41
|
-
@
|
43
|
+
def add_order_by_option(value)
|
44
|
+
@parameters << OrderByParameter.new(value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_last_login_option(value)
|
48
|
+
@filters << Filter.new('last_login', value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_location_option(value)
|
52
|
+
@parameters << LocationParameter.new(value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_radius_option(value)
|
56
|
+
@filters << RadiusFilter.new('radius', value)
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_require_photo_option(value)
|
60
|
+
@filters << RequirePhotoFilter.new('require_photo', value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_relationship_status_option(value)
|
64
|
+
@filters << Filter.new('relationship_status', value)
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_gentation_option(value)
|
68
|
+
@filters << Filter.new('gentation', value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_age_option(value)
|
72
|
+
@filters << AgeFilter.new('age', value)
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_pagination_option(value)
|
76
|
+
@parameters << @pagination = Paginator.new(value)
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_match_limit_option(value)
|
80
|
+
# TODO.
|
42
81
|
end
|
43
82
|
|
44
83
|
def check_for_required_options(options)
|
@@ -63,6 +102,10 @@ class OKCupid
|
|
63
102
|
# relationship_status 'single'
|
64
103
|
def defaults
|
65
104
|
{
|
105
|
+
:pagination => {
|
106
|
+
:page => 1,
|
107
|
+
:per_page => 10
|
108
|
+
},
|
66
109
|
:match_limit => 80,
|
67
110
|
:min_age => 18,
|
68
111
|
:max_age => 99,
|
@@ -78,24 +121,87 @@ class OKCupid
|
|
78
121
|
def results
|
79
122
|
return @results if @results
|
80
123
|
|
81
|
-
|
124
|
+
@browser.pluggable_parser.html = SearchPaginationParser
|
125
|
+
page = @browser.get(ajax_url)
|
126
|
+
|
82
127
|
@results = page.search('.match_row').collect do |node|
|
83
128
|
OKCupid::Profile.from_search_result(node)
|
84
129
|
end
|
130
|
+
|
131
|
+
@browser.pluggable_parser.html = Mechanize::Page
|
132
|
+
|
133
|
+
@results
|
134
|
+
end
|
135
|
+
|
136
|
+
# no idea what the following parameters do. They don't appear to have
|
137
|
+
# an effect:
|
138
|
+
# sort_type=0
|
139
|
+
# fromWhoOnline=0
|
140
|
+
# update_prefs=1
|
141
|
+
# using_saved_search=0
|
142
|
+
# mygender=m
|
143
|
+
# no idea what the following parameters do, but without them, the search
|
144
|
+
# behaves erratically
|
145
|
+
# &timekey=1
|
146
|
+
# &custom_search=0
|
147
|
+
def magic_params_not_truly_understood
|
148
|
+
"timekey=1&custom_search=0"
|
85
149
|
end
|
86
150
|
|
87
151
|
def load_next_page
|
88
152
|
@browser.pluggable_parser.html = SearchPaginationParser
|
89
|
-
|
153
|
+
|
154
|
+
page = @browser.get("#{ajax_url}&#{@pagination.next.to_param}")
|
155
|
+
|
90
156
|
@results += page.search('.match_row').collect do |node|
|
91
157
|
OKCupid::Profile.from_search_result(node)
|
92
158
|
end
|
159
|
+
|
93
160
|
@browser.pluggable_parser.html = Mechanize::Page
|
161
|
+
|
94
162
|
self
|
95
163
|
end
|
96
164
|
|
97
165
|
def url
|
98
|
-
|
166
|
+
"/match?#{filters_as_query}&#{parameters_as_query}&#{magic_params_not_truly_understood}"
|
167
|
+
end
|
168
|
+
|
169
|
+
def ajax_url
|
170
|
+
"#{url}&ajax_load=1"
|
171
|
+
end
|
172
|
+
|
173
|
+
def parameters_as_query
|
174
|
+
@parameters.collect {|param| param.to_param }.join('&')
|
175
|
+
end
|
176
|
+
|
177
|
+
def filters_as_query
|
178
|
+
filters.compact.to_enum(:each_with_index).map {|filter,index| filter.to_param(index+1)}.join('&')
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# used to create the pagination part of a search url:
|
183
|
+
# low=1&count=10&ajax_load=1
|
184
|
+
# where low is the start value
|
185
|
+
# count is the number of items per page
|
186
|
+
class Paginator
|
187
|
+
attr_reader :page, :per_page
|
188
|
+
|
189
|
+
def initialize(options)
|
190
|
+
@per_page = options[:per_page]
|
191
|
+
@page = options[:page]
|
192
|
+
end
|
193
|
+
|
194
|
+
def low
|
195
|
+
@low = ((@page - 1) * @per_page) + 1
|
196
|
+
end
|
197
|
+
|
198
|
+
def next
|
199
|
+
@page +=1
|
200
|
+
self
|
201
|
+
end
|
202
|
+
|
203
|
+
def to_param
|
204
|
+
"low=#{low}&count=#{@per_page}"
|
99
205
|
end
|
100
206
|
end
|
101
207
|
|
@@ -137,13 +243,12 @@ class OKCupid
|
|
137
243
|
end
|
138
244
|
end
|
139
245
|
|
140
|
-
class
|
141
|
-
def
|
142
|
-
|
246
|
+
class LocationParameter
|
247
|
+
def initialize(value)
|
248
|
+
@value = value
|
143
249
|
end
|
144
250
|
|
145
|
-
def to_param
|
146
|
-
|
251
|
+
def to_param
|
147
252
|
# to do: 'anywhere' needs to remove the radius filter
|
148
253
|
if @value.is_a?(String)
|
149
254
|
if @value.downcase == 'near me'
|
@@ -156,24 +261,18 @@ class OKCupid
|
|
156
261
|
end
|
157
262
|
end
|
158
263
|
end
|
159
|
-
|
160
|
-
class
|
161
|
-
def
|
264
|
+
|
265
|
+
class OrderByParameter
|
266
|
+
def initialize(value)
|
267
|
+
@value = value
|
268
|
+
@encoded_value = MagicNumbers::OrderBy[value.downcase]
|
269
|
+
end
|
270
|
+
|
271
|
+
def to_param
|
162
272
|
"matchOrderBy=#{@encoded_value}"
|
163
273
|
end
|
164
274
|
end
|
165
|
-
|
166
|
-
# we fake this by paginating results ourselves.
|
167
|
-
# class MatchLimitFilter < Filter
|
168
|
-
# def lookup(value)
|
169
|
-
# 'MATCH'
|
170
|
-
# end
|
171
|
-
#
|
172
|
-
# def to_param(n)
|
173
|
-
# nil
|
174
|
-
# end
|
175
|
-
# end
|
176
|
-
|
275
|
+
|
177
276
|
class RequirePhotoFilter < Filter
|
178
277
|
def lookup(value)
|
179
278
|
value ? 1 : 0
|
data/lib/lonely_coder.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = "lonely_coder"
|
4
|
+
s.version = '0.1.1'
|
5
|
+
s.platform = Gem::Platform::RUBY
|
6
|
+
s.authors = ["Trek Glowacki"]
|
7
|
+
s.email = ["trek.glowacki@gmail.com"]
|
8
|
+
s.homepage = "http://github.com/trek/lonely_coder"
|
9
|
+
s.summary = %q{A gem for interacting with OKCupid as if it had an API}
|
10
|
+
s.description = %q{A gem for interacting with OKCupid as if it had an API.}
|
11
|
+
|
12
|
+
s.add_dependency 'mechanize', '= 2.0.1'
|
13
|
+
s.add_dependency 'activesupport', '>= 3.2.1'
|
14
|
+
|
15
|
+
s.post_install_message = %q{
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
,d88b.d88b,
|
20
|
+
88888888888
|
21
|
+
`Y8888888Y'
|
22
|
+
`Y888Y'
|
23
|
+
`Y'
|
24
|
+
|
25
|
+
Good luck out there.
|
26
|
+
|
27
|
+
|
28
|
+
}
|
29
|
+
|
30
|
+
s.files = `git ls-files`.split("\n")
|
31
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
32
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
end
|