yieldmanager 0.2.4 → 0.3.0

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/README.rdoc CHANGED
@@ -23,6 +23,8 @@ To use in a Rails project, add this to config/environment.rb:
23
23
 
24
24
  === Creating a Yieldmanager::Client
25
25
 
26
+ require 'yieldmanager'
27
+
26
28
  @ym = Yieldmanager::Client.new(
27
29
  :user => "bob",
28
30
  :pass => "secret",
@@ -36,7 +38,7 @@ To use in a Rails project, add this to config/environment.rb:
36
38
  === Using a service
37
39
 
38
40
  @ym.session do |token|
39
- currencies = @ym.dictionary.getCurrencies(token)
41
+ @currencies = @ym.dictionary.getCurrencies(token)
40
42
  end
41
43
 
42
44
  === Pagination
@@ -55,6 +57,25 @@ the partial dataset on-the-fly or accumulating it for later use.
55
57
  end
56
58
  end
57
59
 
60
+
61
+ === Pulling reports
62
+
63
+ Accessing reportware assumes you've used the "Get Report XML"
64
+ functionality in the UI to get your request XML data, or have
65
+ crafted one from scratch. Assuming it's in a variable called
66
+ *request_xml*, you'd access the data this way:
67
+
68
+ @ym.session do |token|
69
+ report = @ym.pull_report(token, request_xml)
70
+ puts report.headers.join("\t")
71
+ report.data.each do |row|
72
+ puts row.join("\t")
73
+ end
74
+ end
75
+
76
+ *NOTE* Any totals columns your xml requests will be interpreted
77
+ as ordinary data.
78
+
58
79
  === session vs. start_session/end_session
59
80
 
60
81
  The +session+ method opens a session, gives you a token to use in your service
data/Rakefile CHANGED
@@ -11,6 +11,7 @@ begin
11
11
  gem.homepage = "http://github.com/billgathen/yieldmanager"
12
12
  gem.authors = ["Bill Gathen"]
13
13
  gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_dependency "hpricot", ">= 0.8.2"
14
15
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
16
  end
16
17
  Jeweler::GemcutterTasks.new
data/TODO CHANGED
@@ -9,7 +9,11 @@
9
9
  * DONE add pagination
10
10
  * add error-handling (timeouts, too many connections?)
11
11
  * add reporting
12
- ** report(xml) method in Client
13
- ** Yieldmanager::Report DTO
14
- *** headers array (for proper column ordering)
12
+ ** DONE pull_report(xml) method in Client
13
+ ** DONE Yieldmanager::Report DTO
14
+ *** DONE headers array (for proper column ordering)
15
+ *** DONE data as array of arrays
15
16
  *** data as array of hashes
17
+ ** DONE hpricot for parsing (http://github.com/hpricot/hpricot/)
18
+ ** how to handle subtotal/total rows?
19
+ ** cast columns to ruby types based on column[data_type]?
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.4
1
+ 0.3.0
data/lib/yieldmanager.rb CHANGED
@@ -3,6 +3,7 @@ $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
3
3
  # The module that contains everything Yieldmanager-related:
4
4
  #
5
5
  # * Yieldmanager::Client is the class used to interact with Yieldmanager.
6
+ # * Yieldmanager::Report is the data object returned by ReportWare calls.
6
7
  # * Yieldmanager::Builder creates local copies of the YM service wsdls.
7
8
  #
8
9
  module Yieldmanager
@@ -10,3 +11,4 @@ end
10
11
 
11
12
  require 'yieldmanager/client'
12
13
  require 'yieldmanager/builder'
14
+ require 'yieldmanager/report'
@@ -7,6 +7,9 @@ module Yieldmanager
7
7
  # These are used to dynamically-generate the service methods
8
8
  # and instance variables in Yieldmanager::Client.
9
9
  #
10
+ # This shouldn't need to be run by the end-user because the
11
+ # current version of the APIs are pre-generated in the gem.
12
+ #
10
13
  # At some point, the wsdls themselves will actually be used
11
14
  # to build the objects.
12
15
  class Builder
@@ -1,7 +1,6 @@
1
- #!/usr/bin/env ruby -w
2
-
3
1
  require 'soap/wsdlDriver'
4
2
  require 'open-uri'
3
+ require 'hpricot'
5
4
 
6
5
  module Yieldmanager
7
6
  # This is the frontend for using Yieldmanager programmatically.
@@ -9,15 +8,18 @@ module Yieldmanager
9
8
  # new instance and calling +service_name+ to access YM services.
10
9
  # For example:
11
10
  #
12
- # ym = Yieldmanager::Client(
13
- # :user => "bob",
14
- # :pass => "secret",
15
- # :api_version => "1.30"
16
- # )
11
+ # ym = Yieldmanager::Client(
12
+ # :user => "bob",
13
+ # :pass => "secret",
14
+ # :api_version => "1.30"
15
+ # )
16
+ #
17
+ # ym.session do |token|
18
+ # currencies = @ym.dictionary.getCurrencies(token)
19
+ # end
17
20
  #
18
- # ym.session do |token|
19
- # currencies = @ym.dictionary.getCurrencies(token)
20
- # end
21
+ # It also offers simple access to the ReportWare reporting engine
22
+ # via the #pull_report method.
21
23
  class Client
22
24
  # Yieldmanager user
23
25
  attr_reader :user
@@ -60,17 +62,11 @@ module Yieldmanager
60
62
  end.compact
61
63
  end
62
64
 
63
- # Opens Yieldmanager session
64
- def start_session
65
- contact.login(@user,@pass,{'errors_level' => 'throw_errors','multiple_sessions' => '1'})
66
- end
67
-
68
- # Closes Yieldmanager session
69
- def end_session token
70
- contact.logout(token)
71
- end
72
-
73
65
  # Manages Yieldmanager session
66
+ #
67
+ # Returns block with token string to be used in API/report calls
68
+ #
69
+ # Guarantees no hanging sessions except during system crashes
74
70
  def session
75
71
  token = start_session
76
72
  begin
@@ -80,6 +76,20 @@ module Yieldmanager
80
76
  end
81
77
  end
82
78
 
79
+ # Opens Yieldmanager session
80
+ #
81
+ # Use #session if possible: it guarantees no hanging sessions
82
+ def start_session
83
+ contact.login(@user,@pass,{'errors_level' => 'throw_errors','multiple_sessions' => '1'})
84
+ end
85
+
86
+ # Closes Yieldmanager session
87
+ #
88
+ # Use #session if possible: it guarantees no hanging sessions
89
+ def end_session token
90
+ contact.logout(token)
91
+ end
92
+
83
93
  # Allows looping over datasets too large to pull back in one call
84
94
  #
85
95
  # Block must return total rows in dataset to know when to stop!
@@ -92,12 +102,21 @@ module Yieldmanager
92
102
  page += 1
93
103
  end until (block_size * (page-1)) > total
94
104
  end
105
+
106
+ # Pulls report from RightMedia, returned as Yieldmanager::Report
107
+ #
108
+ # Must be called within the context of a session
109
+ def pull_report token, xml
110
+ report = Yieldmanager::Report.new
111
+ report.pull(token, self.report, xml)
112
+ report
113
+ end
95
114
 
96
115
  private
97
116
 
98
117
  def wrap_services
99
118
  available_services.each do |s|
100
- self.instance_variable_set("@#{s}", nil)
119
+ self.class.send(:attr_writer, s.to_sym)
101
120
  # create wrapper method to load it when requested
102
121
  self.class.send(:define_method, s) {
103
122
  unless self.instance_variable_get("@#{s}")
@@ -115,5 +134,4 @@ private
115
134
  SOAP::WSDLDriverFactory.new(wsdl_path).create_rpc_driver
116
135
  end
117
136
  end
118
-
119
137
  end
@@ -0,0 +1,59 @@
1
+ module Yieldmanager
2
+ # This is the data object for all reportware requests.
3
+ #
4
+ # The #pull method is typically called by Yieldmanager::Client#pull_report.
5
+ #
6
+ # Data is returned as an array of arrays.
7
+ #
8
+ # Column order is stored in the *headers* array.
9
+ class Report
10
+ attr_accessor :headers, :data
11
+
12
+ def initialize
13
+ self.headers = []
14
+ self.data = []
15
+ end
16
+
17
+ def pull token, report, xml
18
+ report_token = request_report_token token, report, xml
19
+ report_url = retrieve_report_url token, report, report_token
20
+ retrieve_data report_url
21
+ end
22
+
23
+ private
24
+
25
+ def request_report_token token, report, xml
26
+ report.requestViaXML(token,xml)
27
+ end
28
+
29
+ def retrieve_report_url token, report, report_token
30
+ report_url = nil
31
+ 60.times do |secs| # Poll until report ready
32
+ report_url = report.status(token,report_token)
33
+ break if report_url != nil
34
+ sleep(5)
35
+ end
36
+ report_url
37
+ end
38
+
39
+ def retrieve_data url
40
+ doc = open(url) { |f| Hpricot(f) }
41
+ (doc/"header column").each do |col|
42
+ headers << col.inner_html
43
+ end
44
+ (doc/"row").each_with_index do |row,idx|
45
+ # TODO make data available as keyword hashes, too
46
+ # row_hash = {}
47
+ # (row/"column").each do |col|
48
+ # row_hash[headers[idx]] = col.inner_html
49
+ # end
50
+ # data << row_hash
51
+ # TODO cast elements to appropriate types based on column attrs
52
+ data << (row/"column").collect do |col|
53
+ col.inner_html
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ end
@@ -97,6 +97,17 @@ describe "A new Yieldmanager client" do
97
97
  end
98
98
  end
99
99
 
100
+ describe "A Yieldmanager report" do
101
+
102
+ before(:each) do
103
+ @ym = Yieldmanager::Client.new(login_args)
104
+ end
105
+
106
+ it "returns data" do
107
+ request_xml.should include("advertiser_id")
108
+ end
109
+ end
110
+
100
111
  def login_args
101
112
  unless ENV["YIELDMANAGER_USER"] &&
102
113
  ENV["YIELDMANAGER_PASS"] &&
@@ -109,4 +120,26 @@ describe "A new Yieldmanager client" do
109
120
  :api_version => ENV["YIELDMANAGER_API_VERSION"]
110
121
  }
111
122
  end
123
+
124
+ def request_xml
125
+ <<EOR
126
+ <?xml version="1.0"?>
127
+ <RWRequest clientName="ui.ent.prod">
128
+ <REQUEST domain="network" service="ComplexReport" nocache="n" contact_id="52798" remote_ip_address="99.62.255.163" entity="3" filter_entity_id="3" timezone="EST">
129
+ <ROWS>
130
+ <ROW type="group" priority="1" ref="entity_id" includeascolumn="n"/>
131
+ <ROW type="group" priority="2" ref="advertiser_id" includeascolumn="n"/>
132
+ <ROW type="total"/>
133
+ </ROWS>
134
+ <COLUMNS>
135
+ <COLUMN ref="advertiser_name"/>
136
+ <COLUMN ref="seller_imps"/>
137
+ </COLUMNS>
138
+ <FILTERS>
139
+ <FILTER ref="time" macro="yesterday"/>
140
+ </FILTERS>
141
+ </REQUEST>
142
+ </RWRequest>
143
+ EOR
144
+ end
112
145
  end
@@ -0,0 +1,102 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ NEED_ENV_ARGS_MSG = <<EOM
4
+ Please set these environment variables to match your Yieldmanager account:
5
+ * YIELDMANAGER_USER
6
+ * YIELDMANAGER_PASS
7
+ * YIELDMANAGER_API_VERSION
8
+ * YIELDMANAGER_CONTACT_ID
9
+ * YIELDMANAGER_IP_ADDRESS (your external IP address)
10
+ EOM
11
+
12
+ describe "A Yieldmanager report request" do
13
+
14
+ before(:each) do
15
+ @ym = Yieldmanager::Client.new(login_args)
16
+ end
17
+
18
+ it "returns report object" do
19
+ @ym.session do |token|
20
+ rpt = @ym.pull_report(token, request_xml)
21
+ rpt.should be_instance_of(Yieldmanager::Report)
22
+ end
23
+ end
24
+
25
+ it "makes request and returns report token" do
26
+ @ym.session do |token|
27
+ rpt = Yieldmanager::Report.new
28
+ rpt.send(:request_report_token, token, @ym.report, request_xml).should_not be_nil
29
+ end
30
+ end
31
+
32
+ it "uses report token to pull report url" do
33
+ @ym.session do |token|
34
+ rpt = Yieldmanager::Report.new
35
+ report_token = rpt.send(:request_report_token, token, @ym.report, request_xml)
36
+ report_url = rpt.send(:retrieve_report_url, token, @ym.report, report_token)
37
+ report_url.should_not be_nil
38
+ end
39
+ end
40
+
41
+ it "uses report url to pull report" do
42
+ @ym.session do |token|
43
+ rpt = Yieldmanager::Report.new
44
+ report_token = rpt.send(:request_report_token, token, @ym.report, request_xml)
45
+ report_url = rpt.send(:retrieve_report_url, token, @ym.report, report_token)
46
+
47
+ rpt.send(:retrieve_data, report_url)
48
+ rpt.headers[0].should == "advertiser_name"
49
+ end
50
+ end
51
+
52
+ it "offers data as array of arrays" do
53
+ @ym.session do |token|
54
+ report = @ym.pull_report(token, request_xml)
55
+ report.data[0][0].should_not be_nil
56
+ end
57
+ end
58
+
59
+ it "complains if report token is nil"
60
+
61
+ # need configurable pause and attempts to keep this from running 5 mins!
62
+ it "throws ReportTimeoutException if report data never returns"
63
+
64
+ def login_args
65
+ unless ENV["YIELDMANAGER_USER"] &&
66
+ ENV["YIELDMANAGER_PASS"] &&
67
+ ENV["YIELDMANAGER_API_VERSION"]
68
+ raise(ArgumentError, NEED_ENV_ARGS_MSG)
69
+ end
70
+ @login_args ||= {
71
+ :user => ENV["YIELDMANAGER_USER"],
72
+ :pass => ENV["YIELDMANAGER_PASS"],
73
+ :api_version => ENV["YIELDMANAGER_API_VERSION"]
74
+ }
75
+ end
76
+
77
+ def request_xml
78
+ unless ENV["YIELDMANAGER_CONTACT_ID"] &&
79
+ ENV["YIELDMANAGER_IP_ADDRESS"]
80
+ raise(ArgumentError, NEED_ENV_ARGS_MSG)
81
+ end
82
+ <<EOR
83
+ <?xml version="1.0"?>
84
+ <RWRequest clientName="ui.ent.prod">
85
+ <REQUEST domain="network" service="ComplexReport" nocache="n" contact_id="#{ENV['YIELDMANAGER_CONTACT_ID']}" remote_ip_address="#{ENV['YIELDMANAGER_IP_ADDRESS']}" entity="3" filter_entity_id="3" timezone="EST">
86
+ <ROWS>
87
+ <ROW type="group" priority="1" ref="entity_id" includeascolumn="n"/>
88
+ <ROW type="group" priority="2" ref="advertiser_id" includeascolumn="n"/>
89
+ <ROW type="total"/>
90
+ </ROWS>
91
+ <COLUMNS>
92
+ <COLUMN ref="advertiser_name"/>
93
+ <COLUMN ref="seller_imps"/>
94
+ </COLUMNS>
95
+ <FILTERS>
96
+ <FILTER ref="time" macro="yesterday"/>
97
+ </FILTERS>
98
+ </REQUEST>
99
+ </RWRequest>
100
+ EOR
101
+ end
102
+ end
data/yieldmanager.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{yieldmanager}
8
- s.version = "0.2.4"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Bill Gathen"]
12
- s.date = %q{2009-11-18}
12
+ s.date = %q{2009-11-21}
13
13
  s.description = %q{This gem offers full access to YieldManager's API tools (read/write) as well as ad-hoc reporting through the Reportware tool}
14
14
  s.email = %q{bill@billgathen.com}
15
15
  s.extra_rdoc_files = [
@@ -27,10 +27,12 @@ Gem::Specification.new do |s|
27
27
  "lib/yieldmanager.rb",
28
28
  "lib/yieldmanager/builder.rb",
29
29
  "lib/yieldmanager/client.rb",
30
+ "lib/yieldmanager/report.rb",
30
31
  "spec/spec.opts",
31
32
  "spec/spec_helper.rb",
32
33
  "spec/yieldmanager/builder_spec.rb",
33
34
  "spec/yieldmanager/client_spec.rb",
35
+ "spec/yieldmanager/report_spec.rb",
34
36
  "wsdls/1.30/prod/adjustment.wsdl",
35
37
  "wsdls/1.30/prod/advertiser.wsdl",
36
38
  "wsdls/1.30/prod/campaign.wsdl",
@@ -79,7 +81,8 @@ Gem::Specification.new do |s|
79
81
  s.test_files = [
80
82
  "spec/spec_helper.rb",
81
83
  "spec/yieldmanager/builder_spec.rb",
82
- "spec/yieldmanager/client_spec.rb"
84
+ "spec/yieldmanager/client_spec.rb",
85
+ "spec/yieldmanager/report_spec.rb"
83
86
  ]
84
87
 
85
88
  if s.respond_to? :specification_version then
@@ -88,11 +91,14 @@ Gem::Specification.new do |s|
88
91
 
89
92
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
90
93
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
94
+ s.add_runtime_dependency(%q<hpricot>, [">= 0.8.2"])
91
95
  else
92
96
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
97
+ s.add_dependency(%q<hpricot>, [">= 0.8.2"])
93
98
  end
94
99
  else
95
100
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
101
+ s.add_dependency(%q<hpricot>, [">= 0.8.2"])
96
102
  end
97
103
  end
98
104
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yieldmanager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bill Gathen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-18 00:00:00 -05:00
12
+ date: 2009-11-21 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -22,6 +22,16 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: 1.2.9
24
24
  version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hpricot
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.8.2
34
+ version:
25
35
  description: This gem offers full access to YieldManager's API tools (read/write) as well as ad-hoc reporting through the Reportware tool
26
36
  email: bill@billgathen.com
27
37
  executables: []
@@ -42,10 +52,12 @@ files:
42
52
  - lib/yieldmanager.rb
43
53
  - lib/yieldmanager/builder.rb
44
54
  - lib/yieldmanager/client.rb
55
+ - lib/yieldmanager/report.rb
45
56
  - spec/spec.opts
46
57
  - spec/spec_helper.rb
47
58
  - spec/yieldmanager/builder_spec.rb
48
59
  - spec/yieldmanager/client_spec.rb
60
+ - spec/yieldmanager/report_spec.rb
49
61
  - wsdls/1.30/prod/adjustment.wsdl
50
62
  - wsdls/1.30/prod/advertiser.wsdl
51
63
  - wsdls/1.30/prod/campaign.wsdl
@@ -117,3 +129,4 @@ test_files:
117
129
  - spec/spec_helper.rb
118
130
  - spec/yieldmanager/builder_spec.rb
119
131
  - spec/yieldmanager/client_spec.rb
132
+ - spec/yieldmanager/report_spec.rb