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,104 @@
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
+ class CliRequestReport < CliCommand
28
+
29
+ def self.command
30
+ "request"
31
+ end
32
+
33
+ def self.description
34
+ "schedule a report"
35
+ end
36
+
37
+ def initialize(account)
38
+ @account = account
39
+ end
40
+
41
+ def command_opt_parser(options)
42
+ opt_parser = OptionParser.new
43
+ opt_parser.banner = "Usage #{self.class.command} [command_options ] <report_id>"
44
+ opt_parser.separator ""
45
+ opt_parser.separator "#{self.class.description}"
46
+ opt_parser.on("-h", "--help", "show this message") do
47
+ puts opt_parser
48
+ options.exit = true
49
+ end
50
+ end
51
+
52
+ def parse_and_run(argv)
53
+ options = OpenStruct.new
54
+ rest = command_opt_parser(options).parse( argv )
55
+ if options.exit
56
+ return false
57
+ end
58
+
59
+ report = @account.report do
60
+ name 'boh'
61
+ type 'Url'
62
+ aggregation 'Daily'
63
+ cross_client true
64
+ zero_impression true
65
+
66
+ start_day '2010-01-01'
67
+ end_day '2010-01-30'
68
+
69
+ column "CustomerName"
70
+ column "ExternalCustomerId"
71
+ column "CampaignStatus"
72
+ column "Campaign"
73
+ column "CampaignId"
74
+ column "AdGroup"
75
+ column "AdGroupId"
76
+ column "AdGroupStatus"
77
+ column "QualityScore"
78
+ column "FirstPageCpc"
79
+ column "Keyword"
80
+ column "KeywordId"
81
+ column "KeywordTypeDisplay"
82
+ column "DestinationURL"
83
+ column "Impressions"
84
+ column "Clicks"
85
+ column "CTR"
86
+ column "CPC"
87
+ column "MaximumCPC"
88
+ column "Cost"
89
+ column "AveragePosition"
90
+ end
91
+
92
+ unless report.validate
93
+ puts "report not valid"
94
+ exit
95
+ end
96
+ puts "scheduled job"
97
+ job = report.schedule
98
+ job.wait(5) { |report, status| puts "status #{status}" }
99
+ report.download("test_report.xml")
100
+ account.adwords.p_counters
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,64 @@
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
+ # stdlib
25
+
26
+ module Sem4r
27
+
28
+ class CliSem
29
+
30
+ def self.run
31
+ cli = self.new
32
+ cli.parse_and_run(ARGV)
33
+ end
34
+
35
+ def parse_and_run( argv )
36
+ common_args, command, command_args = CliCommand.split_args(argv)
37
+
38
+ # $stderr.puts "debug -------------------"
39
+ # $stderr.puts "common_args: #{common_args}"
40
+ # $stderr.puts "command: #{command}"
41
+ # $stderr.puts "command_args: #{command_args}"
42
+ # $stderr.puts "debug -------------------"
43
+
44
+ cli_common_args = CliCommonArgs.new
45
+ success = cli_common_args.parse_and_run(common_args)
46
+ return false unless success
47
+
48
+ if command.nil?
49
+ puts "missing command try sem -h for help"
50
+ return false
51
+ end
52
+
53
+ begin
54
+ cmd = CliCommand.commands[command].new(cli_common_args)
55
+ return cmd.parse_and_run(command_args)
56
+ rescue Sem4rError
57
+ puts "I am so sorry! Something went wrong! (exception #{$!.to_s})"
58
+ return false
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,78 @@
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
+ class Operation
28
+ include SoapAttributes
29
+
30
+ enum :Operations, [
31
+ :ADD,
32
+ :REMOVE,
33
+ :SET]
34
+
35
+ attr_reader :operation_type
36
+ g_accessor :operator
37
+
38
+ def add(operand)
39
+ operator "ADD"
40
+ @operand = operand
41
+ self
42
+ end
43
+
44
+ def remove(operand)
45
+ operator "REMOVE"
46
+ @operand = operand
47
+ self
48
+ end
49
+
50
+ def set(operand)
51
+ operator "SET"
52
+ @operand = operand
53
+ self
54
+ end
55
+
56
+ def to_xml(tag)
57
+ if @operand == nil
58
+ raise Sem4rError, "Missing Operand"
59
+ end
60
+
61
+ xml = ""
62
+ if tag
63
+ xml += "<#{tag} xsi:type='#{operation_type}'>"
64
+ end
65
+ xml +=<<-EOS
66
+ <operator>#{operator}</operator>
67
+ #{@operand.to_xml('operand')}
68
+ EOS
69
+
70
+ if tag
71
+ xml += "</#{tag}>"
72
+ end
73
+ xml
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,86 @@
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 Credentials
27
+
28
+ attr_reader :environment
29
+ attr_reader :email
30
+ attr_reader :password
31
+ attr_reader :client_email
32
+ attr_reader :developer_token
33
+ attr_reader :useragent
34
+
35
+ def mutable?; @mutable; end
36
+ def sandbox?; @environment != "production" end
37
+ def production?; !sandbox?; end
38
+
39
+ def initialize( opts, client_email = nil )
40
+ case opts
41
+ when Hash
42
+ @environment= opts[:environment].dup.freeze
43
+ @email= opts[:email].dup.freeze
44
+ @password= opts[:password].dup.freeze
45
+ @useragent= "Sem4r Adwords Ruby Client Library (http://github.com/sem4r/sem4r)"
46
+ @developer_token= opts[:developer_token].dup.freeze
47
+ @mutable= opts[:mutable] ? true : false
48
+ when Credentials
49
+ @credentials = opts
50
+ @environment= @credentials.environment
51
+ @email= @credentials.email
52
+ @password= @credentials.password
53
+ @useragent= @credentials.useragent
54
+ @developer_token= @credentials.developer_token
55
+ @mutable= @credentials.mutable?
56
+ end
57
+
58
+ if client_email
59
+ @client_email = client_email.dup.freeze
60
+ end
61
+ end
62
+
63
+ def to_s
64
+ if @client_email
65
+ "client account: #{@email} - #{@client_email} (#{@mutable ? "mutable" : "read only"})"
66
+ else
67
+ "master account: #{@email} (#{@mutable ? "mutable" : "read only"})"
68
+ end
69
+ end
70
+
71
+ def connector=(connector)
72
+ @connector= connector
73
+ end
74
+
75
+ def authentication_token
76
+ return @authentication_token if @authentication_token
77
+ if @credentials
78
+ return @authentication_token = @credentials.authentication_token
79
+ end
80
+ raise "no connector in credentials! use credentials.connector=" unless @connector
81
+ @authentication_token = @connector.authentication_token(@email, @password)
82
+ @authentication_token
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,62 @@
1
+ module Sem4r #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Hash #:nodoc:
4
+ # Return a new hash with all keys converted to strings.
5
+ def stringify_keys
6
+ inject({}) do |options, (key, value)|
7
+ options[key.to_s] = value
8
+ options
9
+ end
10
+ end
11
+
12
+ # Destructively convert all keys to strings.
13
+ def stringify_keys!
14
+ keys.each do |key|
15
+ self[key.to_s] = delete(key)
16
+ end
17
+ self
18
+ end
19
+
20
+ # Return a new hash with all keys converted to symbols.
21
+ def symbolize_keys
22
+ inject({}) do |options, (key, value)|
23
+ options[(key.to_sym rescue key) || key] = value
24
+ options
25
+ end
26
+ end
27
+
28
+ # Destructively convert all keys to symbols.
29
+ def symbolize_keys!
30
+ self.replace(self.symbolize_keys)
31
+ end
32
+
33
+ alias_method :to_options, :symbolize_keys
34
+ alias_method :to_options!, :symbolize_keys!
35
+
36
+ # Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
37
+ # Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
38
+ # as keys, this will fail.
39
+ #
40
+ # ==== Examples
41
+ # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
42
+ # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
43
+ # { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
44
+ def assert_valid_keys(*valid_keys)
45
+ unknown_keys = keys - [valid_keys].flatten
46
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
47
+ end
48
+
49
+ #
50
+ # Giovanni
51
+ #
52
+ def assert_check_keys(*mkeys)
53
+ missing_keys = [mkeys].flatten - keys
54
+ raise(ArgumentError, "Missing key(s): #{missing_keys.join(", ")}") unless missing_keys.empty?
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ class Hash #:nodoc:
61
+ include Sem4r::CoreExtensions::Hash
62
+ end
@@ -0,0 +1,59 @@
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 GeoLocationService
26
+ include SoapCall
27
+
28
+ def initialize(connector)
29
+ @connector = connector
30
+
31
+ @header_namespace = "https://adwords.google.com/api/adwords/cm/v201003"
32
+ @service_namespace = @header_namespace
33
+
34
+ @sandbox_service_url = "https://adwords-sandbox.google.com/api/adwords/cm/v201003/GeoLocationService"
35
+ @production_service_url = "https://adwords.google.com/api/adwords/cm/v201003/GeoLocationService"
36
+ end
37
+
38
+ soap_call_v2009 :get
39
+
40
+ ################
41
+
42
+ private
43
+
44
+ def _get(xml)
45
+ <<-EOFS
46
+ <s:get>
47
+ <s:selector>
48
+ <addresses>
49
+ <streetAddress>Via Nazionale,10</streetAddress>
50
+ <cityName>Rome</cityName>
51
+ <countryCode>IT</countryCode>
52
+ </addresses>
53
+ </s:selector>
54
+ </s:get>
55
+ EOFS
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,115 @@
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
+ # <env:Body>
25
+ # <n3:get xmlns:n3="https://adwords.google.com/api/adwords/info/v200909">
26
+ # <n3:selector>
27
+ # <n3:dateRange xmlns:n4="https://adwords.google.com/api/adwords/cm/v200909">
28
+ # <n4:min>20090101</n4:min>
29
+ # <n4:max>20091030</n4:max>
30
+ # </n3:dateRange>
31
+ # <n3:apiUsageType>UNIT_COUNT</n3:apiUsageType>
32
+ # </n3:selector>
33
+ # </n3:get>
34
+ # </env:Body>
35
+ #</env:Envelope>
36
+
37
+
38
+ module Sem4r
39
+ class InfoService
40
+ include SoapCall
41
+
42
+ def initialize(connector)
43
+ @connector = connector
44
+ @header_namespace = "https://adwords.google.com/api/adwords/cm/v201003"
45
+ @service_namespace = "https://adwords.google.com/api/adwords/info/v201003"
46
+
47
+ @production_service_url = "https://adwords.google.com/api/adwords/info/v201003/InfoService"
48
+ @sandbox_service_url = "https://adwords-sandbox.google.com/api/adwords/info/v201003/InfoService"
49
+ end
50
+
51
+
52
+ soap_call_v2009 :unit_cost
53
+
54
+ def _unit_cost( usage_type )
55
+ <<-EOFS
56
+ <s:get>
57
+ <s:selector>
58
+ <s:dateRange>
59
+ <min>20090101</min>
60
+ <max>20091105</max>
61
+ </s:dateRange>
62
+ <s:apiUsageType>#{usage_type}</s:apiUsageType>
63
+ </s:selector>
64
+ </s:get>
65
+ EOFS
66
+ end
67
+
68
+
69
+ # Total units used since the beginning of the year: 0
70
+ # def old_unit_cost(credentials)
71
+ #
72
+ # soap_message = @connector.message_v2009(credentials, @header_namespace, @service_namespace )
73
+ # soap_message.body = "soap_body_content"
74
+ #
75
+ #
76
+ # soap_message.instance_eval do
77
+ # def build_soap_message
78
+ # str = <<-EOFS
79
+ #<?xml version="1.0" encoding="utf-8" ?>
80
+ # <env:Envelope
81
+ # xmlns:xsd="http://www.w3.org/2001/XMLSchema"
82
+ # xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
83
+ # xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
84
+ # xmlns="https://adwords.google.com/api/adwords/cm/v200909"
85
+ # xmlns:s="https://adwords.google.com/api/adwords/info/v200909">
86
+ # <env:Header>
87
+ # <s:RequestHeader env:mustUnderstand="0">
88
+ # <authToken>#{@credentials.authentication_token}</authToken>
89
+ # <userAgent>adwords4r: Sample User Agent</userAgent>
90
+ # <developerToken>#{@credentials.developer_token}</developerToken>
91
+ # </s:RequestHeader>
92
+ # </env:Header>
93
+ # <env:Body >
94
+ # <s:get>
95
+ # <s:selector>
96
+ # <s:dateRange>
97
+ # <min>20090101</min>
98
+ # <max>20091105</max>
99
+ # </s:dateRange>
100
+ # <s:apiUsageType>UNIT_COUNT</s:apiUsageType>
101
+ # </s:selector>
102
+ # </s:get>
103
+ # </env:Body>
104
+ # </env:Envelope>
105
+ #EOFS
106
+ # str
107
+ # end
108
+ # end
109
+ #
110
+ # result_xml = soap_message.send(@sandbox_service_url)
111
+ # result_xml
112
+ # end
113
+
114
+ end
115
+ end
@@ -0,0 +1,104 @@
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
+ class ReportDefinition < Base
28
+
29
+ attr_reader :id
30
+
31
+ g_accessor :name
32
+
33
+ def initialize(account, name = nil, &block)
34
+ super( account.adwords, account.credentials )
35
+ @account = account
36
+ self.name = name
37
+ if block_given?
38
+ @inside_initialize = true
39
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
40
+ end
41
+ @inside_initialize = false
42
+ end
43
+
44
+ def inside_initialize?
45
+ @inside_initialize
46
+ end
47
+
48
+ def to_s
49
+ "'#{@name}'"
50
+ end
51
+
52
+ def to_xml(tag)
53
+ builder = Builder::XmlMarkup.new
54
+ builder.tag!(tag) do |t|
55
+ t.reportName @name
56
+ end
57
+ end
58
+
59
+
60
+ ###########################################################################
61
+
62
+ def self.from_element(account, el)
63
+ new(account) do
64
+ @id = el.elements["id"].text.strip.to_i
65
+ name el.elements["name"].text.strip
66
+ status el.elements['status'].text.strip # ACTIVE, PAUSED, DELETED
67
+ serving_status el.elements['servingStatus']
68
+ start_date el.elements['startDate']
69
+ end_date el.elements['endDate']
70
+ end
71
+ end
72
+
73
+ def self.create(account, &block)
74
+ new(account, &block).save
75
+ end
76
+
77
+ def save
78
+ unless @id
79
+ op = ReportDefinitionOperation.new
80
+ op.add(self)
81
+ puts op.to_xml "operations"
82
+ soap_message = service.report_definition.mutate(credentials, op.to_xml("operations"))
83
+ add_counters( soap_message.counters )
84
+ rval = REXML::XPath.first( soap_message.response, "//mutateResponse/rval")
85
+ id = REXML::XPath.match( rval, "value/id" ).first
86
+ @id = id.text.strip.to_i
87
+ end
88
+ self
89
+ end
90
+
91
+ def delete
92
+ soap_message = service.campaign.delete(credentials, @id)
93
+ add_counters( soap_message.counters )
94
+ @id = -1 # logical delete
95
+ end
96
+
97
+ ###########################################################################
98
+
99
+ def empty?
100
+ _ad_groups.empty?
101
+ end
102
+
103
+ end
104
+ end