vast 0.2 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,13 @@
1
1
  = VAST
2
2
 
3
- A library for parsing Digital Video Ad Serving Template (VAST) documents, as outlined by the Interactive Advertising Bureau at
4
- http://www.iab.net/iab_products_and_industry_services/508676/digitalvideo/vast. This library strives to be as true to the
5
- standard as possible, while presenting a Ruby-friendly interface.
3
+ A library for parsing Digital Video Ad Serving Template (VAST) 2.0 XML documents, as outlined by the Interactive Advertising Bureau at
4
+ http://www.iab.net/iab_products_and_industry_services/508676/digitalvideo/vast. VAST outlines a standard document format for communication between digital video players and ad servers, including support for
5
+ multiple forms of creative and tracking support that conforms to the latest IAB standards.
6
6
 
7
- VAST outlines a standard document format for communication between digital video players and ad servers, including support for
8
- multiple forms of creative and tracking support that conforms to the latest IAB standards.
7
+ It's recommended that you review the resources made available for the IAB. Whenever possible the documentation in this library has been
8
+ pulled directly from those resources.
9
+
10
+ This library strives to be as true to the standard as possible, while presenting a Ruby-friendly interface.
9
11
 
10
12
  == Installation
11
13
 
@@ -15,10 +17,16 @@ VAST is available as a RubyGem.
15
17
 
16
18
  == Usage
17
19
 
18
- Parse a VAST document and access it's contents easily. See the documentation for the individual classes for an overview of
19
- what information available for each class.
20
+ Parse a VAST document and access its contents using an easy-to-understand model. For example:
20
21
 
21
22
  document = VAST::Document.parse(File.read("vast_document.xml"))
23
+ inline_ad = document.inline_ads.first
24
+ puts document.linear_creative.mediafile.type
25
+ => "video/x-flv"
26
+ puts document.linear_creative.mediafile.url
27
+ => #<URI::HTTP:0x1015ad5f0 URL:http://creativeurl.ca/mediafile>
28
+
29
+ See the documentation for the individual classes for an overview of what information available for each class.
22
30
 
23
31
  == Documentation
24
32
 
@@ -1,10 +1,14 @@
1
1
  require 'vast/document'
2
+ require 'vast/element'
2
3
  require 'vast/ad'
3
4
  require 'vast/inline_ad'
5
+ require 'vast/wrapper_ad'
4
6
  require 'vast/creative'
5
7
  require 'vast/linear_creative'
6
8
  require 'vast/mediafile'
7
9
  require 'vast/companion_creative'
10
+ require 'vast/non_linear_creative'
11
+ require 'vast/extension'
8
12
 
9
13
  # This module wraps VAST documents, as outlined by the IAB at http://www.iab.net/media/file/VAST-2_0-FINAL.pdf
10
14
  module VAST
@@ -1,10 +1,21 @@
1
1
  module VAST
2
- class Ad
3
- attr_reader :source_node
4
-
5
- def initialize(node)
6
- @source_node = node
7
- end
2
+ # Contains some combination of video, companions, and non-linear units for a single advertiser.
3
+ #
4
+ # A single VAST response may include multiple Ads from multiple advertisers. It will be up to
5
+ # the Video Player to determine the order, timing, placement, etc for the multiple ads. However,
6
+ # the player should generally respect the sequential order of the Ad elements within a VAST response.
7
+ #
8
+ # The VAST response does not contain information on the placement or timing of each ad. It is up
9
+ # to the Video Player to determine the optimal inclusion points of the ads.
10
+ #
11
+ # Can either be of type InlineAd, meaning it contains all the elements necessary to display the
12
+ # visual experience, or of type WrapperAd, which points to a downstream VAST document that must be
13
+ # requested from another server.
14
+ #
15
+ # An Ad may include one or more pieces of creative that are part of a single execution. For example, an Ad
16
+ # may include a linear video element with a set of companion banners; this would be reflected by two Creative
17
+ # elements, one LinearCreative and one CompanionCreative.
18
+ class Ad < Element
8
19
 
9
20
  # Create proper ad type
10
21
  def self.create(node)
@@ -19,12 +30,12 @@ module VAST
19
30
 
20
31
  # Ad id, if indicated
21
32
  def id
22
- @source_node[:id]
33
+ source_node[:id]
23
34
  end
24
35
 
25
36
  # Name of source ad server
26
37
  def ad_system
27
- ad_system_node = @source_node.at("AdSystem")
38
+ ad_system_node = source_node.at("AdSystem")
28
39
  if ad_system_node
29
40
  ad_system_node.content
30
41
  else
@@ -34,45 +45,55 @@ module VAST
34
45
 
