career_builder 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{career_builder}
8
- s.version = "0.1.1"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Guterl"]
12
- s.date = %q{2011-01-06}
12
+ s.date = %q{2011-03-31}
13
13
  s.description = %q{Ruby wrapper for the CareerBuilder V2 HTTP XML API}
14
14
  s.email = %q{mguterl@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -39,13 +39,12 @@ Gem::Specification.new do |s|
39
39
  "lib/career_builder/api/shift_preference.rb",
40
40
  "lib/career_builder/api/word_document.rb",
41
41
  "lib/career_builder/client.rb",
42
+ "lib/career_builder/client/advanced_resume_search.rb",
43
+ "lib/career_builder/client/authentication.rb",
44
+ "lib/career_builder/client/get_resume.rb",
45
+ "lib/career_builder/client/request.rb",
46
+ "lib/career_builder/client/resume_actions_remaining_today.rb",
42
47
  "lib/career_builder/errors.rb",
43
- "lib/career_builder/request.rb",
44
- "lib/career_builder/request/authenticated.rb",
45
- "lib/career_builder/requests/advanced_resume_search.rb",
46
- "lib/career_builder/requests/authentication.rb",
47
- "lib/career_builder/requests/get_resume.rb",
48
- "lib/career_builder/requests/resume_actions_remaining_today.rb",
49
48
  "lib/career_builder/resume.rb",
50
49
  "lib/career_builder/resume/lazy_collection.rb",
51
50
  "spec/career_builder/client_spec.rb",
@@ -30,10 +30,4 @@ require 'career_builder/api/word_document'
30
30
  require 'career_builder/api/resume'
31
31
  require 'career_builder/resume'
32
32
  require 'career_builder/resume/lazy_collection'
33
- require 'career_builder/request'
34
- require 'career_builder/request/authenticated'
35
- require 'career_builder/requests/authentication'
36
- require 'career_builder/requests/advanced_resume_search'
37
- require 'career_builder/requests/get_resume'
38
- require 'career_builder/requests/resume_actions_remaining_today'
39
33
  require 'career_builder/client'
@@ -1,37 +1,30 @@
1
+ require 'career_builder/client/authentication'
2
+ require 'career_builder/client/request'
3
+ require 'career_builder/client/advanced_resume_search'
4
+ require 'career_builder/client/get_resume'
5
+ require 'career_builder/client/resume_actions_remaining_today'
6
+
1
7
  module CareerBuilder
2
8
 
3
9
  class Client
4
10
 
5
- attr_reader :email, :password, :session_token
6
-
7
- def initialize(email, password)
8
- @email, @password = email, password
9
- end
11
+ include Authentication
12
+ include Request
13
+ include AdvancedResumeSearch
14
+ include GetResume
15
+ include ResumeActionsRemainingToday
10
16
 
11
- def authenticate
12
- @session_token = Requests::Authentication.new(self, :email => email, :password => password).perform
13
- end
17
+ attr_reader :email, :password
14
18
 
15
- def authenticated?
16
- !session_token.nil?
19
+ def initialize(email, password, options = {})
20
+ @email, @password = email, password
21
+ @debug = options.fetch(:debug) { false }
17
22
  end
18
23
 
19
24
  def resumes(options = {})
20
25
  Resume::LazyCollection.new(self, options)
21
26
  end
22
27
 
23
- def advanced_resume_search(options = {})
24
- Requests::AdvancedResumeSearch.new(self, options).perform
25
- end
26
-
27
- def get_resume(options = {})
28
- Requests::GetResume.new(self, options).perform
29
- end
30
-
31
- def resume_actions_remaining_today(options = {})
32
- Requests::ResumeActionsRemainingToday.new(self, options).perform
33
- end
34
-
35
28
  end
36
29
 
37
30
  end
@@ -1,8 +1,6 @@
1
1
  module CareerBuilder
2
-
3
- module Requests
4
-
5
- class AdvancedResumeSearch < Request::Authenticated
2
+ class Client
3
+ module AdvancedResumeSearch
6
4
 
7
5
  # List of valid options available at:
8
6
  # http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch_ValidFields
@@ -27,15 +25,16 @@ module CareerBuilder
27
25
  :rsadid, :cb_minimum_experience,
28
26
  :cb_maximum_experience].freeze
