quixoten-craigler 1.0.0 → 1.1.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/LICENSE +2 -0
- data/README.rdoc +22 -3
- data/Rakefile +2 -2
- data/VERSION.yml +2 -2
- data/craigler.gemspec +6 -3
- data/lib/craigler.rb +10 -4
- data/lib/craigler/constants.rb +4 -2
- data/lib/craigler/search.rb +29 -7
- data/test/craigler_search_test.rb +13 -1
- data/test/craigler_test.rb +26 -4
- data/test/test_helper.rb +8 -1
- metadata +4 -3
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,21 +1,40 @@
|
|
1
|
-
=
|
1
|
+
= Craigler
|
2
2
|
|
3
3
|
Search API for craigslist
|
4
4
|
|
5
5
|
== SYNOPSIS:
|
6
|
+
I couldn't decide which API I liked best, so you have two choices.
|
6
7
|
|
7
|
-
Craigler.search(:motorcycles, :in => [:utah, :nevada, :arizona], :for => 'Boulevard M50) do |item|
|
8
|
+
Craigler.search(:motorcycles, :in => [:utah, :nevada, :arizona], :for => 'Boulevard M50') do |item|
|
8
9
|
puts item.title
|
9
10
|
puts item.url
|
10
11
|
puts item.time
|
11
12
|
end
|
13
|
+
|
14
|
+
or
|
12
15
|
|
13
|
-
Craigler.find('Boulevard M50', :in =>
|
16
|
+
Craigler.find('Boulevard M50', :in => :california, :only => :motorcycles) do |item|
|
14
17
|
puts item.title
|
15
18
|
puts item.url
|
16
19
|
puts item.time
|
17
20
|
end
|
18
21
|
|
22
|
+
You can also create a search object to fetch the results later. When no location or category is given Craigler searches <tt>:all_for_sale_or_wanted</tt> in <tt>:anywhere</tt>
|
23
|
+
|
24
|
+
search = Craigler::Search.new('Yamaha')
|
25
|
+
search.results(:page_limit => 1)
|
26
|
+
|
27
|
+
Note that additional calls to <tt>search.results()</tt> will always return the same result set unless refresh is forced
|
28
|
+
search.results(:refresh => true)
|
29
|
+
|
30
|
+
=== Supported Categories
|
31
|
+
<tt>:all_for_sale_or_wanted</tt>, <tt>:art_and_crafts</tt>, <tt>:auto_parts</tt>, <tt>:baby_and_kid_stuff</tt>, <tt>:barter</tt>, <tt>:bicycles</tt>, <tt>:boats</tt>, <tt>:books</tt>, <tt>:business</tt>, <tt>:cars_and_trucks</tt>, <tt>:clothing</tt>, <tt>:collectibles</tt>, <tt>:community</tt>, <tt>:computers_and_tech</tt>, <tt>:electronics</tt>, <tt>:event</tt>, <tt>:farm_and_garden</tt>, <tt>:free_stuff</tt>, <tt>:furniture</tt>, <tt>:games_and_toys</tt>, <tt>:garage_sales</tt>, <tt>:general</tt>, <tt>:gigs</tt>, <tt>:household</tt>, <tt>:housing</tt>, <tt>:items_wanted</tt>, <tt>:jewelry</tt>, <tt>:jobs</tt>, <tt>:materials</tt>, <tt>:media</tt>, <tt>:motorcycles</tt>, <tt>:musical_instruments</tt>, <tt>:personals</tt>, <tt>:photo_and_video</tt>, <tt>:recreational_vehicles</tt>, <tt>:resume</tt>, <tt>:services_offered</tt>, <tt>:sporting_goods</tt>, <tt>:tickets</tt>, <tt>:tools</tt>
|
32
|
+
|
33
|
+
=== Supported Locations
|
34
|
+
<tt>:alaska</tt>, <tt>:arizona</tt>, <tt>:arkansas</tt>, <tt>:california</tt>, <tt>:colorado</tt>, <tt>:connecticut</tt>, <tt>:delaware</tt>, <tt>:dc</tt>, <tt>:florida</tt>, <tt>:georgia</tt>, <tt>:hawaii</tt>, <tt>:idaho</tt>, <tt>:illinois</tt>, <tt>:indiana</tt>, <tt>:iowa</tt>, <tt>:kansas</tt>, <tt>:kentucky</tt>, <tt>:louisiana</tt>, <tt>:maine</tt>, <tt>:maryland</tt>, <tt>:mass</tt>, <tt>:michigan</tt>, <tt>:minnesota</tt>, <tt>:mississippi</tt>, <tt>:missouri</tt>, <tt>:montana</tt>, <tt>:nebraska</tt>, <tt>:nevada</tt>, <tt>:n_hampshire</tt>, <tt>:new_jersey</tt>, <tt>:new_mexico</tt>, <tt>:new_york</tt>, <tt>:n_carolina</tt>, <tt>:north_dakota</tt>, <tt>:ohio</tt>, <tt>:oklahoma</tt>, <tt>:oregon</tt>, <tt>:pennsylvania</tt>, <tt>:rhode_island</tt>, <tt>:s_carolina</tt>, <tt>:south_dakota</tt>, <tt>:tennessee</tt>, <tt>:texas</tt>, <tt>:utah</tt>, <tt>:vermont</tt>, <tt>:virginia</tt>, <tt>:washington</tt>, <tt>:west_virginia</tt> <tt>:wisconsin</tt>, <tt>:wyoming</tt>
|
35
|
+
|
36
|
+
Or use <tt>:anywhere</tt> to search all supported locations.
|
37
|
+
|
19
38
|
== REQUIREMENTS:
|
20
39
|
|
21
40
|
* Hpricot
|
data/Rakefile
CHANGED
@@ -49,8 +49,8 @@ Rake::RDocTask.new do |rdoc|
|
|
49
49
|
end
|
50
50
|
|
51
51
|
rdoc.rdoc_dir = 'rdoc'
|
52
|
-
rdoc.title = "
|
53
|
-
rdoc.rdoc_files.include('README
|
52
|
+
rdoc.title = "Craigler #{version}"
|
53
|
+
rdoc.rdoc_files.include('README.rdoc', 'LICENSE')
|
54
54
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
55
|
end
|
56
56
|
|
data/VERSION.yml
CHANGED
data/craigler.gemspec
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
1
4
|
# -*- encoding: utf-8 -*-
|
2
5
|
|
3
6
|
Gem::Specification.new do |s|
|
4
7
|
s.name = %q{craigler}
|
5
|
-
s.version = "1.
|
8
|
+
s.version = "1.1.0"
|
6
9
|
|
7
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
11
|
s.authors = ["Devin Christensen"]
|
9
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-08-11}
|
10
13
|
s.email = %q{quixoten@gmail.com}
|
11
14
|
s.extra_rdoc_files = [
|
12
15
|
"LICENSE",
|
@@ -30,7 +33,7 @@ Gem::Specification.new do |s|
|
|
30
33
|
s.homepage = %q{http://github.com/quixoten/craigler}
|
31
34
|
s.rdoc_options = ["--charset=UTF-8"]
|
32
35
|
s.require_paths = ["lib"]
|
33
|
-
s.rubygems_version = %q{1.3.
|
36
|
+
s.rubygems_version = %q{1.3.5}
|
34
37
|
s.summary = %q{Search API for craigslist}
|
35
38
|
s.test_files = [
|
36
39
|
"test/craigler_search_test.rb",
|
data/lib/craigler.rb
CHANGED
@@ -5,20 +5,26 @@ require 'craigler/constants'
|
|
5
5
|
require 'craigler/search'
|
6
6
|
|
7
7
|
module Craigler
|
8
|
-
VERSION = '0.1.0'
|
9
|
-
|
10
8
|
class CraiglerError < StandardError; end
|
11
9
|
class InvalidCategory < CraiglerError; end
|
12
10
|
class InvalidSearchTerm < CraiglerError; end
|
13
11
|
class InvalidLocation < CraiglerError; end
|
14
12
|
|
15
13
|
class << self
|
14
|
+
# Interface to Search that may or may not be more readable
|
16
15
|
def search(category, options = {})
|
17
|
-
|
16
|
+
results = Search.new(options[:for], :in => (options[:in] || :anywhere), :only => category).results()
|
17
|
+
results.each {|result| yield(result) } if block_given?
|
18
|
+
results
|
18
19
|
end
|
19
20
|
|
21
|
+
# Interface to Search that somewhat mimics ActiveRecord#find
|
22
|
+
#
|
23
|
+
# Supports all the options of Search#new
|
20
24
|
def find(search_term, options = {})
|
21
|
-
|
25
|
+
results = Search.new(search_term, options).results()
|
26
|
+
results.each {|result| yield(result) } if block_given?
|
27
|
+
results
|
22
28
|
end
|
23
29
|
end
|
24
30
|
end
|
data/lib/craigler/constants.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Craigler
|
2
|
+
RESULTS_PER_PAGE = 25 # :nodoc:
|
3
|
+
|
2
4
|
LOCATIONS = {
|
3
5
|
:alabama => ['http://auburn.craigslist.org/','http://bham.craigslist.org/','http://columbusga.craigslist.org/','http://dothan.craigslist.org/','http://shoals.craigslist.org/','http://gadsden.craigslist.org/','http://huntsville.craigslist.org/','http://mobile.craigslist.org/','http://montgomery.craigslist.org/','http://tuscaloosa.craigslist.org/'],
|
4
6
|
:alaska => ['http://anchorage.craigslist.org/'],
|
@@ -51,7 +53,7 @@ module Craigler
|
|
51
53
|
:west_virginia => ['http://charlestonwv.craigslist.org/','http://huntington.craigslist.org/','http://martinsburg.craigslist.org/','http://morgantown.craigslist.org/','http://parkersburg.craigslist.org/','http://wv.craigslist.org/','http://wheeling.craigslist.org/'],
|
52
54
|
:wisconsin => ['http://appleton.craigslist.org/','http://duluth.craigslist.org/','http://eauclaire.craigslist.org/','http://greenbay.craigslist.org/','http://janesville.craigslist.org/','http://racine.craigslist.org/','http://lacrosse.craigslist.org/','http://madison.craigslist.org/','http://milwaukee.craigslist.org/','http://sheboygan.craigslist.org/','http://wausau.craigslist.org/'],
|
53
55
|
:wyoming => ['http://wyoming.craigslist.org/']
|
54
|
-
}
|
56
|
+
} # :nodoc:
|
55
57
|
|
56
58
|
CATEGORIES = {
|
57
59
|
:community => 'ccc',
|
@@ -94,5 +96,5 @@ module Craigler
|
|
94
96
|
:personals => 'ppp',
|
95
97
|
:resume => 'res',
|
96
98
|
:services_offered => 'bbb'
|
97
|
-
}
|
99
|
+
} # :nodoc:
|
98
100
|
end
|
data/lib/craigler/search.rb
CHANGED
@@ -6,6 +6,13 @@ module Craigler
|
|
6
6
|
|
7
7
|
attr_reader :search_term, :categories, :locations
|
8
8
|
|
9
|
+
# Creates a wrapper object for a craigslist search
|
10
|
+
#
|
11
|
+
# === Options
|
12
|
+
# [:in]
|
13
|
+
# Specifies the location(s) to search in. Defaults to <tt>:anywhere</tt>.
|
14
|
+
# [:only]
|
15
|
+
# Specifies the category or categories to search in. Defaults to <tt>:all_for_sale_or_wanted</tt>
|
9
16
|
def initialize(search_term, options = {})
|
10
17
|
raise InvalidSearchTerm if search_term.nil? || search_term == ''
|
11
18
|
|
@@ -14,15 +21,30 @@ module Craigler
|
|
14
21
|
_parse_options(options)
|
15
22
|
end
|
16
23
|
|
17
|
-
|
18
|
-
|
24
|
+
# Returns the results of the search. If this is the first time
|
25
|
+
# calling #results then they will be fetched over the internet and cached in the search object.
|
26
|
+
#
|
27
|
+
# === Options
|
28
|
+
# [:page_limit]
|
29
|
+
# Maximum number of pages to fetch results from. Defaults to <tt>4</tt>.
|
30
|
+
# <b>Note:</b> A location may, and often does, have more than one searchable
|
31
|
+
# url assciated with it, e.g., {California}[http://geo.craigslist.org/iso/us/ca]. Because
|
32
|
+
# <tt>:page_limit</tt> is applied seperately to each url within the location, searching <tt>:in => :california</tt>
|
33
|
+
# with a <tt>:page_limit => 4</tt> could potentially make up to 100 page requests.</em>
|
34
|
+
# [:refresh]
|
35
|
+
# Set to <tt>true</tt> to force an update across the internet.
|
36
|
+
def results(options = {})
|
37
|
+
options = { :page_limit => 4, :refresh => false }.merge(options)
|
38
|
+
return @results unless @results.nil? || options[:refresh]
|
39
|
+
|
40
|
+
@results = []
|
41
|
+
last_page = options[:page_limit] - 1 # pages start at 0
|
19
42
|
|
20
|
-
@results = []
|
21
43
|
_for_each_locations_search_url() do |location, url|
|
22
|
-
(0..
|
23
|
-
|
24
|
-
@results.push(*
|
25
|
-
break
|
44
|
+
(0..last_page).each do |page|
|
45
|
+
results = _extract_items_from_url(location, "#{url}&s=#{page*25}")
|
46
|
+
@results.push(*results)
|
47
|
+
break if results.size < RESULTS_PER_PAGE
|
26
48
|
end
|
27
49
|
end
|
28
50
|
|
@@ -30,6 +30,12 @@ class CraiglerSearchTest < Test::Unit::TestCase
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
should "use a default category of :all_for_sale_or_wanted" do
|
34
|
+
search = Craigler::Search.new('Buell', :in => :utah)
|
35
|
+
assert(search.categories == [:all_for_sale_or_wanted],
|
36
|
+
"category was [:#{search.categories.join(", :")}] but should have been [:all_for_sale_or_wanted]")
|
37
|
+
end
|
38
|
+
|
33
39
|
should "require that the location is valid" do
|
34
40
|
assert_raises(Craigler::InvalidLocation) do
|
35
41
|
Craigler::Search.new('Honda Nighthawk', :in => :invalid)
|
@@ -45,7 +51,7 @@ class CraiglerSearchTest < Test::Unit::TestCase
|
|
45
51
|
|
46
52
|
context "fetching search results" do
|
47
53
|
setup do
|
48
|
-
@search = Craigler::Search.new('Honda
|
54
|
+
@search = Craigler::Search.new('Honda', :in => :utah, :only => :motorcycles, :page_limit => 1)
|
49
55
|
end
|
50
56
|
|
51
57
|
should "return an array of hashes" do
|
@@ -54,5 +60,11 @@ class CraiglerSearchTest < Test::Unit::TestCase
|
|
54
60
|
assert(results.size > 0, "No results were returned")
|
55
61
|
assert(results.inject(true) {|t,r| t && r.is_a?(Hash)})
|
56
62
|
end
|
63
|
+
|
64
|
+
should "allow us to limit the number of pages searched" do
|
65
|
+
one_page_count = @search.results(:page_limit => 1).size
|
66
|
+
two_page_count = @search.results(:page_limit => 2, :refresh => true).size
|
67
|
+
assert(one_page_count < two_page_count, "#{one_page_count} is not less than #{two_page_count}")
|
68
|
+
end
|
57
69
|
end
|
58
70
|
end
|
data/test/craigler_test.rb
CHANGED
@@ -1,11 +1,33 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class CraiglerTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
4
|
+
context "Search interface" do
|
5
|
+
should "respond to search" do
|
6
|
+
assert_respond_to(Craigler, :search)
|
7
|
+
end
|
8
|
+
|
9
|
+
should "yield results to a block if given" do
|
10
|
+
yielded = false
|
11
|
+
Craigler::search(:motorcycles, :in => :utah, :for => 'Yamaha', :page_limit => 1) do
|
12
|
+
yielded = true; break;
|
13
|
+
end
|
14
|
+
|
15
|
+
assert(yielded, "results were never yielded to the block")
|
16
|
+
end
|
6
17
|
end
|
7
18
|
|
8
|
-
|
9
|
-
|
19
|
+
context "Find interface" do
|
20
|
+
should "respond to find" do
|
21
|
+
assert_respond_to(Craigler, :find)
|
22
|
+
end
|
23
|
+
|
24
|
+
should "yield results to a block if given" do
|
25
|
+
yielded = false
|
26
|
+
Craigler::find('Yamaha', :in => :utah, :only => :motorcycles, :page_limit => 1) do
|
27
|
+
yielded = true; break;
|
28
|
+
end
|
29
|
+
|
30
|
+
assert(yielded, "results were never yielded to the block")
|
31
|
+
end
|
10
32
|
end
|
11
33
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'test/unit'
|
3
3
|
require 'shoulda'
|
4
|
+
require 'ruby-debug'
|
4
5
|
|
5
6
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
7
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
8
|
+
|
7
9
|
require 'craigler'
|
8
10
|
|
9
|
-
|
11
|
+
module Craigler
|
12
|
+
class Search
|
13
|
+
def open(*args)
|
14
|
+
@@results_page ||= Kernel::open("http://saltlakecity.craigslist.org/search/sss?query=Honda&format=rss&s=0").read()
|
15
|
+
end
|
16
|
+
end
|
10
17
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quixoten-craigler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Devin Christensen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-08-11 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -38,6 +38,7 @@ files:
|
|
38
38
|
- test/test_helper.rb
|
39
39
|
has_rdoc: false
|
40
40
|
homepage: http://github.com/quixoten/craigler
|
41
|
+
licenses:
|
41
42
|
post_install_message:
|
42
43
|
rdoc_options:
|
43
44
|
- --charset=UTF-8
|
@@ -58,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
59
|
requirements: []
|
59
60
|
|
60
61
|
rubyforge_project:
|
61
|
-
rubygems_version: 1.
|
62
|
+
rubygems_version: 1.3.5
|
62
63
|
signing_key:
|
63
64
|
specification_version: 3
|
64
65
|
summary: Search API for craigslist
|