35
46
  # URI to request if ad does not play due to error
36
47
  def error_url
37
- error_url_node = @source_node.at("Error")
48
+ error_url_node = source_node.at("Error")
38
49
  URI.parse(error_url_node.content) if error_url_node
39
50
  end
40
51
 
41
52
  # Returns an array containing all linear creatives
42
53
  def linear_creatives
43
- @source_node.xpath('.//Creative/Linear').to_a.collect do |node|
54
+ source_node.xpath('.//Creative/Linear').to_a.collect do |node|
44
55
  LinearCreative.new(node)
45
56
  end
46
57
  end
47
58
 
59
+ # It's common for an ad to contain only one piece of linear creative. This is a
60
+ # convenience method for when only the first piece of linear creative is needed.
61
+ def linear_creative
62
+ linear_creatives.first
63
+ end
64
+
48
65
  # Returns an array containing all non linear creatives
49
66
  def non_linear_creatives
50
- @source_node.xpath('.//Creative/NonLinearAds/NonLinear').to_a.collect do |node|
67
+ source_node.xpath('.//Creative/NonLinearAds/NonLinear').to_a.collect do |node|
51
68
  NonLinearCreative.new(node)
52
69
  end
53
70
  end
54
71
 
55
72
  # Returns an array containing all companion creatives
56
73
  def companion_creatives
57
- @source_node.xpath('.//Creative/CompanionAds/Companion').to_a.collect do |node|
74
+ source_node.xpath('.//Creative/CompanionAds/Companion').to_a.collect do |node|
58
75
  CompanionCreative.new(node)
59
76
  end
60
77
  end
61
78
 
62
- # Each Ad should contain at least one impression.
79
+ # Each Ad must contain at least one impression.
63
80
  def impression
64
- URI.parse(@source_node.at('Impression').content)
81
+ URI.parse(source_node.at('Impression').content)
65
82
  end
66
83
 
67
84
  # Array of all impressions available for this ad, excluding those specific
68
85
  # to a particular creative.
69
86
  def impressions
70
- @source_node.xpath('.//Impression').to_a.collect do |node|
87
+ source_node.xpath('.//Impression').to_a.collect do |node|
71
88
  URI.parse(node)
72
89
  end
73
90
  end
74
91
 
92
+ # Extensions included in the
93
+ def extensions
94
+ source_node.xpath('.//Extension').to_a.collect do |node|
95
+ Extension.new(node)
96
+ end
97
+ end
75
98
  end
76
-
77
- class WrapperAd < Ad; end
78
99
  end
@@ -1,48 +1,55 @@
1
1
  module VAST
2
+ # Commonly text, display ads, rich media, or skins that wrap around the video experience. These ads come
3
+ # in a number of sizes and shapes and typically run alongside or surrounding the video player.
2
4
  class CompanionCreative < Creative
3
5
 
4
6
  def id
5
- @source_node[:id]
7
+ source_node[:id]
6
8
  end
7
9
 
8
10
  # Width in pixels of companion
9
11
  def width
10
- @source_node[:width].to_i
12
+ source_node[:width].to_i
11
13
  end
12
14
 
13
15
  # Height in pixels of companion
14
16
  def height
15
- @source_node[:height].to_i
17
+ source_node[:height].to_i
16
18
  end
17
19
 
18
20
  # Width in pixels of expanding companion ad when in expanded state
19
21
  def expanded_width
20
- @source_node[:expandedWidth].to_i
22
+ source_node[:expandedWidth].to_i
21
23
  end
22
24
 
23
25
  # Height in pixels of expanding companion ad when in expanded state
24
26
  def expanded_height
25
- @source_node[:expandedHeight].to_i
27
+ source_node[:expandedHeight].to_i
28
+ end
29
+
30
+ # Defines the method to use for communication with the companion
31
+ def api_framework
32
+ source_node[:apiFramework]
26
33
  end
27
34
 
28
35
  # URI to open as destination page when user clicks on the video
29
36
  def click_through_url
30
- URI.parse @source_node.at('CompanionClickThrough').content
37
+ URI.parse source_node.at('CompanionClickThrough').content
31
38
  end
32
39
 
33
40
  # Alternate text to be displayed when companion is rendered in HTML environment.
34
41
  def alt_text
35
- node = @source_node.at('AltText')
42
+ node = source_node.at('AltText')
36
43
  node.nil? ? nil : node.content
37
44
  end
38
45
 
39
46
  # Type of companion resource, returned as a symbol. Either :static, :iframe, or :html.
40
47
  def resource_type
41
- if @source_node.at('StaticResource')
48
+ if source_node.at('StaticResource')
42
49
  :static