29
27
 
30
- def perform
31
- super
32
- response = perform_request("V2_AdvancedResumeSearch", transform_options_to_xml(options))
28
+ def advanced_resume_search(options = {})
29
+ unless (invalid_options = options.keys - VALID_OPTIONS).empty?
30
+ raise ArgumentError, "Invalid options #{invalid_options}"
31
+ end
32
+
33
+ response = auth_request("V2_AdvancedResumeSearch", options)
33
34
 
34
35
  API::ResumeSearch.parse(response)
35
36
  end
36
37
 
37
38
  end
38
-
39
39
  end
40
-
41
40
  end
@@ -0,0 +1,30 @@
1
+ module CareerBuilder
2
+ class Client
3
+ module Authentication
4
+
5
+ def session_token
6
+ @session_token
7
+ end
8
+
9
+ def authenticate
10
+ response = request("BeginSessionV2", 'Email' => email, 'Password' => password)
11
+
12
+ packet = Nokogiri::XML(response)
13
+
14
+ if session_token = packet.search("//SessionToken")
15
+ session_token_text = session_token.text
16
+ if session_token_text == "Invalid"
17
+ @session_token = nil
18
+ else
19
+ @session_token = session_token_text
20
+ end
21
+ end
22
+ end
23
+
24
+ def authenticated?
25
+ !session_token.nil?
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -1,14 +1,15 @@
1
1
  module CareerBuilder
2
-
3
- module Requests
4
-
5
- class GetResume < Request::Authenticated
2
+ class Client
3
+ module GetResume
6
4
 
7
5
  VALID_OPTIONS = [:resume_id, :cust_acct_code, :get_word_doc_if_available].freeze
8
6
 
9
- def perform
10
- super
11
- response = perform_request("V2_GetResume", transform_options_to_xml(options))
7
+ def get_resume(options = {})
8
+ unless (invalid_options = options.keys - VALID_OPTIONS).empty?
9
+ raise ArgumentError, "Invalid options #{invalid_options}"
10
+ end
11
+
12
+ response = auth_request("V2_GetResume", options)
12
13
 
13
14
  if response =~ /ResumeID/ # valid response
14
15
  API::Resume.parse(response, :single => true)
@@ -18,7 +19,5 @@ module CareerBuilder
18
19
  end
19
20
 
20
21
  end
21
-
22
22
  end
23
-
24
23
  end
