anideo-embedly 1.3.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.
@@ -0,0 +1,56 @@
1
+ $:.unshift(File.expand_path('../../../lib',__FILE__))
2
+ require 'embedly'
3
+
4
+ # cache for hostnames
5
+ HOSTNAMES = {}
6
+
7
+ Given /an embedly api( with key)?$/ do |key_enabled|
8
+ opts = {}
9
+ if key_enabled
10
+ raise 'Please set env variable $EMBEDLY_KEY' unless ENV['EMBEDLY_KEY']
11
+ opts[:key] = ENV["EMBEDLY_KEY"]
12
+ opts[:secret] = ENV["EMBEDLY_SECRET"]
13
+ end
14
+ if not HOSTNAMES[opts]
15
+ HOSTNAMES[opts] = Embedly::API.new opts
16
+ end
17
+ @api = HOSTNAMES[opts]
18
+ end
19
+
20
+ When /(\w+) is called with the (.*) URLs?( and ([^\s]+) flag)?$/ do |method, urls, _, flag|
21
+ @result = nil
22
+ begin
23
+ urls = urls.split(',')
24
+ opts = {}
25
+ if urls.size == 1
26
+ opts[:url] = urls.first
27
+ else
28
+ opts[:urls] = urls
29
+ end
30
+ opts[flag.to_sym] = true if flag
31
+ @result = @api.send(method, opts)
32
+ rescue
33
+ @error = $!
34
+ end
35
+ end
36
+
37
+ Then /an? (\w+) error should get thrown/ do |error|
38
+ @error.class.to_s.should == error
39
+ end
40
+
41
+ Then /objectify api_version is (\d+)$/ do |version|
42
+ @api.api_version[:objectify].should == version
43
+ end
44
+
45
+ Then /([^\s]+) should be (.+)$/ do |key, value|
46
+ raise @error if @error
47
+ @result.collect do |o|
48
+ o.send(key).to_s
49
+ end.join(',').should == value
50
+ end
51
+
52
+ Then /([^\s]+) should start with ([^\s]+)/ do |key, value|
53
+ raise @error if @error
54
+ v = key.split('.').inject(@result[0]){|o,c| o.send(c)}.to_s
55
+ v.to_s.should match(/^#{value}/)
56
+ end
@@ -0,0 +1,10 @@
1
+ require 'aruba/cucumber'
2
+ require 'embedly'
3
+
4
+ Before do
5
+ @aruba_timeout_seconds = 15
6
+ end
7
+
8
+ Embedly.configure do |config|
9
+ config.debug = !!ENV["EMBEDLY_VERBOSE"]
10
+ end
@@ -0,0 +1,15 @@
1
+ module Embedly
2
+ VERSION = File.read(File.expand_path('../../VERSION', __FILE__)).strip
3
+
4
+ class << self
5
+ def configure
6
+ yield configuration
7
+ end
8
+
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+ end
13
+ end
14
+
15
+ require 'embedly/api'
@@ -0,0 +1,234 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'json'
4
+ require 'ostruct'
5
+ require 'embedly/configuration'
6
+ require 'embedly/model'
7
+ require 'embedly/exceptions'
8
+ require 'querystring'
9
+ require 'oauth'
10
+ require 'typhoeus'
11
+
12
+ # Performs api calls to embedly.
13
+ #
14
+ # You won't find methods. We are using method_missing and passing the method
15
+ # name to apicall.
16
+ #
17
+ # === Currently Supported Methods
18
+ #
19
+ # * +oembed+
20
+ # * +objectify+
21
+ # * +preview+
22
+ #
23
+ # All methods return ostructs, so fields can be accessed with the dot operator. ex.
24
+ #
25
+ # api = Embedly::API.new
26
+ # obj = api.oembed :url => 'http://blog.doki-pen.org/'
27
+ # puts obj[0].title, obj[0].description, obj[0].thumbnail_url
28
+ #
29
+ # Call parameters should be passed as the opts parameter. If set, key will
30
+ # automatically be added to the query string of the call, so no need to set it.
31
+ #
32
+ # This API _would_ be future compatible, if not for the version. In order to
33
+ # add support for a new method, you will need to add a version to the
34
+ # api_version hash. Here is an example.
35
+ #
36
+ # api = Embedly::API.new
37
+ # api.api_version[:new_method] = 3
38
+ # api.new_method :arg1 => '1', :arg2 => '2'
39
+ #
40
+ class Embedly::API
41
+ attr_reader :key, :hostname, :api_version, :headers, :secret
42
+
43
+ # === Options
44
+ #
45
+ # [:+hostname+] Hostname of embedly server. Defaults to api.embed.ly.
46
+ # [:+key+] Your api.embed.ly key.
47
+ # [:+secret+] Your api.embed.ly secret if you are using oauth.
48
+ # [:+user_agent+] Your User-Agent header. Defaults to Mozilla/5.0 (compatible; embedly-ruby/VERSION;)
49
+ # [:+timeout+] Request timeout (in seconds). Defaults to 180 seconds or 3 minutes
50
+ # [:+headers+] Additional headers to send with requests.
51
+ def initialize opts={}
52
+ @endpoints = [:oembed, :objectify, :preview]
53
+ @key = opts[:key]
54
+ @secret = opts[:secret] == "" ? nil : opts[:secret]
55
+ @api_version = Hash.new('1')
56
+ @api_version.merge!({:objectify => '2'})
57
+ @hostname = opts[:hostname] || 'api.embed.ly'
58
+ @timeout = opts[:timeout] || 180
59
+ @headers = {
60
+ 'User-Agent' => opts[:user_agent] || "Mozilla/5.0 (compatible; embedly-ruby/#{Embedly::VERSION};)"
61
+ }.merge(opts[:headers]||{})
62
+ end
63
+
64
+ def _do_typhoeus_call path
65
+ scheme, host, port = uri_parse hostname
66
+ url = "#{scheme}://#{hostname}:#{port}#{path}"
67
+ logger.debug { "calling #{site}#{path} with headers #{headers} using Typhoeus" }
68
+ Typhoeus::Request.get(url, {:headers => headers, :timeout => (@timeout*1000) })
69
+ end
70
+
71
+ def _do_basic_call path
72
+ scheme, host, port = uri_parse hostname
73
+ logger.debug { "calling #{site}#{path} with headers #{headers} using Net::HTTP" }
74
+ Net::HTTP.start(host, port, :use_ssl => scheme == 'https') do |http|
75
+ http.read_timeout = @timeout
76
+ http.get(path, headers)
77
+ end
78
+ end
79
+
80
+ def _do_oauth_call path
81
+ consumer = OAuth::Consumer.new(key, secret,
82
+ :site => site,
83
+ :http_method => :get,
84
+ :scheme => :query_string)
85
+ # our implementation is broken for header authorization, thus the
86
+ # query_string
87
+
88
+ access_token = OAuth::AccessToken.new consumer
89
+ logger.debug { "calling #{site}#{path} with headers #{headers} via OAuth" }
90
+ access_token.get path, headers
91
+ end
92
+
93
+ def _do_call path
94
+ if key and secret
95
+ _do_oauth_call path
96
+ else
97
+ configuration.typhoeus ? _do_typhoeus_call(path) : _do_basic_call(path)
98
+ end
99
+ end
100
+
101
+ # <b>Use methods oembed, objectify, preview in favor of this method.</b>
102
+ #
103
+ # Normalizes url and urls parameters and calls the endpoint. url OR urls
104
+ # must be present
105
+ #
106
+ # === Options
107
+ #
108
+ # [:+url+] _(optional)_ A single url
109
+ # [:+urls+] _(optional)_ An array of urls
110
+ # [:+action+] The method that should be called. ex. oembed, objectify, preview
111
+ # [:+version+] The api version number.
112
+ # [_others_] All other parameters are used as query strings.
113
+ def apicall opts
114
+ opts[:urls] ||= []
115
+ opts[:urls] << opts[:url] if opts[:url]
116
+
117
+ raise 'must pass urls' if opts[:urls].size == 0
118
+
119
+ params = {:urls => opts[:urls]}
120
+
121
+ # store unsupported services as errors and don't send them to embedly
122
+ rejects = []
123
+ if not key
124
+ params[:urls].reject!.with_index do |url, i|
125
+ if url !~ services_regex
126
+ rejects << [i,
127
+ Embedly::EmbedlyObject.new(
128
+ :type => 'error',
129
+ :error_code => 401,
130
+ :error_message => 'Embedly api key is required.'
131
+ )
132
+ ]
133
+ end
134
+ end
135
+ end
136
+
137
+ if params[:urls].size > 0
138
+ params[:key] = key if key and not secret
139
+ params.merge!Hash[
140
+ opts.select{|k,_| not [:url, :urls, :action, :version].index k}
141
+ ]
142
+
143
+ path = "/#{opts[:version]}/#{opts[:action]}?#{QueryString.stringify(params)}"
144
+
145
+ response = _do_call path
146
+
147
+ if response.code.to_i == 200
148
+ logger.debug { response.body }
149
+ # [].flatten is to be sure we have an array
150
+ objs = [JSON.parse(response.body)].flatten.collect do |o|
151
+ Embedly::EmbedlyObject.new(o)
152
+ end
153
+ else
154
+ logger.debug { response }
155
+ raise Embedly::BadResponseException.new(response, path)
156
+ end
157
+
158
+ # re-insert rejects into response
159
+ rejects.each do |i, obj|
160
+ objs.insert i, obj
161
+ end
162
+
163
+ objs
164
+ else
165
+ # we only have rejects, return them without calling embedly
166
+ rejects.collect{|i, obj| obj}
167
+ end
168
+ end
169
+
170
+ # Returns structured data from the services API method.
171
+ #
172
+ # Response is cached per API object.
173
+ #
174
+ # see http://api.embed.ly/docs/service for a description of the response.
175
+ def services
176
+ if not @services
177
+ response = _do_call '/1/services/ruby'
178
+ raise 'services call failed', response if response.code.to_i != 200
179
+ @services = JSON.parse(response.body)
180
+ end
181
+ @services
182
+ end
183
+
184
+ # Returns a regex suitable for checking urls against for non-key usage
185
+ def services_regex
186
+ r = services.collect {|p| p["regex"].join("|")}.join("|")
187
+ Regexp.new r
188
+ end
189
+
190
+ # Performs api call based on method name
191
+ #
192
+ # === Currently supported
193
+ #
194
+ # - +oembed+
195
+ # - +objectify+
196
+ # - +preview+
197
+ #
198
+ def method_missing(name, *args, &block)
199
+ if @endpoints.include?name
200
+ opts = args[0]
201
+ opts[:action] = name
202
+ opts[:version] = @api_version[name]
203
+ apicall opts
204
+ else
205
+ super
206
+ end
207
+ end
208
+
209
+ private
210
+ def uri_parse uri
211
+ uri =~ %r{^((http(s?))://)?([^:/]+)(:([\d]+))?(/.*)?$}
212
+ scheme = $2 || 'http'
213
+ host = $4
214
+ port = $6 ? $6 : ( scheme == 'https' ? 443 : 80)
215
+ [scheme, host, port.to_i]
216
+ end
217
+
218
+ def site
219
+ scheme, host, port = uri_parse hostname
220
+ if (scheme == 'http' and port == 80) or (scheme == 'https' and port == 443)
221
+ "#{scheme}://#{host}"
222
+ else
223
+ "#{scheme}://#{host}:#{port}"
224
+ end
225
+ end
226
+
227
+ def logger
228
+ configuration.logger
229
+ end
230
+
231
+ def configuration
232
+ Embedly.configuration
233
+ end
234
+ end
@@ -0,0 +1,132 @@
1
+ require "optparse"
2
+
3
+ module Embedly
4
+ class CommandLine
5
+
6
+ class Parser
7
+ attr_accessor :options
8
+
9
+ def initialize(args)
10
+ @options, @args = default, args
11
+ end
12
+
13
+ def parse!
14
+ parser.parse!(@args)
15
+ set_urls!
16
+ reject_nil!
17
+ options
18
+ rescue OptionParser::InvalidOption => error
19
+ puts "ERROR: #{error.message}"
20
+ puts parser.on_tail
21
+ exit
22
+ end
23
+
24
+ def self.parse!(args)
25
+ new(args).parse!
26
+ end
27
+
28
+ private
29
+
30
+ def default
31
+ {
32
+ :key => ENV['EMBEDLY_KEY'],
33
+ :secret => ENV['EMBEDLY_SECRET'],
34
+ :headers => {},
35
+ :query => {},
36
+ :typhoeus => true
37
+ }
38
+ end
39
+
40
+ def reject_nil!
41
+ options.reject! { |_, opt| opt.nil? }
42
+ end
43
+
44
+ def set_urls!
45
+ raise(OptionParser::InvalidOption, "url required") if @args.empty?
46
+ options[:query][:urls] = @args
47
+ end
48
+
49
+ def parser
50
+ OptionParser.new do |parser|
51
+ parser.banner = %{
52
+ Fetch JSON from the embedly service.
53
+ Usage [OPTIONS] <url> [url] ..
54
+ }
55
+
56
+ parser.separator ""
57
+ parser.separator "Options:"
58
+
59
+ parser.on('-H', '--hostname ENDPOINT', 'Embedly host. Default is api.embed.ly.') do |hostname|
60
+ options[:hostname] = hostname
61
+ end
62
+
63
+ parser.on("--header NAME=VALUE", "HTTP header to send with requests.") do |hash|
64
+ header, value = hash.split '='
65
+ options[:headers][header] = value
66
+ end
67
+
68
+ parser.on("-k", "--key KEY", "Embedly key [default: EMBEDLY_KEY environmental variable]") do |key|
69
+ options[:key] = key
70
+ end
71
+
72
+ parser.on("-N", "--no-key", "Ignore EMBEDLY_KEY environmental variable") do |key|
73
+ options[:key] = nil
74
+ end
75
+
76
+ parser.on("-s", "--secret SECRET", "Embedly secret [default: EMBEDLY_SECRET environmental variable]") do |secret|
77
+ options[:secret] = secret
78
+ end
79
+
80
+ parser.on("--no-secret", "Ignore EMBEDLY_SECRET environmental variable") do
81
+ options[:secret] = nil
82
+ end
83
+
84
+ parser.on("-o", "--option NAME=VALUE", "Set option to be passed as query param.") do |option|
85
+ key, value = option.split('=')
86
+ options[:query][key.to_sym] = value
87
+ end
88
+
89
+ parser.on("--no-typhoeus", "Don't use typhoeus.") do
90
+ Embedly.configuration.typhoeus = false
91
+ end
92
+
93
+ parser.separator ""
94
+ parser.separator "Common Options:"
95
+
96
+ parser.on("-v", "--[no-]verbose", "Run verbosely") do |verbose|
97
+ Embedly.configuration.debug = verbose
98
+ end
99
+
100
+ parser.on("-h", "--help", "Display this message") do
101
+ puts parser
102
+ exit
103
+ end
104
+
105
+ parser.separator ""
106
+ parser.separator "Bob Corsaro <bob@embed.ly>"
107
+ end
108
+ end
109
+ end
110
+
111
+ class << self
112
+ def run!(endpoint, args = [])
113
+ new(args).run(endpoint)
114
+ end
115
+ end
116
+
117
+ def initialize(args)
118
+ @options, @args = {}, args
119
+ end
120
+
121
+ def run(endpoint = :oembed)
122
+ api_options = options.dup
123
+ query = api_options.delete(:query)
124
+ Embedly::API.new(api_options).send(endpoint, query)
125
+ end
126
+
127
+ def options
128
+ @options = Parser.parse!(@args.dup)
129
+ @options
130
+ end
131
+ end
132
+ end