Skip to content
This repository was archived by the owner on Nov 23, 2021. It is now read-only.

Commit 011e6a9

Browse files
committed
Reorganized filter/parameter classes and added documentation.
1 parent 4ea4d3b commit 011e6a9

File tree

12 files changed

+233
-157
lines changed

12 files changed

+233
-157
lines changed

lib/lonely_coder.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@ def love(n=20)
3131

3232
require 'active_support/core_ext/string/inflections'
3333

34-
require 'lonely_coder/magic_constants'
3534
require 'lonely_coder/profile'
3635
require 'lonely_coder/search'
37-
require 'lonely_coder/search_pagination_parser'
3836
require 'lonely_coder/authentication'
3937
require 'lonely_coder/mailbox'

lib/lonely_coder/search.rb

Lines changed: 24 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
11
require 'uri'
22
require 'set'
33

4+
require 'lonely_coder/search/magic_constants'
5+
require 'lonely_coder/search/search_pagination_parser'
6+
require 'lonely_coder/search/options/filter'
7+
8+
# these are the included filters. See Filter class documentation for adding your own.
9+
require 'lonely_coder/search/options/age'
10+
require 'lonely_coder/search/options/ethnicity'
11+
require 'lonely_coder/search/options/order_by'
12+
require 'lonely_coder/search/options/location'
13+
require 'lonely_coder/search/options/paginator'
14+
require 'lonely_coder/search/options/radius'
15+
require 'lonely_coder/search/options/require_photo'
16+
417
class OKCupid
518
# Creates a new Search with the passed options to act as query parameters.
619
# A search will not trigger a query to OKCupid until `results` is called.
720
#
821
# @param [Hash] options a list of options for the search
9-
# @option options [Integer] :min_age (18) Minimum age to search for
10-
# @option options [Integer] :max_age (99) Maximum age to search for
22+
# @option options [Integer] :min_age (18) Minimum age to search for.
23+
# @option options [Integer] :max_age (99) Maximum age to search for.
24+
# @option options [String] :gentation Gentation is OKCupid's portmanteau for 'gender and orientation'.
25+
# Acceptable values are:
26+
# "girls who like guys", "guys who like girls", "girls who like girls",
27+
# "guys who like guys", "both who like bi guys", "both who like bi girls",
28+
# "straight girls only", "straight guys only", "gay girls only",
29+
# "gay guys only", "bi girls only", "bi guys only", "everybody"
30+
# this option is required.
31+
#
1132
# @option options [String] :order_by ('match %') The sort order of the search results.
1233
# Acceptable values are 'match %','friend %', 'enemy %',
1334
# 'special blend', 'join', and 'last login'.
@@ -24,7 +45,7 @@ class OKCupid
2445
#
2546
# @option options [true, false] :require_photo (true). Search for profiles that have photos
2647
# @option options [String] :relationship_status ('single'). Acceptable values are 'single', 'not single', 'any'
27-
# @return [Search] A Searhc without results loaded. To trigger a query against OKCupid call `results`
48+
# @return [Search] A Search without results loaded. To trigger a query against OKCupid call `results`
2849
def search(options={})
2950
Search.new(options, @browser)
3051
end
@@ -76,42 +97,6 @@ def parse(options)
7697
@timekey = 1
7798
end
7899