43
- elsif @source_node.at('IFrameResource')
50
+ elsif source_node.at('IFrameResource')
44
51
  :iframe
45
- elsif @source_node.at('HTMLResource')
52
+ elsif source_node.at('HTMLResource')
46
53
  :html
47
54
  end
48
55
  end
@@ -50,7 +57,7 @@ module VAST
50
57
  # Returns MIME type of static creative
51
58
  def creative_type
52
59
  if resource_type == :static
53
- @source_node.at('StaticResource')[:creativeType]
60
+ source_node.at('StaticResource')[:creativeType]
54
61
  end
55
62
  end
56
63
 
@@ -58,16 +65,16 @@ module VAST
58
65
  def resource_url
59
66
  case resource_type
60
67
  when :static
61
- URI.parse @source_node.at('StaticResource').content
68
+ URI.parse source_node.at('StaticResource').content
62
69
  when :iframe
63
- URI.parse @source_node.at('IFrameResource').content
70
+ URI.parse source_node.at('IFrameResource').content
64
71
  end
65
72
  end
66
73
 
67
74
  # Returns HTML text for html resource
68
75
  def resource_html
69
76
  if resource_type == :html
70
- @source_node.at('HTMLResource').content
77
+ source_node.at('HTMLResource').content
71
78
  end
72
79
  end
73
80
  end
@@ -1,13 +1,14 @@
1
1
  module VAST
2
- class Creative
3
- attr_reader :source_node
4
-
5
- def initialize(node)
6
- @source_node = node
7
- end
2
+ # Contains the information related to a piece of creative.
3
+ #
4
+ # === Sequence
5
+ # The Creative element takes an optional “sequence” attribute that indicates the suggested order in which the
6
+ # Creatives should be displayed. If two Creative elements are intended to be shown at the same time they should
7
+ # share the same sequence number.
8
+ class Creative < Element
8
9
 
9
10
  def ad
10
- Ad.create @source_node.ancestors('Ad').first
11
+ Ad.create source_node.ancestors('Ad').first
11
12
  end
12
13
 
13
14
  def id
@@ -25,14 +26,19 @@ module VAST
25
26
 
26
27
  # Data to be passed into the video ad.
27
28
  def ad_parameters
28
- @source_node.at('AdParameters').content
29
+ source_node.at('AdParameters').content
29
30
  end
30
31
 
32
+ # Returns a hash, keyed by event name, containing an array of URIs to be called for each event.
31
33
  def tracking_urls
32
34
  tracking_urls = {}
33
- @source_node.xpath('.//Tracking').to_a.collect do |node|
35
+ source_node.xpath('.//Tracking').to_a.collect do |node|
34
36
  underscored_name = underscore(node[:event])
35
- tracking_urls[underscored_name.to_sym] = URI.parse(node.content)
37
+ if tracking_urls[underscored_name.to_sym]
38
+ tracking_urls[underscored_name.to_sym] << URI.parse(node.content)
39
+ else
40
+ tracking_urls[underscored_name.to_sym] = [URI.parse(node.content)]
41
+ end
36
42
  end
37
43
  tracking_urls
38
44
  end
@@ -50,9 +56,7 @@ module VAST
50
56
  private
51
57
 
52
58
  def creative_node
53
- @source_node.ancestors('Creative').first
59
+ source_node.ancestors('Creative').first
54
60
  end
55
61
  end
56
-
57
- class NonLinearCreative < Creative; end
58
62
  end
@@ -20,7 +20,8 @@ module VAST
20
20
  xsd.valid?(self)
21
21
  end
22
22
 
23
- # All ads in the document
23
+ # All ads in the document If no ads of any type are available, it should ould be indicated
24
+ # by the absence of any Ads.
24
25
  def ads
25
26
  self.root.xpath('.//Ad').to_a.collect do |node|
26
27
  Ad.create(node)
@@ -0,0 +1,9 @@
1
+ module VAST
2
+ class Element
3
+ attr_reader :source_node
4
+
5
+ def initialize(node)
6
+ @source_node = node
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module VAST
2
+ class Extension < Element
3
+
4
+ # Extension type
5
+ def type
6
+ source_node[:type]
7
+ end
8
+
9
+ # Access to the XML contents of this extension, as a Nokogiri::XML::Node
10
+ # http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Node.html. Alias of
11
+ # Extension#source_node
12
+ def xml
13
+ source_node
14
+ end
15
+ end
16
+ end
@@ -1,15 +1,17 @@
1
1
  module VAST
2
+ # Contains all the information necessary to display the visual experience of one complete ad.
2
3
  class InlineAd < Ad
3
4
 
4
5
  # URI of request to survey vendor
