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.
Files changed (46) hide show
  1. data/.gitignore +4 -1
  2. data/CHANGELOG.rdoc +49 -0
  3. data/Gemfile.lock +13 -8
  4. data/README.rdoc +79 -0
  5. data/Rakefile +21 -6
  6. data/lib/oembed/errors.rb +23 -4
  7. data/lib/oembed/formatter/json/backends/activesupportjson.rb +28 -0
  8. data/lib/oembed/formatter/json/backends/jsongem.rb +31 -0
  9. data/lib/oembed/formatter/json/backends/yaml.rb +85 -0
  10. data/lib/oembed/formatter/json.rb +69 -0
  11. data/lib/oembed/formatter/xml/backends/rexml.rb +44 -0
  12. data/lib/oembed/formatter/xml/backends/xmlsimple.rb +39 -0
  13. data/lib/oembed/formatter/xml.rb +76 -0
  14. data/lib/oembed/formatter.rb +97 -0
  15. data/lib/oembed/provider.rb +102 -38
  16. data/lib/oembed/provider_discovery.rb +19 -7
  17. data/lib/oembed/providers/embedly_urls.yml +487 -0
  18. data/lib/oembed/providers/oohembed_urls.yml +17 -0
  19. data/lib/oembed/providers.rb +68 -11
  20. data/lib/oembed/response/link.rb +14 -0
  21. data/lib/oembed/response/photo.rb +12 -0
  22. data/lib/oembed/response/rich.rb +11 -0
  23. data/lib/oembed/response/video.rb +10 -0
  24. data/lib/oembed/response.rb +58 -10
  25. data/lib/oembed/version.rb +18 -0
  26. data/lib/oembed.rb +2 -1
  27. data/lib/tasks/oembed.rake +45 -0
  28. data/lib/tasks/rspec.rake +5 -0
  29. data/ruby-oembed.gemspec +38 -17
  30. data/spec/formatter/json/.DS_Store +0 -0
  31. data/spec/formatter/json/jsongem_backend_spec.rb +34 -0
  32. data/spec/formatter/json/yaml_backend_spec.rb +30 -0
  33. data/spec/formatter/xml/rexml_backend_spec.rb +30 -0
  34. data/spec/formatter/xml/xmlsimple_backend_spec.rb +34 -0
  35. data/spec/formatter_spec.rb +35 -0
  36. data/spec/provider_spec.rb +189 -24
  37. data/spec/providers_spec.rb +20 -1
  38. data/spec/response_spec.rb +129 -48
  39. data/spec/spec_helper.rb +5 -6
  40. metadata +45 -38
  41. data/CHANGELOG.md +0 -29
  42. data/README.md +0 -50
  43. data/VERSION +0 -1
  44. data/lib/oembed/embedly_urls.json +0 -227
  45. data/lib/oembed/formatters.rb +0 -40
  46. 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>&lt;i&gt;Cool's&lt;/i&gt;\n the &quot;word&quot;&#x21;</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
@@ -1,55 +1,132 @@
1
1
  module OEmbed
2
+ # An OEmbed::Provider has information about an individual oEmbed enpoint.
2
3
  class Provider
3
- attr_accessor :format, :name, :url, :urls, :endpoint
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
- def initialize(endpoint, format = OEmbed::Formatters::DEFAULT)
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
- # Try to use the best available format
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? Regexp
14
- @urls << url
15
- return
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
- full, scheme, domain, path = *url.match(%r{([^:]*)://?([^/?]*)(.*)})
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
- def build(url, options = {})
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
- query = options.merge({:url => url})
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 format_in_url?
29
- format = endpoint["{format}"] = (query[:format] || @format).to_s
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
- query_string = "?" + query.inject("") do |memo, (key, value)|
108
+ query = "?" + query.inject("") do |memo, (key, value)|
36
109
  "#{key}=#{value}&#{memo}"
37
110
  end.chop
38
111
 
39
- URI.parse(endpoint + query_string).instance_eval do
40
- @format = format; def format; @format; end
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
- def raw(url, options = {})
46
- uri = build(url, options)
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| http.get(uri.request_uri) }
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, uri.format
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
- def raw(url, options = {})
5
- provider = discover_provider(url, options)
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
- def get(url, options = {})
10
- provider = discover_provider(url, options)
11
- provider.get(url, options)
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