sem4r 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. data/Gemfile +11 -0
  2. data/Gemfile.lock +36 -0
  3. data/README.rdoc +30 -0
  4. data/Rakefile +15 -12
  5. data/VERSION.yml +1 -1
  6. data/examples_blog/2009-11-29-hello-world.rb +0 -1
  7. data/examples_sem4r/01_get_account.rb +1 -1
  8. data/examples_sem4r/02_get_info.rb +6 -2
  9. data/examples_sem4r/03_list_ad.rb +1 -1
  10. data/examples_sem4r/04_list_keywords.rb +1 -1
  11. data/examples_sem4r/05_request_report.rb +1 -2
  12. data/examples_sem4r/05_request_report_2010.rb +19 -4
  13. data/examples_sem4r/06_create_campaigns.rb +1 -1
  14. data/examples_sem4r/07_create_campaigns_block.rb +1 -1
  15. data/examples_sem4r/07_create_campaigns_simple.rb +1 -1
  16. data/examples_sem4r/08_ad_params.rb +1 -1
  17. data/examples_sem4r/09_targeting_idea.rb +1 -1
  18. data/examples_sem4r/10_get_location.rb +1 -1
  19. data/examples_sem4r/11_submit_bulk_job.rb +1 -1
  20. data/examples_sem4r/12_list_bulk_job.rb +1 -1
  21. data/examples_sem4r/30_prune_empty_adgroup.rb +1 -1
  22. data/examples_sem4r/31_empty_accounts.rb +1 -1
  23. data/examples_sem4r/example_helper.rb +5 -10
  24. data/lib/sem4r/account.rb +3 -306
  25. data/lib/sem4r/ad_group/ad_group.rb +16 -14
  26. data/lib/sem4r/ad_group/ad_group_bids.rb +11 -10
  27. data/lib/sem4r/ad_group/ad_group_service.rb +5 -5
  28. data/lib/sem4r/ad_group_ad/ad_group_ad.rb +1 -1
  29. data/lib/sem4r/ad_group_ad/ad_group_ad_service.rb +5 -5
  30. data/lib/sem4r/ad_group_ad/ad_group_mobile_ad.rb +9 -9
  31. data/lib/sem4r/ad_group_ad/ad_group_text_ad.rb +9 -9
  32. data/lib/sem4r/ad_group_criterion/ad_group_criterion.rb +6 -6
  33. data/lib/sem4r/ad_group_criterion/ad_group_criterion_bids.rb +5 -6
  34. data/lib/sem4r/ad_group_criterion/ad_group_criterion_operations.rb +0 -1
  35. data/lib/sem4r/ad_group_criterion/ad_group_criterion_service.rb +4 -4
  36. data/lib/sem4r/ad_group_criterion/criterion.rb +3 -3
  37. data/lib/sem4r/ad_group_criterion/criterion_keyword.rb +3 -3
  38. data/lib/sem4r/ad_group_criterion/criterion_placement.rb +2 -2
  39. data/lib/sem4r/ad_param/ad_param.rb +3 -3
  40. data/lib/sem4r/ad_param/ad_param_service.rb +5 -5
  41. data/lib/sem4r/adwords.rb +1 -0
  42. data/lib/sem4r/api_counters.rb +1 -0
  43. data/lib/sem4r/base.rb +1 -0
  44. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job.rb +2 -2
  45. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_account_extension.rb +59 -0
  46. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_service.rb +5 -5
  47. data/lib/sem4r/campaign/campaign.rb +10 -10
  48. data/lib/sem4r/campaign/campaign_account_extension.rb +87 -0
  49. data/lib/sem4r/campaign/campaign_service.rb +6 -6
  50. data/lib/sem4r/campaign_target/campaign_target_service.rb +22 -22
  51. data/lib/sem4r/cli/cli_command.rb +1 -0
  52. data/lib/sem4r/cli/cli_common_args.rb +10 -3
  53. data/lib/sem4r/cli/cli_helpers.rb +1 -0
  54. data/lib/sem4r/cli/cli_sem.rb +1 -0
  55. data/lib/sem4r/cli/{cli_download_report.rb → commands/cli_download_report.rb} +2 -1
  56. data/lib/sem4r/cli/{cli_ideas.rb → commands/cli_ideas.rb} +1 -0
  57. data/lib/sem4r/cli/{cli_commands.rb → commands/cli_info.rb} +3 -23
  58. data/lib/sem4r/cli/{cli_list_ads.rb → commands/cli_list_ads.rb} +1 -0
  59. data/lib/sem4r/cli/commands/cli_list_campaign.rb +35 -0
  60. data/lib/sem4r/cli/commands/cli_list_client.rb +36 -0
  61. data/lib/sem4r/cli/{cli_list_keywords.rb → commands/cli_list_keywords.rb} +1 -0
  62. data/lib/sem4r/cli/commands/cli_list_report.rb +34 -0
  63. data/lib/sem4r/cli/commands/cli_repdef.rb +109 -0
  64. data/lib/sem4r/cli/commands/cli_report.rb +78 -0
  65. data/lib/sem4r/cli/{cli_request_report.rb → commands/cli_request_report.rb} +1 -0
  66. data/lib/sem4r/credentials.rb +1 -0
  67. data/lib/sem4r/extensions.rb +22 -1
  68. data/lib/sem4r/geo_location/geo_location_account_extension.rb +43 -0
  69. data/lib/sem4r/geo_location/geo_location_service.rb +4 -4
  70. data/lib/sem4r/info/info_account_extension.rb +48 -0
  71. data/lib/sem4r/info/info_selector.rb +108 -0
  72. data/lib/sem4r/info/info_service.rb +11 -66
  73. data/lib/sem4r/{common/operation.rb → operation.rb} +3 -1
  74. data/lib/sem4r/report_definition/report_definition.rb +75 -15
  75. data/lib/sem4r/report_definition/report_definition_account_extension.rb +79 -0
  76. data/lib/sem4r/report_definition/report_definition_operation.rb +3 -1
  77. data/lib/sem4r/report_definition/report_definition_service.rb +7 -7
  78. data/lib/sem4r/report_definition/report_field.rb +57 -0
  79. data/lib/sem4r/sem4r_error.rb +1 -0
  80. data/lib/sem4r/services/http_connector.rb +93 -0
  81. data/lib/sem4r/services/service.rb +1 -1
  82. data/lib/sem4r/services/soap_call.rb +27 -5
  83. data/lib/sem4r/services/soap_connector.rb +2 -147
  84. data/lib/sem4r/services/soap_dumper.rb +105 -0
  85. data/lib/sem4r/services/soap_message_v13.rb +15 -9
  86. data/lib/sem4r/services/{soap_message_v2009.rb → soap_message_v2010.rb} +26 -12
  87. data/lib/sem4r/targeting_idea/targeting_idea.rb +16 -11
  88. data/lib/sem4r/targeting_idea/targeting_idea_account_extension.rb +52 -0
  89. data/lib/sem4r/targeting_idea/targeting_idea_selector.rb +36 -10
  90. data/lib/sem4r/targeting_idea/targeting_idea_service.rb +5 -5
  91. data/lib/sem4r/v13_account/account_account_extension.rb +103 -0
  92. data/lib/sem4r/v13_account/billing_address.rb +10 -21
  93. data/lib/sem4r/v13_report/report.rb +8 -8
  94. data/lib/sem4r/v13_report/report_account_extension.rb +63 -0
  95. data/lib/sem4r/v13_report/report_job.rb +1 -1
  96. data/lib/sem4r.rb +27 -6
  97. data/lib/sem4r_cli.rb +4 -6
  98. data/lib/{sem4r → soap_helpers}/soap_attributes.rb +105 -13
  99. data/sem4r.gemspec +229 -190
  100. data/spec/{aggregates_spec_helper.rb → aggregates_rspec_helper.rb} +0 -0
  101. data/spec/build_fixtures.rb +84 -0
  102. data/spec/rspec_hash.rb +66 -0
  103. data/spec/{spec_helper.rb → rspec_helper.rb} +4 -2
  104. data/spec/rspec_matchers.rb +102 -0
  105. data/spec/rspec_sem4r_helper.rb +88 -0
  106. data/spec/sem4r/account_spec.rb +3 -4
  107. data/spec/sem4r/ad_group/ad_group_bids_spec.rb +4 -3
  108. data/spec/sem4r/ad_group/ad_group_service_spec.rb +8 -7
  109. data/spec/sem4r/ad_group/ad_group_spec.rb +5 -4
  110. data/spec/{fixtures/services/ad_group → sem4r/ad_group/fixtures}/get-first-req.xml +0 -0
  111. data/spec/{fixtures/services/ad_group → sem4r/ad_group/fixtures}/get-first-res.xml +0 -0
  112. data/spec/{fixtures/services/ad_group → sem4r/ad_group/fixtures}/get-manual-cpm-bids-req.xml +0 -0
  113. data/spec/{fixtures/services/ad_group → sem4r/ad_group/fixtures}/get-manual-cpm-bids-res.xml +0 -0
  114. data/spec/{fixtures/services/ad_group → sem4r/ad_group/fixtures}/mutate_add-req.xml +0 -0
  115. data/spec/{fixtures/services/ad_group → sem4r/ad_group/fixtures}/mutate_add-res.xml +0 -0
  116. data/spec/sem4r/ad_group_ad/ad_group_ad_operation_spec.rb +3 -3
  117. data/spec/sem4r/ad_group_ad/ad_group_ad_service_spec.rb +6 -5
  118. data/spec/sem4r/ad_group_ad/ad_group_ad_spec.rb +6 -5
  119. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/get_mobile_ad-req.xml +0 -0
  120. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/get_mobile_ad-res.xml +0 -0
  121. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/get_text_ad-req.xml +0 -0
  122. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/get_text_ad-res.xml +0 -0
  123. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/mutate_add_mobile_ad-req.xml +0 -0
  124. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/mutate_add_mobile_ad-res.xml +0 -0
  125. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/mutate_add_text_ad-req.xml +0 -0
  126. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/mutate_add_text_ad-res.xml +0 -0
  127. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/mutate_add_two_criterions-req.xml +0 -0
  128. data/spec/{fixtures/services/ad_group_ad → sem4r/ad_group_ad/fixtures}/mutate_add_two_criterions-res.xml +0 -0
  129. data/spec/sem4r/ad_group_criterion/ad_group_criterion_bids_spec.rb +5 -4
  130. data/spec/sem4r/ad_group_criterion/ad_group_criterion_service_spec.rb +6 -5
  131. data/spec/sem4r/ad_group_criterion/ad_group_criterion_spec.rb +6 -5
  132. data/spec/sem4r/ad_group_criterion/criterion_spec.rb +5 -4
  133. data/spec/{fixtures/services/ad_group_criterion → sem4r/ad_group_criterion/fixtures}/get-req.xml +0 -0
  134. data/spec/{fixtures/services/ad_group_criterion → sem4r/ad_group_criterion/fixtures}/get-res.xml +0 -0
  135. data/spec/{fixtures/services/ad_group_criterion → sem4r/ad_group_criterion/fixtures}/mutate_add_criterion_keyword-req.xml +0 -0
  136. data/spec/{fixtures/services/ad_group_criterion → sem4r/ad_group_criterion/fixtures}/mutate_add_criterion_keyword-res.xml +0 -0
  137. data/spec/{fixtures/services/ad_group_criterion → sem4r/ad_group_criterion/fixtures}/mutate_add_criterion_placement-req.xml +0 -0
  138. data/spec/{fixtures/services/ad_group_criterion → sem4r/ad_group_criterion/fixtures}/mutate_add_criterion_placement-res.xml +0 -0
  139. data/spec/{fixtures/services/ad_group_criterion → sem4r/ad_group_criterion/fixtures}/mutate_add_negative_keyword-req.xml +0 -0
  140. data/spec/{fixtures/services/ad_group_criterion → sem4r/ad_group_criterion/fixtures}/mutate_add_negative_keyword-res.xml +0 -0
  141. data/spec/sem4r/ad_param/ad_param_service_spec.rb +6 -5
  142. data/spec/sem4r/ad_param/ad_param_spec.rb +3 -2
  143. data/spec/{fixtures/services/ad_param → sem4r/ad_param/fixtures}/mutate_set-req.xml +0 -0
  144. data/spec/{fixtures/services/ad_param → sem4r/ad_param/fixtures}/mutate_set-res.xml +0 -0
  145. data/spec/sem4r/adwords_spec.rb +1 -1
  146. data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_service_spec.rb +6 -5
  147. data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_spec.rb +4 -3
  148. data/spec/{fixtures/services/bulk_mutate_job → sem4r/bulk_mutate_job/fixtures}/get-req.xml +0 -0
  149. data/spec/{fixtures/services/bulk_mutate_job → sem4r/bulk_mutate_job/fixtures}/get-res.xml +0 -0
  150. data/spec/{fixtures/services/bulk_mutate_job → sem4r/bulk_mutate_job/fixtures}/mutate-req.xml +0 -0
  151. data/spec/{fixtures/services/bulk_mutate_job → sem4r/bulk_mutate_job/fixtures}/mutate-res.xml +0 -0
  152. data/spec/sem4r/bulk_mutate_job/job_operation_spec.rb +3 -2
  153. data/spec/sem4r/campaign/campaign_service_spec.rb +8 -7
  154. data/spec/sem4r/campaign/campaign_spec.rb +3 -2
  155. data/spec/{fixtures/services/campaign → sem4r/campaign/fixtures}/get-req.xml +0 -0
  156. data/spec/{fixtures/services/campaign → sem4r/campaign/fixtures}/get-res.xml +0 -0
  157. data/spec/{fixtures/services/campaign → sem4r/campaign/fixtures}/mutate_add-req.xml +0 -0
  158. data/spec/{fixtures/services/campaign → sem4r/campaign/fixtures}/mutate_add-res.xml +0 -0
  159. data/spec/sem4r/cli/cli_spec.rb +2 -3
  160. data/spec/sem4r/credentials_spec.rb +1 -1
  161. data/spec/sem4r/info/account_info_extension_spec.rb +51 -0
  162. data/spec/sem4r/info/fixtures/get_unit_count-req.xml +34 -0
  163. data/spec/sem4r/info/fixtures/get_unit_count-res.xml +27 -0
  164. data/spec/sem4r/nokogiri_parsing_spec.rb +105 -0
  165. data/spec/{fixtures/services/report_definition → sem4r/report_definition/fixtures}/mutate_add-req.xml +0 -0
  166. data/spec/{fixtures/services/report_definition → sem4r/report_definition/fixtures}/mutate_add-req_orig.xml +0 -0
  167. data/spec/sem4r/report_definition/report_definition_service_spec.rb +5 -3
  168. data/spec/sem4r/report_definition/report_definition_spec.rb +6 -3
  169. data/spec/sem4r/rexml_parsing_spec.rb +22 -22
  170. data/spec/sem4r/services/service_spec.rb +2 -1
  171. data/spec/sem4r/services/soap_call_spec.rb +6 -5
  172. data/spec/sem4r/services/soap_message_v13_spec.rb +5 -11
  173. data/spec/{fixtures/services/targeting_idea → sem4r/targeting_idea/fixtures}/get-req-all-options.xml +0 -0
  174. data/spec/{fixtures/services/targeting_idea → sem4r/targeting_idea/fixtures}/get-req.xml +9 -11
  175. data/spec/sem4r/targeting_idea/fixtures/get-res.xml +2276 -0
  176. data/spec/sem4r/targeting_idea/targeting_idea_selector_spec.rb +30 -11
  177. data/spec/sem4r/targeting_idea/targeting_idea_service_spec.rb +4 -3
  178. data/spec/sem4r/targeting_idea/targeting_idea_spec.rb +5 -4
  179. data/spec/sem4r/v13_account/account_account_extension_spec.rb +47 -0
  180. data/spec/sem4r/v13_account/account_service_spec.rb +6 -5
  181. data/spec/sem4r/v13_account/billing_address_spec.rb +40 -0
  182. data/spec/{fixtures/services/v13_account → sem4r/v13_account/fixtures}/get_account_info-req.xml +0 -0
  183. data/spec/{fixtures/services/v13_account → sem4r/v13_account/fixtures}/get_account_info-res.xml +0 -0
  184. data/spec/{fixtures/services/v13_account → sem4r/v13_account/fixtures}/get_client_accounts-req.xml +0 -0
  185. data/spec/{fixtures/services/v13_account → sem4r/v13_account/fixtures}/get_client_accounts-res.xml +0 -0
  186. data/spec/{fixtures/services/v13_report → sem4r/v13_report/fixtures}/get_all_jobs-req.xml +0 -0
  187. data/spec/{fixtures/services/v13_report → sem4r/v13_report/fixtures}/get_all_jobs-res.xml +2 -2
  188. data/spec/{fixtures/services/v13_report → sem4r/v13_report/fixtures}/schedule_report_job-req.xml +0 -0
  189. data/spec/{fixtures/services/v13_report → sem4r/v13_report/fixtures}/schedule_report_job-res.xml +0 -0
  190. data/spec/sem4r/v13_report/report_service_spec.rb +13 -11
  191. data/spec/sem4r/v13_report/report_spec.rb +4 -3
  192. data/spec/sem4r_stubs.rb +182 -0
  193. data/spec/soap_helpers/soap_attributes_spec.rb +129 -0
  194. metadata +225 -125
  195. data/spec/fixtures/services/info/get_unit_count-req.xml +0 -30
  196. data/spec/fixtures/services/info/get_unit_count-res.xml +0 -29
  197. data/spec/fixtures/services/targeting_idea/get-res.xml +0 -3601
  198. data/spec/sem4r/soap_attributes_spec.rb +0 -116
  199. data/spec/sem4r_spec_helper.rb +0 -353