5
6
  def survey_url
6
- URI.parse @source_node.at('Survey').content
7
+ URI.parse source_node.at('Survey').content
7
8
  end
8
9
 
9
10
  # Common name of ad
10
11
  def ad_title
11
- @source_node.at('AdTitle').content
12
+ source_node.at('AdTitle').content
12
13
  end
14
+
13
15
  end
14
16
  end
15
17
 
@@ -1,19 +1,21 @@
1
1
  module VAST
2
+ # LinearCreative is presented before, in the middle of, or after the video content is consumed by the user,
3
+ # in very much the same way a TV commercial can play before, during or after the chosen program.
2
4
  class LinearCreative < Creative
3
5
 
4
6
  # Duration of creative
5
7
  def duration
6
- @source_node.at('Duration').content
8
+ source_node.at('Duration').content
7
9
  end
8
10
 
9
11
  # URI to open as destination page when user clicks on the video
10
12
  def click_through_url
11
- URI.parse @source_node.at('ClickThrough').content
13
+ URI.parse source_node.at('ClickThrough').content
12
14
  end
13
15
 
14
16
  # An array of URIs to request for tracking purposes when user clicks on the video
15
17
  def click_tracking_urls
16
- @source_node.xpath('.//ClickTracking').to_a.collect do |node|
18
+ source_node.xpath('.//ClickTracking').to_a.collect do |node|
17
19
  URI.parse node.content
18
20
  end
19
21
  end
@@ -23,7 +25,7 @@ module VAST
23
25
  # used as the key for this hash
24
26
  def custom_click_urls
25
27
  custom_click_urls = {}
26
- @source_node.xpath('.//CustomClick').to_a.collect do |node|
28
+ source_node.xpath('.//CustomClick').to_a.collect do |node|
27
29
  key = underscore(node[:id]).to_sym
28
30
  custom_click_urls[key] = URI.parse(node.content)
29
31
  end
@@ -31,7 +33,7 @@ module VAST
31
33
  end
32
34
 
33
35
  def mediafiles
34
- @source_node.xpath('.//MediaFile').to_a.collect do |node|
36
+ source_node.xpath('.//MediaFile').to_a.collect do |node|
35
37
  Mediafile.new(node)
36
38
  end
37
39
  end
@@ -1,54 +1,54 @@
1
1
  module VAST
2
- class Mediafile
3
- attr_reader :source_node
4
-
5
- def initialize(node)
6
- @source_node = node
7
- end
2
+ class Mediafile < Element
8
3
 
9
4
  # Location of linear file
10
5
  def url
11
- URI.parse @source_node.content
6
+ URI.parse source_node.content
12
7
  end
13
8
 
14
9
  def id
15
- @source_node[:id]
10
+ source_node[:id]
16
11
  end
17
12
 
18
13
  # Method of delivery of ad, either "streaming" or "progressive"
19
14
  def delivery
20
- @source_node[:delivery]
15
+ source_node[:delivery]
21
16
  end
22
17
 
23
18
  # MIME type. Popular MIME types include, but are not limited to “video/x-ms-wmv” for
24
19
  # Windows Media, and “video/x-flv” for Flash Video.
25
20
  def type
26
- @source_node[:type]
21
+ source_node[:type]
27
22
  end
28
23
 
29
24
  # Bitrate of encoded video in Kbps
30
25
  def bitrate
31
- @source_node[:bitrate].to_i
26
+ source_node[:bitrate].to_i
32
27
  end
33
28
 
34
29
  # Pixel dimensions of video width
35
30
  def width
36
- @source_node[:width].to_i
31
+ source_node[:width].to_i
37
32
  end
38
33
 
39
34
  # Pixel dimensions of video height
40
35
  def height
41
- @source_node[:height].to_i
36
+ source_node[:height].to_i
37
+ end
38
+
39
+ # Defines the method to use for communication with the companion
40
+ def api_framework
41
+ source_node[:apiFramework]
42
42
  end
43
43
 
44
- # Whether it is acceptable to scale the image.
44
+ # Whether it is acceptable to scale the mediafile.
45
45
  def scalable?
46
- @source_node[:scalable]=="true"
46
+ source_node[:scalable]=="true"
47
47
  end
48
48
 
49
- # Whether the ad must have its aspect ratio maintained when scaled
49
+ # Whether the mediafile must have its aspect ratio maintained when scaled
50
50
  def maintain_aspect_ratio?
51
- @source_node[:maintainAspectRatio]=="true"
51
+ source_node[:maintainAspectRatio]=="true"
52
52
  end
53
53
  end
54
54
  end
