ruby-oembed 0.7.6 → 0.8.1
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/.gitignore +4 -1
- data/CHANGELOG.rdoc +49 -0
- data/Gemfile.lock +13 -8
- data/README.rdoc +79 -0
- data/Rakefile +21 -6
- data/lib/oembed/errors.rb +23 -4
- data/lib/oembed/formatter/json/backends/activesupportjson.rb +28 -0
- data/lib/oembed/formatter/json/backends/jsongem.rb +31 -0
- data/lib/oembed/formatter/json/backends/yaml.rb +85 -0
- data/lib/oembed/formatter/json.rb +69 -0
- data/lib/oembed/formatter/xml/backends/rexml.rb +44 -0
- data/lib/oembed/formatter/xml/backends/xmlsimple.rb +39 -0
- data/lib/oembed/formatter/xml.rb +76 -0
- data/lib/oembed/formatter.rb +97 -0
- data/lib/oembed/provider.rb +102 -38
- data/lib/oembed/provider_discovery.rb +19 -7
- data/lib/oembed/providers/embedly_urls.yml +487 -0
- data/lib/oembed/providers/oohembed_urls.yml +17 -0
- data/lib/oembed/providers.rb +68 -11
- data/lib/oembed/response/link.rb +14 -0
- data/lib/oembed/response/photo.rb +12 -0
- data/lib/oembed/response/rich.rb +11 -0
- data/lib/oembed/response/video.rb +10 -0
- data/lib/oembed/response.rb +58 -10
- data/lib/oembed/version.rb +18 -0
- data/lib/oembed.rb +2 -1
- data/lib/tasks/oembed.rake +45 -0
- data/lib/tasks/rspec.rake +5 -0
- data/ruby-oembed.gemspec +38 -17
- data/spec/formatter/json/.DS_Store +0 -0
- data/spec/formatter/json/jsongem_backend_spec.rb +34 -0
- data/spec/formatter/json/yaml_backend_spec.rb +30 -0
- data/spec/formatter/xml/rexml_backend_spec.rb +30 -0
- data/spec/formatter/xml/xmlsimple_backend_spec.rb +34 -0
- data/spec/formatter_spec.rb +35 -0
- data/spec/provider_spec.rb +189 -24
- data/spec/providers_spec.rb +20 -1
- data/spec/response_spec.rb +129 -48
- data/spec/spec_helper.rb +5 -6
- metadata +45 -38
- data/CHANGELOG.md +0 -29
- data/README.md +0 -50
- data/VERSION +0 -1
- data/lib/oembed/embedly_urls.json +0 -227
- data/lib/oembed/formatters.rb +0 -40
- data/rails/init.rb +0 -3
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'oembed/formatter/json'
|
2
|
+
require 'oembed/formatter/xml'
|
3
|
+
|
4
|
+
module OEmbed
|
5
|
+
# Takes the raw response from an oEmbed server and turns it into a nice Hash of data.
|
6
|
+
module Formatter
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# Returns the default format for OEmbed::Provider requests as a String.
|
10
|
+
def default
|
11
|
+
# Listed in order of preference.
|
12
|
+
%w{json xml}.detect { |type| supported?(type) rescue false }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Given the name of a format we want to know about (e.g. 'json'), returns
|
16
|
+
# true if there is a valid backend. If there is no backend, raises
|
17
|
+
# OEmbed::FormatNotSupported.
|
18
|
+
def supported?(format)
|
19
|
+
case format.to_s
|
20
|
+
when 'json'
|
21
|
+
JSON.supported?
|
22
|
+
when 'xml'
|
23
|
+
XML.supported?
|
24
|
+
else
|
25
|
+
raise OEmbed::FormatNotSupported, format
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Convert the given value into a nice Hash of values. The format should
|
30
|
+
# be the name of the response format (e.g. 'json'). The value should be
|
31
|
+
# a String or IO containing the response from an oEmbed server.
|
32
|
+
#
|
33
|
+
# For example:
|
34
|
+
# value = '{"version": "1.0", "type": "link", "title": "Some Cool News Article"}'
|
35
|
+
# OEmbed::Formatter.decode('json', value)
|
36
|
+
# #=> {"version": "1.0", "type": "link", "title": "Some Cool News Article"}
|
37
|
+
def decode(format, value)
|
38
|
+
supported?(format)
|
39
|
+
|
40
|
+
case format.to_s
|
41
|
+
when 'json'
|
42
|
+
begin
|
43
|
+
JSON.decode(value)
|
44
|
+
rescue JSON.backend::ParseError
|
45
|
+
raise OEmbed::ParseError, $!.message
|
46
|
+
end
|
47
|
+
when 'xml'
|
48
|
+
begin
|
49
|
+
XML.decode(value)
|
50
|
+
rescue XML.backend::ParseError
|
51
|
+
raise OEmbed::ParseError, $!.message
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Test the given backend to make sure it parses known values correctly.
|
57
|
+
# The backend_module should be either a JSON or XML backend.
|
58
|
+
def test_backend(backend_module)
|
59
|
+
expected = {
|
60
|
+
"version"=>1.0,
|
61
|
+
"string"=>"test",
|
62
|
+
"int"=>42,
|
63
|
+
"html"=>"<i>Cool's</i>\n the \"word\"!",
|
64
|
+
}
|
65
|
+
|
66
|
+
given_value = case backend_module.to_s
|
67
|
+
when /OEmbed::Formatter::JSON::Backends::/
|
68
|
+
<<-JSON
|
69
|
+
{"version":"1.0", "string":"test", "int":42,"html":"<i>Cool's</i>\\n the \\"word\\"\\u0021"}
|
70
|
+
JSON
|
71
|
+
when /OEmbed::Formatter::XML::Backends::/
|
72
|
+
<<-XML
|
73
|
+
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
74
|
+
<oembed>
|
75
|
+
<version>1.0</version>
|
76
|
+
<string>test</string>
|
77
|
+
<int>42</int>
|
78
|
+
<html><i>Cool's</i>\n the "word"!</html>
|
79
|
+
</oembed>
|
80
|
+
XML
|
81
|
+
else
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
actual = backend_module.decode(given_value)
|
86
|
+
|
87
|
+
# For the test to be true the actual output Hash should have the
|
88
|
+
# exact same list of keys _and_ the values should be the same
|
89
|
+
# if we ignoring typecasting.
|
90
|
+
actual.keys.sort == expected.keys.sort &&
|
91
|
+
!actual.detect { |key, value| value.to_s != expected[key].to_s }
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
data/lib/oembed/provider.rb
CHANGED
@@ -1,55 +1,132 @@
|
|
1
1
|
module OEmbed
|
2
|
+
# An OEmbed::Provider has information about an individual oEmbed enpoint.
|
2
3
|
class Provider
|
3
|
-
|
4
|
+
|
5
|
+
# The String that is the http URI of the Provider's oEmbed endpoint.
|
6
|
+
# This URL may also contain a {{format}} portion. In actual requests to
|
7
|
+
# this Provider, this string will be replaced with a string representing
|
8
|
+
# the request format (e.g. "json").
|
9
|
+
attr_accessor :endpoint
|
10
|
+
|
11
|
+
# The name of the default format for all request to this Provider (e.g. 'json').
|
12
|
+
attr_accessor :format
|
13
|
+
|
14
|
+
# An Array of all URL schemes supported by this Provider.
|
15
|
+
attr_accessor :urls
|
16
|
+
|
17
|
+
# The human-readable name of the Provider.
|
18
|
+
#
|
19
|
+
# @deprecated *Note*: This accessor currently isn't used anywhere in the codebase.
|
20
|
+
attr_accessor :name
|
21
|
+
|
22
|
+
# @deprecated *Note*: Added in a fork of the gem, a while back. I really would like
|
23
|
+
# to get rid of it, though. --Marcos
|
24
|
+
attr_accessor :url
|
25
|
+
|
4
26
|
|
5
|
-
|
27
|
+
# Construct a new OEmbed::Provider instance, pointing at a specific oEmbed
|
28
|
+
# endpoint.
|
29
|
+
#
|
30
|
+
# The endpoint should be a String representing the http URI of the Provider's
|
31
|
+
# oEmbed endpoint. The endpoint String may also contain a {format} portion.
|
32
|
+
# In actual requests to this Provider, this string will be replaced with a String
|
33
|
+
# representing the request format (e.g. "json").
|
34
|
+
#
|
35
|
+
# If give, the format should be the name of the default format for all request
|
36
|
+
# to this Provider (e.g. 'json'). Defaults to OEmbed::Formatter.default
|
37
|
+
#
|
38
|
+
# For example:
|
39
|
+
# # If requests should be sent to:
|
40
|
+
# # "http://my.service.com/oembed?format=#{OEmbed::Formatter.default}"
|
41
|
+
# @provider = OEmbed::Provider.new("http://my.service.com/oembed")
|
42
|
+
#
|
43
|
+
# # If requests should be sent to:
|
44
|
+
# # "http://my.service.com/oembed.xml"
|
45
|
+
# @xml_provider = OEmbed::Provider.new("http://my.service.com/oembed.{format}", :xml)
|
46
|
+
def initialize(endpoint, format = OEmbed::Formatter.default)
|
47
|
+
endpoint_uri = URI.parse(endpoint.gsub(/[\{\}]/,'')) rescue nil
|
48
|
+
raise ArgumentError, "The given endpoint isn't a valid http(s) URI: #{endpoint.to_s}" unless endpoint_uri.is_a?(URI::HTTP)
|
49
|
+
|
6
50
|
@endpoint = endpoint
|
7
51
|
@urls = []
|
8
|
-
|
9
|
-
@format = OEmbed::Formatters.verify?(format)
|
52
|
+
@format = format
|
10
53
|
end
|
11
54
|
|
55
|
+
# Adds the given url scheme to this Provider instance.
|
56
|
+
# The url scheme can be either a String, containing wildcards specified
|
57
|
+
# with an asterisk, (see http://oembed.com/#section2.1 for details),
|
58
|
+
# or a Regexp.
|
59
|
+
#
|
60
|
+
# For example:
|
61
|
+
# @provider << "http://my.service.com/video/*"
|
62
|
+
# @provider << "http://*.service.com/photo/*/slideshow"
|
63
|
+
# @provider << %r{^http://my.service.com/((help)|(faq))/\d+[#\?].*}
|
12
64
|
def <<(url)
|
13
|
-
if url.is_a?
|
14
|
-
|
15
|
-
|
65
|
+
if !url.is_a?(Regexp)
|
66
|
+
full, scheme, domain, path = *url.match(%r{([^:]*)://?([^/?]*)(.*)})
|
67
|
+
domain = Regexp.escape(domain).gsub("\\*", "(.*?)").gsub("(.*?)\\.", "([^\\.]+\\.)?")
|
68
|
+
path = Regexp.escape(path).gsub("\\*", "(.*?)")
|
69
|
+
url = Regexp.new("^#{Regexp.escape(scheme)}://#{domain}#{path}")
|
16
70
|
end
|
17
|
-
|
18
|
-
domain = Regexp.escape(domain).gsub("\\*", "(.*?)").gsub("(.*?)\\.", "([^\\.]+\\.)?")
|
19
|
-
path = Regexp.escape(path).gsub("\\*", "(.*?)")
|
20
|
-
@urls << Regexp.new("^#{Regexp.escape(scheme)}://#{domain}#{path}")
|
71
|
+
@urls << url
|
21
72
|
end
|
22
73
|
|
23
|
-
|
74
|
+
# Send a request to the Provider endpoint to get information about the
|
75
|
+
# given url and return the appropriate OEmbed::Response.
|
76
|
+
#
|
77
|
+
# The query parameter should be a Hash of values which will be
|
78
|
+
# sent as query parameters in this request to the Provider endpoint. The
|
79
|
+
# following special cases apply to the query Hash:
|
80
|
+
# :format:: overrides this Provider's default request format.
|
81
|
+
# :url:: will be ignored, replaced by the url param.
|
82
|
+
def get(url, query = {})
|
83
|
+
query[:format] ||= @format
|
84
|
+
OEmbed::Response.create_for(raw(url, query), self, url, query[:format].to_s)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Determine whether the given url is supported by this Provider by matching
|
88
|
+
# against the Provider's URL schemes.
|
89
|
+
def include?(url)
|
90
|
+
@urls.empty? || !!@urls.detect{ |u| u =~ url }
|
91
|
+
end
|
92
|
+
|
93
|
+
# @deprecated *Note*: This method will be made private in the future.
|
94
|
+
def build(url, query = {})
|
24
95
|
raise OEmbed::NotFound, url unless include?(url)
|
25
|
-
|
96
|
+
|
97
|
+
query = query.merge({:url=>url})
|
98
|
+
# TODO: move this code exclusively into the get method, once build is private.
|
99
|
+
this_format = (query[:format] ||= @format.to_s).to_s
|
100
|
+
|
26
101
|
endpoint = @endpoint.clone
|
27
102
|
|
28
|
-
if
|
29
|
-
|
103
|
+
if endpoint.include?("{format}")
|
104
|
+
endpoint["{format}"] = this_format
|
30
105
|
query.delete(:format)
|
31
|
-
else
|
32
|
-
format = query[:format] ||= @format
|
33
106
|
end
|
34
107
|
|
35
|
-
|
108
|
+
query = "?" + query.inject("") do |memo, (key, value)|
|
36
109
|
"#{key}=#{value}&#{memo}"
|
37
110
|
end.chop
|
38
111
|
|
39
|
-
URI.parse(endpoint +
|
40
|
-
@format =
|
112
|
+
URI.parse(endpoint + query).instance_eval do
|
113
|
+
@format = this_format
|
114
|
+
def format
|
115
|
+
@format
|
116
|
+
end
|
41
117
|
self
|
42
118
|
end
|
43
119
|
end
|
44
120
|
|
45
|
-
|
46
|
-
|
121
|
+
# @deprecated *Note*: This method will be made private in the future.
|
122
|
+
def raw(url, query = {})
|
123
|
+
uri = build(url, query)
|
47
124
|
|
48
125
|
found = false
|
49
126
|
max_redirects = 4
|
50
127
|
until found
|
51
128
|
host, port = uri.host, uri.port if uri.host && uri.port
|
52
|
-
res = Net::HTTP.start(uri.host, uri.port) {|http|
|
129
|
+
res = Net::HTTP.start(uri.host, uri.port) {|http| http.get(uri.request_uri) }
|
53
130
|
res.header['location'] ? uri = URI.parse(res.header['location']) : found = true
|
54
131
|
if max_redirects == 0
|
55
132
|
found = true
|
@@ -60,7 +137,7 @@ module OEmbed
|
|
60
137
|
|
61
138
|
case res
|
62
139
|
when Net::HTTPNotImplemented
|
63
|
-
raise OEmbed::UnknownFormat,
|
140
|
+
raise OEmbed::UnknownFormat, format
|
64
141
|
when Net::HTTPNotFound
|
65
142
|
raise OEmbed::NotFound, url
|
66
143
|
when Net::HTTPOK
|
@@ -74,24 +151,11 @@ module OEmbed
|
|
74
151
|
# OEmbed. The following are known errors:
|
75
152
|
# * Net::* errors like Net::HTTPBadResponse
|
76
153
|
# * JSON::JSONError errors like JSON::ParserError
|
77
|
-
if $!.is_a?(JSON::JSONError) || $!.class.to_s =~ /\ANet::/
|
154
|
+
if defined?(::JSON) && $!.is_a?(::JSON::JSONError) || $!.class.to_s =~ /\ANet::/
|
78
155
|
raise OEmbed::UnknownResponse, res && res.respond_to?(:code) ? res.code : 'Error'
|
79
156
|
else
|
80
157
|
raise $!
|
81
158
|
end
|
82
159
|
end
|
83
|
-
|
84
|
-
def get(url, options = {})
|
85
|
-
options[:format] ||= @format if @format
|
86
|
-
OEmbed::Response.create_for(raw(url, options), self, url, options[:format])
|
87
|
-
end
|
88
|
-
|
89
|
-
def format_in_url?
|
90
|
-
@endpoint.include?("{format}")
|
91
|
-
end
|
92
|
-
|
93
|
-
def include?(url)
|
94
|
-
@urls.empty? || !!@urls.detect{ |u| u =~ url }
|
95
|
-
end
|
96
160
|
end
|
97
161
|
end
|
@@ -1,16 +1,29 @@
|
|
1
1
|
module OEmbed
|
2
|
+
# Uses {oEmbed Discover}[http://oembed.com/#section4] to generate a new Provider
|
3
|
+
# instance about a URL for which a Provider didn't previously exist.
|
2
4
|
class ProviderDiscovery
|
3
5
|
class << self
|
4
|
-
|
5
|
-
|
6
|
+
|
7
|
+
# Discover the Provider for the given url, then call Provider#raw on that provider.
|
8
|
+
# The query parameter will be passed to both discover_provider and Provider#raw
|
9
|
+
# @deprecated *Note*: This method will be made private in the future.
|
10
|
+
def raw(url, query={})
|
11
|
+
provider = discover_provider(url, query)
|
6
12
|
provider.raw(url, options)
|
7
13
|
end
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
15
|
+
# Discover the Provider for the given url, then call Provider#get on that provider.
|
16
|
+
# The query parameter will be passed to both discover_provider and Provider#get
|
17
|
+
def get(url, query={})
|
18
|
+
provider = discover_provider(url, query)
|
19
|
+
provider.get(url, query)
|
12
20
|
end
|
13
21
|
|
22
|
+
# Returns a new Provider instance based on information from oEmbed discovery
|
23
|
+
# performed on the given url.
|
24
|
+
#
|
25
|
+
# The options Hash recognizes the following keys:
|
26
|
+
# :format:: If given only discover endpoints for the given format. If not format is given, use the first available format found.
|
14
27
|
def discover_provider(url, options = {})
|
15
28
|
uri = URI.parse(url)
|
16
29
|
|
@@ -43,8 +56,7 @@ module OEmbed
|
|
43
56
|
raise OEmbed::NotFound, url
|
44
57
|
end
|
45
58
|
|
46
|
-
|
47
|
-
Provider.new(provider_endpoint, format || OEmbed::Formatters::DEFAULT)
|
59
|
+
Provider.new(provider_endpoint, format || OEmbed::Formatter.default)
|
48
60
|
else
|
49
61
|
raise OEmbed::UnknownResponse, res.code
|
50
62
|
end
|