@@ -0,0 +1,105 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ # -------------------------------------------------------------------------
24
+
25
+ module Sem4r
26
+
27
+ module SoapDumper
28
+
29
+ def initialize
30
+ @soap_dump = false
31
+ @soap_dump_log = nil
32
+ end
33
+
34
+ def dump_soap_options( dump_options )
35
+ @soap_dump = true
36
+ @soap_dump_log = nil
37
+
38
+ if dump_options[:directory]
39
+ @soap_dump_dir = dump_options[:directory]
40
+ else
41
+ @soap_dump_log = File.open( dump_options[:file], "w" )
42
+ end
43
+ @soap_dump_format = false || dump_options[:format]
44
+
45
+ @soap_dump_interceptor = dump_options[:interceptor] if dump_options[:interceptor]
46
+ end
47
+
48
+ def dump_soap_request(service_url, request_xml)
49
+ return unless @soap_dump
50
+ %w{email password developerToken authToken clientEmail}.each do |tag|
51
+ request_xml = request_xml.gsub(/<#{tag}([^>]*)>.*<\/#{tag}>/, "<#{tag}\\1>***censured***</#{tag}>")
52
+ end
53
+ str = ""
54
+ str << "<!-- Post to '#{service_url}' -->\n"
55
+ str << xml_to_s(request_xml) << "\n"
56
+ dump(service_url, "req", str)
57
+ end
58
+
59
+ def dump_soap_response(service_url, response_xml)
60
+ return unless @soap_dump
61
+ response_xml.gsub(/<email[^>]*>.+<\/email>/, "<email>**censured**</email>")
62
+ str = ""
63
+ str << "<!-- response -->\n" unless @soap_dump_dir
64
+ str << xml_to_s(response_xml) << "\n"
65
+ str << "<!-- end -->" unless @soap_dump_dir
66
+ dump(service_url, "res", str)
67
+ end
68
+
69
+ private
70
+
71
+ def dump(service_url, type, str)
72
+
73
+ @soap_dump_interceptor.call(service_url, type, str) if @soap_dump_interceptor
74
+
75
+ if @soap_dump_dir
76
+ service = service_url.match(/\/([^\/]*)$/)[1]
77
+ filename = Time.now.strftime "%Y%m%d-%H%M%S-%L-#{service}-#{type}.xml"
78
+
79
+ FileUtils.mkdir_p(@soap_dump_dir) unless File.directory?(@soap_dump_dir)
80
+ pathname = File.join(@soap_dump_dir, filename)
81
+ File.open(pathname, "w") {|f|
82
+ f.puts str
83
+ }
84
+ else
85
+ @soap_dump_log.puts str
86
+ @soap_dump_log.flush
87
+ end
88
+ end
89
+
90
+ def xml_to_s(xml)
91
+ if !@soap_dump_format
92
+ xml
93
+ else
94
+ # TODO: using nokogiri also for pretty print xml ?
95
+ require 'rexml/document'
96
+ xml_document = REXML::Document.new(xml)
97
+ f = REXML::Formatters::Pretty.new
98
+ out = String.new
99
+ f.write(xml_document, out)
100
+ # remove xml directive
101
+ out.gsub("<?xml version='1.0' encoding='UTF-8'?>","")
102
+ end
103
+ end
104
+ end
105
+ end
@@ -43,8 +43,12 @@ module Sem4r
43
43
  soap_message = build_soap_message
44
44
  response_xml = @connector.send(service_url, soap_action, soap_message)
45
45
  # erase namespace 'nsX'so it more simple parsing the xml
46
- response_xml = response_xml.gsub(/ns\d:/, "")
47
- @response = REXML::Document.new(response_xml)
46
+
47
+ # response_xml = response_xml.gsub(/ns\d:/, "")
48
+ # @response = REXML::Document.new(response_xml)
49
+ response_xml.gsub!(/\b(ns\d:|xsi:|s:|soapenv:|env:|soap:)/, "")
50
+ response_xml.gsub!(/xmlns=["'].*?['"]/, '')
51
+ @response = Nokogiri::XML::Document.parse(response_xml)
48
52
 
49
53
  # extract information from header
50
54
  # <soapenv:Header>
@@ -53,12 +57,13 @@ module Sem4r
53
57
  # <units soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0" xmlns="https://adwords.google.com/api/adwords/v13">5</units>
54
58
  # <requestId soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0" xmlns="https://adwords.google.com/api/adwords/v13">abade53d3dbecd45600e7d14563f10f1</requestId>
55
59
  # </soapenv:Header>
56
- header = REXML::XPath.first(@response, "//soapenv:Header")
60
+
61
+ header = @response.xpath("//Header").first
57
62
  if header
58
63
  @counters = {
59
- :response_time => header.elements['responseTime'].text.to_i,
60
- :operations => header.elements['operations'].text.to_i,
61
- :units => header.elements['units'].text.to_i
64
+ :response_time => header.at_xpath('responseTime').text.to_i,
65
+ :operations => header.at_xpath('operations').text.to_i,
66
+ :units => header.at_xpath('units').text.to_i
62
67
  }
63
68
  end
64
69
 
@@ -77,10 +82,11 @@ module Sem4r
77
82
  # </soapenv:Fault>
78
83
  # </soapenv:Body>
79
84
  #</soapenv:Envelope>
80
- fault_el = REXML::XPath.first(@response, "//soapenv:Fault")
85
+ #=======
86
+ fault_el = @response.xpath("//Fault").first
81
87
  if fault_el
82
- fault_code = fault_el.elements['faultcode'].text
83
- fault_string = fault_el.elements['faultstring'].text
88
+ fault_code = fault_el.at_xpath('faultcode').text
89
+ fault_string = fault_el.at_xpath('faultstring').text
84
90
  raise SoapError, "#{fault_code}: '#{fault_string}'"
85
91
  end
86
92
  self
@@ -23,7 +23,7 @@
23
23
 
24
24
  module Sem4r
25
25
 
26
- class SoapMessageV2009
26
+ class SoapMessageV2010
27
27
 
28
28
  attr_reader :response
29
29
  attr_reader :counters
@@ -50,29 +50,45 @@ module Sem4r
50
50
  end
51
51
 
52
52
  def send(service_url)
53
- response_xml = @connector.send(service_url, "", build_soap_message)
53
+ send_raw(service_url, build_soap_message)
54
+ end
55
+
56
+ def send_raw(service_url, soap_message)
57
+ soap_message = soap_message.dup
58
+ soap_message.gsub!(/{authentication_token}/, @credentials.authentication_token)
59
+ soap_message.gsub!(/{useragent}/, @credentials.useragent)
60
+ soap_message.gsub!(/{developer_token}/, @credentials.developer_token)
61
+ # soap_message.gsub!(/{client_email}/, @credentials.client_email)
62
+ _send_raw(service_url, soap_message)
63
+ end
64
+
65
+ private
66
+
67
+ def _send_raw(service_url, soap_message)
68
+ response_xml = @connector.send(service_url, "", soap_message)
54
69
  # erase namespace so it more simple parsing the xml
55
- response_xml = response_xml.gsub(/ns\d:/, "")
56
- @response = REXML::Document.new(response_xml)
70
+ response_xml.gsub!(/\b(ns\d:|xsi:|s:|soapenv:|env:|soap:)/, "")
71
+ response_xml.gsub!(/xmlns=["'].*?['"]/, '')
72
+ @response = Nokogiri::XML::Document.parse(response_xml)
57
73
 
58
74
  #
59
75
  # extract information from header
60
76
  #
61
- header = REXML::XPath.first(@response, "//ResponseHeader")
77
+ header = @response.at_xpath("//ResponseHeader")
62
78
  if header
63
79
  @counters = {
64
- :operations => header.elements['operations'].text.to_i,
65
- :response_time => header.elements['responseTime'].text.to_i,
66
- :units => header.elements['units'].text.to_i
80
+ :operations => header.at_xpath("operations").text.to_i,
81
+ :response_time => header.at_xpath("responseTime").text.to_i,
82
+ :units => header.at_xpath("units").text.to_i
67
83
  }
68
84
  end
69
85
 
70
86
  #
71
87
  # check soap fault
72
88
  #
73
- fault_el = REXML::XPath.first(@response, "//soap:Fault")
89
+ fault_el = @response.at_xpath("//Fault")
74
90
  if fault_el
75
- fault_string = fault_el.elements['faultstring'].text
91
+ fault_string = fault_el.at_xpath('faultstring').text
76
92
  @logger.error("soap error: #{fault_string}") if @logger
77
93
  raise fault_string
78
94
  end
@@ -108,8 +124,6 @@ module Sem4r
108
124
  #</soap:Envelope>
109
125
  end
110
126
 
111
- private
112
-
113
127
  def build_soap_header
114
128
  auth_token = @credentials.authentication_token
115
129
 
@@ -56,10 +56,10 @@ module Sem4r
56
56
  end
57
57
 
58
58
  def self.from_element(el)
59
- els = REXML::XPath.match( el, "data")
59
+ els = el.xpath("data")
60
60
  @attributes = els.map do |el|
61
- el1 = el.elements["value"]
62
- xml_type = el1.elements["Attribute.Type"].text.strip
61
+ el1 = el.at_xpath("value")
62
+ xml_type = el1.at_xpath("Attribute.Type").text.strip
63
63
  case xml_type
64
64
  when IdeaTypeAttribute
65
65
  TIdeaTypeAttribute.from_element(el1)
@@ -67,6 +67,11 @@ module Sem4r
67
67
  TKeywordAttribute.from_element(el1)
68
68
  when MonthlySearchVolumeAttribute
69
69
  TMonthlySearchVolumeAttribute.from_element(el1)
70
+ else
71
+ # added from biilmann trunk
72
+ Struct.new(:key, :text).new(
73
+ el.xpath("key").text.strip,
74
+ el1.xpath("value").text.strip)
70
75
  end
71
76
  end
72
77
  end
@@ -90,10 +95,10 @@ module Sem4r
90
95
  end
91
96
 
92
97
  def self.from_element( el )
93
- el1 = el.elements["value"]
98
+ el1 = el.at_xpath("value")
94
99
  new do
95
- text el1.elements["text"].text
96
- match_type el1.elements["matchType"].text
100
+ text el1.at_xpath("text").text
101
+ match_type el1.at_xpath("matchType").text
97
102
  end
98
103
  end
99
104
 
@@ -116,11 +121,11 @@ module Sem4r
116
121
 
117
122
  def self.from_element( el )
118
123
  historical_values = []
119
- el.elements.each do |node|
124
+ el.children.each do |node|
120
125
  next if node.name == "Attribute.Type"
121
- historical_value = { :year => node.elements["year"].text,
122
- :month => node.elements["month"].text}
123
- historical_value.merge!(:count => node.elements["count"].text) if node.elements["count"]
126
+ historical_value = { :year => node.at_xpath("year").text,
127
+ :month => node.at_xpath("month").text}
128
+ historical_value.merge!(:count => node.at_xpath("count").text) if node.at_xpath("count")
124
129
  historical_values << historical_value
125
130
  end
126
131
  new do
@@ -146,7 +151,7 @@ module Sem4r
146
151
 
147
152
  def self.from_element( el )
148
153
  new do
149
- value el.elements["value"].text
154
+ value el.at_xpath("value").text
150
155
  end
151
156
  end
152
157
 
@@ -0,0 +1,52 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ # -------------------------------------------------------------------------
24
+
25
+ module Sem4r
26
+
27
+ module TargetingIdeaExtension
28
+ ############################################################################
29
+ # Targeting Idea
30
+
31
+ def targeting_idea(&block)
32
+ selector = TargetingIdeaSelector.new(&block)
33
+ soap_message = service.targeting_idea.get(@credentials, selector.to_xml)
34
+ add_counters( soap_message.counters )
35
+ rval = soap_message.response.at_xpath("//getResponse/rval")
36
+ els = rval.xpath("entries")
37
+ els.map do |el|
38
+ TargetingIdea.from_element( el )
39
+ end
40
+ end
41
+
42
+ def p_targeting_idea(&block)
43
+ targeting_ideas = targeting_idea(&block)
44
+ targeting_ideas.each{ |idea| puts idea }
45
+ end
46
+ end
47
+
48
+ class Account
49
+ include TargetingIdeaExtension
50
+ end
51
+
52
+ end
@@ -27,7 +27,7 @@ module Sem4r
27
27
  class RelatedToKeywordSearchParameter
28
28
  include SoapAttributes
29
29
 
30
- g_accessor :text
30
+ g_set_accessor :text
31
31
  g_accessor :match_type
32
32
 
33
33
  def initialize(&block)
@@ -37,15 +37,16 @@ module Sem4r
37
37
  end
38
38
 
39
39
  def to_xml
40
- <<-EOS
41
- <s:searchParameters xsi:type="s:RelatedToKeywordSearchParameter">
42
- <s:keywords xsi:type="Keyword">
43
- <Criterion.Type>Keyword</Criterion.Type>
44
- <text>#{text}</text>
45
- <matchType>#{match_type}</matchType>
46
- </s:keywords>
47
- </s:searchParameters>
48
- EOS
40
+ xml = ""
41
+ xml << '<s:searchParameters xsi:type="s:RelatedToKeywordSearchParameter">'
42
+ texts.each do |t|
43
+ xml << '<s:keywords xsi:type="Keyword">'
44
+ xml << "<Criterion.Type>Keyword</Criterion.Type>"
45
+ xml << "<text>#{t}</text>"
46
+ xml << "<matchType>#{match_type}</matchType>"
47
+ xml << "</s:keywords>"
48
+ end
49
+ xml << '</s:searchParameters>'
49
50
  end
50
51
  end
51
52
 
@@ -118,6 +119,27 @@ module Sem4r
118
119
  end
119
120
  end
120
121
 
122
+ class NgramGroupsSearchParameter
123
+ include SoapAttributes
124
+
125
+ g_set_accessor :ngram
126
+
127
+ def initialize(&block)
128
+ if block_given?
129
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
130
+ end
131
+ end
132
+
133
+ def to_xml
134
+ xml = ""
135
+ xml << '<s:searchParameters xsi:type="s:NgramGroupsSearchParameter">'
136
+ ngrams.each do |t|
137
+ xml << "<s:ngramGroups>#{t}</s:ngramGroups>"
138
+ end
139
+ xml << '</s:searchParameters>'
140
+ end
141
+ end
142
+
121
143
  class TargetingIdeaSelector
122
144
  include SoapAttributes
123
145
 
@@ -153,6 +175,10 @@ module Sem4r
153
175
  def country_target_search_parameter(&block)
154
176
  @search_parameters << CountryTargetSearchParameter.new(&block)
155
177
  end
178
+
179
+ def ngram_group_search_parameter(&block)
180
+ @search_parameters << NgramGroupsSearchParameter.new(&block)
181
+ end
156
182
 
157
183
  def to_xml
158
184
  xml=<<-EOFS
@@ -28,14 +28,14 @@ module Sem4r
28
28
  def initialize(connector)
29
29
  @connector = connector
30
30
 
31
- @header_namespace = "https://adwords.google.com/api/adwords/cm/v201003"
32
- @service_namespace = "https://adwords.google.com/api/adwords/o/v201003"
31
+ @header_namespace = "https://adwords.google.com/api/adwords/cm/v201008"
32
+ @service_namespace = "https://adwords.google.com/api/adwords/o/v201008"
33
33
 
34
- @sandbox_service_url = "https://adwords-sandbox.google.com/api/adwords/o/v201003/TargetingIdeaService"
35
- @production_service_url = "https://adwords.google.com/api/adwords/o/v201003/TargetingIdeaService"
34
+ @sandbox_service_url = "https://adwords-sandbox.google.com/api/adwords/o/v201008/TargetingIdeaService"
35
+ @production_service_url = "https://adwords.google.com/api/adwords/o/v201008/TargetingIdeaService"
36
36
  end
37
37
 
38
- soap_call_v2009 :get, :mutate => false
38
+ soap_call_v2010 :get, :mutate => false
39
39
 
40
40
  ################
41
41
 
@@ -0,0 +1,103 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ # -------------------------------------------------------------------------
24
+
25
+ module Sem4r
26
+
27
+ module AccountAccountExtension
28
+ ############################################################################
29
+ # Info Account - Service Account
30
+
31
+ def p_info
32
+ _info unless @currency_code
33
+ puts "currency_code: #{@currency_code}"
34
+ puts "customer_id: #{@customer_id}"
35
+ puts @billing_address
36
+ end
37
+
38
+ def currency_code
39
+ _info unless @currency_code
40
+ @currency_code
41
+ end
42
+
43
+ def customer_id
44
+ _info unless @customer_id
45
+ @customer_id
46
+ end
47
+
48
+ private
49
+
50
+ def _info
51
+ soap_message = service.account.account_info(credentials)
52
+ add_counters( soap_message.counters )
53
+ el = soap_message.response.at_xpath("//getAccountInfoResponse/getAccountInfoReturn")
54
+ @currency_code = el.at_xpath('currencyCode').text.strip
55
+ @customer_id = el.at_xpath('customerId').text.strip
56
+ @billing_address = BillingAddress.from_element( el.at_xpath('billingAddress') )
57
+ end
58
+
59
+ public
60
+
61
+ ############################################################################
62
+ # Account - Service Account
63
+
64
+ def client_accounts(refresh = false)
65
+ _client_accounts unless @accounts and !refresh
66
+ @accounts
67
+ end
68
+
69
+ def p_client_accounts(refresh = false)
70
+ cs = client_accounts(refresh)
71
+ # puts "#{cs.length} client accounts"
72
+ cs.each do |account|
73
+ puts account.to_s
74
+ end
75
+ self
76
+ end
77
+
78
+ alias clients client_accounts
79
+ alias p_clients p_client_accounts
80
+
81
+ private
82
+
83
+ def _client_accounts
84
+ soap_message = service.account.client_accounts(credentials)
85
+ add_counters( soap_message.counters )
86
+ els = soap_message.response.xpath("//getClientAccountsReturn")
87
+ @accounts = els.map do |el|
88
+ client_email = el.text
89
+ Account.new( adwords, Credentials.new(@credentials, client_email) )
90
+ end
91
+ end
92
+
93
+ public
94
+
95
+ ###########################################################################
96
+
97
+ end
98
+
99
+ class Account
100
+ include AccountAccountExtension
101
+ end
102
+
103
+ end
@@ -30,6 +30,13 @@ module Sem4r
30
30
  g_accessor :address_line1
31
31
  g_accessor :address_line2
32
32
  g_accessor :city
33
+ g_accessor :country_code
34
+ g_accessor :email, :xpath => 'emailAddress'
35
+ g_accessor :fax_number
36
+ g_accessor :name
37
+ g_accessor :phone, :xpath => 'phoneNumber'
38
+ g_accessor :postal_code
39
+ g_accessor :state
33
40
 
34
41
  def initialize(&block)
35
42
  if block_given?
@@ -37,28 +44,10 @@ module Sem4r
37
44
  end
38
45
  end
39
46
 
40
- # <billingAddress>
41
- # <addressLine1>1600 Amphitheatre Parkway</addressLine1>
42
- # <addressLine2>Building #42</addressLine2>
43
- # <city>Mountain View</city>
44
- # <companyName>Some Company</companyName>
45
- # <countryCode>US</countryCode>
46
- # <emailAddress>Some@email</emailAddress>
47
- # <faxNumber>4085551213</faxNumber>
48
- # <name>Some contact</name>
49
- # <phoneNumber>4085551212</phoneNumber>
50
- # <postalCode>94043</postalCode>
51
- # <state>CA</state>
52
- # </billingAddress>
53
- def self.from_element(el)
54
- new do
55
- company_name el.elements["companyName"].text.strip
56
- address_line1 el.elements["addressLine1"].text.strip
57
- address_line2 el.elements["addressLine2"].text.strip
58
- city el.elements["city"].text.strip
59
- end
47
+ def self.from_element(*args)
48
+ _from_element(*args)
60
49
  end
61
-
50
+
62
51
  def to_s
63
52
  "#{@company_name} #{@address_line1} #{@address_line2} #{@city}"
64
53
  end
@@ -130,11 +130,11 @@ module Sem4r
130
130
 
131
131
  def self.from_element(account, el)
132
132
  new(account) do
133
- @id = el.elements["id"].text.strip.to_i # id is read only
134
- name el.elements["name"].text.strip
135
- start_day el.elements["startDay"].text.strip
136
- end_day el.elements["endDay"].text.strip
137
- @status = el.elements["status"].text.strip # status is read only
133
+ @id = el.at_xpath("id").text.strip.to_i # id is read only
134
+ name el.at_xpath("name").text.strip
135
+ start_day el.at_xpath("startDay").text.strip
136
+ end_day el.at_xpath("endDay").text.strip
137
+ @status = el.at_xpath("status").text.strip # status is read only
138
138
  end
139
139
  end
140
140
 
@@ -144,7 +144,7 @@ module Sem4r
144
144
  return @status unless refresh
145
145
  soap_message = service.report.status(credentials, @id)
146
146
  add_counters( soap_message.counters )
147
- el = REXML::XPath.first( soap_message.response, "//getReportJobStatusResponse/getReportJobStatusReturn")
147
+ el = soap_message.response.xpath("//getReportJobStatusResponse/getReportJobStatusReturn").first
148
148
  @status = el.text
149
149
  end
150
150
 
@@ -163,7 +163,7 @@ module Sem4r
163
163
  def schedule
164
164
  soap_message = service.report.schedule(credentials, to_xml)
165
165
  add_counters( soap_message.counters )
166
- el = REXML::XPath.first( soap_message.response, "//scheduleReportJobResponse/scheduleReportJobReturn")
166
+ el = soap_message.response.xpath("//scheduleReportJobResponse/scheduleReportJobReturn").first
167
167
  @id = el.text
168
168
  # puts "requested report assigned job nr. #{@job_id}"
169
169
  ReportJob.new(self, @id)
@@ -172,7 +172,7 @@ module Sem4r
172
172
  def url
173
173
  soap_message = service.report.url(credentials, @id)
174
174
  add_counters( soap_message.counters )
175
- el = REXML::XPath.first( soap_message.response, "//getReportDownloadUrlResponse/getReportDownloadUrlReturn")
175
+ el = soap_message.response.xpath("//getReportDownloadUrlResponse/getReportDownloadUrlReturn").first
176
176
  url = el.text
177
177
  url
178
178
  end