@@ -0,0 +1,76 @@
1
+ module CareerBuilder
2
+ class Client
3
+ module Request
4
+
5
+ RESUME_SERVICE_ENDPOINT_URL = 'http://ws.careerbuilder.com/resumes/resumes.asmx'
6
+
7
+ def auth_request(meth, options = {})
8
+ if !authenticated? && !authenticate
9
+ raise InvalidCredentials
10
+ end
11
+
12
+ options.merge!(:session_token => session_token)
13
+
14
+ request meth, options
15
+ end
16
+
17
+ def request(meth, options = {})
18
+ uri = URI.parse(RESUME_SERVICE_ENDPOINT_URL + "/#{meth}")
19
+
20
+ options_as_xml = transform_options_to_xml(options)
21
+
22
+ form_data = { 'Packet' => "<Packet>#{options_as_xml}</Packet>" }
23
+
24
+ req = Net::HTTP::Post.new(uri.path)
25
+ req.form_data = form_data
26
+ http = Net::HTTP.new(uri.host, uri.port)
27
+ http.set_debug_output $stderr if @debug
28
+ response = http.start { |http|
29
+ http.request(req)
30
+ }
31
+
32
+ parse_terrible_response(response)
33
+ end
34
+
35
+ def parse_terrible_response(response)
36
+ xml_body = Nokogiri::XML(response.body) # not sure why I have to do it this way
37
+ inner_xml = xml_body.children.first
38
+ inner_xml.text
39
+ end
40
+
41
+ CUSTOM_KEY_TRANSFORMS = {
42
+ :resume_id => "ResumeID",
43
+ :account_did => "AccountDID"
44
+ }
45
+
46
+ def transform_key(key)
47
+ if custom_transform = CUSTOM_KEY_TRANSFORMS[key]
48
+ custom_transform
49
+ else
50
+ key.to_s.camelize
51
+ end
52
+ end
53
+
54
+ def transform_key_value_to_tag(key, value)
55
+ "<#{transform_key(key)}>#{value}</#{transform_key(key)}>"
56
+ end
57
+
58
+ def transform_options_to_xml(options)
59
+ elements = []
60
+
61
+ # let's make sure SessionToken is always at the top of the request
62
+ if session_key = options.delete(:session_token)
63
+ elements << transform_key_value_to_tag(:session_token, session_token)
64
+ end
65
+
66
+ options.sort_by { |k, v| k.to_s }.each do |key, value|
67
+ elements << transform_key_value_to_tag(key, value)
68
+ end
69
+
70
+ elements.join
71
+ end
72
+
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,16 @@
1
+ module CareerBuilder
2
+ class Client
3
+ module ResumeActionsRemainingToday
4
+
5
+ VALID_OPTIONS = [:account_did]
6
+
7
+ def resume_actions_remaining_today(options = {})
8
+ response = auth_request("V2_ResumeActionsRemainingToday", options)
9
+
10
+ doc = Nokogiri::XML(response)
11
+ doc.xpath("//Packet").text.to_i
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -12,25 +12,20 @@ module CareerBuilder
12
12
  def each
13
13
  current_page = search_options[:page] || 1
14
14
 
15
- search = client.advanced_resume_search(search_options.merge(:page_number => current_page))
15
+ search = client.advanced_resume_search(search_options.merge(:page_number => current_page, :rows_per_page => 500))
16
16
 
17
17
  results = search.results
18
- hits = search.hits
19
- max_page = search.max_page
20
18
 
21
19
  loop do
22
-
23
20
  results.each do |resume|
24
21
  yield Resume.new(client, resume)
25
22
  end
26
23
 
27
24
  current_page += 1
28
25
 
29
- break if current_page > max_page
30
-
31
- search = client.advanced_resume_search(search_options.merge(:page_number => current_page))
26
+ search = client.advanced_resume_search(search_options.merge(:page_number => current_page, :rows_per_page => 500))
32
27
  results = search.results
33
-
28
+ break if results.empty?
34
29
  end
35
30
  end
36
31
 
@@ -5,8 +5,12 @@ describe CareerBuilder::Resume::LazyCollection do
5
5
  describe "#each" do
6
6
 
7
7
  before do
