lonely_coder 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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, nil, code)
38
+ super(uri, response, '', code)
39
39
  end
40
40
  end
41
41
  end
@@ -66,7 +66,7 @@ class OKCupid
66
66
  # "v_looks" => 23,
67
67
  # "v_personality" => 25,
68
68
 
69
- # added by us
69
+ # filters
70
70
  'match_limit' => 'match_limit',
71
71
  'order_by' => 'order_by',
72
72
  'location' => 'location'
@@ -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
- remove_match_limit(options)
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
- @filters << OKCupid.const_get("#{name.to_s.camelize}Filter").new(name, value)
34
- else
35
- @filters << Filter.new(name, value)
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 remove_match_limit(options)
41
- @match_limit = options.delete(:match_limit)
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
- page = @browser.get(url)
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
- page = @browser.get("#{url}&low=11&count=10&ajax_load=1")
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
- '/match?' + filters.compact.to_enum(:each_with_index).map {|filter,index| filter.to_param(index+1)}.join('&')
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 LocationFilter < Filter
141
- def lookup(value)
142
- ''
246
+ class LocationParameter
247
+ def initialize(value)
248
+ @value = value
143
249
  end
144
250
 
145
- def to_param(n)
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 OrderByFilter < Filter
161
- def to_param(n)
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
@@ -11,7 +11,7 @@ require 'mechanize'
11
11
 
12
12
  class OKCupid
13
13
  BaseUrl = 'http://www.okcupid.com'
14
- VERSION = '0.1.0'
14
+ VERSION = '0.1.1'
15
15
 
16
16
  def initialize(username=nil, password=nil)
17
17
  @browser = Mechanize.new
@@ -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