sem4r 0.1.1

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.
Files changed (187) hide show
  1. data/LICENSE +22 -0
  2. data/README.rdoc +74 -0
  3. data/Rakefile +126 -0
  4. data/VERSION.yml +5 -0
  5. data/bin/sem +34 -0
  6. data/config/sem4r.example.yml +51 -0
  7. data/examples_blog/2009-11-29-hello-world.rb +12 -0
  8. data/examples_blog/2009-12-12-create-campaign.rb +29 -0
  9. data/examples_blog/2010-02-06-constants-scope.rb +8 -0
  10. data/examples_blog/2010-02-07-ad-parameters.rb +47 -0
  11. data/examples_sem4r/01_get_account.rb +37 -0
  12. data/examples_sem4r/02_get_info.rb +32 -0
  13. data/examples_sem4r/03_list_ad.rb +47 -0
  14. data/examples_sem4r/04_list_keywords.rb +54 -0
  15. data/examples_sem4r/05_request_report.rb +51 -0
  16. data/examples_sem4r/05_request_report_2010.rb +40 -0
  17. data/examples_sem4r/06_create_campaigns.rb +86 -0
  18. data/examples_sem4r/07_create_campaigns_block.rb +99 -0
  19. data/examples_sem4r/07_create_campaigns_simple.rb +65 -0
  20. data/examples_sem4r/08_ad_params.rb +70 -0
  21. data/examples_sem4r/09_targeting_idea.rb +59 -0
  22. data/examples_sem4r/10_get_location.rb +28 -0
  23. data/examples_sem4r/11_submit_bulk_job.rb +82 -0
  24. data/examples_sem4r/12_list_bulk_job.rb +29 -0
  25. data/examples_sem4r/30_prune_empty_adgroup.rb +50 -0
  26. data/examples_sem4r/31_empty_accounts.rb +40 -0
  27. data/examples_sem4r/example_helper.rb +115 -0
  28. data/lib/sem4r/account.rb +349 -0
  29. data/lib/sem4r/ad_extension_override/ad_extension_override_service.rb +30 -0
  30. data/lib/sem4r/ad_group/ad_group.rb +340 -0
  31. data/lib/sem4r/ad_group/ad_group_bids.rb +170 -0
  32. data/lib/sem4r/ad_group/ad_group_service.rb +75 -0
  33. data/lib/sem4r/ad_group/mobile_ad_image.rb +33 -0
  34. data/lib/sem4r/ad_group_ad/ad_group_ad.rb +98 -0
  35. data/lib/sem4r/ad_group_ad/ad_group_ad_operations.rb +38 -0
  36. data/lib/sem4r/ad_group_ad/ad_group_ad_service.rb +56 -0
  37. data/lib/sem4r/ad_group_ad/ad_group_mobile_ad.rb +137 -0
  38. data/lib/sem4r/ad_group_ad/ad_group_text_ad.rb +98 -0
  39. data/lib/sem4r/ad_group_criterion/ad_group_criterion.rb +144 -0
  40. data/lib/sem4r/ad_group_criterion/ad_group_criterion_bids.rb +115 -0
  41. data/lib/sem4r/ad_group_criterion/ad_group_criterion_operations.rb +35 -0
  42. data/lib/sem4r/ad_group_criterion/ad_group_criterion_service.rb +58 -0
  43. data/lib/sem4r/ad_group_criterion/criterion.rb +67 -0
  44. data/lib/sem4r/ad_group_criterion/criterion_keyword.rb +80 -0
  45. data/lib/sem4r/ad_group_criterion/criterion_placement.rb +66 -0
  46. data/lib/sem4r/ad_param/ad_param.rb +96 -0
  47. data/lib/sem4r/ad_param/ad_param_operation.rb +34 -0
  48. data/lib/sem4r/ad_param/ad_param_service.rb +59 -0
  49. data/lib/sem4r/adwords.rb +242 -0
  50. data/lib/sem4r/api_counters.rb +7 -0
  51. data/lib/sem4r/base.rb +43 -0
  52. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job.rb +108 -0
  53. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_selector.rb +56 -0
  54. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_service.rb +57 -0
  55. data/lib/sem4r/bulk_mutate_job/job_operations.rb +35 -0
  56. data/lib/sem4r/campaign/campaign.rb +193 -0
  57. data/lib/sem4r/campaign/campaign_service.rb +91 -0
  58. data/lib/sem4r/campaign_criterion/campaign_criterion_service.rb +30 -0
  59. data/lib/sem4r/campaign_target/campaign_target_service.rb +30 -0
  60. data/lib/sem4r/cli/cli_command.rb +101 -0
  61. data/lib/sem4r/cli/cli_commands.rb +60 -0
  62. data/lib/sem4r/cli/cli_common_args.rb +293 -0
  63. data/lib/sem4r/cli/cli_download_report.rb +81 -0
  64. data/lib/sem4r/cli/cli_helpers.rb +57 -0
  65. data/lib/sem4r/cli/cli_ideas.rb +100 -0
  66. data/lib/sem4r/cli/cli_list_ads.rb +74 -0
  67. data/lib/sem4r/cli/cli_list_keywords.rb +76 -0
  68. data/lib/sem4r/cli/cli_request_report.rb +104 -0
  69. data/lib/sem4r/cli/cli_sem.rb +64 -0
  70. data/lib/sem4r/common/operation.rb +78 -0
  71. data/lib/sem4r/credentials.rb +86 -0
  72. data/lib/sem4r/extensions.rb +62 -0
  73. data/lib/sem4r/geo_location/geo_location_service.rb +59 -0
  74. data/lib/sem4r/info/info_service.rb +115 -0
  75. data/lib/sem4r/report_definition/report_definition.rb +104 -0
  76. data/lib/sem4r/report_definition/report_definition_operation.rb +34 -0
  77. data/lib/sem4r/report_definition/report_definition_selector.rb +31 -0
  78. data/lib/sem4r/report_definition/report_definition_service.rb +55 -0
  79. data/lib/sem4r/sem4r_error.rb +28 -0
  80. data/lib/sem4r/services/service.rb +74 -0
  81. data/lib/sem4r/services/soap_call.rb +100 -0
  82. data/lib/sem4r/services/soap_connector.rb +284 -0
  83. data/lib/sem4r/services/soap_error.rb +38 -0
  84. data/lib/sem4r/services/soap_message_v13.rb +129 -0
  85. data/lib/sem4r/services/soap_message_v2009.rb +170 -0
  86. data/lib/sem4r/soap_attributes.rb +141 -0
  87. data/lib/sem4r/targeting_idea/targeting_idea.rb +158 -0
  88. data/lib/sem4r/targeting_idea/targeting_idea_selector.rb +200 -0
  89. data/lib/sem4r/targeting_idea/targeting_idea_service.rb +51 -0
  90. data/lib/sem4r/v13_account/account_service.rb +54 -0
  91. data/lib/sem4r/v13_account/billing_address.rb +67 -0
  92. data/lib/sem4r/v13_report/report.rb +185 -0
  93. data/lib/sem4r/v13_report/report_job.rb +51 -0
  94. data/lib/sem4r/v13_report/report_service.rb +89 -0
  95. data/lib/sem4r/v13_traffic_estimator/traffic_estimator_service.rb +30 -0
  96. data/lib/sem4r.rb +142 -0
  97. data/lib/sem4r_cli.rb +40 -0
  98. data/sem4r.gemspec +247 -0
  99. data/spec/aggregates_spec_helper.rb +59 -0
  100. data/spec/fixtures/sem4r.example.yml +26 -0
  101. data/spec/fixtures/services/ad_group/get-first-req.xml +28 -0
  102. data/spec/fixtures/services/ad_group/get-first-res.xml +91 -0
  103. data/spec/fixtures/services/ad_group/get-manual-cpm-bids-req.xml +106 -0
  104. data/spec/fixtures/services/ad_group/get-manual-cpm-bids-res.xml +75 -0
  105. data/spec/fixtures/services/ad_group/mutate_add-req.xml +52 -0
  106. data/spec/fixtures/services/ad_group/mutate_add-res.xml +33 -0
  107. data/spec/fixtures/services/ad_group_ad/get_mobile_ad-req.xml +28 -0
  108. data/spec/fixtures/services/ad_group_ad/get_mobile_ad-res.xml +194 -0
  109. data/spec/fixtures/services/ad_group_ad/get_text_ad-req.xml +29 -0
  110. data/spec/fixtures/services/ad_group_ad/get_text_ad-res.xml +55 -0
  111. data/spec/fixtures/services/ad_group_ad/mutate_add_mobile_ad-req.xml +50 -0
  112. data/spec/fixtures/services/ad_group_ad/mutate_add_mobile_ad-res.xml +42 -0
  113. data/spec/fixtures/services/ad_group_ad/mutate_add_text_ad-req.xml +37 -0
  114. data/spec/fixtures/services/ad_group_ad/mutate_add_text_ad-res.xml +32 -0
  115. data/spec/fixtures/services/ad_group_ad/mutate_add_two_criterions-req.xml +83 -0
  116. data/spec/fixtures/services/ad_group_ad/mutate_add_two_criterions-res.xml +95 -0
  117. data/spec/fixtures/services/ad_group_criterion/get-req.xml +28 -0
  118. data/spec/fixtures/services/ad_group_criterion/get-res.xml +242 -0
  119. data/spec/fixtures/services/ad_group_criterion/mutate_add_criterion_keyword-req.xml +48 -0
  120. data/spec/fixtures/services/ad_group_criterion/mutate_add_criterion_keyword-res.xml +47 -0
  121. data/spec/fixtures/services/ad_group_criterion/mutate_add_criterion_placement-req.xml +35 -0
  122. data/spec/fixtures/services/ad_group_criterion/mutate_add_criterion_placement-res.xml +32 -0
  123. data/spec/fixtures/services/ad_group_criterion/mutate_add_negative_keyword-req.xml +37 -0
  124. data/spec/fixtures/services/ad_group_criterion/mutate_add_negative_keyword-res.xml +51 -0
  125. data/spec/fixtures/services/ad_param/mutate_set-req.xml +43 -0
  126. data/spec/fixtures/services/ad_param/mutate_set-res.xml +29 -0
  127. data/spec/fixtures/services/bulk_mutate_job/get-req.xml +36 -0
  128. data/spec/fixtures/services/bulk_mutate_job/get-res.xml +54 -0
  129. data/spec/fixtures/services/bulk_mutate_job/mutate-req.xml +69 -0
  130. data/spec/fixtures/services/bulk_mutate_job/mutate-res.xml +48 -0
  131. data/spec/fixtures/services/campaign/get-req.xml +37 -0
  132. data/spec/fixtures/services/campaign/get-res.xml +1986 -0
  133. data/spec/fixtures/services/campaign/mutate_add-req.xml +37 -0
  134. data/spec/fixtures/services/campaign/mutate_add-res.xml +42 -0
  135. data/spec/fixtures/services/error.xml +28 -0
  136. data/spec/fixtures/services/info/get_unit_count-req.xml +30 -0
  137. data/spec/fixtures/services/info/get_unit_count-res.xml +29 -0
  138. data/spec/fixtures/services/report_definition/mutate_add-req.xml +24 -0
  139. data/spec/fixtures/services/report_definition/mutate_add-req_orig.xml +45 -0
  140. data/spec/fixtures/services/targeting_idea/get-req-all-options.xml +57 -0
  141. data/spec/fixtures/services/targeting_idea/get-req.xml +60 -0
  142. data/spec/fixtures/services/targeting_idea/get-res.xml +3601 -0
  143. data/spec/fixtures/services/v13_account/get_account_info-req.xml +23 -0
  144. data/spec/fixtures/services/v13_account/get_account_info-res.xml +54 -0
  145. data/spec/fixtures/services/v13_account/get_client_accounts-req.xml +22 -0
  146. data/spec/fixtures/services/v13_account/get_client_accounts-res.xml +37 -0
  147. data/spec/fixtures/services/v13_report/get_all_jobs-req.xml +21 -0
  148. data/spec/fixtures/services/v13_report/get_all_jobs-res.xml +109 -0
  149. data/spec/fixtures/services/v13_report/schedule_report_job-req.xml +56 -0
  150. data/spec/fixtures/services/v13_report/schedule_report_job-res.xml +24 -0
  151. data/spec/sem4r/account_spec.rb +86 -0
  152. data/spec/sem4r/ad_group/ad_group_bids_spec.rb +67 -0
  153. data/spec/sem4r/ad_group/ad_group_service_spec.rb +66 -0
  154. data/spec/sem4r/ad_group/ad_group_spec.rb +212 -0
  155. data/spec/sem4r/ad_group_ad/ad_group_ad_operation_spec.rb +88 -0
  156. data/spec/sem4r/ad_group_ad/ad_group_ad_service_spec.rb +55 -0
  157. data/spec/sem4r/ad_group_ad/ad_group_ad_spec.rb +173 -0
  158. data/spec/sem4r/ad_group_criterion/ad_group_criterion_bids_spec.rb +60 -0
  159. data/spec/sem4r/ad_group_criterion/ad_group_criterion_service_spec.rb +55 -0
  160. data/spec/sem4r/ad_group_criterion/ad_group_criterion_spec.rb +103 -0
  161. data/spec/sem4r/ad_group_criterion/criterion_spec.rb +85 -0
  162. data/spec/sem4r/ad_param/ad_param_service_spec.rb +55 -0
  163. data/spec/sem4r/ad_param/ad_param_spec.rb +59 -0
  164. data/spec/sem4r/adwords_spec.rb +110 -0
  165. data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_service_spec.rb +63 -0
  166. data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_spec.rb +69 -0
  167. data/spec/sem4r/bulk_mutate_job/job_operation_spec.rb +48 -0
  168. data/spec/sem4r/campaign/campaign_service_spec.rb +66 -0
  169. data/spec/sem4r/campaign/campaign_spec.rb +105 -0
  170. data/spec/sem4r/cli/cli_spec.rb +71 -0
  171. data/spec/sem4r/credentials_spec.rb +65 -0
  172. data/spec/sem4r/report_definition/report_definition_service_spec.rb +44 -0
  173. data/spec/sem4r/report_definition/report_definition_spec.rb +105 -0
  174. data/spec/sem4r/rexml_parsing_spec.rb +103 -0
  175. data/spec/sem4r/services/service_spec.rb +36 -0
  176. data/spec/sem4r/services/soap_call_spec.rb +115 -0
  177. data/spec/sem4r/services/soap_message_v13_spec.rb +54 -0
  178. data/spec/sem4r/soap_attributes_spec.rb +116 -0
  179. data/spec/sem4r/targeting_idea/targeting_idea_selector_spec.rb +120 -0
  180. data/spec/sem4r/targeting_idea/targeting_idea_service_spec.rb +44 -0
  181. data/spec/sem4r/targeting_idea/targeting_idea_spec.rb +53 -0
  182. data/spec/sem4r/v13_account/account_service_spec.rb +60 -0
  183. data/spec/sem4r/v13_report/report_service_spec.rb +104 -0
  184. data/spec/sem4r/v13_report/report_spec.rb +79 -0
  185. data/spec/sem4r_spec_helper.rb +353 -0
  186. data/spec/spec_helper.rb +12 -0
  187. metadata +375 -0