8
- stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").with(:body => 'Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e1%3c%2fPageNumber%3e%3c%2fPacket%3e').to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\">&lt;Packet&gt;&lt;Errors /&gt;&lt;PageNumber&gt;1&lt;/PageNumber&gt;&lt;SearchTime&gt;06/25/2010 12:03:14&lt;/SearchTime&gt;&lt;FirstRec&gt;1&lt;/FirstRec&gt;&lt;LastRec&gt;100&lt;/LastRec&gt;&lt;Hits&gt;4&lt;/Hits&gt;&lt;MaxPage&gt;2&lt;/MaxPage&gt;&lt;Results&gt;&lt;ResumeResultItem_V3&gt;&lt;ContactEmail&gt;Rhd4G067G4JVTLW99H7_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com&lt;/ContactEmail&gt;&lt;ContactName&gt;Rebecca Bernard&lt;/ContactName&gt;&lt;HomeLocation&gt;US-OH-Milford&lt;/HomeLocation&gt;&lt;LastUpdate&gt;2010/5/13&lt;/LastUpdate&gt;&lt;ResumeTitle&gt;BERNARD_SYSTEMS_ENGINEER&lt;/ResumeTitle&gt;&lt;JobTitle&gt;BERNARD_SYSTEMS_ENGINEER&lt;/JobTitle&gt;&lt;RecentEmployer&gt;TATA CONSULTANCY SERVICES&lt;/RecentEmployer&gt;&lt;RecentJobTitle&gt;CONSULTANCY SERVICES- Systems Engineer&lt;/RecentJobTitle&gt;&lt;RecentPay&gt;0&lt;/RecentPay&gt;&lt;ResumeID&gt;Rhd4G067G4JVTLW99H7&lt;/ResumeID&gt;&lt;UserDID&gt;U7X86R61VVKS4FWS03T&lt;/UserDID&gt;&lt;ContactEmailMD5&gt;139013c2fa2b945bdc340f8a698b009e&lt;/ContactEmailMD5&gt;&lt;/ResumeResultItem_V3&gt;&lt;ResumeResultItem_V3&gt;&lt;ContactEmail&gt;Rhe7TZ764LHG1GQTPSM_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com&lt;/ContactEmail&gt;&lt;ContactName&gt;chris grader&lt;/ContactName&gt;&lt;HomeLocation&gt;US-OH-Milford&lt;/HomeLocation&gt;&lt;LastUpdate&gt;2010/6/4&lt;/LastUpdate&gt;&lt;ResumeTitle&gt;Chris Grader resume&lt;/ResumeTitle&gt;&lt;JobTitle&gt;Chris Grader resume&lt;/JobTitle&gt;&lt;RecentEmployer&gt;Millennial Medical, Inc&lt;/RecentEmployer&gt;&lt;RecentJobTitle&gt;Regional Sales Manager/Midwest Distributor&lt;/RecentJobTitle&gt;&lt;RecentPay&gt;0&lt;/RecentPay&gt;&lt;ResumeID&gt;Rhe7TZ764LHG1GQTPSM&lt;/ResumeID&gt;&lt;UserDID&gt;U346V1MKGCHPGCF9S8&lt;/UserDID&gt;&lt;ContactEmailMD5&gt;cfba57bf848b78211d99348cf0f90879&lt;/ContactEmailMD5&gt;&lt;/ResumeResultItem_V3&gt;&lt;ResumeResultItem_V3&gt;&lt;ContactEmail&gt;RH52G867678F7GH02Q3_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com&lt;/ContactEmail&gt;&lt;ContactName&gt;Jeffrey Davis&lt;/ContactName&gt;&lt;HomeLocation&gt;US-OH-Goshen&lt;/HomeLocation&gt;&lt;LastUpdate&gt;2010/5/23&lt;/LastUpdate&gt;&lt;ResumeTitle&gt;Warehouse Distribution Specialist&lt;/ResumeTitle&gt;&lt;JobTitle&gt;Warehouse Distribution Specialist&lt;/JobTitle&gt;&lt;RecentEmployer&gt;OWENS &amp;amp; MINOR&lt;/RecentEmployer&gt;&lt;RecentJobTitle&gt;Warehouse Lead Supervisor&lt;/RecentJobTitle&gt;&lt;RecentPay&gt;35776&lt;/RecentPay&gt;&lt;ResumeID&gt;RH52G867678F7GH02Q3&lt;/ResumeID&gt;&lt;UserDID&gt;U1C29V68M3YM95SP0XK&lt;/UserDID&gt;&lt;ContactEmailMD5&gt;e814ebaa93aae5c3719e27d26d5af917&lt;/ContactEmailMD5&gt;&lt;/ResumeResultItem_V3&gt;&lt;/Results&gt;&lt;/Packet&gt;</string>")
9
- stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").with(:body => 'Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e2%3c%2fPageNumber%3e%3c%2fPacket%3e').to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\">&lt;Packet&gt;&lt;Errors/&gt;&lt;PageNumber&gt;2&lt;/PageNumber&gt;&lt;SearchTime&gt;06/25/2010 12:03:14&lt;/SearchTime&gt;&lt;FirstRec&gt;1&lt;/FirstRec&gt;&lt;LastRec&gt;100&lt;/LastRec&gt;&lt;Hits&gt;4&lt;/Hits&gt;&lt;MaxPage&gt;2&lt;/MaxPage&gt;&lt;Results&gt;&lt;ResumeResultItem_V3&gt;&lt;ContactEmail&gt;Rhd4G067G4JVTLW99H7_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com&lt;/ContactEmail&gt;&lt;ContactName&gt;Michael Guterl&lt;/ContactName&gt;&lt;HomeLocation&gt;US-OH-Loveland&lt;/HomeLocation&gt;&lt;LastUpdate&gt;2010/5/13&lt;/LastUpdate&gt;&lt;ResumeTitle&gt;BERNARD_SYSTEMS_ENGINEER&lt;/ResumeTitle&gt;&lt;JobTitle&gt;BERNARD_SYSTEMS_ENGINEER&lt;/JobTitle&gt;&lt;RecentEmployer&gt;TATA CONSULTANCY SERVICES&lt;/RecentEmployer&gt;&lt;RecentJobTitle&gt;CONSULTANCY SERVICES- Systems Engineer&lt;/RecentJobTitle&gt;&lt;RecentPay&gt;0&lt;/RecentPay&gt;&lt;ResumeID&gt;RD52G867678F7GH0123&lt;/ResumeID&gt;&lt;UserDID&gt;U7X86R61VVKS4FWS03T&lt;/UserDID&gt;&lt;ContactEmailMD5&gt;139013c2fa2b945bdc340f8a698b009e&lt;/ContactEmailMD5&gt;&lt;/ResumeResultItem_V3&gt;&lt;/Results&gt;&lt;/Packet&gt;</string>")
8
+ stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").with(:body => 'Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e1%3c%2fPageNumber%3e%3cRowsPerPage%3e500%3c%2fRowsPerPage%3e%3c%2fPacket%3e').to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\">&lt;Packet&gt;&lt;Errors /&gt;&lt;PageNumber&gt;1&lt;/PageNumber&gt;&lt;SearchTime&gt;06/25/2010 12:03:14&lt;/SearchTime&gt;&lt;FirstRec&gt;1&lt;/FirstRec&gt;&lt;LastRec&gt;100&lt;/LastRec&gt;&lt;Hits&gt;4&lt;/Hits&gt;&lt;MaxPage&gt;2&lt;/MaxPage&gt;&lt;Results&gt;&lt;ResumeResultItem_V3&gt;&lt;ContactEmail&gt;Rhd4G067G4JVTLW99H7_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com&lt;/ContactEmail&gt;&lt;ContactName&gt;Rebecca Bernard&lt;/ContactName&gt;&lt;HomeLocation&gt;US-OH-Milford&lt;/HomeLocation&gt;&lt;LastUpdate&gt;2010/5/13&lt;/LastUpdate&gt;&lt;ResumeTitle&gt;BERNARD_SYSTEMS_ENGINEER&lt;/ResumeTitle&gt;&lt;JobTitle&gt;BERNARD_SYSTEMS_ENGINEER&lt;/JobTitle&gt;&lt;RecentEmployer&gt;TATA CONSULTANCY SERVICES&lt;/RecentEmployer&gt;&lt;RecentJobTitle&gt;CONSULTANCY SERVICES- Systems Engineer&lt;/RecentJobTitle&gt;&lt;RecentPay&gt;0&lt;/RecentPay&gt;&lt;ResumeID&gt;Rhd4G067G4JVTLW99H7&lt;/ResumeID&gt;&lt;UserDID&gt;U7X86R61VVKS4FWS03T&lt;/UserDID&gt;&lt;ContactEmailMD5&gt;139013c2fa2b945bdc340f8a698b009e&lt;/ContactEmailMD5&gt;&lt;/ResumeResultItem_V3&gt;&lt;ResumeResultItem_V3&gt;&lt;ContactEmail&gt;Rhe7TZ764LHG1GQTPSM_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com&lt;/ContactEmail&gt;&lt;ContactName&gt;chris grader&lt;/ContactName&gt;&lt;HomeLocation&gt;US-OH-Milford&lt;/HomeLocation&gt;&lt;LastUpdate&gt;2010/6/4&lt;/LastUpdate&gt;&lt;ResumeTitle&gt;Chris Grader resume&lt;/ResumeTitle&gt;&lt;JobTitle&gt;Chris Grader resume&lt;/JobTitle&gt;&lt;RecentEmployer&gt;Millennial Medical, Inc&lt;/RecentEmployer&gt;&lt;RecentJobTitle&gt;Regional Sales Manager/Midwest Distributor&lt;/RecentJobTitle&gt;&lt;RecentPay&gt;0&lt;/RecentPay&gt;&lt;ResumeID&gt;Rhe7TZ764LHG1GQTPSM&lt;/ResumeID&gt;&lt;UserDID&gt;U346V1MKGCHPGCF9S8&lt;/UserDID&gt;&lt;ContactEmailMD5&gt;cfba57bf848b78211d99348cf0f90879&lt;/ContactEmailMD5&gt;&lt;/ResumeResultItem_V3&gt;&lt;ResumeResultItem_V3&gt;&lt;ContactEmail&gt;RH52G867678F7GH02Q3_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com&lt;/ContactEmail&gt;&lt;ContactName&gt;Jeffrey Davis&lt;/ContactName&gt;&lt;HomeLocation&gt;US-OH-Goshen&lt;/HomeLocation&gt;&lt;LastUpdate&gt;2010/5/23&lt;/LastUpdate&gt;&lt;ResumeTitle&gt;Warehouse Distribution Specialist&lt;/ResumeTitle&gt;&lt;JobTitle&gt;Warehouse Distribution Specialist&lt;/JobTitle&gt;&lt;RecentEmployer&gt;OWENS &amp;amp; MINOR&lt;/RecentEmployer&gt;&lt;RecentJobTitle&gt;Warehouse Lead Supervisor&lt;/RecentJobTitle&gt;&lt;RecentPay&gt;35776&lt;/RecentPay&gt;&lt;ResumeID&gt;RH52G867678F7GH02Q3&lt;/ResumeID&gt;&lt;UserDID&gt;U1C29V68M3YM95SP0XK&lt;/UserDID&gt;&lt;ContactEmailMD5&gt;e814ebaa93aae5c3719e27d26d5af917&lt;/ContactEmailMD5&gt;&lt;/ResumeResultItem_V3&gt;&lt;/Results&gt;&lt;/Packet&gt;</string>")
9
+ stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").with(:body => 'Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e2%3c%2fPageNumber%3e%3cRowsPerPage%3e500%3c%2fRowsPerPage%3e%3c%2fPacket%3e').to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\">&lt;Packet&gt;&lt;Errors/&gt;&lt;PageNumber&gt;2&lt;/PageNumber&gt;&lt;SearchTime&gt;06/25/2010 12:03:14&lt;/SearchTime&gt;&lt;FirstRec&gt;1&lt;/FirstRec&gt;&lt;LastRec&gt;100&lt;/LastRec&gt;&lt;Hits&gt;4&lt;/Hits&gt;&lt;MaxPage&gt;2&lt;/MaxPage&gt;&lt;Results&gt;&lt;ResumeResultItem_V3&gt;&lt;ContactEmail&gt;Rhd4G067G4JVTLW99H7_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com&lt;/ContactEmail&gt;&lt;ContactName&gt;Michael Guterl&lt;/ContactName&gt;&lt;HomeLocation&gt;US-OH-Loveland&lt;/HomeLocation&gt;&lt;LastUpdate&gt;2010/5/13&lt;/LastUpdate&gt;&lt;ResumeTitle&gt;BERNARD_SYSTEMS_ENGINEER&lt;/ResumeTitle&gt;&lt;JobTitle&gt;BERNARD_SYSTEMS_ENGINEER&lt;/JobTitle&gt;&lt;RecentEmployer&gt;TATA CONSULTANCY SERVICES&lt;/RecentEmployer&gt;&lt;RecentJobTitle&gt;CONSULTANCY SERVICES- Systems Engineer&lt;/RecentJobTitle&gt;&lt;RecentPay&gt;0&lt;/RecentPay&gt;&lt;ResumeID&gt;RD52G867678F7GH0123&lt;/ResumeID&gt;&lt;UserDID&gt;U7X86R61VVKS4FWS03T&lt;/UserDID&gt;&lt;ContactEmailMD5&gt;139013c2fa2b945bdc340f8a698b009e&lt;/ContactEmailMD5&gt;&lt;/ResumeResultItem_V3&gt;&lt;/Results&gt;&lt;/Packet&gt;</string>")
10
+ stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").
11
+ with(:body => "Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e3%3c%2fPageNumber%3e%3cRowsPerPage%3e500%3c%2fRowsPerPage%3e%3c%2fPacket%3e").
12
+ to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\">&lt;Packet&gt;&lt;Errors/&gt;&lt;PageNumber&gt;2&lt;/PageNumber&gt;&lt;SearchTime&gt;06/25/2010 12:03:14&lt;/SearchTime&gt;&lt;FirstRec&gt;1&lt;/FirstRec&gt;&lt;LastRec&gt;100&lt;/LastRec&gt;&lt;Hits&gt;4&lt;/Hits&gt;&lt;MaxPage&gt;2&lt;/MaxPage&gt;&lt;Results&gt;&lt;/Results&gt;&lt;/Packet&gt;</string>")
13
+
10
14
  @client = CareerBuilder::Client.new("valid_email", "valid_password")