@@ -0,0 +1,93 @@
1
+ module VAST
2
+ # NonLinearCreative runs concurrently with the video content so the users see the ad while viewing
3
+ # the content. Non-linear video ads can be delivered as text, graphical ads, or as video overlays.
4
+ class NonLinearCreative < Creative
5
+
6
+ def id
7
+ source_node[:id]
8
+ end
9
+
10
+ # Width in pixels
11
+ def width
12
+ source_node[:width].to_i
13
+ end
14
+
15
+ # Height in pixels
16
+ def height
17
+ source_node[:height].to_i
18
+ end
19
+
20
+ # Width in pixels when in expanded state
21
+ def expanded_width
22
+ source_node[:expandedWidth].to_i
23
+ end
24
+
25
+ # Height in pixels when in expanded state
26
+ def expanded_height
27
+ source_node[:expandedHeight].to_i
28
+ end
29
+
30
+ # Defines the method to use for communication with the companion
31
+ def api_framework
32
+ source_node[:apiFramework]
33
+ end
34
+
35
+ # URI to open as destination page when user clicks on creative
36
+ def click_through_url
37
+ URI.parse source_node.at('NonLinearClickThrough').content
38
+ end
39
+
40
+ # Whether it is acceptable to scale the mediafile.
41
+ def scalable?
42
+ source_node[:scalable]=="true"
43
+ end
44
+
45
+ # Whether the mediafile must have its aspect ratio maintained when scaled
46
+ def maintain_aspect_ratio?
47
+ source_node[:maintainAspectRatio]=="true"
48
+ end
49
+
50
+ # Suggested duration to display non-linear ad, typically for animation to complete.
51
+ # Expressed in standard time format hh:mm:ss
52
+ def min_suggested_duration
53
+ source_node[:minSuggestedDuration]
54
+ end
55
+
56
+
57
+ # Type of non-linear resource, returned as a symbol. Either :static, :iframe, or :html.
58
+ def resource_type
59
+ if source_node.at('StaticResource')
60
+ :static
61
+ elsif source_node.at('IFrameResource')
62
+ :iframe
63
+ elsif source_node.at('HTMLResource')
64
+ :html
65
+ end
66
+ end
67
+
68
+ # Returns MIME type of static creative
69
+ def creative_type
70
+ if resource_type == :static
71
+ source_node.at('StaticResource')[:creativeType]
72
+ end
73
+ end
74
+
75
+ # Returns URI for static or iframe resource
76
+ def resource_url
77
+ case resource_type
78
+ when :static
79
+ URI.parse source_node.at('StaticResource').content
80
+ when :iframe
81
+ URI.parse source_node.at('IFrameResource').content
82
+ end
83
+ end
84
+
85
+ # Returns HTML text for html resource
86
+ def resource_html
87
+ if resource_type == :html
88
+ source_node.at('HTMLResource').content
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,19 @@
1
+ module VAST
2
+ # Points to another VAST document on a different server.
3
+ #
4
+ # WrapperAds may include any number of tracking urls to allow CompanionCreatives to be served
5
+ # from an InlineAd response but tracked separately from the Impression. It may also include
6
+ # tracking elements for separately tracking LinearCreative or NonLinearCreative views or events.
7
+ #
8
+ # The server providing the WrapperAd may not know exactly which creative elements are to be
9
+ # delivered downline in inline ads; in that case the WrapperAd should include placeholders for
10
+ # the maximum set of Creatives that could be played within the Video Player.
11
+ class WrapperAd < Ad
12
+
13
+ # URI of ad tag of downstream Secondary Ad Server
14
+ def ad_tag_url
15
+ URI.parse source_node.at('VASTAdTagURI').content
16
+ end
17
+
18
+ end
19
+ end
@@ -60,12 +60,20 @@ class AdTest < Test::Unit::TestCase
60
60
  end
61
61
  end
62
62
 
63
+ def test_ad_should_know_first_linear_creative
64
+ document_file = example_file('document_with_one_inline_ad.xml')
65
+ document = VAST::Document.parse!(document_file)
66
+ ad = document.inline_ads.first
67
+
68
+ assert_equal ad.linear_creative.id, ad.linear_creatives.first.id
69
+ end
70
+
63
71
  def test_ad_should_know_non_linear_creatives
64
72
  document_file = example_file('document_with_one_inline_ad.xml')
65
73
  document = VAST::Document.parse!(document_file)
66
74
  ad = document.inline_ads.first
67
75
 
68
- assert_equal 1, ad.non_linear_creatives.count
76
+ assert_equal 2, ad.non_linear_creatives.count
69
77
  ad.non_linear_creatives.each do |creative|
70
78
  assert creative.kind_of?(VAST::NonLinearCreative)
71
79
  end
