open_graph_reader 0.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.
- checksums.yaml +7 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.yardopts +1 -0
- data/lib/open_graph_reader.rb +83 -0
- data/lib/open_graph_reader/base.rb +57 -0
- data/lib/open_graph_reader/builder.rb +100 -0
- data/lib/open_graph_reader/definitions.rb +333 -0
- data/lib/open_graph_reader/fetcher.rb +82 -0
- data/lib/open_graph_reader/object.rb +95 -0
- data/lib/open_graph_reader/object/dsl.rb +130 -0
- data/lib/open_graph_reader/object/dsl/types.rb +71 -0
- data/lib/open_graph_reader/object/registry.rb +54 -0
- data/lib/open_graph_reader/parser.rb +85 -0
- data/lib/open_graph_reader/parser/graph.rb +136 -0
- data/lib/open_graph_reader/version.rb +4 -0
- data/spec/fixtures/examples/apple-touch-icon-precomposed.png +0 -0
- data/spec/fixtures/examples/apple-touch-icon.png +0 -0
- data/spec/fixtures/examples/article-offset.html +25 -0
- data/spec/fixtures/examples/article-utc.html +25 -0
- data/spec/fixtures/examples/article.html +25 -0
- data/spec/fixtures/examples/audio-array.html +27 -0
- data/spec/fixtures/examples/audio-url.html +25 -0
- data/spec/fixtures/examples/audio.html +24 -0
- data/spec/fixtures/examples/book-isbn10.html +27 -0
- data/spec/fixtures/examples/book.html +27 -0
- data/spec/fixtures/examples/canadian.html +16 -0
- data/spec/fixtures/examples/error.html +17 -0
- data/spec/fixtures/examples/errors/article-date.html +25 -0
- data/spec/fixtures/examples/errors/book-author.html +27 -0
- data/spec/fixtures/examples/errors/book.html +27 -0
- data/spec/fixtures/examples/errors/gender.html +20 -0
- data/spec/fixtures/examples/errors/geo.html +23 -0
- data/spec/fixtures/examples/errors/type.html +16 -0
- data/spec/fixtures/examples/errors/video-duration.html +42 -0
- data/spec/fixtures/examples/favicon.ico +0 -0
- data/spec/fixtures/examples/filters/xss-image.html +15 -0
- data/spec/fixtures/examples/image-array.html +26 -0
- data/spec/fixtures/examples/image-toosmall.html +24 -0
- data/spec/fixtures/examples/image-url.html +22 -0
- data/spec/fixtures/examples/image.html +21 -0
- data/spec/fixtures/examples/index.html +67 -0
- data/spec/fixtures/examples/media/audio/1khz.mp3 +0 -0
- data/spec/fixtures/examples/media/audio/250hz.mp3 +0 -0
- data/spec/fixtures/examples/media/images/1.png +0 -0
- data/spec/fixtures/examples/media/images/50.png +0 -0
- data/spec/fixtures/examples/media/images/75.png +0 -0
- data/spec/fixtures/examples/media/images/icon.png +0 -0
- data/spec/fixtures/examples/media/images/logo.png +0 -0
- data/spec/fixtures/examples/media/images/train.jpg +0 -0
- data/spec/fixtures/examples/media/video/train.flv +0 -0
- data/spec/fixtures/examples/media/video/train.mp4 +0 -0
- data/spec/fixtures/examples/media/video/train.webm +0 -0
- data/spec/fixtures/examples/min.html +14 -0
- data/spec/fixtures/examples/nomedia.html +20 -0
- data/spec/fixtures/examples/plain.html +10 -0
- data/spec/fixtures/examples/profile.html +25 -0
- data/spec/fixtures/examples/required.html +20 -0
- data/spec/fixtures/examples/robots.txt +4 -0
- data/spec/fixtures/examples/sitemap.xml +23 -0
- data/spec/fixtures/examples/video-array.html +36 -0
- data/spec/fixtures/examples/video-movie.html +42 -0
- data/spec/fixtures/examples/video.html +26 -0
- data/spec/integration/invalid_examples_spec.rb +69 -0
- data/spec/integration/valid_examples_spec.rb +76 -0
- data/spec/open_graph_reader_spec.rb +94 -0
- data/spec/spec_helper.rb +35 -0
- metadata +247 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fb82d8a9867ad4c1cf0258ef4e97f993cccdc6aa
|
4
|
+
data.tar.gz: ef67382716657161c2098380bf00c6abc48e6a4e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a60f2d67610ab9d1cd0587c58b92452f07fff77da489eec68c7906af650247bd42e26506a5d323f9d6ebe4b3bb247b7b26aba2dac5389634c660d80801b6f32b
|
7
|
+
data.tar.gz: 423fb2fe90278c64bd089579c5165c9ee468663c3d9eeb0661c1dfa0a5adc74f12a8772f7f5bdeff0d15ecb52493887d822e13a68dae31de98f9056636e21666
|
data/.gitmodules
ADDED
data/.rspec
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'faraday_middleware/response/follow_redirects'
|
5
|
+
rescue LoadError; end
|
6
|
+
|
7
|
+
require 'open_graph_reader/base'
|
8
|
+
require 'open_graph_reader/builder'
|
9
|
+
require 'open_graph_reader/definitions'
|
10
|
+
require 'open_graph_reader/fetcher'
|
11
|
+
require 'open_graph_reader/object'
|
12
|
+
require 'open_graph_reader/parser'
|
13
|
+
require 'open_graph_reader/version'
|
14
|
+
|
15
|
+
# @todo quirks mode where invalid attributes don't raise?
|
16
|
+
# @todo 1.1 compatibility mode?
|
17
|
+
# This module provides the main entry to the library. Please see the
|
18
|
+
# {file:README.md} for usage examples.
|
19
|
+
module OpenGraphReader
|
20
|
+
# Fetch the OpenGraph object at the given URL. Raise if there are any issues.
|
21
|
+
#
|
22
|
+
# @param [URI,#to_s] url The URL of the OpenGraph object to retrieve.
|
23
|
+
# @return [Base] The base object from which you can obtain the root objects.
|
24
|
+
# @raise [NoOpenGraphDataError] {include:NoOpenGraphDataError}
|
25
|
+
# @raise [InvalidObjectError] {include:InvalidObjectError}
|
26
|
+
def self.fetch! url
|
27
|
+
case url
|
28
|
+
when URI
|
29
|
+
target = Fetcher.new(url)
|
30
|
+
raise NoOpenGraphDataError, "#{url} doesn't contain any HTML" unless target.html?
|
31
|
+
parse! target.body, target.url
|
32
|
+
else
|
33
|
+
fetch! URI.parse(url.to_s)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Parse the OpenGraph object in the given HTML document. Raise if there are any issues.
|
38
|
+
#
|
39
|
+
# @param [#to_s, Nokogiri::XML::Node] html A HTML document that contains an OpenGraph object.
|
40
|
+
# @param [#to_s] origin The source from where the given document was fetched.
|
41
|
+
# @return [Base] The base object from which you can obtain the root objects.
|
42
|
+
# @raise [NoOpenGraphDataError] {include:NoOpenGraphDataError}
|
43
|
+
# @raise [InvalidObjectError] {include:InvalidObjectError}
|
44
|
+
def self.parse! html, origin=nil
|
45
|
+
parser = Parser.new html
|
46
|
+
raise NoOpenGraphDataError, "#{origin || html} does not contain any OpenGraph tags" unless parser.has_tags?
|
47
|
+
Builder.new(parser.graph, parser.additional_namespaces).base.tap {|base|
|
48
|
+
base.origin = origin.to_s if origin
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# Convenience wrapper around {OpenGraphReader.fetch!} that swallows the esceptions
|
53
|
+
# and returns nil instead.
|
54
|
+
#
|
55
|
+
# @param [URI,#to_s] url The URL of the OpenGraph object to retrieve.
|
56
|
+
# @return [Base, nil] The base object from which you can obtain the root objects.
|
57
|
+
# @see OpenGraphReader.fetch!
|
58
|
+
def self.fetch url
|
59
|
+
fetch! url
|
60
|
+
rescue NoOpenGraphDataError, InvalidObjectError
|
61
|
+
end
|
62
|
+
|
63
|
+
# Convenience wrapper around {OpenGraphReader.parse!} that swallows the esceptions
|
64
|
+
# and returns nil instead.
|
65
|
+
#
|
66
|
+
# @param [#to_s] html A HTML document that contains an OpenGraph object.
|
67
|
+
# @param [#to_s] origin The source from where the given document was fetched.
|
68
|
+
# @return [Base, nil] The base object from which you can obtain the root objects.
|
69
|
+
# @see OpenGraphReader.parse!
|
70
|
+
def self.parse html, origin=nil
|
71
|
+
parse! html, origin
|
72
|
+
rescue NoOpenGraphDataError, InvalidObjectError
|
73
|
+
end
|
74
|
+
|
75
|
+
# The target couldn't be fetched, didn't contain any HTML or
|
76
|
+
# any OpenGraph tags.
|
77
|
+
class NoOpenGraphDataError < StandardError
|
78
|
+
end
|
79
|
+
|
80
|
+
# The target did contain OpenGraph tags, but they're not valid.
|
81
|
+
class InvalidObjectError < StandardError
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module OpenGraphReader
|
4
|
+
# You get an instance of this class as result of your quest to obtain
|
5
|
+
# an OpenGraph object. It simply contains and returns the root objects,
|
6
|
+
# most commonly <tt>og</tt>.
|
7
|
+
class Base
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
# @!method [](name)
|
11
|
+
# Get a root object by name.
|
12
|
+
#
|
13
|
+
# @param [String] name The name of the root namespace.
|
14
|
+
# @return [Object, nil] The corresponding root object if available.
|
15
|
+
# @api private
|
16
|
+
# @!method []=(name, object)
|
17
|
+
# Make a new root object available on this base.
|
18
|
+
#
|
19
|
+
# @param [String] name The name of the root namespace.
|
20
|
+
# @param [Object] object The corresponding root object.
|
21
|
+
# @api private
|
22
|
+
def_delegators :@bases, :[], :[]=
|
23
|
+
|
24
|
+
# If available, contains the source location of the document the
|
25
|
+
# available objects were parsed from.
|
26
|
+
#
|
27
|
+
# @return [String, nil]
|
28
|
+
attr_reader :origin
|
29
|
+
|
30
|
+
# Set origin.
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
# @see #origin
|
34
|
+
attr_writer :origin
|
35
|
+
|
36
|
+
# @api private
|
37
|
+
def initialize
|
38
|
+
@bases = {}
|
39
|
+
end
|
40
|
+
|
41
|
+
# @private
|
42
|
+
def respond_to_missing?(method, include_private=false)
|
43
|
+
@bases.has_key? method.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
# Makes the found root objects available.
|
47
|
+
# @return [Object]
|
48
|
+
def method_missing(method, *args, &block)
|
49
|
+
name = method.to_s
|
50
|
+
if respond_to_missing? name
|
51
|
+
@bases[name]
|
52
|
+
else
|
53
|
+
super(method, *args, &block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module OpenGraphReader
|
2
|
+
# Convert a {Parser::Graph} into the right hierarchy of {Object}s attached
|
3
|
+
# to a {Base}.
|
4
|
+
#
|
5
|
+
# @todo validate required, verticals
|
6
|
+
# @api private
|
7
|
+
class Builder
|
8
|
+
# Well-known types from
|
9
|
+
#
|
10
|
+
# @see http://ogp.me
|
11
|
+
KNOWN_TYPES = %w(
|
12
|
+
website
|
13
|
+
music.song
|
14
|
+
music.album
|
15
|
+
music.playlist
|
16
|
+
music.radio_station
|
17
|
+
video.movie
|
18
|
+
video.episode
|
19
|
+
video.tv_show
|
20
|
+
video.other
|
21
|
+
article
|
22
|
+
book
|
23
|
+
profile
|
24
|
+
).freeze
|
25
|
+
|
26
|
+
# Create a new builder.
|
27
|
+
#
|
28
|
+
# @param [Parser::Graph] graph
|
29
|
+
# @param [Array<String>] additional_namespaces Namespaces found in the
|
30
|
+
# prefix attribute of the head tag of the HTML document
|
31
|
+
# @see Parser#graph
|
32
|
+
# @see Parser#additional_namespaces
|
33
|
+
def initialize graph, additional_namespaces=[]
|
34
|
+
@graph = graph
|
35
|
+
@additional_namespaces = additional_namespaces
|
36
|
+
end
|
37
|
+
|
38
|
+
# Build and return the base.
|
39
|
+
#
|
40
|
+
# @return [Base]
|
41
|
+
def base
|
42
|
+
base = Base.new
|
43
|
+
|
44
|
+
type = @graph.fetch 'og:type', 'website'
|
45
|
+
|
46
|
+
validate_type type
|
47
|
+
|
48
|
+
@graph.each do |property|
|
49
|
+
root, *path, name = property.path
|
50
|
+
base[root] ||= Object::Registry[root].new
|
51
|
+
object = resolve base[root], root, path
|
52
|
+
|
53
|
+
if object.respond_to? "#{name}s" # Collection # TODO
|
54
|
+
collection = object.public_send "#{name}s" #TODO
|
55
|
+
if Object::Registry.registered? property.fullname # of subobjects
|
56
|
+
object = Object::Registry[property.fullname].new
|
57
|
+
collection << object
|
58
|
+
object.content = property.content
|
59
|
+
else # of type
|
60
|
+
collection << property.content
|
61
|
+
end
|
62
|
+
elsif Object::Registry.registered? property.fullname # Subobject
|
63
|
+
object[name] ||= Object::Registry[property.fullname].new
|
64
|
+
object[name].content = property.content
|
65
|
+
else # Direct attribute
|
66
|
+
object[name] = property.content
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
base
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def resolve object, last_namespace, path
|
76
|
+
return object if path.empty?
|
77
|
+
|
78
|
+
next_name = path.shift
|
79
|
+
if object.respond_to? "#{next_name}s" # collection # TODO: do not respond_to? with user data
|
80
|
+
collection = object.public_send("#{next_name}s") # TODO: do not public_send with user data
|
81
|
+
next_object = collection.last
|
82
|
+
if next_object.nil? #|| path.empty? # Final namespace or missing previous declaration, create a new collection item
|
83
|
+
next_object = Object::Registry[[*last_namespace, next_name].join(':')].new
|
84
|
+
collection << next_object
|
85
|
+
end
|
86
|
+
else
|
87
|
+
next_object = object[next_name]
|
88
|
+
next_object ||= Object::Registry[[*last_namespace, next_name].join(':')].new
|
89
|
+
end
|
90
|
+
|
91
|
+
next_object
|
92
|
+
end
|
93
|
+
|
94
|
+
def validate_type type
|
95
|
+
unless KNOWN_TYPES.include?(type) || @additional_namespaces.include?(type)
|
96
|
+
raise InvalidObjectError, "Undefined type #{type}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,333 @@
|
|
1
|
+
require 'open_graph_reader/object'
|
2
|
+
|
3
|
+
module OpenGraphReader
|
4
|
+
# @see http://ogp.me/#metadata
|
5
|
+
class Og
|
6
|
+
include Object
|
7
|
+
|
8
|
+
namespace :og
|
9
|
+
|
10
|
+
# @!macro property
|
11
|
+
# @return [String]
|
12
|
+
string :type, required: true, default: 'website'
|
13
|
+
|
14
|
+
# @!macro property
|
15
|
+
# @return [String]
|
16
|
+
string :title, required: true
|
17
|
+
|
18
|
+
# @!attribute [r] images
|
19
|
+
# @return [Array<Image>]
|
20
|
+
# @!macro property
|
21
|
+
# @return [Image]
|
22
|
+
url :image, required: true, collection: true
|
23
|
+
|
24
|
+
# @!macro property
|
25
|
+
# @return [String, nil]
|
26
|
+
url :url
|
27
|
+
|
28
|
+
# @!macro property
|
29
|
+
# @return [Audio, nil]
|
30
|
+
url :audio
|
31
|
+
|
32
|
+
# @!macro property
|
33
|
+
# @return [String, nil]
|
34
|
+
string :description
|
35
|
+
|
36
|
+
# @!macro property
|
37
|
+
# @return [String]
|
38
|
+
enum :determiner, ['', 'a', 'an', 'the', 'auto'], default: ''
|
39
|
+
|
40
|
+
# @!macro property
|
41
|
+
# @return [Locale, nil]
|
42
|
+
string :locale
|
43
|
+
|
44
|
+
# @!macro property
|
45
|
+
# @return [String, nil]
|
46
|
+
string :site_name
|
47
|
+
|
48
|
+
# @!macro property
|
49
|
+
# @return [Video, nil]
|
50
|
+
url :video
|
51
|
+
|
52
|
+
# @see http://ogp.me/#structured
|
53
|
+
class Image
|
54
|
+
include Object
|
55
|
+
|
56
|
+
namespace :og, :image
|
57
|
+
content :url
|
58
|
+
|
59
|
+
url :url
|
60
|
+
|
61
|
+
# @!macro property
|
62
|
+
# @return [String, nil]
|
63
|
+
url :secure_url
|
64
|
+
|
65
|
+
# @!macro property
|
66
|
+
# @return [String, nil]
|
67
|
+
string :type
|
68
|
+
|
69
|
+
# @!macro property
|
70
|
+
# @return [Integer, nil]
|
71
|
+
integer :width
|
72
|
+
|
73
|
+
# @!macro property
|
74
|
+
# @return [Integer, nil]
|
75
|
+
integer :height
|
76
|
+
|
77
|
+
# @return [String, nil]
|
78
|
+
def url
|
79
|
+
secure_url || properties[:url] || content
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @see http://ogp.me/#structured
|
84
|
+
class Audio
|
85
|
+
include Object
|
86
|
+
|
87
|
+
namespace :og, :audio
|
88
|
+
content :url
|
89
|
+
|
90
|
+
# This property is not listed on http://ogp.me, but commonly found
|
91
|
+
url :url
|
92
|
+
|
93
|
+
# @!macro property
|
94
|
+
# @return [String, nil]
|
95
|
+
url :secure_url
|
96
|
+
|
97
|
+
# @!macro property
|
98
|
+
# @return [String, nil]
|
99
|
+
string :type
|
100
|
+
|
101
|
+
# @return [String, nil]
|
102
|
+
def url
|
103
|
+
secure_url || properties[:url] || content
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# @see http://ogp.me/#metadata
|
108
|
+
class Locale
|
109
|
+
include Object
|
110
|
+
|
111
|
+
namespace :og, :locale
|
112
|
+
content :string
|
113
|
+
|
114
|
+
# @!attribute [r] alternates
|
115
|
+
# @return [Array<String>]
|
116
|
+
# @!macro property
|
117
|
+
# @return [String, nil]
|
118
|
+
string :alternate, collection: true
|
119
|
+
end
|
120
|
+
|
121
|
+
# @see http://ogp.me/#structured
|
122
|
+
class Video
|
123
|
+
include Object
|
124
|
+
|
125
|
+
namespace :og, :video
|
126
|
+
content :url
|
127
|
+
|
128
|
+
# @!macro property
|
129
|
+
# @return [String, nil]
|
130
|
+
url :secure_url
|
131
|
+
|
132
|
+
# @!macro property
|
133
|
+
# @return [String, nil]
|
134
|
+
string :type
|
135
|
+
|
136
|
+
# @!macro property
|
137
|
+
# @return [Integer, nil]
|
138
|
+
integer :width
|
139
|
+
|
140
|
+
# @!macro property
|
141
|
+
# @return [Integer, nil]
|
142
|
+
integer :height
|
143
|
+
|
144
|
+
# @return [String, nil]
|
145
|
+
def url
|
146
|
+
secure_url || content
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# @see http://ogp.me/#type_profile
|
152
|
+
class Profile
|
153
|
+
include Object
|
154
|
+
|
155
|
+
namespace :profile
|
156
|
+
content :url
|
157
|
+
|
158
|
+
# @!macro property
|
159
|
+
# @return [String, nil]
|
160
|
+
string :first_name
|
161
|
+
|
162
|
+
# @!macro property
|
163
|
+
# @return [String, nil]
|
164
|
+
string :last_name
|
165
|
+
|
166
|
+
# @!macro property
|
167
|
+
# @return [String, nil]
|
168
|
+
string :username
|
169
|
+
|
170
|
+
# @!macro property
|
171
|
+
# @return [String, nil]
|
172
|
+
enum :gender, %w(male female)
|
173
|
+
|
174
|
+
# @!macro property
|
175
|
+
# @return [String, nil]
|
176
|
+
# This one only exists because video had to define a video:actor:role,
|
177
|
+
# yay for designing a protocol with implementations in mind
|
178
|
+
string :role
|
179
|
+
end
|
180
|
+
|
181
|
+
# @see http://ogp.me/#type_article
|
182
|
+
class Article
|
183
|
+
include Object
|
184
|
+
|
185
|
+
namespace :article
|
186
|
+
|
187
|
+
# @!macro property
|
188
|
+
# @return [DateTime, nil]
|
189
|
+
datetime :published_time
|
190
|
+
|
191
|
+
# @!macro property
|
192
|
+
# @return [DateTime, nil]
|
193
|
+
datetime :modified_time
|
194
|
+
|
195
|
+
# @!macro property
|
196
|
+
# @return [DateTime, nil]
|
197
|
+
datetime :expiration_time
|
198
|
+
|
199
|
+
# @todo This one is a reference to another OpenGraph object. Support fetching it?
|
200
|
+
# @!attribute [r] authors
|
201
|
+
# @return [Array<Profile>]
|
202
|
+
# @!macro property
|
203
|
+
# @return [Profile, nil]
|
204
|
+
url :author, collection: true, to: Profile
|
205
|
+
|
206
|
+
# @!macro property
|
207
|
+
# @return [String, nil]
|
208
|
+
string :section
|
209
|
+
|
210
|
+
# @!attribute [r] tags
|
211
|
+
# @return [Array<String>]
|
212
|
+
# @!macro property
|
213
|
+
# @return [String, nil]
|
214
|
+
string :tag, collection: true
|
215
|
+
end
|
216
|
+
|
217
|
+
# @see http://ogp.me/#type_video
|
218
|
+
class Video
|
219
|
+
include Object
|
220
|
+
|
221
|
+
namespace :video
|
222
|
+
|
223
|
+
# @!attribute [r] actors
|
224
|
+
# @return [Array<Profile>]
|
225
|
+
# @!macro property
|
226
|
+
# @return [Profile, nil]
|
227
|
+
url :actor, to: Profile, verticals: %w(movie episode tv_show other), collection: true
|
228
|
+
|
229
|
+
# @!attribute [r] directors
|
230
|
+
# @return [Array<Profile>]
|
231
|
+
# @!macro property
|
232
|
+
# @return [Profile, nil]
|
233
|
+
url :director, to: Profile, verticals: %w(movie episode tv_show other), collection: true
|
234
|
+
|
235
|
+
# @!attribute [r] writers
|
236
|
+
# @return [Array<Profile>]
|
237
|
+
# @!macro property
|
238
|
+
# @return [Profile, nil]
|
239
|
+
url :writer, to: Profile, verticals: %w(movie episode tv_show other), collection: true
|
240
|
+
|
241
|
+
# @!macro property
|
242
|
+
# @return [Integer, nil]
|
243
|
+
integer :duration, verticals: %w(movie episode tv_show other)
|
244
|
+
|
245
|
+
# @!macro property
|
246
|
+
# @return [DateTime, nil]
|
247
|
+
datetime :release_date, verticals: %w(movie episode tv_show other)
|
248
|
+
|
249
|
+
# @!attribute [r] tags
|
250
|
+
# @return [Array<String>]
|
251
|
+
# @!macro property
|
252
|
+
# @return [String, nil]
|
253
|
+
string :tag, verticals: %w(movie episode tv_show other), collection: true
|
254
|
+
|
255
|
+
# @todo validate that target vertical is video.tv_show ?
|
256
|
+
# @!macro property
|
257
|
+
# @return [Sring, nil]
|
258
|
+
url :series, to: Video, verticals: %w(episode)
|
259
|
+
end
|
260
|
+
|
261
|
+
# @see http://ogp.me/#type_book
|
262
|
+
class Book
|
263
|
+
include Object
|
264
|
+
|
265
|
+
namespace :book
|
266
|
+
|
267
|
+
# @todo This one is a reference to another OpenGraph object. Support fetching it?
|
268
|
+
# @!attribute [r] authors
|
269
|
+
# @return [Array<Profile>]
|
270
|
+
# @!macro property
|
271
|
+
# @return [Profile, nil]
|
272
|
+
url :author, collection: true, to: Profile
|
273
|
+
|
274
|
+
# @!macro property
|
275
|
+
# @return [Sring, nil]
|
276
|
+
string :isbn
|
277
|
+
|
278
|
+
# @!macro property
|
279
|
+
# @return [DateTime, nil]
|
280
|
+
datetime :release_date
|
281
|
+
|
282
|
+
# @!attribute [r] tags
|
283
|
+
# @return [Array<String>]
|
284
|
+
# @!macro property
|
285
|
+
# @return [String, nil]
|
286
|
+
string :tag, collection: true
|
287
|
+
end
|
288
|
+
|
289
|
+
# @see http://ogp.me/#type_music
|
290
|
+
class Music
|
291
|
+
include Object
|
292
|
+
|
293
|
+
namespace :music
|
294
|
+
|
295
|
+
# @!macro property
|
296
|
+
# @return [Integer, nil]
|
297
|
+
integer :duration, verticals: %w(song)
|
298
|
+
|
299
|
+
|
300
|
+
# @todo validate that target vertical is music.album/music.song ?
|
301
|
+
# @!attribute [r] albums
|
302
|
+
# @return [Array<Music>]
|
303
|
+
# @macro property
|
304
|
+
# @return [Music, nil]
|
305
|
+
url :album, to: Music, verticals: %w(song), collection: true
|
306
|
+
|
307
|
+
# @macro property
|
308
|
+
# @return [Integer, nil]
|
309
|
+
integer :disc, verticals: %w(song album playlist)
|
310
|
+
|
311
|
+
# @macro property
|
312
|
+
# @return [Integer, nil]
|
313
|
+
integer :track, verticals: %w(song album playlist)
|
314
|
+
|
315
|
+
# @!attribute [r] musicians
|
316
|
+
# @return [Array<Profile>]
|
317
|
+
# @!macro property
|
318
|
+
# @return [Profile, nil]
|
319
|
+
url :musician, to: Profile, verticals: %w(song album), collection: true
|
320
|
+
|
321
|
+
# @macro property
|
322
|
+
# @return [Music, nil]
|
323
|
+
url :song, to: Music, verticals: %w(album playlist)
|
324
|
+
|
325
|
+
# @macro property
|
326
|
+
# @return [DateTime, nil]
|
327
|
+
datetime :release_date, verticals: %w(album)
|
328
|
+
|
329
|
+
# @macro property
|
330
|
+
# @return [Profile, nil]
|
331
|
+
url :creator, to: Profile, verticals: %w(playlist radio_station)
|
332
|
+
end
|
333
|
+
end
|