11
15
  @client.stub(:session_token).and_return(42)
12
16
  @client.stub(:authenticate).and_return(true)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: career_builder
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Michael Guterl
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-06 00:00:00 -05:00
18
+ date: 2011-03-31 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -166,13 +166,12 @@ files:
166
166
  - lib/career_builder/api/shift_preference.rb
167
167
  - lib/career_builder/api/word_document.rb
168
168
  - lib/career_builder/client.rb
169
+ - lib/career_builder/client/advanced_resume_search.rb
170
+ - lib/career_builder/client/authentication.rb
171
+ - lib/career_builder/client/get_resume.rb
172
+ - lib/career_builder/client/request.rb
173
+ - lib/career_builder/client/resume_actions_remaining_today.rb
169
174
  - lib/career_builder/errors.rb
170
- - lib/career_builder/request.rb
171
- - lib/career_builder/request/authenticated.rb
172
- - lib/career_builder/requests/advanced_resume_search.rb
173
- - lib/career_builder/requests/authentication.rb
174
- - lib/career_builder/requests/get_resume.rb
175
- - lib/career_builder/requests/resume_actions_remaining_today.rb
176
175
  - lib/career_builder/resume.rb
177
176
  - lib/career_builder/resume/lazy_collection.rb
178
177
  - spec/career_builder/client_spec.rb