79-
def add_order_by_option(value)
80-
@parameters << OrderByParameter.new(value)
81-
end
82-
83-
def add_last_login_option(value)
84-
@filters << Filter.new('last_login', value)
85-
end
86-
87-
def add_location_option(value)
88-
@parameters << LocationParameter.new(value)
89-
end
90-
91-
def add_radius_option(value)
92-
@filters << RadiusFilter.new('radius', value)
93-
end
94-
95-
def add_require_photo_option(value)
96-
@filters << RequirePhotoFilter.new('require_photo', value)
97-
end
98-
99-
def add_relationship_status_option(value)
100-
@filters << Filter.new('relationship_status', value)
101-
end
102-
103-
def add_gentation_option(value)
104-
@filters << Filter.new('gentation', value)
105-
end
106-
107-
def add_age_option(value)
108-
@filters << AgeFilter.new('age', value)
109-
end
110-
111-
def add_pagination_option(value)
112-
@parameters << @pagination = Paginator.new(value)
113-
end
114-
115100
def check_for_required_options(options)
116101
raise(FilterError, 'gentation is a required option') unless options.has_key?(:gentation)
117102
end
@@ -219,120 +204,4 @@ def filters_as_query
219204
filters.compact.to_enum(:each_with_index).map {|filter,index| filter.to_param(index+1)}.join('&')
220205
end
221206
end
222-
223-
# used to create the pagination part of a search url:
224-
# low=1&count=10&ajax_load=1
225-
# where low is the start value
226-
# count is the number of items per page
227-
class Paginator
228-
attr_reader :page, :per_page
229-
230-
def initialize(options)
231-
@per_page = options[:per_page]
232-
@page = options[:page]
233-
end
234-
235-
def low
236-
@low = ((@page - 1) * @per_page) + 1
237-
end
238-
239-
def next
240-
@page +=1
241-
self
242-
end
243-
244-
def to_param
245-
"low=#{low}&count=#{@per_page}"
246-
end
247-
end
248-
249-
class Filter
250-
class NoSuchFilter < StandardError; end
251-
class BadValue < StandardError; end
252-
253-
attr_reader :name, :value, :code
254-
255-
def initialize(name, value)
256-
@code = MagicNumbers::Filters[name.to_s]
257-
raise(NoSuchFilter, name) unless @code
258-
259-
@name = name.to_s
260-
@value = value
261-
@encoded_value = lookup(@value)
262-
unless @encoded_value
263-
raise(BadValue, "#{@value.inspect} is not a possible value for #{@name}. Try one of #{allowed_values.map(&:inspect).join(', ')}")
264-
end
265-
end
266-
267-
def allowed_values
268-
MagicNumbers.const_get(@name.camelize).keys
269-
end
270-
271-
def lookup(value)
272-
MagicNumbers.const_get(@name.camelize)[value.downcase]
273-
end
274-
275-
def to_param(n)
276-
"filter#{n}=#{@code},#{@encoded_value}"
277-
end
278-
end
279-
280-
class EthnicityFilter < Filter
281-
def lookup(values)
282-
# lookup the race values and sum them. I think OKC is doing some kind of base2 math on them
283-
values.collect {|v| MagicNumbers::Ethnicity[v.downcase]}.inject(0, :+)
284-
end
285-
end
286-
287-
class LocationParameter
288-
def initialize(value)
289-
@value = value
290-
end
291-
292-
def to_param
293-
if @value.is_a?(String)
294-
if @value.downcase == 'near me'
295-
"locid=0"
296-
else
297-
"locid=#{Search.location_id_for(@value)}&lquery=#{URI.escape(@value)}"
298-
end
299-
else
300-
"locid=#{@value}"
301-
end
302-
end
303-
end
304-
305-
class OrderByParameter
306-
def initialize(value)
307-
@value = value
308-
@encoded_value = MagicNumbers::OrderBy[value.downcase]
309-
end
310-
311-
def to_param
312-
"matchOrderBy=#{@encoded_value}"
313-
end
314-
end
315-
316-
class RequirePhotoFilter < Filter
317-
def lookup(value)
318-
value ? 1 : 0
319-
end
320-
end
321-
322-
class RadiusFilter < Filter
323-
def lookup(value)
324-
value.nil? ? '' : value
325-
end
326-
327-
def to_param(n)
328-
return nil if @encoded_value === ''
329-
super
330-
end
331-
end
332-
333-
class AgeFilter < Filter
334-
def lookup(value)
335-
"#{value[0]},#{value[1]}"
336-
end
337-
end
338207
end
File renamed without changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class OKCupid
2+
class AgeFilter < Filter
3+
def lookup(value)
4+
"#{value[0]},#{value[1]}"
5+
end
6+
end
7+
8+
class Search
9+
def add_age_option(value)
10+
@filters << AgeFilter.new('age', value)
11+
end
12+
end
13+
end
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class OKCupid
2+
class EthnicityFilter < Filter
3+
def lookup(values)
4+
# lookup the race values and sum them. I think OKC is doing some kind of base2 math on them
5+
values.collect {|v| MagicNumbers::Ethnicity[v.downcase]}.inject(0, :+)
6+
end
7+
end
8+
9+
class Search
10+
def add_ethnicity_option(value)
11+
# implement
12+
end
13+
end
14+
end
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
class OKCupid
2+
# Filter instances are used to build the query parameters for a search on OKCupid.
3+
# OKCupid has specific coded values for many search values, you should check the magic_constants file
4+
# for a list. Not all of them have been implemented yet.
5+
#
6+
# Adding a Filter takes one of three forms:
7+
# 1) implementing a add_<filter_name>_option method on Search
8+
# that pushes a new named Filter to the @filters array for unmamed query parts
9+
#
10+
# 2) Subclassing Filter for filters that have atypical parameterization behavior.
11+
# where you'll implement a add_<filter_name>_option method on Search
12+
# and provide a custom class overriding `lookup` or `to_param` to create
13+
# a correct url query part.
14+
#
15+
# 3) Creating a new class to handle query parameters that are specifically named
16+
# These are refered to as "Parameters" to contrast them with "Filters" which
17+
# are parameterized in the "filterN=code,value" pattern (e.g. filter4=22,7).
18+
# Parameters are not numbered and have specific names, e.g. "loc_id=1234567"
19+
# You'll also implement a add_<filter_name>_option that adds an instance of this
20+
# class to the @parameters array (not the @filters array).
21+
#
22+
# See the included Filter and Parameter classes for ideas on how to structure these objects.
23+
#
24+
# OKCupid's query system is a bit obtuse and the details aren't published anywhere.
25+
# If you're implementing a new filter, you may need to spend some time figuring out
26+
# what data they expect to receive and the kinds of results it will return.
27+
class Filter
28+
class NoSuchFilter < StandardError; end
29+
class BadValue < StandardError; end
30+
31+
attr_reader :name, :value, :code
32+
33+
def initialize(name, value)
34+
@code = MagicNumbers::Filters[name.to_s]
35+
raise(NoSuchFilter, name) unless @code
36+
37+
@name = name.to_s
38+
@value = value
39+
@encoded_value = lookup(@value)
40+
unless @encoded_value
41+
raise(BadValue, "#{@value.inspect} is not a possible value for #{@name}. Try one of #{allowed_values.map(&:inspect).join(', ')}")
42+
end
43+
end
44+
45+
def allowed_values
46+
MagicNumbers.const_get(@name.camelize).keys
47+
end
48+
49+
def lookup(value)
50+
MagicNumbers.const_get(@name.camelize)[value.downcase]
51+
end
52+
53+
def to_param(n)
54+
"filter#{n}=#{@code},#{@encoded_value}"
55+
end
56+
end
57+
58+
# All filters that follow the base Filter pattern are exposed here through a
59+
# add_<filter_name>_option method. Custom filters and parameters are defined
60+
# in their own files and include the appropriate add_<option_name>_option method.
61+
class Search
62+
def add_relationship_status_option(value)
63+
@filters << Filter.new('relationship_status', value)
64+
end
65+
66+
def add_gentation_option(value)
67+
@filters << Filter.new('gentation', value)
68+
end
69+
70+
def add_last_login_option(value)
71+
@filters << Filter.new('last_login', value)
72+
end
73+
end
74+
end
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
class OKCupid
2+
class LocationParameter
3+
def initialize(value)
4+
@value = value
5+
end
6+
7+
def to_param
8+
if @value.is_a?(String)
9+
if @value.downcase == 'near me'
10+
"locid=0"
11+
else
12+
"locid=#{Search.location_id_for(@value)}&lquery=#{URI.escape(@value)}"
13+
end
14+
else
15+
"locid=#{@value}"
16+
end
17+
end
18+
end
19+
20+
class Search
21+
def add_location_option(value)
22+
@parameters << LocationParameter.new(value)
23+
end
24+
end
25+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class OKCupid
2+
class OrderByParameter
3+
def initialize(value)
4+
@value = value
5+
@encoded_value = MagicNumbers::OrderBy[value.downcase]
6+
end
7+
8+
def to_param
9+
"matchOrderBy=#{@encoded_value}"
10+
end
11+
end
12+
13+
# Reopen Search to accept order_by filters
14+
class Search
15+
def add_order_by_option(value)
16+
@parameters << OrderByParameter.new(value)
17+
end
18+
end
19+
end

0 commit comments

Comments
 (0)