ruby-oembed 0.7.6 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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