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,98 @@
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 AdGroupAd < Base
26
+
27
+ #
28
+ # Ad.type
29
+ #
30
+ enum :Types, [
31
+ :DeprecatedAd,
32
+ :MobileAd,
33
+ :TextAd,
34
+ :MobileImageAd,
35
+ :ImageAd,
36
+ :LocalBusinessAd,
37
+ :TemplateAd
38
+ ]
39
+
40
+ #
41
+ # AdGroupAd.Status
42
+ #
43
+ enum :Statuses, [
44
+ :ENABLED,
45
+ :PAUSED,
46
+ :DISABLED
47
+ ]
48
+
49
+ #
50
+ # Ad.ApprovalStatus
51
+ #
52
+ enum :ApprovalStatus, [
53
+ :APPROVED,
54
+ :FAMILY_SAFE,
55
+ :NON_FAMILY_SAFE,
56
+ :PORN,
57
+ :UNCHECKED, # Pending review
58
+ :DISAPPROVED
59
+ ]
60
+
61
+ attr_reader :ad_group
62
+ attr_accessor :type
63
+
64
+ # g_reader :type
65
+ g_accessor :url
66
+ g_accessor :display_url
67
+ g_accessor :status, {:default => "ENABLED"}
68
+
69
+ def initialize(ad_group, &block)
70
+ super( ad_group.adwords, ad_group.credentials )
71
+ @ad_group = ad_group
72
+ if block_given?
73
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
74
+ end
75
+ end
76
+
77
+ def saved?
78
+ !@id.nil?
79
+ end
80
+
81
+ # try to save when accessing id
82
+ def id
83
+ save unless @id
84
+ @id
85
+ end
86
+
87
+ def self.from_element( ad_group, el )
88
+ xml_type = el.elements["Ad.Type"].text.strip
89
+ case xml_type
90
+ when TextAd
91
+ AdGroupTextAd.from_element(ad_group, el)
92
+ when MobileAd
93
+ AdGroupMobileAd.from_element(ad_group, el)
94
+ end
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,38 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ # -------------------------------------------------------------------------
24
+
25
+ module Sem4r
26
+
27
+ class AdGroupAdOperation < Operation
28
+
29
+ def initialize(&block)
30
+ @operation_type = "AdGroupAdOperation"
31
+ if block_given?
32
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ 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
+ module Sem4r
25
+ class AdGroupAdService
26
+ include SoapCall
27
+
28
+ def initialize(connector)
29
+ @connector = connector
30
+ @service_namespace = "https://adwords.google.com/api/adwords/cm/v201003"
31
+ @header_namespace = @service_namespace
32
+
33
+ @sandbox_service_url = "https://adwords-sandbox.google.com/api/adwords/cm/v201003/AdGroupAdService"
34
+ end
35
+
36
+ soap_call_v2009 :all, :mutate => false
37
+ soap_call_v2009 :mutate
38
+
39
+ private
40
+
41
+ def _all(ad_group_id)
42
+ <<-EOFS
43
+ <get xmlns="#{@service_namespace}">
44
+ <selector>
45
+ <adGroupIds>#{ad_group_id}</adGroupIds>
46
+ </selector>
47
+ </get>
48
+ EOFS
49
+ end
50
+
51
+ def _mutate(xml)
52
+ "<mutate xmlns=\"#{@service_namespace}\">#{xml}</mutate>"
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,137 @@
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
+ # From: http://code.google.com/apis/adwords/v2009/docs/reference/AdGroupAdService.MobileAd.html
28
+ # A mobile ad can contain a click-to-call phone number, a link to a website, or both.
29
+ # You specify which features you want by setting certain fields, as shown in the following table.
30
+ # For example, to create a click-to-call mobile ad, set the fields in the Click-to-call column.
31
+ # A hyphen means don't set the corresponding field.
32
+ class AdGroupMobileAd < AdGroupAd
33
+
34
+ enum :Markups, [
35
+ :CHTML,
36
+ :HTML,
37
+ :WML,
38
+ :XHTML
39
+ ]
40
+
41
+ def initialize(ad_group, &block)
42
+ @carriers = []
43
+ self.type = MobileAd
44
+ super
45
+ end
46
+
47
+ # MobileAd
48
+ g_accessor :headline
49
+ g_accessor :description
50
+ g_set_accessor :markup, {:values_in => :Markups}
51
+ g_set_accessor :carrier # default carrier 'ALLCARRIERS'
52
+ g_accessor :business_name # 20 caratteri 10 per il giappone
53
+ g_accessor :country_code
54
+ g_accessor :phone_number
55
+
56
+ def image
57
+ @image
58
+ end
59
+
60
+ def image(&block)
61
+ @image = MobileAdImage.new(self, &block)
62
+ end
63
+
64
+ def xml(t)
65
+ t.adGroupId ad_group.id
66
+ t.ad("xsi:type" => "MobileAd") do |ad|
67
+ ad.headline headline
68
+ ad.description description
69
+ unless markups.empty?
70
+ markups.each do |m|
71
+ ad.markupLanguages m
72
+ end
73
+ end
74
+ unless carriers.empty?
75
+ carriers.each do |carrier|
76
+ ad.mobileCarriers carrier
77
+ end
78
+ end
79
+ ad.businessName business_name
80
+ ad.countryCode country_code
81
+ ad.phoneNumber phone_number
82
+ end
83
+ t.status status
84
+ end
85
+
86
+ def to_xml(tag)
87
+ builder = Builder::XmlMarkup.new
88
+ builder.tag!(tag, "xsi:type" => "AdGroupAd") do |t|
89
+ xml(t)
90
+ # t.adGroupId ad_group.id
91
+ # t.ad("xsi:type" => "MobileAd") do |ad|
92
+ # ad.headline headline
93
+ # ad.description description
94
+ # unless markups.empty?
95
+ # markups.each do |m|
96
+ # ad.markupLanguages m
97
+ # end
98
+ # end
99
+ # unless carriers.empty?
100
+ # carriers.each do |carrier|
101
+ # ad.mobileCarriers carrier
102
+ # end
103
+ # end
104
+ # ad.businessName business_name
105
+ # ad.countryCode country_code
106
+ # ad.phoneNumber phone_number
107
+ # end
108
+ # t.status status
109
+ end
110
+ end
111
+
112
+ def self.from_element(ad_group, el)
113
+ new(ad_group) do
114
+ @id = el.elements["id"].text.strip.to_i
115
+ # type el.elements["Ad.Type"].text
116
+ headline el.elements["headline"].text.strip
117
+ description el.elements["description"].text.strip
118
+ business_name el.elements["businessName"].text.strip
119
+ country_code el.elements["countryCode"].text.strip
120
+ phone_number el.elements["phoneNumber"].text.strip
121
+ # TODO: estrarre le carriers
122
+ end
123
+ end
124
+
125
+ def save
126
+ unless @id
127
+ soap_message = service.ad_group_ad.create(credentials, to_xml("operand"))
128
+ add_counters( soap_message.counters )
129
+ rval = REXML::XPath.first( soap_message.response, "//mutateResponse/rval")
130
+ id = REXML::XPath.match( rval, "value/ad/id" ).first
131
+ @id = id.text.strip.to_i
132
+ end
133
+ self
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,98 @@
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 AdGroupTextAd < AdGroupAd
27
+
28
+ g_accessor :headline
29
+ g_accessor :description1
30
+ g_accessor :description2
31
+
32
+ def initialize(ad_group, &block)
33
+ self.type = TextAd
34
+ super
35
+ end
36
+
37
+ def to_s
38
+ "#{@id} textad '#{headline}' #{url}"
39
+ end
40
+
41
+ def xml(t)
42
+ t.adGroupId ad_group.id
43
+ t.ad("xsi:type" => "TextAd") do |ad|
44
+ ad.url url
45
+ ad.displayUrl display_url
46
+ ad.headline headline
47
+ ad.description1 description1
48
+ ad.description2 description2
49
+ end
50
+ t.status status
51
+ end
52
+
53
+ def to_xml(tag)
54
+ builder = Builder::XmlMarkup.new
55
+ builder.tag!(tag, "xsi:type" => "AdGroupAd") do |t|
56
+ xml(t)
57
+ # t.adGroupId ad_group.id
58
+ # t.ad("xsi:type" => "TextAd") do |ad|
59
+ # ad.url url
60
+ # ad.displayUrl display_url
61
+ # ad.headline headline
62
+ # ad.description1 description1
63
+ # ad.description2 description2
64
+ # end
65
+ # t.status status
66
+ end
67
+ end
68
+
69
+ def self.from_element(ad_group, el)
70
+ new(ad_group) do
71
+ @id = el.elements["id"].text.strip.to_i
72
+ # type el.elements["Ad.Type"].text
73
+ url el.elements["url"].text.strip
74
+ display_url el.elements["displayUrl"].text.strip
75
+ headline el.elements["headline"].text.strip
76
+ description1 el.elements["description1"].text.strip
77
+ description2 el.elements["description2"].text.strip
78
+ end
79
+ end
80
+
81
+ def self.create(ad_group, &block)
82
+ new(ad_group, &block).save
83
+ end
84
+
85
+ def save
86
+ unless @id
87
+ ad_operation = AdGroupAdOperation.new.add self
88
+ soap_message = service.ad_group_ad.mutate(credentials, ad_operation.to_xml("operations"))
89
+ add_counters( soap_message.counters )
90
+ rval = REXML::XPath.first( soap_message.response, "//mutateResponse/rval")
91
+ id = REXML::XPath.match( rval, "value/ad/id" ).first
92
+ @id = id.text.strip.to_i
93
+ end
94
+ self
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,144 @@
1
+ # -------------------------------------------------------------------
2
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ # -------------------------------------------------------------------
23
+
24
+ module Sem4r
25
+
26
+ #
27
+ # http://code.google.com/apis/adwords/v2009/docs/reference/AdGroupCriterionService.AdGroupCriterion.html
28
+ #
29
+ class AdGroupCriterion
30
+ include SoapAttributes
31
+
32
+ g_accessor :criterion
33
+
34
+ def initialize(&block)
35
+ if block_given?
36
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
37
+ end
38
+ end
39
+
40
+ def self.from_element(ad_group, el)
41
+ type = el.elements["AdGroupCriterion.Type"].text.strip
42
+ klass = Module::const_get(type)
43
+ klass.from_element(ad_group, el)
44
+ end
45
+
46
+ def saved?
47
+ criterion.saved?
48
+ end
49
+
50
+ def save
51
+ unless criterion.saved?
52
+ o = AdGroupCriterionOperation.new.add(self)
53
+ soap_message =
54
+ criterion.service.ad_group_criterion.mutate(criterion.credentials, o.to_xml("operations"))
55
+ criterion.add_counters( soap_message.counters )
56
+ rval = REXML::XPath.first( soap_message.response, "//mutateResponse/rval")
57
+ id = REXML::XPath.match( rval, "value/criterion/id" ).first
58
+ criterion.instance_eval{ @id = id.text.strip.to_i }
59
+ end
60
+ self
61
+ end
62
+
63
+ end
64
+
65
+ class BiddableAdGroupCriterion < AdGroupCriterion
66
+
67
+ g_accessor :bids
68
+
69
+ def initialize(ad_group, &block)
70
+ @ad_group = ad_group
71
+ if block_given?
72
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
73
+ end
74
+ end
75
+
76
+ def to_s
77
+ "biddable " + criterion.to_s
78
+ end
79
+
80
+ def self.from_element(ad_group, el)
81
+ new(ad_group) do
82
+ criterion Criterion.from_element(ad_group, el.elements["criterion"])
83
+ bids AdGroupCriterionBids.from_element(el.elements["bids"])
84
+ end
85
+ end
86
+
87
+ def xml(t)
88
+ t.adGroupId @ad_group.id
89
+ # t.status "ENABLED"
90
+ criterion.xml(t)
91
+ @bids.xml(t) if @bids
92
+ end
93
+
94
+ def to_xml(tag)
95
+ builder = Builder::XmlMarkup.new
96
+ builder.tag!(tag, "xsi:type" => "BiddableAdGroupCriterion") do |t|
97
+ xml(t)
98
+ # t.adGroupId @ad_group.id
99
+ # # t.status "ENABLED"
100
+ # criterion.to_xml(t)
101
+ # @bids.to_xml(t) if @bids
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ class NegativeAdGroupCriterion < AdGroupCriterion
108
+
109
+ def initialize(ad_group, &block)
110
+ @ad_group = ad_group
111
+ if block_given?
112
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
113
+ end
114
+ end
115
+
116
+ def to_s
117
+ "negative " + criterion.to_s
118
+ end
119
+
120
+ def self.from_element(ad_group, el)
121
+ new(ad_group) do
122
+ criterion Criterion.from_element(ad_group, el.elements["criterion"])
123
+ end
124
+ end
125
+
126
+ def xml(t)
127
+ t.adGroupId criterion.ad_group.id
128
+ # t.status "ENABLED"
129
+ criterion.xml(t)
130
+ end
131
+
132
+ def to_xml(tag)
133
+ builder = Builder::XmlMarkup.new
134
+ builder.tag!(tag, "xsi:type" => "NegativeAdGroupCriterion") do |t|
135
+ xml(t)
136
+ # t.adGroupId criterion.ad_group.id
137
+ # # t.status "ENABLED"
138
+ # criterion.to_xml(t)
139
+ end
140
+ end
141
+
142
+ end
143
+
144
+ end
@@ -0,0 +1,115 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ # -------------------------------------------------------------------------
24
+
25
+ module Sem4r
26
+
27
+ class AdGroupCriterionBids
28
+ include SoapAttributes
29
+
30
+ enum :Types, [
31
+ :BudgetOptimizerAdGroupCriterionBids,
32
+ :ConversionOptimizerAdGroupCriterionBids,
33
+ :ManualCPCAdGroupCriterionBids,
34
+ :ManualCPMAdGroupCriterionBids
35
+ ]
36
+
37
+ def self.from_element(el)
38
+ type = el.elements["AdGroupCriterionBids.Type"].text.strip
39
+ klass = Module::const_get(type)
40
+ klass.from_element(el)
41
+ end
42
+ end
43
+
44
+ class BudgetOptimizerAdGroupCriterionBids < AdGroupCriterionBids
45
+ end
46
+
47
+ class ConversionOptimizerAdGroupCriterionBids < AdGroupCriterionBids
48
+ end
49
+
50
+ #
51
+ # http://code.google.com/apis/adwords/v2009/docs/reference/AdGroupCriterionService.ManualCPCAdGroupCriterionBids.html
52
+ #
53
+ class ManualCPCAdGroupCriterionBids < AdGroupCriterionBids
54
+
55
+ g_accessor :bid_source
56
+ g_accessor :max_cpc
57
+
58
+ def initialize(&block)
59
+ if block_given?
60
+ block.arity < 1 ? instance_eval(&block) : block.call(self)
61
+ end
62
+ end
63
+
64
+ def self.from_element(el)
65
+ new do
66
+ bid_source el.elements["bidSource"].text.strip
67
+
68
+ el_maxCpc = el.elements["maxCpc"]
69
+ el_amount = el_maxCpc.elements["amount"]
70
+ max_cpc el_amount.elements["microAmount"].text.strip.to_i
71
+
72
+ # TODO: it is possible something like:
73
+ # el.elements["maxCpc"] do |el|
74
+ # el.elements["amount"] do el
75
+ # max_cpc el["microAmount"]
76
+ # end
77
+ # end
78
+ end
79
+ end
80
+
81
+ def xml(t)
82
+ t.tag!('bids', 'xsi:type' => 'ManualCPCAdGroupCriterionBids') {
83
+ t.tag!('AdGroupCriterionBids.Type') { t.text! 'ManualCPCAdGroupCriterionBids' }
84
+ t.maxCpc {
85
+ t.amount {
86
+ t.tag!('ComparableValue.Type') { t.text! 'Money' }
87
+ t.microAmount max_cpc
88
+ }
89
+ }
90
+ }
91
+ end
92
+
93
+ def to_xml(tag = 'bids')
94
+ builder = Builder::XmlMarkup.new
95
+ xml = builder.tag!(tag, 'xsi:type' => 'ManualCPCAdGroupCriterionBids') { |xml|
96
+ xml.tag!('AdGroupCriterionBids.Type') { xml.text! 'ManualCPCAdGroupCriterionBids' }
97
+ xml.maxCpc {
98
+ xml.amount {
99
+ xml.tag!('ComparableValue.Type') { xml.text! 'Money' }
100
+ xml.microAmount max_cpc
101
+ }
102
+ }
103
+ }
104
+ end
105
+
106
+ def to_s
107
+ "#{@maxcpc / 10000} cents"
108
+ end
109
+
110
+ end
111
+
112
+ class ManualCPMAdGroupCriterionBids < AdGroupCriterionBids
113
+ end
114
+
115
+ end