career_builder 0.1.1 → 0.2.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/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