@@ -1,82 +0,0 @@
1
- module CareerBuilder
2
-
3
- class Request
4
-
5
- RESUME_SERVICE_ENDPOINT_URL = 'http://ws.careerbuilder.com/resumes/resumes.asmx'
6
-
7
- attr_reader :options, :client
8
-
9
- def initialize(client, options = {})
10
- @client, @options = client, options
11
- end
12
-
13
- def perform
14
- validate_options if defined?(self.class.const_get(:VALID_OPTIONS))
15
- end
16
-
17
- private
18
-
19
- def validate_options
20
- raise ArgumentError, "Invalid options #{invalid_options}" unless valid_options?
21
- end
22
-
23
- def invalid_options
24
- (options.keys - self.class.const_get(:VALID_OPTIONS))
25
- end
26
-
27
- def valid_options?
28
- invalid_options.empty?
29
- end
30
-
31
- def session_token
32
- client.session_token
33
- end
34
-
35
- def parse_terrible_response(response)
36
- xml_body = Nokogiri::XML(response.body) # not sure why I have to do it this way
37
- inner_xml = xml_body.children.first
38
- inner_xml.text
39
- end
40
-
41
- CUSTOM_KEY_TRANSFORMS = {
42
- :resume_id => "ResumeID",
43
- :account_did => "AccountDID"
44
- }
45
-
46
- def transform_key(key)
47
- if custom_transform = CUSTOM_KEY_TRANSFORMS[key]
48
- custom_transform
49
- else
50
- key.to_s.camelize
51
- end
52
- end
53
-
54
- def transform_key_value_to_tag(key, value)
55
- "<#{transform_key(key)}>#{value}</#{transform_key(key)}>"
56
- end
57
-
58
- def transform_options_to_xml(options)
59
- elements = []
60
-
61
- # let's make sure SessionToken is always at the top of the request
62
- if session_key = options.delete(:session_token)
63
- elements << transform_key_value_to_tag(:session_token, session_token)
64
- end
65
-
66
- options.sort_by { |k, v| k.to_s }.each do |key, value|
67
- elements << transform_key_value_to_tag(key, value)
68
- end
69
-
70
- elements.join
71
- end
72
-
73
- def perform_request(method, packet_contents)
74
- parse_terrible_response Net::HTTP.post_form(URI.parse(RESUME_SERVICE_ENDPOINT_URL + "/#{method}"), 'Packet' => "<Packet>#{packet_contents}</Packet>")
75
- rescue Errno::ECONNRESET
76
- warn "The connection was reset, retrying"
77
- retry
78
- end
79
-
80
- end
81
-
82
- end
@@ -1,23 +0,0 @@
1
- module CareerBuilder
2
-
3
- class Request::Authenticated < Request
4
-
5
- def perform
6
- super
7
- require_authentication
8
- options.merge!(:session_token => session_token) unless options.has_key?(:session_token)
9
- end
10
-
11
- private
12
-
13
- def require_authentication
14
- if !client.authenticated?
15
- unless client.authenticate
16
- raise InvalidCredentials
17
- end
18
- end
19
- end
20
-
21
- end
22
-
23
- end
@@ -1,25 +0,0 @@
1
- module CareerBuilder
2
-
3
- module Requests
4
-
5
- class Authentication < Request
6
-
7
- def perform
8
- response = perform_request("BeginSessionV2", "<Email>#{options[:email]}</Email><Password>#{options[:password]}</Password>")
9
- packet = Nokogiri::XML(response)
10
-
11
- if session_token = packet.search("//SessionToken")
12
- session_token_text = session_token.text
13
- if session_token_text == "Invalid"
14
- return nil
15
- else
16
- return session_token_text
17
- end
18
- end
19
- end
20
-
21
- end
22
-
23
- end
24
-
25
- end
@@ -1,21 +0,0 @@
1
- module CareerBuilder
2
-
3
- module Requests
4
-
5
- class ResumeActionsRemainingToday < Request::Authenticated
6
-
7
- VALID_OPTIONS = [:account_did]
8
-
9
- def perform
10
- super
11
- response = perform_request("V2_ResumeActionsRemainingToday", transform_options_to_xml(options))
12
-
13
- doc = Nokogiri::XML(response)
14
- doc.xpath("//Packet").text.to_i
15
- end
16
-
17
- end
18
-
19
- end
20
-
21
- end