@@ -0,0 +1,34 @@
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
+ class ReportDefinitionOperation < Operation
27
+ def initialize(&block)
28
+ @operation_type = "ReportDefinitionOperation"
29
+ if block_given?
30
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,31 @@
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
+ class ReportDefinitionSelector
27
+ def to_xml
28
+ "<selector></selector>"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
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
+ module Sem4r
25
+
26
+ class ReportDefinitionService
27
+ include SoapCall
28
+
29
+ def initialize(connector)
30
+ @connector = connector
31
+ @service_namespace = "https://adwords.google.com/api/adwords/cm/v201003"
32
+ @header_namespace = @service_namespace
33
+
34
+ @sandbox_service_url = "https://adwords-sandbox.google.com/api/adwords/cm/v201003/ReportDefinitionService"
35
+ end
36
+
37
+ soap_call_v2009 :get, :mutate => false
38
+ soap_call_v2009 :getReportFields, :mutate => false
39
+ soap_call_v2009 :mutate
40
+
41
+ private
42
+
43
+ def _get(xml)
44
+ "<get>#{xml}</get>"
45
+ end
46
+
47
+ def _get_report_fields
48
+ end
49
+
50
+ def _mutate(xml)
51
+ "<mutate>#{xml}</mutate>"
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,28 @@
1
+ # -------------------------------------------------------------------
2
+ # Copyright (c) 2009 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
+ module Sem4r
25
+ class Sem4rError < StandardError
26
+ end
27
+ end
28
+
@@ -0,0 +1,74 @@
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
+ module Sem4r
25
+ class Service
26
+
27
+ def initialize(connector)
28
+ @connector = connector
29
+ end
30
+
31
+ ###########################################################################
32
+ # services v13
33
+
34
+ %w{ account report traffic_estimator }.each do |service|
35
+ klass_name = service.split('_').map{|p| p.capitalize}.join('')
36
+ str=<<-EOFR
37
+ require 'sem4r/v13_#{service}/#{service}_service'
38
+ def #{service}
39
+ return @#{service}_service if @#{service}_service
40
+ @#{service}_service = #{klass_name}Service.new(@connector)
41
+ end
42
+ EOFR
43
+ eval str
44
+ end
45
+
46
+ ###########################################################################
47
+ # services v201003
48
+
49
+ %w{ ad_extension_override
50
+ ad_group
51
+ ad_group_ad
52
+ ad_param
53
+ ad_group_criterion
54
+ campaign
55
+ campaign_criterion
56
+ campaign_target
57
+ geo_location
58
+ info
59
+ targeting_idea
60
+ bulk_mutate_job
61
+ report_definition }.each do |service|
62
+ klass_name = service.split('_').map{|p| p.capitalize}.join('')
63
+ str=<<-EOFR
64
+ require 'sem4r/#{service}/#{service}_service'
65
+ def #{service}
66
+ return @#{service}_service if @#{service}_service
67
+ @#{service}_service = #{klass_name}Service.new(@connector)
68
+ end
69
+ EOFR
70
+ eval str
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,100 @@
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
+ module Sem4r
25
+ module SoapCall
26
+
27
+ def self.included(base)
28
+ base.extend ClassMethods
29
+ end
30
+
31
+ def helper_call_v13(credentials, soap_body_content)
32
+ re = /<(\w+)/m # use double blackslash because we are into string
33
+ match_data = soap_body_content.match(re)
34
+ if match_data
35
+ soap_action = match_data[1]
36
+ else
37
+ puts "errore"
38
+ puts soap_body_content
39
+ raise "Soapaction not found"
40
+ end
41
+
42
+ soap_message = SoapMessageV13.new( @connector, credentials)
43
+ soap_message.body = soap_body_content
44
+ if credentials.sandbox?
45
+ soap_message.send(@sandbox_service_url, soap_action)
46
+ else
47
+ soap_message.send(@production_service_url, soap_action)
48
+ end
49
+ end
50
+
51
+ def helper_call_v2009(credentials, soap_body_content)
52
+ soap_message = SoapMessageV2009.new(@connector, credentials)
53
+ soap_message.init( @header_namespace, @service_namespace )
54
+ soap_message.body = soap_body_content
55
+ if credentials.sandbox?
56
+ soap_message.send(@sandbox_service_url)
57
+ else
58
+ soap_message.send(@production_service_url)
59
+ end
60
+ end
61
+
62
+ module ClassMethods
63
+ def soap_call(helper_version, method, options = {})
64
+ options.assert_valid_keys(:mutate)
65
+ mutate = options.delete :mutate
66
+ if mutate.nil? or mutate
67
+ smutate = "credentials.mutable?"
68
+ else
69
+ smutate = "true"
70
+ end
71
+ # public_method_pars = ['credentials'].concat(args).join(",")
72
+
73
+ # private_method_pars = args.join(",")
74
+ # private_method_pars = ", #{private_method_pars}" unless private_method_pars.empty?
75
+
76
+ rubystr =<<-EOFS
77
+ define_method :#{method.to_sym} do |*args|
78
+ credentials = args.shift
79
+ if #{smutate}
80
+ soap_body_content = send("_#{method}", *args)
81
+ #{helper_version}(credentials, soap_body_content)
82
+ else
83
+ raise "mutate methods '#{method}' cannot be called on read_only profile"
84
+ end
85
+ end
86
+ EOFS
87
+ eval rubystr
88
+ end
89
+
90
+ def soap_call_v13(method, options = {})
91
+ soap_call("helper_call_v13", method, options)
92
+ end
93
+
94
+ def soap_call_v2009(method, options = {})
95
+ soap_call("helper_call_v2009", method, options)
96
+ end
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,284 @@
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
+ module Sem4r
25
+
26
+ class HttpConnector
27
+ begin
28
+ require 'patron'
29
+ UsePatron = false
30
+ # $stderr.puts "Using patron gems"
31
+ rescue LoadError
32
+ UsePatron = false
33
+ # $stderr.puts "Patron not found, degrade to net/https"
34
+ end
35
+
36
+ if !UsePatron
37
+ require 'net/https'
38
+ require 'uri'
39
+ # $stderr.puts "Using standard net/https"
40
+ end
41
+
42
+ def get_sess_for_host(uri)
43
+ @sessions ||= {}
44
+
45
+ if UsePatron
46
+ url = uri.scheme + "://" + uri.host
47
+ sess = @sessions[url]
48
+ unless sess
49
+ sess = Patron::Session.new
50
+ # sess.connect_timeout = 3000 #millis
51
+ sess.timeout = 12
52
+ sess.base_url = url
53
+ sess.headers['User-Agent'] = 'ruby'
54
+ @sessions[url] = sess
55
+ end
56
+ sess
57
+ else
58
+ url = uri.scheme + "://" + uri.host
59
+ sess = @sessions[url]
60
+ unless sess
61
+ sess = Net::HTTP.new(uri.host, uri.port)
62
+ sess.use_ssl = (uri.scheme == "https")
63
+ @sessions[url] = sess
64
+ end
65
+ sess
66
+ end
67
+ end
68
+
69
+ def invalidate_sess(uri)
70
+ sess = @sessions[uri.host]
71
+ if sess
72
+ # sess.close
73
+ @sessions[uri.host] = nil
74
+ end
75
+ end
76
+
77
+ def download(url, path_name)
78
+
79
+ if UsePatron
80
+ uri = URI.parse(url)
81
+ sess = get_sess_for_host(uri)
82
+ sess.get_file(uri.path, path_name)
83
+ else
84
+ require 'open-uri'
85
+ data = open(url){ |f| f.read }
86
+ File.open(path_name, "w") { |f| f.write(data) }
87
+ end
88
+
89
+ end
90
+ end
91
+
92
+ module SoapDumper
93
+
94
+ def initialize
95
+ @soap_dump = false
96
+ @soap_dump_log = nil
97
+ end
98
+
99
+ def dump_soap_options( dump_options )
100
+ @soap_dump = true
101
+ @soap_dump_log = nil
102
+
103
+ if dump_options[:directory]
104
+ @soap_dump_dir = dump_options[:directory]
105
+ else
106
+ @soap_dump_log = File.open( dump_options[:file], "w" )
107
+ end
108
+ @soap_dump_format = false || dump_options[:format]
109
+ end
110
+
111
+ def dump_soap(service_url, request_xml, response_xml)
112
+ return unless @soap_dump
113
+
114
+ %w{email password developerToken authToken clientEmail}.each do |tag|
115
+ request_xml = request_xml.gsub(/<#{tag}([^>]*)>.*<\/#{tag}>/, "<#{tag}\\1>***censured***</#{tag}>")
116
+ end
117
+ response_xml.gsub(/<email[^>]*>.+<\/email>/, "<email>**censured**</email>")
118
+
119
+ str =""
120
+ str << "<!-- Post to '#{service_url}' -->\n"
121
+
122
+ if !@soap_dump_format
123
+ str << request_xml
124
+ else
125
+ xml_document = REXML::Document.new(request_xml)
126
+ f = REXML::Formatters::Pretty.new
127
+ out = String.new
128
+ f.write(xml_document, out)
129
+ str << out
130
+ end
131
+ str << "\n"
132
+
133
+ str << "<!-- response -->\n"
134
+ if !@soap_dump_format
135
+ str << response_xml
136
+ else
137
+ xml_document = REXML::Document.new(response_xml)
138
+ f = REXML::Formatters::Pretty.new
139
+ out = String.new
140
+ f.write(xml_document, out)
141
+ str << out
142
+ end
143
+ str << "\n"
144
+ str << "<!-- end -->"
145
+
146
+ if @soap_dump_dir
147
+ service = service_url.match(/\/([^\/]*)$/)[1]
148
+ filename = Time.now.strftime "%Y%m%d-%H%M%S-%L-#{service}.log.xml"
149
+
150
+ if not File.directory?(@soap_dump_dir)
151
+ FileUtils.mkdir_p(@soap_dump_dir)
152
+ end
153
+
154
+ pathname = File.join(@soap_dump_dir, filename)
155
+ File.open(pathname, "w") {|f|
156
+ f.puts str
157
+ }
158
+ else
159
+ @soap_dump_log.puts str
160
+ @soap_dump_log.flush
161
+ end
162
+ end
163
+
164
+ end
165
+
166
+ #################
167
+
168
+ class SoapConnector < HttpConnector
169
+ include SoapDumper
170
+
171
+ MAXRETRIES = 3
172
+
173
+ def initialize
174
+ super
175
+ @logger = nil
176
+ end
177
+
178
+ def logger=(log)
179
+ @logger = log
180
+ end
181
+
182
+ def authentication_token(email, password)
183
+ str = "accountType=GOOGLE&Email=#{email}&Passwd=#{password}&service=adwords"
184
+ str = URI.escape(str)
185
+
186
+ uri = URI.parse( "https://www.google.com/accounts/ClientLogin" )
187
+ sess = get_sess_for_host(uri)
188
+ retries = 0; response = nil
189
+ while retries <= MAXRETRIES and response.nil?
190
+ retries += 1
191
+
192
+ headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
193
+
194
+ #########################
195
+ if UsePatron
196
+ begin
197
+ e = nil
198
+ response = sess.post( uri.path, str, headers )
199
+ status = response.status
200
+ rescue Patron::Error => e
201
+ end
202
+ else
203
+ response = sess.request_post(uri.path, str, headers )
204
+ # pp response.methods
205
+ # pp response.class.to_s
206
+ status = response.code.to_i
207
+ # pp "status: #{status}"
208
+ end
209
+ ##########################
210
+
211
+ if e
212
+ @logger.warn("authentication retries!!! #{e.to_s}") if @logger
213
+ invalidate_sess(uri)
214
+ sleep(2 * retries) # wait 1 sec
215
+ sess = get_sess_for_host(uri)
216
+ end
217
+ end
218
+ unless response
219
+ raise "Connection Error, Network is down?? :-((("
220
+ end
221
+
222
+ if status == 200
223
+ return response.body[/Auth=(.*)/, 1]
224
+ end
225
+ raise Sem4rError, "authentication failed status is #{status}"
226
+ end
227
+
228
+ def send(service_url, soap_action, soap_message)
229
+ begin
230
+ uri = URI.parse(service_url)
231
+ rescue URI::InvalidURIError
232
+ puts "Invalid url -- #{service_url}"
233
+ raise
234
+ end
235
+
236
+ headers = {
237
+ "Content-Type" => "text/xml; charset=utf-8",
238
+ "Content-Length" => soap_message.length.to_s,
239
+ "SOAPAction" => soap_action}
240
+
241
+ retries = 0; response = nil
242
+ sess = get_sess_for_host(uri)
243
+ while retries <= MAXRETRIES and response.nil?
244
+ retries += 1
245
+ @logger.info("Post to #{uri.path} (#{soap_action})") if @logger
246
+
247
+ ############################
248
+ if UsePatron
249
+ begin
250
+ e = nil
251
+ response = sess.post(uri.path, soap_message, headers)
252
+ rescue Patron::Error => e
253
+ end
254
+ else
255
+ begin
256
+ response = sess.request_post(uri.path, soap_message, headers)
257
+ rescue
258
+ raise
259
+ end
260
+ end
261
+ ##############################
262
+
263
+ if e
264
+ @logger.warn("soap_connector.send retries!!! #{e.to_s}") if @logger
265
+ invalidate_sess(uri)
266
+ sleep(2 * retries) # wait 1 sec
267
+ sess = get_sess_for_host(uri)
268
+ end
269
+ end
270
+ unless response
271
+ raise Sem4rError, "Connection Error"
272
+ end
273
+
274
+ response_xml = response.body
275
+ dump_soap(service_url, soap_message, response_xml)
276
+ response_xml
277
+ end
278
+
279
+ private
280
+
281
+
282
+ end
283
+
284
+ end
@@ -0,0 +1,38 @@
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
+ module Sem4r
25
+ class SoapError < Sem4rError
26
+ # attr_reader :fault_code
27
+ # attr_reader :fault_string
28
+ #
29
+ # def initialize(fault_code, fault_string)
30
+ # @fault_code = fault_code
31
+ # @fault_string = fault_string
32
+ # end
33
+ #
34
+ # def to_s
35
+ # "#{@fault_code}: '#{@fault_string}'"
36
+ # end
37
+ end
38
+ end