vast 0.2 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +15 -7
- data/lib/vast.rb +4 -0
- data/lib/vast/ad.rb +38 -17
- data/lib/vast/companion_creative.rb +21 -14
- data/lib/vast/creative.rb +17 -13
- data/lib/vast/document.rb +2 -1
- data/lib/vast/element.rb +9 -0
- data/lib/vast/extension.rb +16 -0
- data/lib/vast/inline_ad.rb +4 -2
- data/lib/vast/linear_creative.rb +7 -5
- data/lib/vast/mediafile.rb +17 -17
- data/lib/vast/non_linear_creative.rb +93 -0
- data/lib/vast/wrapper_ad.rb +19 -0
- data/test/ad_test.rb +20 -1
- data/test/companion_creative_test.rb +1 -0
- data/test/creative_test.rb +2 -2
- data/test/examples/document_with_one_inline_ad.xml +25 -6
- data/test/extension_test.rb +20 -0
- data/test/mediafile_test.rb +1 -0
- data/test/non_linear_creative_test.rb +39 -0
- data/test/wrapper_ad_test.rb +16 -0
- metadata +9 -3
- data/README.md +0 -45
data/README.rdoc
CHANGED
@@ -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.
|
5
|
-
|
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
|
-
|
8
|
-
|
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
|
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
|
|
data/lib/vast.rb
CHANGED
@@ -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
|
data/lib/vast/ad.rb
CHANGED
@@ -1,10 +1,21 @@
|
|
1
1
|
module VAST
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
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 =
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
79
|
+
# Each Ad must contain at least one impression.
|
63
80
|
def impression
|
64
|
-
URI.parse(
|
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
|
-
|
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
|
-
|
7
|
+
source_node[:id]
|
6
8
|
end
|
7
9
|
|
8
10
|
# Width in pixels of companion
|
9
11
|
def width
|
10
|
-
|
12
|
+
source_node[:width].to_i
|
11
13
|
end
|
12
14
|
|
13
15
|
# Height in pixels of companion
|
14
16
|
def height
|
15
|
-
|
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
|
-
|
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
|
-
|
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
|
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 =
|
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
|
48
|
+
if source_node.at('StaticResource')
|
42
49
|
:static
|
43
|
-
elsif
|
50
|
+
elsif source_node.at('IFrameResource')
|
44
51
|
:iframe
|
45
|
-
elsif
|
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
|
-
|
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
|
68
|
+
URI.parse source_node.at('StaticResource').content
|
62
69
|
when :iframe
|
63
|
-
URI.parse
|
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
|
-
|
77
|
+
source_node.at('HTMLResource').content
|
71
78
|
end
|
72
79
|
end
|
73
80
|
end
|
data/lib/vast/creative.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
module VAST
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
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
|
-
|
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
|
-
|
35
|
+
source_node.xpath('.//Tracking').to_a.collect do |node|
|
34
36
|
underscored_name = underscore(node[:event])
|
35
|
-
tracking_urls[underscored_name.to_sym]
|
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
|
-
|
59
|
+
source_node.ancestors('Creative').first
|
54
60
|
end
|
55
61
|
end
|
56
|
-
|
57
|
-
class NonLinearCreative < Creative; end
|
58
62
|
end
|
data/lib/vast/document.rb
CHANGED
@@ -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)
|
data/lib/vast/element.rb
ADDED
@@ -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
|
data/lib/vast/inline_ad.rb
CHANGED
@@ -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
|
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
|
-
|
12
|
+
source_node.at('AdTitle').content
|
12
13
|
end
|
14
|
+
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
data/lib/vast/linear_creative.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
36
|
+
source_node.xpath('.//MediaFile').to_a.collect do |node|
|
35
37
|
Mediafile.new(node)
|
36
38
|
end
|
37
39
|
end
|
data/lib/vast/mediafile.rb
CHANGED
@@ -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
|
6
|
+
URI.parse source_node.content
|
12
7
|
end
|
13
8
|
|
14
9
|
def id
|
15
|
-
|
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
|
-
|
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
|
-
|
21
|
+
source_node[:type]
|
27
22
|
end
|
28
23
|
|
29
24
|
# Bitrate of encoded video in Kbps
|
30
25
|
def bitrate
|
31
|
-
|
26
|
+
source_node[:bitrate].to_i
|
32
27
|
end
|
33
28
|
|
34
29
|
# Pixel dimensions of video width
|
35
30
|
def width
|
36
|
-
|
31
|
+
source_node[:width].to_i
|
37
32
|
end
|
38
33
|
|
39
34
|
# Pixel dimensions of video height
|
40
35
|
def height
|
41
|
-
|
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
|
44
|
+
# Whether it is acceptable to scale the mediafile.
|
45
45
|
def scalable?
|
46
|
-
|
46
|
+
source_node[:scalable]=="true"
|
47
47
|
end
|
48
48
|
|
49
|
-
# Whether the
|
49
|
+
# Whether the mediafile must have its aspect ratio maintained when scaled
|
50
50
|
def maintain_aspect_ratio?
|
51
|
-
|
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
|
data/test/ad_test.rb
CHANGED
@@ -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
|
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
|
data/test/creative_test.rb
CHANGED
@@ -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/
|
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/
|
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
|
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
|
data/test/mediafile_test.rb
CHANGED
@@ -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
|
-
|
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.
|