yieldmanager 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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