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.
- data/LICENSE +22 -0
- data/README.rdoc +74 -0
- data/Rakefile +126 -0
- data/VERSION.yml +5 -0
- data/bin/sem +34 -0
- data/config/sem4r.example.yml +51 -0
- data/examples_blog/2009-11-29-hello-world.rb +12 -0
- data/examples_blog/2009-12-12-create-campaign.rb +29 -0
- data/examples_blog/2010-02-06-constants-scope.rb +8 -0
- data/examples_blog/2010-02-07-ad-parameters.rb +47 -0
- data/examples_sem4r/01_get_account.rb +37 -0
- data/examples_sem4r/02_get_info.rb +32 -0
- data/examples_sem4r/03_list_ad.rb +47 -0
- data/examples_sem4r/04_list_keywords.rb +54 -0
- data/examples_sem4r/05_request_report.rb +51 -0
- data/examples_sem4r/05_request_report_2010.rb +40 -0
- data/examples_sem4r/06_create_campaigns.rb +86 -0
- data/examples_sem4r/07_create_campaigns_block.rb +99 -0
- data/examples_sem4r/07_create_campaigns_simple.rb +65 -0
- data/examples_sem4r/08_ad_params.rb +70 -0
- data/examples_sem4r/09_targeting_idea.rb +59 -0
- data/examples_sem4r/10_get_location.rb +28 -0
- data/examples_sem4r/11_submit_bulk_job.rb +82 -0
- data/examples_sem4r/12_list_bulk_job.rb +29 -0
- data/examples_sem4r/30_prune_empty_adgroup.rb +50 -0
- data/examples_sem4r/31_empty_accounts.rb +40 -0
- data/examples_sem4r/example_helper.rb +115 -0
- data/lib/sem4r/account.rb +349 -0
- data/lib/sem4r/ad_extension_override/ad_extension_override_service.rb +30 -0
- data/lib/sem4r/ad_group/ad_group.rb +340 -0
- data/lib/sem4r/ad_group/ad_group_bids.rb +170 -0
- data/lib/sem4r/ad_group/ad_group_service.rb +75 -0
- data/lib/sem4r/ad_group/mobile_ad_image.rb +33 -0
- data/lib/sem4r/ad_group_ad/ad_group_ad.rb +98 -0
- data/lib/sem4r/ad_group_ad/ad_group_ad_operations.rb +38 -0
- data/lib/sem4r/ad_group_ad/ad_group_ad_service.rb +56 -0
- data/lib/sem4r/ad_group_ad/ad_group_mobile_ad.rb +137 -0
- data/lib/sem4r/ad_group_ad/ad_group_text_ad.rb +98 -0
- data/lib/sem4r/ad_group_criterion/ad_group_criterion.rb +144 -0
- data/lib/sem4r/ad_group_criterion/ad_group_criterion_bids.rb +115 -0
- data/lib/sem4r/ad_group_criterion/ad_group_criterion_operations.rb +35 -0
- data/lib/sem4r/ad_group_criterion/ad_group_criterion_service.rb +58 -0
- data/lib/sem4r/ad_group_criterion/criterion.rb +67 -0
- data/lib/sem4r/ad_group_criterion/criterion_keyword.rb +80 -0
- data/lib/sem4r/ad_group_criterion/criterion_placement.rb +66 -0
- data/lib/sem4r/ad_param/ad_param.rb +96 -0
- data/lib/sem4r/ad_param/ad_param_operation.rb +34 -0
- data/lib/sem4r/ad_param/ad_param_service.rb +59 -0
- data/lib/sem4r/adwords.rb +242 -0
- data/lib/sem4r/api_counters.rb +7 -0
- data/lib/sem4r/base.rb +43 -0
- data/lib/sem4r/bulk_mutate_job/bulk_mutate_job.rb +108 -0
- data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_selector.rb +56 -0
- data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_service.rb +57 -0
- data/lib/sem4r/bulk_mutate_job/job_operations.rb +35 -0
- data/lib/sem4r/campaign/campaign.rb +193 -0
- data/lib/sem4r/campaign/campaign_service.rb +91 -0
- data/lib/sem4r/campaign_criterion/campaign_criterion_service.rb +30 -0
- data/lib/sem4r/campaign_target/campaign_target_service.rb +30 -0
- data/lib/sem4r/cli/cli_command.rb +101 -0
- data/lib/sem4r/cli/cli_commands.rb +60 -0
- data/lib/sem4r/cli/cli_common_args.rb +293 -0
- data/lib/sem4r/cli/cli_download_report.rb +81 -0
- data/lib/sem4r/cli/cli_helpers.rb +57 -0
- data/lib/sem4r/cli/cli_ideas.rb +100 -0
- data/lib/sem4r/cli/cli_list_ads.rb +74 -0
- data/lib/sem4r/cli/cli_list_keywords.rb +76 -0
- data/lib/sem4r/cli/cli_request_report.rb +104 -0
- data/lib/sem4r/cli/cli_sem.rb +64 -0
- data/lib/sem4r/common/operation.rb +78 -0
- data/lib/sem4r/credentials.rb +86 -0
- data/lib/sem4r/extensions.rb +62 -0
- data/lib/sem4r/geo_location/geo_location_service.rb +59 -0
- data/lib/sem4r/info/info_service.rb +115 -0
- data/lib/sem4r/report_definition/report_definition.rb +104 -0
- data/lib/sem4r/report_definition/report_definition_operation.rb +34 -0
- data/lib/sem4r/report_definition/report_definition_selector.rb +31 -0
- data/lib/sem4r/report_definition/report_definition_service.rb +55 -0
- data/lib/sem4r/sem4r_error.rb +28 -0
- data/lib/sem4r/services/service.rb +74 -0
- data/lib/sem4r/services/soap_call.rb +100 -0
- data/lib/sem4r/services/soap_connector.rb +284 -0
- data/lib/sem4r/services/soap_error.rb +38 -0
- data/lib/sem4r/services/soap_message_v13.rb +129 -0
- data/lib/sem4r/services/soap_message_v2009.rb +170 -0
- data/lib/sem4r/soap_attributes.rb +141 -0
- data/lib/sem4r/targeting_idea/targeting_idea.rb +158 -0
- data/lib/sem4r/targeting_idea/targeting_idea_selector.rb +200 -0
- data/lib/sem4r/targeting_idea/targeting_idea_service.rb +51 -0
- data/lib/sem4r/v13_account/account_service.rb +54 -0
- data/lib/sem4r/v13_account/billing_address.rb +67 -0
- data/lib/sem4r/v13_report/report.rb +185 -0
- data/lib/sem4r/v13_report/report_job.rb +51 -0
- data/lib/sem4r/v13_report/report_service.rb +89 -0
- data/lib/sem4r/v13_traffic_estimator/traffic_estimator_service.rb +30 -0
- data/lib/sem4r.rb +142 -0
- data/lib/sem4r_cli.rb +40 -0
- data/sem4r.gemspec +247 -0
- data/spec/aggregates_spec_helper.rb +59 -0
- data/spec/fixtures/sem4r.example.yml +26 -0
- data/spec/fixtures/services/ad_group/get-first-req.xml +28 -0
- data/spec/fixtures/services/ad_group/get-first-res.xml +91 -0
- data/spec/fixtures/services/ad_group/get-manual-cpm-bids-req.xml +106 -0
- data/spec/fixtures/services/ad_group/get-manual-cpm-bids-res.xml +75 -0
- data/spec/fixtures/services/ad_group/mutate_add-req.xml +52 -0
- data/spec/fixtures/services/ad_group/mutate_add-res.xml +33 -0
- data/spec/fixtures/services/ad_group_ad/get_mobile_ad-req.xml +28 -0
- data/spec/fixtures/services/ad_group_ad/get_mobile_ad-res.xml +194 -0
- data/spec/fixtures/services/ad_group_ad/get_text_ad-req.xml +29 -0
- data/spec/fixtures/services/ad_group_ad/get_text_ad-res.xml +55 -0
- data/spec/fixtures/services/ad_group_ad/mutate_add_mobile_ad-req.xml +50 -0
- data/spec/fixtures/services/ad_group_ad/mutate_add_mobile_ad-res.xml +42 -0
- data/spec/fixtures/services/ad_group_ad/mutate_add_text_ad-req.xml +37 -0
- data/spec/fixtures/services/ad_group_ad/mutate_add_text_ad-res.xml +32 -0
- data/spec/fixtures/services/ad_group_ad/mutate_add_two_criterions-req.xml +83 -0
- data/spec/fixtures/services/ad_group_ad/mutate_add_two_criterions-res.xml +95 -0
- data/spec/fixtures/services/ad_group_criterion/get-req.xml +28 -0
- data/spec/fixtures/services/ad_group_criterion/get-res.xml +242 -0
- data/spec/fixtures/services/ad_group_criterion/mutate_add_criterion_keyword-req.xml +48 -0
- data/spec/fixtures/services/ad_group_criterion/mutate_add_criterion_keyword-res.xml +47 -0
- data/spec/fixtures/services/ad_group_criterion/mutate_add_criterion_placement-req.xml +35 -0
- data/spec/fixtures/services/ad_group_criterion/mutate_add_criterion_placement-res.xml +32 -0
- data/spec/fixtures/services/ad_group_criterion/mutate_add_negative_keyword-req.xml +37 -0
- data/spec/fixtures/services/ad_group_criterion/mutate_add_negative_keyword-res.xml +51 -0
- data/spec/fixtures/services/ad_param/mutate_set-req.xml +43 -0
- data/spec/fixtures/services/ad_param/mutate_set-res.xml +29 -0
- data/spec/fixtures/services/bulk_mutate_job/get-req.xml +36 -0
- data/spec/fixtures/services/bulk_mutate_job/get-res.xml +54 -0
- data/spec/fixtures/services/bulk_mutate_job/mutate-req.xml +69 -0
- data/spec/fixtures/services/bulk_mutate_job/mutate-res.xml +48 -0
- data/spec/fixtures/services/campaign/get-req.xml +37 -0
- data/spec/fixtures/services/campaign/get-res.xml +1986 -0
- data/spec/fixtures/services/campaign/mutate_add-req.xml +37 -0
- data/spec/fixtures/services/campaign/mutate_add-res.xml +42 -0
- data/spec/fixtures/services/error.xml +28 -0
- data/spec/fixtures/services/info/get_unit_count-req.xml +30 -0
- data/spec/fixtures/services/info/get_unit_count-res.xml +29 -0
- data/spec/fixtures/services/report_definition/mutate_add-req.xml +24 -0
- data/spec/fixtures/services/report_definition/mutate_add-req_orig.xml +45 -0
- data/spec/fixtures/services/targeting_idea/get-req-all-options.xml +57 -0
- data/spec/fixtures/services/targeting_idea/get-req.xml +60 -0
- data/spec/fixtures/services/targeting_idea/get-res.xml +3601 -0
- data/spec/fixtures/services/v13_account/get_account_info-req.xml +23 -0
- data/spec/fixtures/services/v13_account/get_account_info-res.xml +54 -0
- data/spec/fixtures/services/v13_account/get_client_accounts-req.xml +22 -0
- data/spec/fixtures/services/v13_account/get_client_accounts-res.xml +37 -0
- data/spec/fixtures/services/v13_report/get_all_jobs-req.xml +21 -0
- data/spec/fixtures/services/v13_report/get_all_jobs-res.xml +109 -0
- data/spec/fixtures/services/v13_report/schedule_report_job-req.xml +56 -0
- data/spec/fixtures/services/v13_report/schedule_report_job-res.xml +24 -0
- data/spec/sem4r/account_spec.rb +86 -0
- data/spec/sem4r/ad_group/ad_group_bids_spec.rb +67 -0
- data/spec/sem4r/ad_group/ad_group_service_spec.rb +66 -0
- data/spec/sem4r/ad_group/ad_group_spec.rb +212 -0
- data/spec/sem4r/ad_group_ad/ad_group_ad_operation_spec.rb +88 -0
- data/spec/sem4r/ad_group_ad/ad_group_ad_service_spec.rb +55 -0
- data/spec/sem4r/ad_group_ad/ad_group_ad_spec.rb +173 -0
- data/spec/sem4r/ad_group_criterion/ad_group_criterion_bids_spec.rb +60 -0
- data/spec/sem4r/ad_group_criterion/ad_group_criterion_service_spec.rb +55 -0
- data/spec/sem4r/ad_group_criterion/ad_group_criterion_spec.rb +103 -0
- data/spec/sem4r/ad_group_criterion/criterion_spec.rb +85 -0
- data/spec/sem4r/ad_param/ad_param_service_spec.rb +55 -0
- data/spec/sem4r/ad_param/ad_param_spec.rb +59 -0
- data/spec/sem4r/adwords_spec.rb +110 -0
- data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_service_spec.rb +63 -0
- data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_spec.rb +69 -0
- data/spec/sem4r/bulk_mutate_job/job_operation_spec.rb +48 -0
- data/spec/sem4r/campaign/campaign_service_spec.rb +66 -0
- data/spec/sem4r/campaign/campaign_spec.rb +105 -0
- data/spec/sem4r/cli/cli_spec.rb +71 -0
- data/spec/sem4r/credentials_spec.rb +65 -0
- data/spec/sem4r/report_definition/report_definition_service_spec.rb +44 -0
- data/spec/sem4r/report_definition/report_definition_spec.rb +105 -0
- data/spec/sem4r/rexml_parsing_spec.rb +103 -0
- data/spec/sem4r/services/service_spec.rb +36 -0
- data/spec/sem4r/services/soap_call_spec.rb +115 -0
- data/spec/sem4r/services/soap_message_v13_spec.rb +54 -0
- data/spec/sem4r/soap_attributes_spec.rb +116 -0
- data/spec/sem4r/targeting_idea/targeting_idea_selector_spec.rb +120 -0
- data/spec/sem4r/targeting_idea/targeting_idea_service_spec.rb +44 -0
- data/spec/sem4r/targeting_idea/targeting_idea_spec.rb +53 -0
- data/spec/sem4r/v13_account/account_service_spec.rb +60 -0
- data/spec/sem4r/v13_report/report_service_spec.rb +104 -0
- data/spec/sem4r/v13_report/report_spec.rb +79 -0
- data/spec/sem4r_spec_helper.rb +353 -0
- data/spec/spec_helper.rb +12 -0
- metadata +375 -0
|
@@ -0,0 +1,242 @@
|
|
|
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 Adwords
|
|
27
|
+
|
|
28
|
+
attr_reader :profile
|
|
29
|
+
|
|
30
|
+
class << self
|
|
31
|
+
def sandbox( config = nil )
|
|
32
|
+
new( "sandbox", config )
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def production( config = nil )
|
|
36
|
+
new( "production", config )
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def search_config_file
|
|
40
|
+
config_filename = "sem4r.yml"
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# try current directory
|
|
44
|
+
#
|
|
45
|
+
return File.expand_path(config_filename) if File.exists?( config_filename)
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# try ~/.sem4r/sem4r.yml
|
|
49
|
+
#
|
|
50
|
+
# require 'etc'
|
|
51
|
+
# homedir = Etc.getpwuid.dir
|
|
52
|
+
homedir = ENV['HOME']
|
|
53
|
+
config_filepath = File.join( homedir, ".sem4r", config_filename)
|
|
54
|
+
return config_filepath if File.exists?( config_filepath )
|
|
55
|
+
|
|
56
|
+
#
|
|
57
|
+
# try <home_sem4r>/config/sem4r
|
|
58
|
+
#
|
|
59
|
+
config_filepath = File.expand_path( File.join( File.dirname( __FILE__ ), "..", "..", "config", config_filename ) )
|
|
60
|
+
return config_filepath if File.exists?( config_filepath )
|
|
61
|
+
|
|
62
|
+
config_filepath = File.expand_path( File.join( File.dirname( __FILE__ ), "..", "..", "config", "sem4r.example.yml" ) )
|
|
63
|
+
return config_filepath if File.exists?( config_filepath )
|
|
64
|
+
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def profiles( profile_file = nil )
|
|
69
|
+
profile_file = search_config_file unless profile_file
|
|
70
|
+
unless profile_file
|
|
71
|
+
raise Sem4rError, "config file 'sem4r' not found"
|
|
72
|
+
end
|
|
73
|
+
# puts "Loaded profiles from #{profile_file}"
|
|
74
|
+
yaml = YAML::load( File.open( profile_file ) )
|
|
75
|
+
profiles = yaml['google_adwords']
|
|
76
|
+
profiles
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# new( "sandbox", {:email=>"..."} )
|
|
81
|
+
# new( {:environment=>"...", email => "..." } )
|
|
82
|
+
# new( "sandbox" )
|
|
83
|
+
# new() sandbox default
|
|
84
|
+
def initialize( profile = "sandbox", options = nil )
|
|
85
|
+
@logger = nil
|
|
86
|
+
if not options.nil?
|
|
87
|
+
# new( "sandbox", {:email=>"..."} )
|
|
88
|
+
@profile = profile.to_s
|
|
89
|
+
options = options.stringify_keys
|
|
90
|
+
options.assert_valid_keys("environment", "email", "password", "developer_token", "mutable", "config_file")
|
|
91
|
+
f = options.delete("config_file")
|
|
92
|
+
self.config_file= f if f
|
|
93
|
+
@options = load_config(@profile)
|
|
94
|
+
@options = @options.merge(options)
|
|
95
|
+
elsif profile.respond_to?(:keys)
|
|
96
|
+
# new( {:environment=>"...", email => "..." } )
|
|
97
|
+
@options = profile.stringify_keys
|
|
98
|
+
@options.assert_valid_keys("environment", "email", "password", "developer_token", "mutable")
|
|
99
|
+
@profile = "anonymous_" + @options["environment"]
|
|
100
|
+
else
|
|
101
|
+
# new( "sandbox" )
|
|
102
|
+
@profile = profile.to_s
|
|
103
|
+
@options = load_config(@profile)
|
|
104
|
+
end
|
|
105
|
+
if ["sandbox", "production"].include?(profile)
|
|
106
|
+
if @options["environment"].nil?
|
|
107
|
+
@options["environment"] = profile
|
|
108
|
+
end
|
|
109
|
+
if @options["environment"] != profile
|
|
110
|
+
raise "you cannot use profile '#{profile}' with environment #{@options["environment"]}"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def to_s
|
|
116
|
+
"adwords profile: '#{profile}' config file: '#{config_file}'"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def config_file=(file_path)
|
|
120
|
+
config_filepath = File.expand_path(file_path)
|
|
121
|
+
if File.exists?( config_filepath)
|
|
122
|
+
@config_filepath = config_filepath
|
|
123
|
+
else
|
|
124
|
+
puts "#{config_filepath} not exists"
|
|
125
|
+
end
|
|
126
|
+
@config_filepath
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# return the config file name
|
|
130
|
+
def config_file
|
|
131
|
+
return @config_filepath if @config_filepath
|
|
132
|
+
@config_file_path = Adwords.search_config_file
|
|
133
|
+
@config_file_path
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def load_config(profile)
|
|
137
|
+
unless config_file
|
|
138
|
+
raise Sem4rError, "config file 'sem4r' not found"
|
|
139
|
+
end
|
|
140
|
+
# puts "Loaded profiles from #{config_file}"
|
|
141
|
+
yaml = YAML::load( File.open( config_file ) )
|
|
142
|
+
config = yaml['google_adwords'][profile]
|
|
143
|
+
config || {}
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
##########################################################################
|
|
147
|
+
# logging
|
|
148
|
+
|
|
149
|
+
def dump_soap_options( dump_options )
|
|
150
|
+
@dump_soap_options = dump_options
|
|
151
|
+
@connector.dump_soap_options( dump_options ) if @connector
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def dump_soap?
|
|
155
|
+
not @dump_soap_options.nil?
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def dump_soap_where
|
|
159
|
+
if @dump_soap_options[:directory]
|
|
160
|
+
"directory:#{@dump_soap_options[:directory]}"
|
|
161
|
+
else
|
|
162
|
+
"file:#{@dump_soap_options[:file]}"
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def logger= logger
|
|
167
|
+
unless logger.instance_of?(Logger)
|
|
168
|
+
file = File.open( logger, "a" )
|
|
169
|
+
file.sync = true
|
|
170
|
+
logger = Logger.new(file)
|
|
171
|
+
logger.formatter = proc { |severity, datetime, progname, msg|
|
|
172
|
+
"#{datetime.strftime("%H:%M:%S")}: #{msg}\n"
|
|
173
|
+
}
|
|
174
|
+
end
|
|
175
|
+
@logger= logger
|
|
176
|
+
|
|
177
|
+
@connector.logger= logger if @connector
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def logger
|
|
181
|
+
@logger
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def account
|
|
185
|
+
deferred_initialize unless @initialized
|
|
186
|
+
@account
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def p_counters
|
|
190
|
+
operations = @counters[:operations]
|
|
191
|
+
units = @counters[:units]
|
|
192
|
+
response_time = @counters[:response_time]
|
|
193
|
+
puts "#{units} unit spent for #{operations} operations in #{response_time}ms"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
##########################################################################
|
|
197
|
+
# methods only for internal use
|
|
198
|
+
|
|
199
|
+
attr_reader :service
|
|
200
|
+
|
|
201
|
+
#
|
|
202
|
+
# TODO: credentials are necessary because you might use more then account/credentials
|
|
203
|
+
# at the same time
|
|
204
|
+
#
|
|
205
|
+
def add_counters( credentials, counters )
|
|
206
|
+
counters.each_pair { |k,v|
|
|
207
|
+
@counters[k] ||= 0
|
|
208
|
+
@counters[k] += v
|
|
209
|
+
}
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
private
|
|
213
|
+
|
|
214
|
+
def deferred_initialize
|
|
215
|
+
@initialized = true
|
|
216
|
+
|
|
217
|
+
@connector = SoapConnector.new
|
|
218
|
+
@connector.dump_soap_options(@dump_soap_options) if @dump_soap_options
|
|
219
|
+
@connector.logger=(@logger) if @logger
|
|
220
|
+
|
|
221
|
+
@credentials = Credentials.new(
|
|
222
|
+
:environment => @options["environment"],
|
|
223
|
+
:email => @options["email"],
|
|
224
|
+
:password => @options["password"],
|
|
225
|
+
:useragent => "Sem4r Adwords Ruby Client Library (http://github.com/sem4r/sem4r)",
|
|
226
|
+
:developer_token => @options["developer_token"],
|
|
227
|
+
:mutable => @options["mutable"]
|
|
228
|
+
)
|
|
229
|
+
@credentials.connector = @connector
|
|
230
|
+
|
|
231
|
+
@service = Service.new(@connector)
|
|
232
|
+
@account = Account.new( self, @credentials )
|
|
233
|
+
@counters = {
|
|
234
|
+
:operations => 0,
|
|
235
|
+
:response_time => 0,
|
|
236
|
+
:units => 0
|
|
237
|
+
}
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
end
|
data/lib/sem4r/base.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
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 Base
|
|
26
|
+
include SoapAttributes
|
|
27
|
+
|
|
28
|
+
attr_reader :adwords
|
|
29
|
+
attr_reader :credentials
|
|
30
|
+
attr_reader :service
|
|
31
|
+
|
|
32
|
+
def initialize(adwords, credentials)
|
|
33
|
+
@adwords = adwords
|
|
34
|
+
@credentials = credentials
|
|
35
|
+
@service = adwords.service
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def add_counters( counters )
|
|
39
|
+
@adwords.add_counters( @credentials, counters )
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
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 BulkMutateJob
|
|
27
|
+
include SoapAttributes
|
|
28
|
+
|
|
29
|
+
attr_reader :id
|
|
30
|
+
attr_accessor :campaign_id
|
|
31
|
+
attr_reader :operations
|
|
32
|
+
|
|
33
|
+
g_accessor :status
|
|
34
|
+
|
|
35
|
+
def initialize(&block)
|
|
36
|
+
@operations = []
|
|
37
|
+
if block_given?
|
|
38
|
+
block.arity < 1 ? instance_eval(&block) : block.call(self)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def add_operation(operation)
|
|
43
|
+
@operations << operation
|
|
44
|
+
self
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def empty?
|
|
48
|
+
@operations.empty?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def add( something )
|
|
52
|
+
case something
|
|
53
|
+
when AdGroupTextAd
|
|
54
|
+
ad_operation = AdGroupAdOperation.new
|
|
55
|
+
ad_operation.add something
|
|
56
|
+
else
|
|
57
|
+
raise "how you suppose I must do when incounter a #{something.class}?"
|
|
58
|
+
end
|
|
59
|
+
self
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def to_xml(tag)
|
|
63
|
+
xml =""
|
|
64
|
+
|
|
65
|
+
if tag
|
|
66
|
+
xml += "<operand xsi:type='BulkMutateJob'>"
|
|
67
|
+
end
|
|
68
|
+
xml += <<-EOS
|
|
69
|
+
<request>
|
|
70
|
+
<partIndex>0</partIndex>
|
|
71
|
+
<operationStreams>
|
|
72
|
+
<scopingEntityId>
|
|
73
|
+
<type>CAMPAIGN_ID</type>
|
|
74
|
+
<value>#{campaign_id}</value>
|
|
75
|
+
</scopingEntityId>
|
|
76
|
+
EOS
|
|
77
|
+
|
|
78
|
+
if @operations
|
|
79
|
+
@operations.each do |operation|
|
|
80
|
+
xml += operation.to_xml('operations')
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
xml +=<<-EOS
|
|
85
|
+
</operationStreams>
|
|
86
|
+
</request>
|
|
87
|
+
<numRequestParts>1</numRequestParts>
|
|
88
|
+
EOS
|
|
89
|
+
|
|
90
|
+
if tag
|
|
91
|
+
xml += "</operand>"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.from_element(el)
|
|
96
|
+
new do
|
|
97
|
+
@id = el.elements["id"].text.strip.to_i
|
|
98
|
+
status el.elements["status"].text
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def to_s
|
|
103
|
+
"#{@id} #{status}"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
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 BulkMutateJobSelector
|
|
27
|
+
include SoapAttributes
|
|
28
|
+
|
|
29
|
+
def initialize(&block)
|
|
30
|
+
if block_given?
|
|
31
|
+
block.arity < 1 ? instance_eval(&block) : block.call(self)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
enum :JobStatuses, [
|
|
36
|
+
:COMPLETED,
|
|
37
|
+
:PROCESSING,
|
|
38
|
+
:FAILED,
|
|
39
|
+
:PENDING]
|
|
40
|
+
|
|
41
|
+
def to_xml
|
|
42
|
+
<<-EOFS
|
|
43
|
+
<selector>
|
|
44
|
+
<customerJobKeys></customerJobKeys>
|
|
45
|
+
<jobStatuses>COMPLETED</jobStatuses>
|
|
46
|
+
<jobStatuses>PROCESSING</jobStatuses>
|
|
47
|
+
<jobStatuses>FAILED</jobStatuses>
|
|
48
|
+
<jobStatuses>PENDING</jobStatuses>
|
|
49
|
+
</selector>
|
|
50
|
+
EOFS
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##########################################################################
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
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 BulkMutateJobService
|
|
27
|
+
include SoapCall
|
|
28
|
+
|
|
29
|
+
def initialize(connector)
|
|
30
|
+
@connector = connector
|
|
31
|
+
|
|
32
|
+
@service_namespace = "https://adwords.google.com/api/adwords/cm/v201003"
|
|
33
|
+
@header_namespace = @service_namespace
|
|
34
|
+
|
|
35
|
+
@sandbox_service_url = "https://adwords-sandbox.google.com/api/adwords/job/v201003/BulkMutateJobService"
|
|
36
|
+
@production_service_url = "https://adwords.google.com/api/adwords/job/v201003/BulkMutateJobService"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
soap_call_v2009 :all, :mutate => false
|
|
40
|
+
soap_call_v2009 :mutate
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def _all(selector)
|
|
45
|
+
"<get xmlns=\"#{@service_namespace}\">" + selector.to_xml + '</get>';
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def _mutate(job_operation)
|
|
49
|
+
<<-EOFS
|
|
50
|
+
<mutate xmlns="#{@service_namespace}">
|
|
51
|
+
#{job_operation.to_xml('operation')}
|
|
52
|
+
</mutate>
|
|
53
|
+
EOFS
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
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 JobOperation < Operation
|
|
28
|
+
def initialize(&block)
|
|
29
|
+
@operation_type = "JobOperation"
|
|
30
|
+
if block_given?
|
|
31
|
+
block.arity < 1 ? instance_eval(&block) : block.call(self)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|