@@ -100,4 +108,15 @@ class AdTest < Test::Unit::TestCase
100
108
  assert_equal "http://myTrackingURL/impression", ad.impressions.first.to_s
101
109
  assert_equal "http://myTrackingURL/anotherImpression", ad.impressions.last.to_s
102
110
  end
111
+
112
+ def test_extensions
113
+ document_file = example_file('document_with_one_inline_ad.xml')
114
+ document = VAST::Document.parse!(document_file)
115
+ ad = document.inline_ads.first
116
+
117
+ assert_equal 2, ad.extensions.count
118
+ ad.extensions.each do |extension|
119
+ assert extension.kind_of?(VAST::Extension)
120
+ end
121
+ end
103
122
  end
@@ -14,6 +14,7 @@ class CompanionCreativeTest < Test::Unit::TestCase
14
14
  assert_equal 500, creative.expanded_height
15
15
  assert_equal "http://www.tremormedia.com", creative.click_through_url.to_s
16
16
  assert_equal "Display this instead of the ad", creative.alt_text
17
+ assert_equal "VPAID", creative.api_framework
17
18
  end
18
19
 
19
20
  def test_should_know_static_resource
@@ -27,8 +27,8 @@ class CreativeTest < Test::Unit::TestCase
27
27
  document = VAST::Document.parse!(document_with_creative)
28
28
  creative = document.ads.first.linear_creatives.first
29
29
 
30
- assert_equal "http://myTrackingURL/creativeView", creative.tracking_urls[:creative_view].to_s
31
- assert_equal "http://myTrackingURL/start", creative.tracking_urls[:start].to_s
30
+ assert_equal ["http://myTrackingURL/creativeView"], creative.tracking_urls[:creative_view].collect{ |url| url.to_s }
31
+ assert_equal ["http://myTrackingURL/start1", "http://myTrackingURL/start2"], creative.tracking_urls[:start].collect{ |url| url.to_s }
32
32
  ## There are more tracking urls, refer to spec for complete list
33
33
  end
34
34
 
@@ -18,7 +18,8 @@
18
18
  <TrackingEvents>
