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,293 @@
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 CliCommonArgs
28
+
29
+ def initialize
30
+ # defaults
31
+ @options = OpenStruct.new({
32
+ :verbose => true,
33
+ :force => false,
34
+ :default_logging => true,
35
+ # :dump_soap_to_file => true,
36
+ # :dump_soap_to_directory => true,
37
+ :profile => 'sandbox'
38
+ })
39
+ end
40
+
41
+ def parse_and_run(argv)
42
+ parse(argv)
43
+ end
44
+
45
+ def parse(argv)
46
+
47
+ begin
48
+ rest = opt_parser(@options).parse(argv)
49
+ rescue OptionParser::AmbiguousOption => e
50
+ puts e.message
51
+ return false
52
+ end
53
+
54
+ if rest.length > 0
55
+ # cannot happen
56
+ puts "unknow options #{rest.join}"
57
+ return false
58
+ end
59
+
60
+ if @options.list_profiles
61
+ puts "Profiles:"
62
+ profiles = Adwords.profiles( @options.config_name )
63
+ names = profiles.keys.map &:to_s
64
+ names.sort.each do |s|
65
+ puts " #{s} (#{profiles[s]['email']})"
66
+ end
67
+ end
68
+
69
+ !@options.exit
70
+ end
71
+
72
+ def opt_parser(options)
73
+ opt_parser = OptionParser.new
74
+ opt_parser.banner = "Sem is a simple command line interface using the sem4r library."
75
+ opt_parser.separator "It's alpha software, please don't use in production or use it at your risk!"
76
+ opt_parser.separator "Further information: http://www.sem4r.com"
77
+ opt_parser.separator ""
78
+ opt_parser.separator "Usage: sem [options] [COMMAND [command options]]"
79
+
80
+ opt_parser.separator ""
81
+ opt_parser.separator "execute COMMAND to an adwords account using google adwords api"
82
+ opt_parser.separator "To view help and options for a particular command, use 'sem COMMAND -h'"
83
+
84
+ #
85
+ # common options
86
+ #
87
+ opt_parser.separator ""
88
+ opt_parser.separator "common options: "
89
+ opt_parser.separator ""
90
+
91
+ opt_parser.on("-h", "--help", "show this message") do
92
+ puts opt_parser
93
+ options.exit = true
94
+ end
95
+
96
+ opt_parser.on("--version", "show the sem4r version") do
97
+ puts "sem4r version #{Sem4r::version}"
98
+ options.exit = true
99
+ end
100
+
101
+ opt_parser.on("-v", "--[no-]verbose", "run verbosely") do |v|
102
+ options.verbose = v
103
+ end
104
+
105
+ opt_parser.on("-q", "--quiet", "quiet mode as --no-verbose") do |v|
106
+ options.verbose = false
107
+ end
108
+
109
+ opt_parser.on("-l", "--list-commands", "list commands") do
110
+ puts "SEM commands are:"
111
+ commands = CliCommand.commands.values.sort {|a,b| a.command <=> b.command }
112
+ commands.each do |cmd|
113
+ printf " %-20s %s\n", cmd.command, cmd.description
114
+ end
115
+ puts
116
+ puts "For help on a particular command, use 'sem COMMAND -h'"
117
+ options.exit = true
118
+ end
119
+
120
+ opt_parser.separator ""
121
+ opt_parser.separator "logging options: "
122
+ opt_parser.separator ""
123
+
124
+ opt_parser.on("--log FILE", "log sem4r messages to file") do |v|
125
+ options.logger = v
126
+ end
127
+
128
+ opt_parser.on("-f", "--dump-file FILE", "dump soap conversation to file") do |v|
129
+ options.dump_soap_to_file = v
130
+ end
131
+
132
+ str = "dump soap conversation to directory: each \n"
133
+ str << (" " * 37) + "request/response is in a single file"
134
+ opt_parser.on("-d", "--dump-dir DIRECTORY", str) do |v|
135
+ options.dump_soap_to_directory = v
136
+ end
137
+
138
+ opt_parser.separator ""
139
+ opt_parser.separator "profile and credentials options: "
140
+ opt_parser.separator " credentials options overwrite profile attributes"
141
+ opt_parser.separator ""
142
+
143
+ str = "file where profiles are defined\n"
144
+ str << (" " * 37) + "(default $HOME/.sem4r/sem4r.yaml)"
145
+ opt_parser.on("--config CONFIG", str) do |config|
146
+ options.config_name = config
147
+ end
148
+
149
+ opt_parser.on("--list-profiles", "list profiles") do
150
+ options.list_profiles = true
151
+ options.exit = true
152
+ end
153
+
154
+ opt_parser.on("-p", "--profile PROFILE", "select profile (default is sandbox)") do |profile|
155
+ options.profile = profile
156
+ end
157
+
158
+ # email
159
+ opt_parser.on("--email EMAIL",
160
+ "email of adwords account") do |email|
161
+ options.email = email
162
+ end
163
+
164
+ # password
165
+ opt_parser.on("--password PASSWORD",
166
+ "password of adwords account") do |password|
167
+ options.password = password
168
+ end
169
+
170
+ # developer token
171
+ opt_parser.on("--token TOKEN",
172
+ "developer token to access adwords api") do |token|
173
+ options.developer_token = token
174
+ end
175
+
176
+ # client account
177
+ opt_parser.on("-c", "--client EMAIL",
178
+ "email for client account") do |email|
179
+ options.client_email = email
180
+ end
181
+ opt_parser.separator ""
182
+ opt_parser
183
+ end
184
+
185
+ def read_credentials_from_console
186
+ unless @options.environment
187
+ # The new and improved choose()...
188
+ say("\nThis is the new mode (default)...")
189
+ choose do |menu|
190
+ menu.prompt = "Please choose your favorite programming language? "
191
+
192
+ menu.choice :ruby do say("Good choice!") end
193
+ menu.choices(:python, :perl) do say("Not from around here, are you?") end
194
+ end
195
+ end
196
+
197
+ @options.email ||= ask("Enter adwords email: ")
198
+ @options.password ||= ask("Enter adwords password: ") { |q| q.echo = "x" }
199
+ @options.developer_token ||= ask("Enter adwords developer_token: ")
200
+
201
+ config = {
202
+ :environment => @options.environment,
203
+ :email => @options.email,
204
+ :password => @options.password,
205
+ :developer_token => @options.developer_token
206
+ }
207
+
208
+ pp config
209
+ unless agree("credentials are correct?")
210
+ exit
211
+ end
212
+ config
213
+ end
214
+
215
+ def account
216
+ #
217
+ # select profile
218
+ #
219
+ options = {}
220
+ if @options.config_name
221
+ options[:config_file] = @options.config_name
222
+ end
223
+ adwords = Adwords.new( @options.profile, options )
224
+ if @options.verbose
225
+ puts "using #{adwords.profile} profile"
226
+ puts "config file is #{adwords.config_file}"
227
+ end
228
+
229
+ #
230
+ # logging soap conversation
231
+ #
232
+ if @options.default_logging
233
+ configdir = File.join( ENV['HOME'], ".sem4r" )
234
+ unless File.exists?(configdir)
235
+ puts "Directory #{configdir} not exists"
236
+ FileUtils.mkdir(configdir)
237
+ end
238
+ dir = File.join(configdir, Time.new.strftime("%Y%m%d-soap-dump"))
239
+ @options.dump_soap_to_directory = dir
240
+
241
+ file = File.join(configdir, Time.new.strftime("%Y%m%d-sem4r-log"))
242
+ @options.logger = file
243
+ end
244
+
245
+ if @options.dump_soap_to_file
246
+ filename = @options.dump_soap_to_file
247
+ o = { :file => filename }
248
+ adwords.dump_soap_options( o )
249
+ end
250
+ if @options.dump_soap_to_directory
251
+ dir = @options.dump_soap_to_directory
252
+ o = { :directory => dir, :format => true }
253
+ adwords.dump_soap_options( o )
254
+ end
255
+ if @options.verbose and adwords.dump_soap?
256
+ puts "Logging soap conversation to '#{adwords.dump_soap_where}'"
257
+ end
258
+ if !adwords.dump_soap?
259
+ puts "it is highly recommended to activate the dump soap log"
260
+ end
261
+
262
+ #
263
+ # logging
264
+ #
265
+ # filename = File.join( tmp_dirname, File.basename(example_file).sub(/\.rb$/, ".log") )
266
+ if @options.logger
267
+ # filename = "sem.log"
268
+ adwords.logger = @options.logger
269
+ end
270
+ if adwords.logger
271
+ puts "Logger activated"
272
+ end
273
+ # adwords.logger = Logger.new(STDOUT)
274
+
275
+ #
276
+ # select account for command
277
+ #
278
+ if @options.client_email
279
+ account = adwords.account.client_accounts.find{ |c| c.client_email =~ /^#{@options.client_email}/ }
280
+ if account.nil?
281
+ puts "client account not found"
282
+ else
283
+ puts "using client #{account.client_email}"
284
+ end
285
+ else
286
+ account = adwords.account
287
+ end
288
+ return account
289
+ end
290
+
291
+ end
292
+
293
+ end
@@ -0,0 +1,81 @@
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 CliDownloadReport < CliCommand
27
+
28
+ def self.command
29
+ "download"
30
+ end
31
+
32
+ def self.description
33
+ "download a generated report"
34
+ end
35
+
36
+ def initialize(common_args)
37
+ @common_args = common_args
38
+ end
39
+
40
+ def command_opt_parser(options)
41
+ opt_parser = OptionParser.new
42
+ opt_parser.banner = "Usage #{self.class.command} [command_options ] <report_id>"
43
+ opt_parser.separator ""
44
+ opt_parser.separator "#{self.class.description}"
45
+ opt_parser.on("-h", "--help", "show this message") do
46
+ puts opt_parser
47
+ options.exit = true
48
+ end
49
+ end
50
+
51
+ def parse_and_run(argv)
52
+ options = OpenStruct.new
53
+ rest = command_opt_parser(options).parse( argv )
54
+ if options.exit
55
+ return false
56
+ end
57
+ if rest.length != 1
58
+ puts "missing report id"
59
+ return false
60
+ end
61
+
62
+ account = @common_args.account
63
+ report_id = rest[0].to_i
64
+ report = account.reports.find { |r| r.id == report_id }
65
+ if report.nil?
66
+ puts "report '#{report_id}' not found"
67
+ return false
68
+ end
69
+
70
+ if report.status != 'Completed'
71
+ puts "cannot donwload report with status '#{report.status}'"
72
+ return false
73
+ end
74
+ report.download("test_report.xml")
75
+
76
+ account.adwords.p_counters
77
+ return true
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,57 @@
1
+ module Sem4r
2
+ # From http://gist.github.com/72234
3
+ #
4
+ # mysql-style output for an array of ActiveRecord objects
5
+ #
6
+ # Usage:
7
+ # report(records) # displays report with all fields
8
+ # report(records, :field1, :field2, ...) # displays report with given fields
9
+ #
10
+ # Example:
11
+ # >> report(records, :id, :amount, :created_at)
12
+ # +------+-----------+--------------------------------+
13
+ # | id | amount | created_at |
14
+ # +------+-----------+--------------------------------+
15
+ # | 8301 | $12.40 | Sat Feb 28 09:20:47 -0800 2009 |
16
+ # | 6060 | $39.62 | Sun Feb 15 14:45:38 -0800 2009 |
17
+ # | 6061 | $167.52 | Sun Feb 15 14:45:38 -0800 2009 |
18
+ # | 6067 | $12.00 | Sun Feb 15 14:45:40 -0800 2009 |
19
+ # | 6059 | $1,000.00 | Sun Feb 15 14:45:38 -0800 2009 |
20
+ # +------+-----------+--------------------------------+
21
+ # 5 rows in set
22
+ #
23
+ def self.report(items, *fields)
24
+ # find max length for each field; start with the field names themselves
25
+ max_len = Hash[*fields.map {|f| [f, f.to_s.length]}.flatten]
26
+
27
+ items.each do |item|
28
+ fields.each do |field|
29
+ len = item.send(field).to_s.length
30
+ max_len[field] = len if len > max_len[field]
31
+ end
32
+ end
33
+
34
+ border = '+-' + fields.map {|f| '-' * max_len[f] }.join('-+-') + '-+'
35
+ title_row = '| ' + fields.map {|f| sprintf("%-#{max_len[f]}s", f.to_s) }.join(' | ') + ' |'
36
+
37
+ puts border
38
+ puts title_row
39
+ puts border
40
+
41
+ items.each do |item|
42
+ row = '| ' + fields.map {|f| sprintf("%-#{max_len[f]}s", item.send(f)) }.join(' | ') + ' |'
43
+ puts row
44
+ end
45
+
46
+ puts border
47
+ puts "#{items.length} rows in set\n"
48
+ end
49
+ end
50
+
51
+ if __FILE__ == $0
52
+ require 'ostruct'
53
+ o = OpenStruct.new
54
+ o.a = 1
55
+ o.b = 2
56
+ Sem4r::report( [o], :a, :b )
57
+ 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
+
25
+ module Sem4r
26
+
27
+ class CliIdeas < CliCommand
28
+
29
+ def self.command
30
+ "ideas"
31
+ end
32
+
33
+ def self.description
34
+ "list ideas"
35
+ end
36
+
37
+ def initialize(common_args)
38
+ @common_args = common_args
39
+ end
40
+
41
+ def opt_parser(options)
42
+ opt_parser = OptionParser.new
43
+ opt_parser.banner= "#{self.class.description}"
44
+ opt_parser.separator "Usage: sem [options] idea <keyword>"
45
+
46
+ opt_parser.separator ""
47
+ opt_parser.separator "common options: "
48
+ opt_parser.separator ""
49
+ opt_parser.on("-h", "--help", "show this message") do
50
+ puts opt_parser
51
+ options.exit = true
52
+ end
53
+ end
54
+
55
+ def parse_and_run(argv)
56
+ options = OpenStruct.new
57
+ rest = opt_parser(options).parse( argv )
58
+ return false if options.exit
59
+ if rest.length < 1
60
+ puts "keyword missing see help"
61
+ return false
62
+ end
63
+
64
+ @keyword = rest[1]
65
+ account = @common_args.account
66
+ unless account
67
+ puts "select an account!"
68
+ else
69
+ _run account
70
+ end
71
+ end
72
+
73
+ def _run(account)
74
+ ideas = account.targeting_idea do
75
+ idea_type "KEYWORD"
76
+ request_type "IDEAS"
77
+
78
+ related_to_keyword_search_parameter do
79
+ text @keyword
80
+ match_type 'EXACT'
81
+ end
82
+ end
83
+
84
+ items = []
85
+ ideas.each do |i|
86
+ i.each do |a|
87
+ next if a.class != TKeywordAttribute
88
+ o = OpenStruct.new
89
+ o.text = a.text
90
+ o.match = a.match_type
91
+ items << o
92
+ end
93
+ end
94
+
95
+ Sem4r::report(items, :text, :match)
96
+ account.adwords.p_counters
97
+ end
98
+
99
+ end
100
+ end
@@ -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
+
25
+ module Sem4r
26
+
27
+ CliListAds = CliCommand.define_command("ads", "list ads") do |account|
28
+ puts "List AdGroup Advertising"
29
+
30
+ # if the accounts have client_accounts it is a master
31
+ client_accounts = account.client_accounts
32
+ if client_accounts.empty?
33
+ client_accounts = [account]
34
+ end
35
+
36
+ items = []
37
+ need_newline = false
38
+
39
+ client_accounts.each do |client_account|
40
+ if need_newline
41
+ puts
42
+ need_newline = false
43
+ end
44
+
45
+ #--
46
+ puts "examinate account '#{client_account.credentials.client_email}'"
47
+ client_account.campaigns.each do |campaign|
48
+ # puts "examinate campaign '#{campaign}'"
49
+ campaign.ad_groups.each do |ad_group|
50
+ # puts "examinate adgroup '#{ad_group}'"
51
+ ad_group.ads.each do |ad|
52
+ o = OpenStruct.new
53
+ o.client = client_account.credentials.client_email
54
+ o.campaign = campaign.name
55
+ o.ad_group = ad_group.name
56
+ o.url = ad.url
57
+ o.url = ad.display_url
58
+ items << o
59
+ end
60
+ print "."
61
+ need_newline = true
62
+ end
63
+ end
64
+ #--
65
+
66
+ end
67
+ if need_newline
68
+ puts
69
+ need_newline = false
70
+ end
71
+ report(items, :client, :campaign, :ad_group, :url, :display_url)
72
+ account.adwords.p_counters
73
+ end
74
+ end
@@ -0,0 +1,76 @@
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
+ CliListKeywords = CliCommand.define_command("keywords", "list keywords") do |account |
28
+
29
+ # if the account have client_accounts it is a master
30
+ client_accounts = account.client_accounts
31
+ if client_accounts.empty?
32
+ client_accounts = [account]
33
+ end
34
+
35
+ items = []
36
+ need_newline = false
37
+ client_accounts.each do |client_account|
38
+ if need_newline
39
+ puts
40
+ need_newline = false
41
+ end
42
+ puts "examinate account '#{client_account.credentials.client_email}'"
43
+ client_account.campaigns.each do |campaign|
44
+ # puts "examinate campaign '#{campaign}'"
45
+ campaign.ad_groups.each do |ad_group|
46
+ ad_group.criterions.each do |criterion|
47
+
48
+ row = OpenStruct.new
49
+ row.client = client_account.credentials.client_email
50
+ row.campaign = campaign.name
51
+ row.ad_group = ad_group.name
52
+
53
+ row.type = criterion.type
54
+ case criterion.type
55
+ when Criterion::Keyword
56
+ row.text = criterion.text
57
+ row.match = criterion.match
58
+ when Criterion::Placement
59
+ row.text = criterion.url
60
+ end
61
+ items << row
62
+ print "."
63
+ need_newline = true
64
+ end
65
+ end
66
+ end
67
+ end
68
+ if need_newline
69
+ puts
70
+ need_newline = false
71
+ end
72
+ report(items, :client, :campaign, :ad_group, :type, :text, :match)
73
+ account.adwords.p_counters
74
+ end
75
+
76
+ end