anideo-embedly 1.3.0

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