19
19
  <Tracking event="creativeView"><![CDATA[http://myTrackingURL/creativeView]]></Tracking>
20
20
 
21
- <Tracking event="start"><![CDATA[http://myTrackingURL/start]]></Tracking>
21
+ <Tracking event="start"><![CDATA[http://myTrackingURL/start1]]></Tracking>
22
+ <Tracking event="start"><![CDATA[http://myTrackingURL/start2]]></Tracking>
22
23
  <Tracking event="midpoint"><![CDATA[http://myTrackingURL/midpoint]]></Tracking>
23
24
  <Tracking event="firstQuartile"><![CDATA[http://myTrackingURL/firstQuartile]]></Tracking>
24
25
  <Tracking event="thirdQuartile"><![CDATA[http://myTrackingURL/thirdQuartile]]></Tracking>
@@ -43,13 +44,13 @@
43
44
  <CustomClick id="customTwo"><![CDATA[http://myTrackingURL/custom2]]></CustomClick>
44
45
  </VideoClicks>
45
46
  <MediaFiles>
46
- <MediaFile id="firstFile" delivery="progressive" type="video/x-flv" bitrate="500" width="400" height="300" scalable="true" maintainAspectRatio="true"><![CDATA[http://cdnp.tremormedia.com/video/acudeo/Carrot_400x300_500kb.flv]]></MediaFile>
47
+ <MediaFile id="firstFile" delivery="progressive" type="video/x-flv" bitrate="500" width="400" height="300" scalable="true" maintainAspectRatio="true" apiFramework="VPAID"><![CDATA[http://cdnp.tremormedia.com/video/acudeo/Carrot_400x300_500kb.flv]]></MediaFile>
47
48
  </MediaFiles>
48
49
  </Linear>
49
50
  </Creative>
50
51
  <Creative AdID="601364-Companion">
51
52
  <CompanionAds>
52
- <Companion id="big_box" width="300" height="250" expandedWidth="600" expandedHeight="500">
53
+ <Companion id="big_box" width="300" height="250" expandedWidth="600" expandedHeight="500" apiFramework="VPAID">
53
54
  <StaticResource creativeType="image/jpeg">http://demo.tremormedia.com/proddev/vast/Blistex1.jpg</StaticResource>
54
55
  <TrackingEvents>
55
56
  <Tracking event="creativeView">http://myTrackingURL/firstCompanionCreativeView</Tracking>
@@ -65,13 +66,31 @@
65
66
  </Creative>
66
67
  <Creative AdID="601365">
67
68
  <NonLinearAds>
68
- <NonLinear width="300" height="50">
69
+ <NonLinear id="special_overlay" width="300" height="50" expandedWidth="600" expandedHeight="500" apiFramework="VPAID" scalable="true" maintainAspectRatio="true">
69
70
  <StaticResource creativeType="image/jpeg"><![CDATA[http://cdn.liverail.com/adasset/228/330/overlay.jpg]]></StaticResource>
70
- <NonLinearClickThrough><![CDATA[http://t3.liverail.com/?metric=clickthru&pos=1&pid=1331&coid=135&nid=0&cid=330&kid=228&vid=&amid=&cc=default&pp=&url=&cb=9185&x=&y=&xy=&redirect=http%3A%2F%2Fliverail.com%2F]]></NonLinearClickThrough>
71
- </NonLinear>
71
+ <NonLinearClickThrough><![CDATA[http://t3.liverail.com]]></NonLinearClickThrough>
72
+ </NonLinear>
73
+ <NonLinear width="728" height="90">
74
+ <IFrameResource><![CDATA[http://ad3.liverail.com/util/non_linear.php]]></IFrameResource>
75
+ <NonLinearClickThrough>http://www.tremormedia.com</NonLinearClickThrough>
76
+ </NonLinear>
72
77
  </NonLinearAds>
73
78
  </Creative>
74
79
  </Creatives>
80
+ <Extensions>
81
+ <Extension type="DART">
82
+ <AdServingData>
83
+ <DeliveryData>
84
+ <GeoData><![CDATA[ct=CA&st=ON&ac=905&zp=L6V1X9&bw=0&dma=1&city=1869]]></GeoData>
85
+ </DeliveryData>
86
+ </AdServingData>
87
+ </Extension>
88
+ <Extension type="value">
89
+ <CostPerThousand currency="CAD">
90
+ 125.00
91
+ </CostPerThousand>
92
+ </Extension>
93
+ </Extensions>
75
94
  </InLine>
76
95
  </Ad>
77
96
 
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class ExtensionTest < Test::Unit::TestCase
4
+
5
+ def test_should_know_attributes
6
+ document_file = example_file('document_with_one_inline_ad.xml')
7
+ document = VAST::Document.parse!(document_file)
8
+ extension = VAST::Extension.new(document.at('Extension'))
9
+
10
+ assert_equal "DART", extension.type
11
+ end
12
+
13
+ def test_should_know_attributes
14
+ document_file = example_file('document_with_one_inline_ad.xml')
15
+ document = VAST::Document.parse!(document_file)
16
+ extension = VAST::Extension.new(document.at('Extension'))
17
+
18
+ assert_equal extension.source_node, extension.xml
19
+ end
20
+ end
@@ -13,6 +13,7 @@ class MediafileTest < Test::Unit::TestCase
13
13
  assert_equal 400, mediafile.width
14
14
  assert_equal 300, mediafile.height
15
15
  assert_equal 500, mediafile.bitrate
16
+ assert_equal "VPAID", mediafile.api_framework
16
17
  assert mediafile.scalable?
17
18
  assert mediafile.maintain_aspect_ratio?
18
19
  end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+
3
+ class NonLinearCreativeTest < Test::Unit::TestCase
4
+
5
+ def test_should_know_attributes
6
+ document_file = example_file('document_with_one_inline_ad.xml')
7
+ document = VAST::Document.parse!(document_file)
8
+ creative = document.inline_ads.first.non_linear_creatives.first
9
+
10
+ assert_equal "special_overlay", creative.id
11
+ assert_equal 300, creative.width
12
+ assert_equal 50, creative.height
13
+ assert_equal 600, creative.expanded_width
14
+ assert_equal 500, creative.expanded_height
15
+ assert_equal "http://t3.liverail.com", creative.click_through_url.to_s
16
+ assert_equal "VPAID", creative.api_framework
17
+ assert creative.scalable?
18
+ assert creative.maintain_aspect_ratio?
19
+ end
20
+
21
+ def test_should_know_static_resource
22
+ document_file = example_file('document_with_one_inline_ad.xml')
23
+ document = VAST::Document.parse!(document_file)
24
+ creative_with_static_resource = document.inline_ads.first.non_linear_creatives.first
25
+
26
+ assert_equal :static, creative_with_static_resource.resource_type
27
+ assert_equal "image/jpeg", creative_with_static_resource.creative_type
28
+ assert_equal "http://cdn.liverail.com/adasset/228/330/overlay.jpg", creative_with_static_resource.resource_url.to_s
29
+ end
30
+
31
+ def test_should_know_iframe_resource
32
+ document_file = example_file('document_with_one_inline_ad.xml')
33
+ document = VAST::Document.parse!(document_file)
34
+ creative_with_iframe_resource = document.inline_ads.first.non_linear_creatives.last
35
+
36
+ assert_equal :iframe, creative_with_iframe_resource.resource_type
37
+ assert_equal "http://ad3.liverail.com/util/non_linear.php", creative_with_iframe_resource.resource_url.to_s
38
+ end
39
+ end
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+
3
+ class WrapperAdTest < Test::Unit::TestCase
4
+
5
+ def test_should_know_ad_tag_url
6
+ document_with_wrapper_ad = example_file('document_with_one_wrapper_ad.xml')
7
+ document = VAST::Document.parse!(document_with_wrapper_ad)
8
+
9
+ ad_node = document.root.xpath('.//Ad').first
10
+ ad = VAST::WrapperAd.new(ad_node)
11
+
12
+ assert ad.ad_tag_url.kind_of?(URI)
13
+ assert_equal "http://demo.tremormedia.com/proddev/vast/vast_inline_linear.xml", ad.ad_tag_url.to_s
14
+ end
15
+
16
+ end
metadata CHANGED
@@ -3,9 +3,9 @@ name: vast
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
+ - 1
6
7
  - 0
7
- - 2
8
- version: "0.2"
8
+ version: "1.0"
9
9
  platform: ruby
10
10
  authors:
11
11
  - Chris Dinn
@@ -46,17 +46,24 @@ files:
46
46
  - lib/vast/companion_creative.rb
47
47
  - lib/vast/creative.rb
48
48
  - lib/vast/document.rb
49
+ - lib/vast/element.rb
50
+ - lib/vast/extension.rb
49
51
  - lib/vast/inline_ad.rb
50
52
  - lib/vast/linear_creative.rb
51
53
  - lib/vast/mediafile.rb
54
+ - lib/vast/non_linear_creative.rb
55
+ - lib/vast/wrapper_ad.rb
52
56
  - test/ad_test.rb
53
57
  - test/companion_creative_test.rb
54
58
  - test/creative_test.rb
55
59
  - test/document_test.rb
60
+ - test/extension_test.rb
56
61
  - test/inline_ad_test.rb
57
62
  - test/linear_creative_test.rb
58
63
  - test/mediafile_test.rb
64
+ - test/non_linear_creative_test.rb
59
65
  - test/test_helper.rb
66
+ - test/wrapper_ad_test.rb
60
67
  - test/examples/document_with_no_ads.xml
61
68
  - test/examples/document_with_one_inline_ad.xml
62
69
  - test/examples/document_with_one_inline_and_one_wrapper_ad.xml
@@ -66,7 +73,6 @@ files:
66
73
  - test/examples/invalid_document_with_missing_ad_type.xml
67
74
  - test/examples/invalid_document_with_missing_creative_type.xml
68
75
  - LICENSE
69
- - README.md
70
76
  - README.rdoc
71
77
  has_rdoc: true
72
78
  homepage: http://github.com/chrisdinn/vast
data/README.md DELETED
@@ -1,45 +0,0 @@
1
- VAST
2
- =====
3
-
4
- A library for parsing Digital Video Ad Serving Template (VAST) documents, as outlined by the Interactive Advertising Bureau at
5
- [http://www.iab.net/iab_products_and_industry_services/508676/digitalvideo/vast]. This library strives to be as true to the
6
- standard as possible, while presenting a Ruby-friendly interface.
7
-
8
- VAST outlines a standard document format for communication between digital video players and ad servers, including support for
9
- multiple forms of creative and tracking support that conforms to the latest IAB standards.
10
-
11
- Installation
12
- ------------
13
-
14
- VAST is available as a RubyGem.
15
-
16
- gem install vast
17
-
18
- Usage
19
- -----
20
-
21
- Parse a VAST document and access it's contents easily. See the documentation for the individual classes for an overview of
22
- what information available for each class.
23
-
24
- document = VAST::Document.parse(File.read("vast_document.xml"))
25
-
26
- Problems/Bugs/Requests
27
- -----------------------------
28
-
29
- Please, file an issue.
30
-
31
- Note on Patches/Pull Requests
32
- -----------------------------
33
-
34
- * Fork the project.
35
- * Make your feature addition or bug fix.
36
- * Add tests for it. This is important so I don't break it in a
37
- future version unintentionally.
38
- * Commit, do not mess with rakefile, version, or history.
39
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
40
- * Send me a pull request. Bonus points for topic branches.
41
-
42
- Copyright
43
- -----------------------------
44
-
45
- © 2010 Chris Dinn. See [LICENSE](http://github.com/chrisdinn/vast/blob/master/LICENSE) for details.