sem4r 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +13 -2
- data/Gemfile.lock +13 -7
- data/README.rdoc +44 -7
- data/Rakefile +2 -122
- data/VERSION.yml +1 -1
- data/bin/sem +1 -0
- data/examples_sem4r/01_get_account.rb +1 -0
- data/examples_sem4r/02_get_info.rb +1 -0
- data/examples_sem4r/03_list_ad.rb +1 -0
- data/examples_sem4r/04_list_keywords.rb +1 -0
- data/examples_sem4r/05_request_report.rb +25 -14
- data/examples_sem4r/{05_request_report_2010.rb → 06_request_report_definition.rb} +2 -4
- data/examples_sem4r/{06_create_campaigns.rb → 07_create_campaigns.rb} +1 -0
- data/examples_sem4r/{07_create_campaigns_block.rb → 08_create_campaigns_block.rb} +1 -0
- data/examples_sem4r/{07_create_campaigns_simple.rb → 09_create_campaigns_simple.rb} +1 -0
- data/examples_sem4r/{08_ad_params.rb → 10_ad_params.rb} +1 -0
- data/examples_sem4r/{09_targeting_idea.rb → 11_targeting_idea.rb} +1 -0
- data/examples_sem4r/{10_get_location.rb → 12_get_location.rb} +1 -0
- data/examples_sem4r/{11_submit_bulk_job.rb → 13_submit_bulk_job.rb} +1 -1
- data/examples_sem4r/{12_list_bulk_job.rb → 14_list_bulk_job.rb} +3 -0
- data/examples_sem4r/30_prune_empty_adgroup.rb +1 -0
- data/examples_sem4r/31_empty_accounts.rb +1 -0
- data/examples_sem4r/example_helper.rb +2 -1
- data/lib/sem4r/ad_group/ad_group.rb +22 -7
- data/lib/sem4r/ad_group/ad_group_bids.rb +1 -1
- data/lib/sem4r/ad_group/ad_group_service.rb +12 -5
- data/lib/sem4r/ad_group_ad/ad_group_ad.rb +1 -0
- data/lib/sem4r/ad_group_ad/ad_group_ad_operations.rb +1 -0
- data/lib/sem4r/ad_group_ad/ad_group_ad_service.rb +14 -9
- data/lib/sem4r/ad_group_ad/ad_group_mobile_ad.rb +16 -25
- data/lib/sem4r/ad_group_ad/ad_group_text_ad.rb +18 -14
- data/lib/sem4r/ad_group_criterion/ad_group_criterion.rb +27 -19
- data/lib/sem4r/ad_group_criterion/ad_group_criterion_bids.rb +2 -1
- data/lib/sem4r/ad_group_criterion/ad_group_criterion_operations.rb +1 -0
- data/lib/sem4r/ad_group_criterion/ad_group_criterion_service.rb +9 -4
- data/lib/sem4r/ad_group_criterion/criterion.rb +1 -0
- data/lib/sem4r/ad_group_criterion/criterion_keyword.rb +1 -0
- data/lib/sem4r/ad_group_criterion/criterion_placement.rb +1 -0
- data/lib/sem4r/ad_param/ad_param.rb +24 -8
- data/lib/sem4r/ad_param/ad_param_service.rb +8 -5
- data/lib/sem4r/adwords.rb +232 -76
- data/lib/sem4r/base.rb +1 -1
- data/lib/sem4r/bulk_mutate_job/bulk_mutate_job.rb +41 -35
- data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_account_extension.rb +49 -15
- data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_selector.rb +29 -20
- data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_service.rb +13 -14
- data/lib/sem4r/bulk_mutate_job/job_operations.rb +1 -1
- data/lib/sem4r/campaign/campaign.rb +1 -0
- data/lib/sem4r/campaign/campaign_account_extension.rb +2 -1
- data/lib/sem4r/campaign/campaign_service.rb +9 -5
- data/lib/sem4r/credentials.rb +11 -5
- data/lib/sem4r/geo_location/address.rb +56 -0
- data/lib/sem4r/geo_location/geo_location_account_extension.rb +27 -6
- data/lib/sem4r/geo_location/geo_location_selector.rb +57 -0
- data/lib/sem4r/geo_location/geo_location_service.rb +9 -16
- data/lib/sem4r/info/info_account_extension.rb +3 -2
- data/lib/sem4r/info/info_selector.rb +2 -1
- data/lib/sem4r/info/info_service.rb +10 -3
- data/lib/sem4r/operation.rb +39 -20
- data/lib/sem4r/report_definition/report_definition.rb +37 -19
- data/lib/sem4r/report_definition/report_definition_account_extension.rb +66 -16
- data/lib/sem4r/report_definition/report_definition_operation.rb +2 -2
- data/lib/sem4r/report_definition/report_definition_selector.rb +1 -1
- data/lib/sem4r/report_definition/report_definition_service.rb +11 -7
- data/lib/sem4r/report_definition/report_field.rb +3 -2
- data/lib/sem4r/sem4r_templates.rb +77 -0
- data/lib/sem4r/{services/service.rb → service.rb} +23 -23
- data/lib/sem4r/targeting_idea/targeting_idea.rb +4 -4
- data/lib/sem4r/targeting_idea/targeting_idea_account_extension.rb +1 -1
- data/lib/sem4r/targeting_idea/targeting_idea_selector.rb +6 -6
- data/lib/sem4r/targeting_idea/targeting_idea_service.rb +7 -5
- data/lib/sem4r/v13_account/account_account_extension.rb +7 -10
- data/lib/sem4r/v13_account/account_service.rb +10 -4
- data/lib/sem4r/v13_account/billing_address.rb +2 -2
- data/lib/sem4r/v13_report/report_service.rb +11 -9
- data/lib/sem4r.rb +46 -31
- data/lib/{sem4r/cli → sem4r_cli}/cli_helpers.rb +3 -2
- data/lib/{sem4r/cli/cli_command.rb → sem4r_cli/cli_mini_framework.rb} +77 -32
- data/lib/{sem4r/cli/cli_common_args.rb → sem4r_cli/cli_sem.rb} +177 -157
- data/lib/{sem4r/cli/commands/cli_list_ads.rb → sem4r_cli/commands/cli_ads.rb} +7 -9
- data/lib/sem4r_cli/commands/cli_campaign.rb +69 -0
- data/lib/{sem4r/cli/commands/cli_list_client.rb → sem4r_cli/commands/cli_clients.rb} +2 -2
- data/lib/{sem4r/cli → sem4r_cli}/commands/cli_ideas.rb +35 -27
- data/lib/{sem4r/cli → sem4r_cli}/commands/cli_info.rb +3 -4
- data/lib/{sem4r/cli/commands/cli_repdef.rb → sem4r_cli/commands/cli_job.rb} +57 -55
- data/lib/{sem4r/cli/commands/cli_list_keywords.rb → sem4r_cli/commands/cli_keywords.rb} +14 -13
- data/lib/sem4r_cli/commands/cli_profile.rb +138 -0
- data/lib/{sem4r/cli/commands/cli_report.rb → sem4r_cli/commands/cli_repdef.rb} +67 -20
- data/lib/{sem4r/cli/commands/cli_request_report.rb → sem4r_cli/commands/cli_report.rb} +82 -19
- data/lib/sem4r_cli.rb +5 -7
- data/lib/sem4r_soap/http_connector.rb +206 -0
- data/lib/{soap_helpers → sem4r_soap}/soap_attributes.rb +8 -3
- data/lib/{sem4r/services → sem4r_soap}/soap_dumper.rb +36 -20
- data/lib/{sem4r/services → sem4r_soap}/soap_error.rb +5 -2
- data/lib/sem4r_soap/soap_response.rb +75 -0
- data/lib/sem4r_soap/soap_service.rb +137 -0
- data/lib/{sem4r/cli/cli_sem.rb → sem4r_soap/soap_service_v13.rb} +27 -28
- data/lib/sem4r_soap/soap_service_v2010.rb +80 -0
- data/lib/sem4r_soap.rb +17 -0
- data/sem4r.gemspec +93 -58
- data/spec/build_fixtures.rb +49 -42
- data/spec/fixtures/password.example.yml +3 -0
- data/spec/fixtures/sem4r.example.yml +6 -0
- data/spec/fixtures/{services/error.xml → soap_error.xml} +0 -0
- data/spec/fixtures/soap_error2.xml +29 -0
- data/spec/helpers/dump_interceptor.rb +90 -0
- data/spec/helpers/fixtures_bulk_mutate_job.rb +48 -0
- data/spec/helpers/fixtures_geo_location.rb +45 -0
- data/{lib/sem4r/campaign_criterion/campaign_criterion_service.rb → spec/helpers/fixtures_info.rb} +10 -6
- data/spec/helpers/fixtures_report_definition.rb +65 -0
- data/spec/{rspec_hash.rb → helpers/rspec_hash.rb} +1 -0
- data/spec/{rspec_matchers.rb → helpers/rspec_matchers.rb} +46 -19
- data/spec/{rspec_sem4r_helper.rb → helpers/rspec_sem4r_helper.rb} +19 -16
- data/spec/{sem4r_stubs.rb → helpers/sem4r_stubs.rb} +5 -4
- data/spec/rspec_helper.rb +4 -4
- data/spec/sem4r/account_spec.rb +2 -3
- data/spec/sem4r/ad_group/ad_group_service_spec.rb +1 -1
- data/spec/sem4r/ad_group/ad_group_spec.rb +1 -1
- data/spec/sem4r/ad_group_ad/ad_group_ad_operation_spec.rb +3 -3
- data/spec/sem4r/adwords_spec.rb +62 -39
- data/{lib/sem4r/cli/commands/cli_list_campaign.rb → spec/sem4r/bulk_mutate_job/bulk_mutate_job_selector_spec.rb} +14 -11
- data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_service_spec.rb +2 -3
- data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_spec.rb +23 -17
- data/spec/sem4r/bulk_mutate_job/fixtures/get-list_job-req.xml +35 -0
- data/spec/sem4r/bulk_mutate_job/fixtures/get-list_job-res.xml +417 -0
- data/spec/sem4r/bulk_mutate_job/fixtures/mutate-add_job-req.xml +106 -0
- data/spec/sem4r/bulk_mutate_job/fixtures/mutate-add_job-res.xml +48 -0
- data/spec/sem4r/bulk_mutate_job/job_operation_spec.rb +5 -7
- data/spec/sem4r/campaign/campaign_service_spec.rb +2 -2
- data/spec/sem4r/credentials_spec.rb +10 -8
- data/spec/sem4r/geo_location/address_spec.rb +62 -0
- data/spec/sem4r/geo_location/fixtures/get-req.xml +42 -0
- data/spec/sem4r/geo_location/fixtures/get-res.xml +60 -0
- data/spec/sem4r/info/fixtures/get-req.xml +34 -0
- data/spec/sem4r/info/fixtures/get-res.xml +27 -0
- data/spec/sem4r/nokogiri_parsing_spec.rb +1 -0
- data/spec/sem4r/operation_spec.rb +72 -0
- data/spec/sem4r/report_definition/fixtures/get-list-repdef-req.xml +22 -0
- data/spec/sem4r/report_definition/fixtures/get-list-repdef-res.xml +73 -0
- data/spec/sem4r/report_definition/fixtures/getReportFields-req.xml +24 -0
- data/spec/sem4r/report_definition/fixtures/getReportFields-res.xml +1199 -0
- data/spec/sem4r/report_definition/fixtures/mutate-add-report-req.xml +63 -0
- data/spec/sem4r/report_definition/fixtures/mutate-add-report-res.xml +68 -0
- data/spec/sem4r/report_definition/report_definition_service_spec.rb +5 -5
- data/spec/sem4r/report_definition/report_definition_spec.rb +28 -43
- data/{lib/sem4r/cli/commands/cli_list_report.rb → spec/sem4r/report_definition/report_field_spec.rb} +12 -10
- data/spec/sem4r/rexml_parsing_spec.rb +1 -0
- data/spec/sem4r/{services/service_spec.rb → service_spec.rb} +1 -1
- data/spec/sem4r/targeting_idea/targeting_idea_selector_spec.rb +1 -1
- data/spec/sem4r/targeting_idea/targeting_idea_service_spec.rb +1 -1
- data/spec/sem4r/targeting_idea/targeting_idea_spec.rb +1 -1
- data/spec/sem4r/v13_account/account_service_spec.rb +2 -2
- data/spec/sem4r/v13_report/report_service_spec.rb +2 -2
- data/spec/{sem4r/cli → sem4r_cli}/cli_spec.rb +22 -27
- data/spec/{soap_helpers → sem4r_soap}/soap_attributes_spec.rb +3 -3
- data/spec/{sem4r/services/soap_message_v13_spec.rb → sem4r_soap/soap_response_spec.rb} +10 -15
- data/spec/{sem4r/services/soap_call_spec.rb → sem4r_soap/soap_service_spec.rb} +35 -54
- data/tasks/jeweler.rake +66 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/sem4r.rake +25 -0
- data/tasks/yard.rake +31 -0
- metadata +173 -76
- data/lib/sem4r/ad_extension_override/ad_extension_override_service.rb +0 -30
- data/lib/sem4r/api_counters.rb +0 -8
- data/lib/sem4r/campaign_target/campaign_target_service.rb +0 -30
- data/lib/sem4r/cli/commands/cli_download_report.rb +0 -82
- data/lib/sem4r/services/http_connector.rb +0 -93
- data/lib/sem4r/services/soap_call.rb +0 -122
- data/lib/sem4r/services/soap_connector.rb +0 -139
- data/lib/sem4r/services/soap_message_v13.rb +0 -135
- data/lib/sem4r/services/soap_message_v2010.rb +0 -184
- data/lib/sem4r/v13_traffic_estimator/traffic_estimator_service.rb +0 -30
- data/spec/aggregates_rspec_helper.rb +0 -59
- data/spec/sem4r/report_definition/fixtures/mutate_add-req.xml +0 -24
- data/spec/sem4r/report_definition/fixtures/mutate_add-req_orig.xml +0 -45
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
#
|
|
2
|
+
# -------------------------------------------------------------------
|
|
3
3
|
# Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
|
|
4
|
-
#
|
|
4
|
+
#
|
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
6
6
|
# a copy of this software and associated documentation files (the
|
|
7
7
|
# "Software"), to deal in the Software without restriction, including
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
10
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
11
11
|
# the following conditions:
|
|
12
|
-
#
|
|
12
|
+
#
|
|
13
13
|
# The above copyright notice and this permission notice shall be
|
|
14
14
|
# included in all copies or substantial portions of the Software.
|
|
15
|
-
#
|
|
15
|
+
#
|
|
16
16
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
17
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
18
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
@@ -20,63 +20,181 @@
|
|
|
20
20
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
# -------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
module Sem4rCli
|
|
26
|
+
|
|
27
|
+
#
|
|
28
|
+
# Macro helper for define new sem4r command
|
|
29
|
+
#
|
|
30
|
+
def self.define_command_sem4r(command_name, description, &block)
|
|
31
|
+
CliCommand.define_command(command_name, description) do |cli|
|
|
32
|
+
account = cli.account
|
|
33
|
+
unless account
|
|
34
|
+
puts "please select a valid account!"
|
|
35
|
+
false
|
|
36
|
+
else
|
|
37
|
+
block.call(account)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
#
|
|
43
|
+
# CliSem Driver
|
|
44
|
+
# parses common options
|
|
45
|
+
# finds command and instantiate command
|
|
46
|
+
# passes the unparsed parameter to command
|
|
47
|
+
# leaves control to command
|
|
48
|
+
#
|
|
49
|
+
class CliSem < Cli
|
|
29
50
|
|
|
30
51
|
def initialize
|
|
31
52
|
# defaults
|
|
32
53
|
@options = OpenStruct.new({
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
54
|
+
:verbose => true,
|
|
55
|
+
:force => false,
|
|
56
|
+
:default_logging => true,
|
|
57
|
+
# :dump_soap_to_file => true,
|
|
58
|
+
# :dump_soap_to_directory => true,
|
|
59
|
+
:profile => 'sandbox',
|
|
60
|
+
:ask_password => false
|
|
61
|
+
})
|
|
40
62
|
end
|
|
41
63
|
|
|
42
|
-
def parse_and_run(
|
|
43
|
-
parse(argv)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def parse(argv)
|
|
64
|
+
def parse_and_run(all_args)
|
|
47
65
|
|
|
48
66
|
begin
|
|
49
|
-
|
|
67
|
+
command_args = opt_parser(@options).order(all_args)
|
|
50
68
|
rescue OptionParser::AmbiguousOption => e
|
|
51
69
|
puts e.message
|
|
52
70
|
return false
|
|
53
71
|
end
|
|
72
|
+
return true if @options.exit
|
|
73
|
+
|
|
74
|
+
if command_args.empty?
|
|
75
|
+
puts "missing command try sem -h for help"
|
|
76
|
+
return false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
command = command_args[0]
|
|
80
|
+
command_args = command_args[1..-1]
|
|
54
81
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
puts "unknow
|
|
82
|
+
# find command
|
|
83
|
+
if CliCommand.commands[command].nil?
|
|
84
|
+
puts "unknow command #{command}"
|
|
58
85
|
return false
|
|
59
86
|
end
|
|
60
87
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
88
|
+
begin
|
|
89
|
+
cmd = CliCommand.commands[command].new(self)
|
|
90
|
+
return cmd.parse_and_run(command_args)
|
|
91
|
+
rescue Sem4rError
|
|
92
|
+
puts "I am so sorry! Something went wrong! (exception #{$!.to_s})"
|
|
93
|
+
return false
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
#
|
|
98
|
+
# initialize adwords according to command line options
|
|
99
|
+
# return [Sem4r::Adwords]
|
|
100
|
+
#
|
|
101
|
+
def adwords
|
|
102
|
+
return @adwords if @adwords
|
|
103
|
+
|
|
104
|
+
#
|
|
105
|
+
# select profile
|
|
106
|
+
#
|
|
107
|
+
options = {}
|
|
108
|
+
if @options.config_name
|
|
109
|
+
options[:config_file] = @options.config_name
|
|
110
|
+
end
|
|
111
|
+
@adwords = Adwords.new(@options.profile, options)
|
|
112
|
+
if @options.verbose
|
|
113
|
+
puts "using #{@adwords.profile} profile"
|
|
114
|
+
puts "config file is #{@adwords.config_file}"
|
|
115
|
+
end
|
|
116
|
+
#
|
|
117
|
+
# Extracts dump soap options
|
|
118
|
+
#
|
|
119
|
+
if @options.default_logging
|
|
120
|
+
configdir = File.join(ENV['HOME'], ".sem4r")
|
|
121
|
+
unless File.exists?(configdir)
|
|
122
|
+
puts "Directory #{configdir} not exists"
|
|
123
|
+
FileUtils.mkdir(configdir)
|
|
67
124
|
end
|
|
125
|
+
dir = File.join(configdir, Time.new.strftime("%Y%m%d-soap-dump"))
|
|
126
|
+
@options.dump_soap_to_directory = dir
|
|
127
|
+
|
|
128
|
+
file = File.join(configdir, Time.new.strftime("%Y%m%d-sem4r-log"))
|
|
129
|
+
@options.logger = file
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if @options.dump_soap_to_file
|
|
133
|
+
filename = @options.dump_soap_to_file
|
|
134
|
+
o = {:file => filename}
|
|
135
|
+
@adwords.dump_soap_options(o)
|
|
136
|
+
end
|
|
137
|
+
if @options.dump_soap_to_directory
|
|
138
|
+
dir = @options.dump_soap_to_directory
|
|
139
|
+
o = {:directory => dir, :format => true}
|
|
140
|
+
@adwords.dump_soap_options(o)
|
|
141
|
+
end
|
|
142
|
+
if @options.verbose and adwords.dump_soap?
|
|
143
|
+
puts "Logging soap conversation to '#{adwords.dump_soap_where}'"
|
|
144
|
+
end
|
|
145
|
+
if !@adwords.dump_soap?
|
|
146
|
+
puts "it is highly recommended to activate the dump soap log"
|
|
68
147
|
end
|
|
69
148
|
|
|
70
|
-
|
|
71
|
-
|
|
149
|
+
#
|
|
150
|
+
# Extracts log options
|
|
151
|
+
#
|
|
152
|
+
# filename = File.join( tmp_dirname, File.basename(example_file).sub(/\.rb$/, ".log") )
|
|
153
|
+
if @options.logger
|
|
154
|
+
# filename = "sem.log"
|
|
155
|
+
@adwords.logger = @options.logger
|
|
72
156
|
end
|
|
157
|
+
if @adwords.logger
|
|
158
|
+
puts "Logger is active" if @options.verbose
|
|
159
|
+
end
|
|
160
|
+
@adwords
|
|
161
|
+
end
|
|
73
162
|
|
|
74
|
-
|
|
163
|
+
#
|
|
164
|
+
# select account according to the command line arguments
|
|
165
|
+
# return [Sem4r::Account]
|
|
166
|
+
#
|
|
167
|
+
def account
|
|
168
|
+
return @account if @account
|
|
169
|
+
|
|
170
|
+
adwords # initialize sem4r lib adwords
|
|
171
|
+
if @options.ask_password or !@adwords.has_password?
|
|
172
|
+
pwd = read_password_from_terminal
|
|
173
|
+
@adwords.password = pwd
|
|
174
|
+
@adwords.save_passwords
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
#
|
|
178
|
+
# select account for command
|
|
179
|
+
#
|
|
180
|
+
if @options.client_email
|
|
181
|
+
account = @adwords.account.client_accounts.find { |c| c.client_email =~ /#{@options.client_email}/ }
|
|
182
|
+
if account.nil?
|
|
183
|
+
puts "client account not found"
|
|
184
|
+
else
|
|
185
|
+
puts "using client #{account.client_email}"
|
|
186
|
+
end
|
|
187
|
+
else
|
|
188
|
+
account = @adwords.account
|
|
189
|
+
end
|
|
190
|
+
@account = account
|
|
75
191
|
end
|
|
76
192
|
|
|
193
|
+
private
|
|
194
|
+
|
|
77
195
|
def opt_parser(options)
|
|
78
|
-
opt_parser
|
|
79
|
-
opt_parser.banner =
|
|
196
|
+
opt_parser = OptionParser.new
|
|
197
|
+
opt_parser.banner = "Sem is a simple command line interface using the sem4r library."
|
|
80
198
|
opt_parser.separator "It's alpha software, please don't use in production or use it at your risk!"
|
|
81
199
|
opt_parser.separator "Further information: http://www.sem4r.com"
|
|
82
200
|
opt_parser.separator ""
|
|
@@ -113,7 +231,7 @@ module Sem4r
|
|
|
113
231
|
|
|
114
232
|
opt_parser.on("-l", "--list-commands", "list commands") do
|
|
115
233
|
puts "SEM commands are:"
|
|
116
|
-
commands = CliCommand.commands.values.sort {|a,b| a.command <=> b.command }
|
|
234
|
+
commands = CliCommand.commands.values.sort { |a, b| a.command <=> b.command }
|
|
117
235
|
commands.each do |cmd|
|
|
118
236
|
printf " %-20s %s\n", cmd.command, cmd.description
|
|
119
237
|
end
|
|
@@ -122,6 +240,9 @@ module Sem4r
|
|
|
122
240
|
options.exit = true
|
|
123
241
|
end
|
|
124
242
|
|
|
243
|
+
#
|
|
244
|
+
# Logging
|
|
245
|
+
#
|
|
125
246
|
opt_parser.separator ""
|
|
126
247
|
opt_parser.separator "logging options: "
|
|
127
248
|
opt_parser.separator ""
|
|
@@ -130,171 +251,70 @@ module Sem4r
|
|
|
130
251
|
options.logger = v
|
|
131
252
|
end
|
|
132
253
|
|
|
133
|
-
opt_parser.on("
|
|
254
|
+
opt_parser.on("--dump-file FILE", "dump soap conversation to file") do |v|
|
|
134
255
|
options.dump_soap_to_file = v
|
|
135
256
|
end
|
|
136
257
|
|
|
137
258
|
str = "dump soap conversation to directory: each \n"
|
|
138
259
|
str << (" " * 37) + "request/response is in a single file"
|
|
139
|
-
opt_parser.on("
|
|
260
|
+
opt_parser.on("--dump-dir DIRECTORY", str) do |v|
|
|
140
261
|
options.dump_soap_to_directory = v
|
|
141
262
|
end
|
|
142
263
|
|
|
264
|
+
#
|
|
265
|
+
# Profile - Configuration
|
|
266
|
+
#
|
|
143
267
|
opt_parser.separator ""
|
|
144
268
|
opt_parser.separator "profile and credentials options: "
|
|
145
269
|
opt_parser.separator " credentials options overwrite profile attributes"
|
|
146
270
|
opt_parser.separator ""
|
|
147
271
|
|
|
148
|
-
str =
|
|
272
|
+
str = "file where profiles are defined\n"
|
|
149
273
|
str << (" " * 37) + "(default $HOME/.sem4r/sem4r.yaml)"
|
|
150
274
|
opt_parser.on("--config CONFIG", str) do |config|
|
|
151
275
|
options.config_name = config
|
|
152
276
|
end
|
|
153
277
|
|
|
154
|
-
opt_parser.on("--list-profiles", "list profiles") do
|
|
155
|
-
options.list_profiles = true
|
|
156
|
-
options.exit = true
|
|
157
|
-
end
|
|
158
|
-
|
|
159
278
|
opt_parser.on("-p", "--profile PROFILE", "select profile (default is sandbox)") do |profile|
|
|
160
279
|
options.profile = profile
|
|
161
280
|
end
|
|
162
281
|
|
|
163
282
|
# email
|
|
164
283
|
opt_parser.on("--email EMAIL",
|
|
165
|
-
|
|
284
|
+
"email of adwords account") do |email|
|
|
166
285
|
options.email = email
|
|
167
286
|
end
|
|
168
287
|
|
|
169
288
|
# password
|
|
170
|
-
opt_parser.on("--password
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
289
|
+
opt_parser.on("-a", "--ask-password",
|
|
290
|
+
"ask password on terminal") do
|
|
291
|
+
options.ask_password = true
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
opt_parser.on("--password PASSWORD",
|
|
295
|
+
"password of adwords account") do |password|
|
|
174
296
|
options.password = password if password
|
|
175
297
|
end
|
|
176
298
|
|
|
177
299
|
# developer token
|
|
178
300
|
opt_parser.on("--token TOKEN",
|
|
179
|
-
|
|
301
|
+
"developer token to access adwords api") do |token|
|
|
180
302
|
options.developer_token = token
|
|
181
303
|
end
|
|
182
304
|
|
|
183
305
|
# client account
|
|
184
306
|
opt_parser.on("-c", "--client EMAIL",
|
|
185
|
-
|
|
307
|
+
"email for client account") do |email|
|
|
186
308
|
options.client_email = email
|
|
187
309
|
end
|
|
188
310
|
opt_parser.separator ""
|
|
189
311
|
opt_parser
|
|
190
312
|
end
|
|
191
313
|
|
|
192
|
-
def
|
|
193
|
-
|
|
194
|
-
# The new and improved choose()...
|
|
195
|
-
say("\nThis is the new mode (default)...")
|
|
196
|
-
choose do |menu|
|
|
197
|
-
menu.prompt = "Please choose your favorite programming language? "
|
|
198
|
-
|
|
199
|
-
menu.choice :ruby do say("Good choice!") end
|
|
200
|
-
menu.choices(:python, :perl) do say("Not from around here, are you?") end
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
@options.email ||= ask("Enter adwords email: ")
|
|
205
|
-
@options.password ||= ask("Enter adwords password: ") { |q| q.echo = "x" }
|
|
206
|
-
@options.developer_token ||= ask("Enter adwords developer_token: ")
|
|
207
|
-
|
|
208
|
-
config = {
|
|
209
|
-
:environment => @options.environment,
|
|
210
|
-
:email => @options.email,
|
|
211
|
-
:password => @options.password,
|
|
212
|
-
:developer_token => @options.developer_token
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
pp config
|
|
216
|
-
unless agree("credentials are correct?")
|
|
217
|
-
exit
|
|
218
|
-
end
|
|
219
|
-
config
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
def account
|
|
223
|
-
#
|
|
224
|
-
# select profile
|
|
225
|
-
#
|
|
226
|
-
options = {}
|
|
227
|
-
if @options.config_name
|
|
228
|
-
options[:config_file] = @options.config_name
|
|
229
|
-
end
|
|
230
|
-
adwords = Adwords.new( @options.profile, options )
|
|
231
|
-
if @options.verbose
|
|
232
|
-
puts "using #{adwords.profile} profile"
|
|
233
|
-
puts "config file is #{adwords.config_file}"
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
#
|
|
237
|
-
# logging soap conversation
|
|
238
|
-
#
|
|
239
|
-
if @options.default_logging
|
|
240
|
-
configdir = File.join( ENV['HOME'], ".sem4r" )
|
|
241
|
-
unless File.exists?(configdir)
|
|
242
|
-
puts "Directory #{configdir} not exists"
|
|
243
|
-
FileUtils.mkdir(configdir)
|
|
244
|
-
end
|
|
245
|
-
dir = File.join(configdir, Time.new.strftime("%Y%m%d-soap-dump"))
|
|
246
|
-
@options.dump_soap_to_directory = dir
|
|
247
|
-
|
|
248
|
-
file = File.join(configdir, Time.new.strftime("%Y%m%d-sem4r-log"))
|
|
249
|
-
@options.logger = file
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
if @options.dump_soap_to_file
|
|
253
|
-
filename = @options.dump_soap_to_file
|
|
254
|
-
o = { :file => filename }
|
|
255
|
-
adwords.dump_soap_options( o )
|
|
256
|
-
end
|
|
257
|
-
if @options.dump_soap_to_directory
|
|
258
|
-
dir = @options.dump_soap_to_directory
|
|
259
|
-
o = { :directory => dir, :format => true }
|
|
260
|
-
adwords.dump_soap_options( o )
|
|
261
|
-
end
|
|
262
|
-
if @options.verbose and adwords.dump_soap?
|
|
263
|
-
puts "Logging soap conversation to '#{adwords.dump_soap_where}'"
|
|
264
|
-
end
|
|
265
|
-
if !adwords.dump_soap?
|
|
266
|
-
puts "it is highly recommended to activate the dump soap log"
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
#
|
|
270
|
-
# logging
|
|
271
|
-
#
|
|
272
|
-
# filename = File.join( tmp_dirname, File.basename(example_file).sub(/\.rb$/, ".log") )
|
|
273
|
-
if @options.logger
|
|
274
|
-
# filename = "sem.log"
|
|
275
|
-
adwords.logger = @options.logger
|
|
276
|
-
end
|
|
277
|
-
if adwords.logger
|
|
278
|
-
puts "Logger activated"
|
|
279
|
-
end
|
|
280
|
-
# adwords.logger = Logger.new(STDOUT)
|
|
281
|
-
|
|
282
|
-
#
|
|
283
|
-
# select account for command
|
|
284
|
-
#
|
|
285
|
-
if @options.client_email
|
|
286
|
-
account = adwords.account.client_accounts.find{ |c| c.client_email =~ /^#{@options.client_email}/ }
|
|
287
|
-
if account.nil?
|
|
288
|
-
puts "client account not found"
|
|
289
|
-
else
|
|
290
|
-
puts "using client #{account.client_email}"
|
|
291
|
-
end
|
|
292
|
-
else
|
|
293
|
-
account = adwords.account
|
|
294
|
-
end
|
|
295
|
-
return account
|
|
314
|
+
def read_password_from_terminal
|
|
315
|
+
ask("Enter your password: ") { |q| q.echo = "x" }
|
|
296
316
|
end
|
|
297
317
|
|
|
298
318
|
end
|
|
299
319
|
|
|
300
|
-
end
|
|
320
|
+
end # module Sem4rCli
|
|
@@ -20,13 +20,12 @@
|
|
|
20
20
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
-
#
|
|
24
23
|
# -------------------------------------------------------------------------
|
|
25
24
|
|
|
26
|
-
module
|
|
25
|
+
module Sem4rCli
|
|
27
26
|
|
|
28
|
-
CliListAds =
|
|
29
|
-
puts "
|
|
27
|
+
CliListAds = define_command_sem4r("ads", "list ads") do |account|
|
|
28
|
+
puts "Collecting ads from account(s) - please wait"
|
|
30
29
|
|
|
31
30
|
# if the accounts have client_accounts it is a master
|
|
32
31
|
client_accounts = account.client_accounts
|
|
@@ -34,7 +33,7 @@ module Sem4r
|
|
|
34
33
|
client_accounts = [account]
|
|
35
34
|
end
|
|
36
35
|
|
|
37
|
-
items
|
|
36
|
+
items = []
|
|
38
37
|
need_newline = false
|
|
39
38
|
|
|
40
39
|
client_accounts.each do |client_account|
|
|
@@ -43,14 +42,13 @@ module Sem4r
|
|
|
43
42
|
need_newline = false
|
|
44
43
|
end
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
puts "examinate account '#{client_account.credentials.client_email}'"
|
|
45
|
+
puts "look in account '#{client_account.credentials.client_email}'"
|
|
48
46
|
client_account.campaigns.each do |campaign|
|
|
49
47
|
# puts "examinate campaign '#{campaign}'"
|
|
50
48
|
campaign.ad_groups.each do |ad_group|
|
|
51
49
|
# puts "examinate adgroup '#{ad_group}'"
|
|
52
50
|
ad_group.ads.each do |ad|
|
|
53
|
-
o
|
|
51
|
+
o = OpenStruct.new
|
|
54
52
|
o.client = client_account.credentials.client_email
|
|
55
53
|
o.campaign = campaign.name
|
|
56
54
|
o.ad_group = ad_group.name
|
|
@@ -62,7 +60,6 @@ module Sem4r
|
|
|
62
60
|
need_newline = true
|
|
63
61
|
end
|
|
64
62
|
end
|
|
65
|
-
#--
|
|
66
63
|
|
|
67
64
|
end
|
|
68
65
|
if need_newline
|
|
@@ -71,5 +68,6 @@ module Sem4r
|
|
|
71
68
|
end
|
|
72
69
|
report(items, :client, :campaign, :ad_group, :url, :display_url)
|
|
73
70
|
account.adwords.p_counters
|
|
71
|
+
true
|
|
74
72
|
end
|
|
75
73
|
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# -------------------------------------------------------------------------
|
|
3
|
+
# Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
# a copy of this software and associated documentation files (the
|
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
# the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be
|
|
14
|
+
# included in all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
# -------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
module Sem4rCli
|
|
26
|
+
|
|
27
|
+
CliListCampaign = define_command_sem4r("campaigns", "list campaigns") do |account|
|
|
28
|
+
puts "Collecting campaign from account(s) - please wait"
|
|
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
|
+
puts "look in account '#{client_account.credentials.client_email}'"
|
|
46
|
+
client_account.campaigns.each do |campaign|
|
|
47
|
+
|
|
48
|
+
o = OpenStruct.new
|
|
49
|
+
o.client = client_account.credentials.client_email
|
|
50
|
+
o.id = campaign.id
|
|
51
|
+
o.name = campaign.name
|
|
52
|
+
o.status = campaign.status
|
|
53
|
+
items << o
|
|
54
|
+
|
|
55
|
+
print "."
|
|
56
|
+
need_newline = true
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if need_newline
|
|
61
|
+
puts
|
|
62
|
+
need_newline = false
|
|
63
|
+
end
|
|
64
|
+
report(items, :client, :id, :name, :status)
|
|
65
|
+
account.adwords.p_counters
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
#
|
|
24
24
|
# -------------------------------------------------------------------------
|
|
25
25
|
|
|
26
|
-
module
|
|
26
|
+
module Sem4rCli
|
|
27
27
|
|
|
28
|
-
CliListClient =
|
|
28
|
+
CliListClient = define_command_sem4r("clients", "list clients account") do |account|
|
|
29
29
|
puts account.adwords.to_s
|
|
30
30
|
puts account.to_s
|
|
31
31
|
account.p_client_accounts
|
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
#
|
|
24
24
|
# -------------------------------------------------------------------------
|
|
25
25
|
|
|
26
|
-
module
|
|
26
|
+
module Sem4rCli
|
|
27
27
|
|
|
28
|
+
#
|
|
29
|
+
# idea
|
|
30
|
+
#
|
|
28
31
|
class CliIdeas < CliCommand
|
|
29
32
|
|
|
30
33
|
def self.command
|
|
@@ -39,8 +42,29 @@ module Sem4r
|
|
|
39
42
|
@common_args = common_args
|
|
40
43
|
end
|
|
41
44
|
|
|
45
|
+
def parse_and_run(argv)
|
|
46
|
+
options = OpenStruct.new
|
|
47
|
+
rest = opt_parser(options).parse(argv)
|
|
48
|
+
return false if options.exit
|
|
49
|
+
|
|
50
|
+
if rest.length < 1
|
|
51
|
+
puts "keyword missing; see help"
|
|
52
|
+
return false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
keyword = rest[1]
|
|
56
|
+
account = @common_args.account
|
|
57
|
+
unless account
|
|
58
|
+
puts "select an account!"
|
|
59
|
+
return false
|
|
60
|
+
end
|
|
61
|
+
_run(account, keyword)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
42
66
|
def opt_parser(options)
|
|
43
|
-
opt_parser
|
|
67
|
+
opt_parser = OptionParser.new
|
|
44
68
|
opt_parser.banner= "#{self.class.description}"
|
|
45
69
|
opt_parser.separator "Usage: sem [options] idea <keyword>"
|
|
46
70
|
|
|
@@ -53,31 +77,13 @@ module Sem4r
|
|
|
53
77
|
end
|
|
54
78
|
end
|
|
55
79
|
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return false if options.exit
|
|
60
|
-
if rest.length < 1
|
|
61
|
-
puts "keyword missing see help"
|
|
62
|
-
return false
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
@keyword = rest[1]
|
|
66
|
-
account = @common_args.account
|
|
67
|
-
unless account
|
|
68
|
-
puts "select an account!"
|
|
69
|
-
else
|
|
70
|
-
_run account
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def _run(account)
|
|
75
|
-
ideas = account.targeting_idea do
|
|
76
|
-
idea_type "KEYWORD"
|
|
80
|
+
def _run(account, keyword)
|
|
81
|
+
ideas = account.targeting_idea do
|
|
82
|
+
idea_type "KEYWORD"
|
|
77
83
|
request_type "IDEAS"
|
|
78
84
|
|
|
79
85
|
related_to_keyword_search_parameter do
|
|
80
|
-
text
|
|
86
|
+
text keyword
|
|
81
87
|
match_type 'EXACT'
|
|
82
88
|
end
|
|
83
89
|
end
|
|
@@ -86,16 +92,18 @@ module Sem4r
|
|
|
86
92
|
ideas.each do |i|
|
|
87
93
|
i.each do |a|
|
|
88
94
|
next if a.class != TKeywordAttribute
|
|
89
|
-
o
|
|
95
|
+
o = OpenStruct.new
|
|
90
96
|
o.text = a.text
|
|
91
97
|
o.match = a.match_type
|
|
92
98
|
items << o
|
|
93
99
|
end
|
|
94
100
|
end
|
|
95
101
|
|
|
96
|
-
|
|
102
|
+
Sem4rCli::report(items, :text, :match)
|
|
97
103
|
account.adwords.p_counters
|
|
104
|
+
true
|
|
98
105
|
end
|
|
99
106
|
|
|
100
107
|
end
|
|
101
|
-
|
|
108
|
+
|
|
109
|
+
end # module Sem4rCli
|