avvo_api 0.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/.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
|