vast 0.2 → 1.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 +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.
|