avvo_api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +31 -0
- data/README.rdoc +63 -0
- data/Rakefile +19 -0
- data/avvo_api.gemspec +25 -0
- data/examples/avvo_cli.rb +74 -0
- data/lib/avvo_api.rb +28 -0
- data/lib/avvo_api/address.rb +35 -0
- data/lib/avvo_api/advanced_training.rb +35 -0
- data/lib/avvo_api/base.rb +18 -0
- data/lib/avvo_api/doctor.rb +22 -0
- data/lib/avvo_api/headshot.rb +20 -0
- data/lib/avvo_api/language.rb +16 -0
- data/lib/avvo_api/lawyer.rb +20 -0
- data/lib/avvo_api/phone.rb +37 -0
- data/lib/avvo_api/professional_methods.rb +52 -0
- data/lib/avvo_api/review.rb +21 -0
- data/lib/avvo_api/school.rb +18 -0
- data/lib/avvo_api/specialty.rb +19 -0
- data/lib/avvo_api/version.rb +3 -0
- data/test/test_helper.rb +14 -0
- data/test/unit/address_test.rb +31 -0
- data/test/unit/advanced_training_test.rb +11 -0
- data/test/unit/base_test.rb +135 -0
- data/test/unit/doctor_test.rb +46 -0
- data/test/unit/headshot_test.rb +46 -0
- data/test/unit/language_test.rb +14 -0
- data/test/unit/lawyer_test.rb +170 -0
- data/test/unit/phone_test.rb +22 -0
- data/test/unit/review_test.rb +14 -0
- data/test/unit/school_test.rb +14 -0
- data/test/unit/specialty_test.rb +14 -0
- metadata +154 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
avvo_api (0.1.0)
|
5
|
+
reactive_resource (~> 0.5.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activeresource (2.3.10)
|
11
|
+
activesupport (= 2.3.10)
|
12
|
+
activesupport (2.3.10)
|
13
|
+
addressable (2.2.2)
|
14
|
+
crack (0.1.8)
|
15
|
+
rake (0.8.7)
|
16
|
+
reactive_resource (0.5.0)
|
17
|
+
activeresource (~> 2.3.10)
|
18
|
+
shoulda (2.11.3)
|
19
|
+
webmock (1.6.2)
|
20
|
+
addressable (>= 2.2.2)
|
21
|
+
crack (>= 0.1.7)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
avvo_api!
|
28
|
+
rake
|
29
|
+
reactive_resource (~> 0.5.0)
|
30
|
+
shoulda (~> 2.11.3)
|
31
|
+
webmock (~> 1.6.1)
|
data/README.rdoc
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
= Avvo API Client
|
2
|
+
|
3
|
+
This gem provides an
|
4
|
+
{ActiveResource}[http://api.rubyonrails.org/classes/ActiveResource/Base.html]-based
|
5
|
+
client to information on {Avvo}[http://www.avvo.com], a directory of lawyers and loctors.
|
6
|
+
|
7
|
+
== Requirements
|
8
|
+
|
9
|
+
Apart from the gems installed as dependencies, this gem requires an
|
10
|
+
account on Avvo associated with an API key. Visit the {API
|
11
|
+
Documentation}[http://api.avvo.com] for details.
|
12
|
+
|
13
|
+
== Usage
|
14
|
+
|
15
|
+
Somewhere during your app's initialization, you should include the gem
|
16
|
+
and set it up with your Avvo credentials:
|
17
|
+
|
18
|
+
require 'avvo_api'
|
19
|
+
AvvoApi.setup('user@avvo.com', 'password')
|
20
|
+
|
21
|
+
For the most part, the models supplied by this gem should act like
|
22
|
+
ActiveRecord models. These models parallel the resources listed on
|
23
|
+
http://api.avvo.com, and everything accessible from the Avvo API is
|
24
|
+
accessible using this gem.
|
25
|
+
|
26
|
+
== Examples
|
27
|
+
|
28
|
+
Details about the specific information returned by these calls can be
|
29
|
+
found in the documentation at http://api.avvo.com. An example of using
|
30
|
+
the API in a command-line program can be found in the +examples+
|
31
|
+
subdirectory.
|
32
|
+
|
33
|
+
=== Find a lawyer with a known ID
|
34
|
+
|
35
|
+
l = AvvoApi::Lawyer.find(28995)
|
36
|
+
|
37
|
+
=== Find a lawyer based on known attributes, like email, zip code, etc.
|
38
|
+
|
39
|
+
l = AvvoApi::Lawyer.resolve(:name => 'Mark Britton', :zip_code => '98101')
|
40
|
+
|
41
|
+
=== Search for lawyers matching a keyword in a specific location
|
42
|
+
|
43
|
+
AvvoApi::Lawyer.search(:q => 'criminal defense', :loc => 'seattle')
|
44
|
+
|
45
|
+
=== Retrieve the headshot URL for a lawyer
|
46
|
+
|
47
|
+
AvvoApi::Lawyer.find(28995).headshot.headshot_url
|
48
|
+
|
49
|
+
or
|
50
|
+
|
51
|
+
AvvoApi::Headshot.find(:one, :params => {:lawyer_id => 28995}).headshot_url
|
52
|
+
|
53
|
+
=== Getting a list of addresses for a doctor
|
54
|
+
|
55
|
+
addresses = AvvoApi::Doctor.find(1).addresses
|
56
|
+
|
57
|
+
or
|
58
|
+
|
59
|
+
addresses = AvvoApi::Address.find(:all, :params => {:doctor_id => doctor.id})
|
60
|
+
|
61
|
+
=== Getting the main address for a doctor
|
62
|
+
|
63
|
+
main_address = AvvoApi::Address.main(:doctor_id => doctor.id)
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
task :default => :test
|
7
|
+
task :build => :test
|
8
|
+
|
9
|
+
Rake::TestTask.new do |t|
|
10
|
+
t.libs << "test"
|
11
|
+
t.test_files = FileList['test/**/*_test.rb']
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
Rake::RDocTask.new do |rd|
|
16
|
+
rd.main = "README.rdoc"
|
17
|
+
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
18
|
+
rd.rdoc_dir = 'doc'
|
19
|
+
end
|
data/avvo_api.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "avvo_api/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "avvo_api"
|
7
|
+
s.version = AvvoApi::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Justin Weiss"]
|
10
|
+
s.email = ["jweiss@avvo.com"]
|
11
|
+
s.homepage = "http://api.avvo.com"
|
12
|
+
s.summary = %q{An ActiveResource client to the Avvo API}
|
13
|
+
s.description = %q{An ActiveResource client to the Avvo API}
|
14
|
+
|
15
|
+
s.add_dependency "reactive_resource", '~> 0.5.0'
|
16
|
+
s.add_development_dependency "shoulda", '~> 2.11.3'
|
17
|
+
s.add_development_dependency "webmock", '~> 1.6.1'
|
18
|
+
|
19
|
+
s.rubyforge_project = "avvo_api"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# A command-line interface to the Avvo API, as an example of how the
|
4
|
+
# API can be used. Before using the API, you must create a YAML file
|
5
|
+
# in ~/.avvo containing your email and password.
|
6
|
+
require 'optparse'
|
7
|
+
require 'avvo_api'
|
8
|
+
|
9
|
+
professional_klass = nil
|
10
|
+
professional_param = nil
|
11
|
+
|
12
|
+
opts = OptionParser.new("Usage: avvo_cli.rb [options] ID")
|
13
|
+
opts.on("-l", "--lawyer", "Get details about a lawyer") { professional_klass = AvvoApi::Lawyer; professional_param = :lawyer_id }
|
14
|
+
opts.on("-d", "--doctor", "Get details about a doctor") { professional_klass = AvvoApi::Doctor; professional_param = :doctor_id }
|
15
|
+
rest = opts.parse ARGV
|
16
|
+
|
17
|
+
if !professional_klass
|
18
|
+
puts "You must specify either --lawyer or --doctor"
|
19
|
+
puts opts
|
20
|
+
exit(1)
|
21
|
+
elsif !rest.first
|
22
|
+
puts "You must specify the ID of the professional you are looking for"
|
23
|
+
puts opts
|
24
|
+
exit(1)
|
25
|
+
else
|
26
|
+
begin
|
27
|
+
config = YAML.load(File.read(File.expand_path("~/.avvo")))
|
28
|
+
rescue
|
29
|
+
puts "Please put your Avvo API credentials in ~/.avvo. This is a simple yaml file, which should look like:
|
30
|
+
email: email@domain.com
|
31
|
+
password: your_avvo_password"
|
32
|
+
exit(1)
|
33
|
+
end
|
34
|
+
AvvoApi.setup(config["email"], config["password"])
|
35
|
+
AvvoApi::Base.site = 'http://localhost.local:3000'
|
36
|
+
|
37
|
+
professional = professional_klass.find(rest.first)
|
38
|
+
|
39
|
+
address = AvvoApi::Address.main(professional_param => professional.id)
|
40
|
+
phones = address.phones
|
41
|
+
specialties = professional.specialties
|
42
|
+
reviews = professional.reviews
|
43
|
+
|
44
|
+
format = "%12s %s\n"
|
45
|
+
puts
|
46
|
+
printf format, "ID:", professional.id
|
47
|
+
printf format, "Name:", [professional.firstname, professional.middlename, professional.lastname].join(' ')
|
48
|
+
printf format, "Website:", professional.website_url if professional.website_url
|
49
|
+
printf format, "Profile URL:", professional.profile_url
|
50
|
+
|
51
|
+
printf format, "Address:", address.address_line1
|
52
|
+
printf format, "", address.address_line2 if address.address_line2
|
53
|
+
printf format, "", address.city + ", " + address.state + " " + address.postal_code
|
54
|
+
|
55
|
+
phones.each do |phone|
|
56
|
+
printf format, "#{phone.phone_type}:", phone.phone_number
|
57
|
+
end
|
58
|
+
|
59
|
+
specialties.each_with_index do |specialty, i|
|
60
|
+
header = i == 0 ? "Specialties:" : ""
|
61
|
+
printf format, header, "#{specialty.specialty_name.strip} (#{specialty.specialty_percent}%)"
|
62
|
+
end
|
63
|
+
|
64
|
+
puts
|
65
|
+
printf format, "Reviews ", ''
|
66
|
+
reviews.each do |review|
|
67
|
+
printf format, "Rating:", review.overall_rating
|
68
|
+
printf format, "Title:", review.title
|
69
|
+
printf format, "URL:", review.url
|
70
|
+
printf format, "By:", review.posted_by
|
71
|
+
puts
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/lib/avvo_api.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'avvo_api/base'
|
2
|
+
require 'avvo_api/professional_methods'
|
3
|
+
|
4
|
+
# The Avvo API Client. All API models live in this module.
|
5
|
+
module AvvoApi
|
6
|
+
|
7
|
+
autoload :Lawyer, 'avvo_api/lawyer'
|
8
|
+
autoload :Doctor, 'avvo_api/doctor'
|
9
|
+
autoload :School, 'avvo_api/school'
|
10
|
+
autoload :Address, 'avvo_api/address'
|
11
|
+
autoload :Phone, 'avvo_api/phone'
|
12
|
+
autoload :Language, 'avvo_api/language'
|
13
|
+
autoload :Specialty, 'avvo_api/specialty'
|
14
|
+
autoload :Headshot, 'avvo_api/headshot'
|
15
|
+
autoload :AdvancedTraining, 'avvo_api/advanced_training'
|
16
|
+
autoload :Review, 'avvo_api/review'
|
17
|
+
|
18
|
+
# Tells this client to use +email+ and +password+ to authenticate to
|
19
|
+
# the Avvo API.
|
20
|
+
def self.setup(email, password)
|
21
|
+
AvvoApi::Base.password = password
|
22
|
+
AvvoApi::Base.user = email
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Post parameters as <tt>{:lawyer => {...params...}}</tt> so the server
|
27
|
+
# can separate the object's params from the request params
|
28
|
+
ActiveResource::Base.include_root_in_json = true
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Represents an address. One of the following attributes MUST
|
2
|
+
# be set when using this model:
|
3
|
+
#
|
4
|
+
# * doctor_id
|
5
|
+
# * lawyer_id
|
6
|
+
#
|
7
|
+
# This model has the following attributes:
|
8
|
+
#
|
9
|
+
# * id
|
10
|
+
# * address_line1
|
11
|
+
# * address_line2
|
12
|
+
# * city
|
13
|
+
# * state
|
14
|
+
# * postal_code
|
15
|
+
# * latitude
|
16
|
+
# * longitude
|
17
|
+
#
|
18
|
+
class AvvoApi::Address < AvvoApi::Base
|
19
|
+
belongs_to :lawyer
|
20
|
+
belongs_to :doctor
|
21
|
+
has_many :phones
|
22
|
+
|
23
|
+
# Returns the 'main' address associated with the passed in
|
24
|
+
# professional. This is usually the address you want to
|
25
|
+
# use. +params+ is a hash of <tt>{:lawyer_id => lawyer.id}</tt> or
|
26
|
+
# <tt>{:doctor_id => doctor.id}</tt>
|
27
|
+
def self.main(params)
|
28
|
+
response = self.get(:main, params)
|
29
|
+
if response && response["id"]
|
30
|
+
new(params.merge(response))
|
31
|
+
elsif response && response["address"]
|
32
|
+
new(params.merge(response["address"]))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Constants representing the possible values of the
|
2
|
+
# advanced_training_type_id parameter of AvvoApi::AdvancedTraining
|
3
|
+
module AvvoApi::AdvancedTrainingType
|
4
|
+
|
5
|
+
# Unknown training type
|
6
|
+
UNKNOWN = 1
|
7
|
+
|
8
|
+
# Represents an internship
|
9
|
+
INTERNSHIP = 2
|
10
|
+
|
11
|
+
# Represents a residency
|
12
|
+
RESIDENCY = 3
|
13
|
+
|
14
|
+
# Represents a fellowship
|
15
|
+
FELLOWSHIP = 4
|
16
|
+
end
|
17
|
+
|
18
|
+
# Represents advanced training, like residencies, for doctors. This
|
19
|
+
# model is only applicable to doctors. The following attributes MUST
|
20
|
+
# be set when using this model:
|
21
|
+
#
|
22
|
+
# * doctor_id
|
23
|
+
#
|
24
|
+
# This model has the following attributes:
|
25
|
+
#
|
26
|
+
# * id - The model's id
|
27
|
+
# * advanced_training_type_id - an AvvoApi::AdvancedTrainingType constant
|
28
|
+
# * specialty_name - The name of the specialty this advanced training is in
|
29
|
+
# * hospital_name - The normalized name of the hospital. This will be
|
30
|
+
# resolved by Avvo when it is set by this client.
|
31
|
+
# * graduation_date - The date this training was completed
|
32
|
+
#
|
33
|
+
class AvvoApi::AdvancedTraining < AvvoApi::Base
|
34
|
+
belongs_to :doctor
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'reactive_resource'
|
2
|
+
|
3
|
+
|
4
|
+
module AvvoApi
|
5
|
+
# The class that all AvvoApi resources inherit from. This sets up the
|
6
|
+
# base URL and URL structure that the rest of the models use to hit
|
7
|
+
# Avvo.
|
8
|
+
class Base < ReactiveResource::Base
|
9
|
+
|
10
|
+
# The current version of the Avvo API
|
11
|
+
API_VERSION = 1
|
12
|
+
|
13
|
+
self.site = "https://api.avvo.com/"
|
14
|
+
self.prefix = "/api/#{API_VERSION}/"
|
15
|
+
self.format = :json
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Represents a doctor on Avvo. Attributes include:
|
2
|
+
#
|
3
|
+
# * id: The id of this doctor
|
4
|
+
# * firstname: the first name of this doctor
|
5
|
+
# * middlename: the middle name of this doctor
|
6
|
+
# * lastname: the last name of this doctor
|
7
|
+
# * suffix: the suffix of the doctor's name
|
8
|
+
# * avvo_rating: The doctor's Avvo Rating, from 0.0 to 10.0
|
9
|
+
# * email_address
|
10
|
+
# * website_url
|
11
|
+
# * profile_url
|
12
|
+
#
|
13
|
+
class AvvoApi::Doctor < AvvoApi::Base
|
14
|
+
has_many :addresses
|
15
|
+
has_many :reviews
|
16
|
+
has_many :schools
|
17
|
+
has_many :languages
|
18
|
+
has_many :specialties
|
19
|
+
has_many :advanced_trainings
|
20
|
+
has_one :headshot
|
21
|
+
include AvvoApi::ProfessionalMethods
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Represents a professional's headshot. Each professional only has one
|
2
|
+
# headshot, so finding a headshot should happen with the following call:
|
3
|
+
#
|
4
|
+
# AvvoApi::Headshot.find(:one, :lawyer_id => l.id)
|
5
|
+
#
|
6
|
+
# When using this model, one of the following attributes MUST be set:
|
7
|
+
#
|
8
|
+
# * doctor_id
|
9
|
+
# * lawyer_id
|
10
|
+
#
|
11
|
+
# This model has the following attribute:
|
12
|
+
#
|
13
|
+
# * headshot_url: The url to the standard-size headshot.
|
14
|
+
#
|
15
|
+
class AvvoApi::Headshot < AvvoApi::Base
|
16
|
+
singleton
|
17
|
+
|
18
|
+
belongs_to :lawyer
|
19
|
+
belongs_to :doctor
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Represents a language. One of the following attributes MUST
|
2
|
+
# be set when using this model:
|
3
|
+
#
|
4
|
+
# * doctor_id
|
5
|
+
# * lawyer_id
|
6
|
+
#
|
7
|
+
# This model has the following attributes:
|
8
|
+
#
|
9
|
+
# * id
|
10
|
+
# * name: The language name.
|
11
|
+
# * specialty_id: The language id. 'name' takes priority over this if both are set.
|
12
|
+
#
|
13
|
+
class AvvoApi::Language < AvvoApi::Base
|
14
|
+
belongs_to :lawyer
|
15
|
+
belongs_to :doctor
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Represents a lawyer on Avvo. Attributes include:
|
2
|
+
#
|
3
|
+
# * id: The id of this lawyer
|
4
|
+
# * firstname: the first name of this lawyer
|
5
|
+
# * middlename: the middle name of this lawyer
|
6
|
+
# * lastname: the last name of this lawyer
|
7
|
+
# * suffix: the suffix of the lawyer's name
|
8
|
+
# * email_address
|
9
|
+
# * website_url
|
10
|
+
#
|
11
|
+
class AvvoApi::Lawyer < AvvoApi::Base
|
12
|
+
|
13
|
+
has_many :addresses
|
14
|
+
has_many :reviews
|
15
|
+
has_many :schools
|
16
|
+
has_many :languages
|
17
|
+
has_many :specialties
|
18
|
+
has_one :headshot
|
19
|
+
include AvvoApi::ProfessionalMethods
|
20
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Constants representing the various values for +phone_type_id+ in AvvoApi::Phone
|
2
|
+
module AvvoApi::PhoneType
|
3
|
+
|
4
|
+
# There is no type specified for this number
|
5
|
+
UNKNOWN = 1
|
6
|
+
|
7
|
+
# This is an office number
|
8
|
+
OFFICE = 2
|
9
|
+
|
10
|
+
# This is a fax number
|
11
|
+
FAX = 3
|
12
|
+
|
13
|
+
# This is a mobile number
|
14
|
+
MOBILE = 4
|
15
|
+
end
|
16
|
+
|
17
|
+
# Represents a phone number tied to an address. One of the
|
18
|
+
# following attributes MUST be set when using this model:
|
19
|
+
#
|
20
|
+
# * doctor_id
|
21
|
+
# * lawyer_id
|
22
|
+
#
|
23
|
+
# Additionally, the following attribute MUST be set when using this model:
|
24
|
+
#
|
25
|
+
# * address_id
|
26
|
+
#
|
27
|
+
# This model has the following attributes:
|
28
|
+
#
|
29
|
+
# * id
|
30
|
+
# * phone_number: The phone number. Will be normalized by Avvo.
|
31
|
+
# * phone_type_id: The type of the phone number, as an AvvoApi::PhoneType
|
32
|
+
# constant. (Only applicable when creating or updating records)
|
33
|
+
# * phone_type: A string representation of the phone type
|
34
|
+
#
|
35
|
+
class AvvoApi::Phone < AvvoApi::Base
|
36
|
+
belongs_to :address
|
37
|
+
end
|