Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Profile, Connection APIs

  • Loading branch information...
commit 75fb55de51fb8c6bfccbe0252c72b450345b3dbf 1 parent 20810bf
Wynn Netherland authored
View
14 .autotest
@@ -0,0 +1,14 @@
+Autotest.add_hook(:initialize) do |at|
+ at.add_exception(".git")
+end
+
+Autotest.add_hook(:initialize) do |at|
+ at.clear_mappings
+
+ at.add_mapping %r%/^lib/(.*)\.rb$% do |_, m|
+ possible = File.basename(m[1])
+ files_matching %r%^test/.*(#{possible}_test|test_#{possible})\.rb$%
+ end
+
+ at.add_mapping(%r%^test/.*\.rb$%) {|filename, _| filename }
+end
View
14 README.rdoc → README.markdown
@@ -1,8 +1,12 @@
-= linkedin
+# linkedin
-Description goes here.
+Ruby wrapper for the [LinkedIn API](http://developer.linkedin.com)
-== Note on Patches/Pull Requests
+## TODO
+* Implement Search, Status, Invitation APIs
+* Swap Crack for ROXML for cleaner attribute access
+
+## Note on Patches/Pull Requests
* Fork the project.
* Make your feature addition or bug fix.
@@ -13,6 +17,6 @@ Description goes here.
bump version in a commit by itself I can ignore when I pull)
* Send me a pull request. Bonus points for topic branches.
-== Copyright
+## Copyright
-Copyright (c) 2009 Wynn Netherland. See LICENSE for details.
+Copyright (c) 2009 [Wynn Netherland](http://wynnnetherland.com). See LICENSE for details.
View
23 Rakefile
@@ -5,12 +5,22 @@ begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "linkedin"
- gem.summary = %Q{TODO: one-line summary of your gem}
- gem.description = %Q{TODO: longer description of your gem}
- gem.email = "wynn@squeejee.com"
+ gem.summary = %Q{Ruby wrapper for the LinkedIn API}
+ gem.description = %Q{Ruby wrapper for the LinkedIn API}
+ gem.email = "wynn.netherland@gmail.com"
gem.homepage = "http://github.com/pengwynn/linkedin"
gem.authors = ["Wynn Netherland"]
- gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
+ gem.files = FileList["[A-Z]*", "{examples,lib,test}/**/*"]
+
+
+ gem.add_dependency('oauth', '~> 0.3.5')
+ gem.add_dependency('hashie', '~> 0.1.3')
+ gem.add_dependency('crack', '~> 0.1.4')
+
+ gem.add_development_dependency('thoughtbot-shoulda', '>= 2.10.1')
+ gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
+ gem.add_development_dependency('mocha', '0.9.4')
+ gem.add_development_dependency('fakeweb', '>= 1.2.5')
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
end
Jeweler::GemcutterTasks.new
@@ -20,8 +30,9 @@ end
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
- test.libs << 'lib' << 'test'
- test.pattern = 'test/**/test_*.rb'
+ test.libs << 'test'
+ test.ruby_opts << '-rubygems'
+ test.pattern = 'test/**/*_test.rb'
test.verbose = true
end
View
130 lib/linked_in/client.rb
@@ -0,0 +1,130 @@
+module LinkedIn
+ class Client
+
+ attr_reader :ctoken, :csecret, :consumer_options
+
+ def initialize(ctoken, csecret, options={})
+ opts = {
+ :request_token_path => "/uas/oauth/requestToken",
+ :access_token_path => "/uas/oauth/accessToken",
+ :authorize_path => "/uas/oauth/authorize"
+ }
+ @ctoken, @csecret, @consumer_options = ctoken, csecret, opts.merge(options)
+ end
+
+ def consumer
+ @consumer ||= ::OAuth::Consumer.new(@ctoken, @csecret, {:site => 'https://api.linkedin.com'}.merge(consumer_options))
+ end
+
+ def set_callback_url(url)
+ clear_request_token
+ request_token(:oauth_callback => url)
+ end
+
+ # Note: If using oauth with a web app, be sure to provide :oauth_callback.
+ # Options:
+ # :oauth_callback => String, url that twitter should redirect to
+ def request_token(options={})
+ @request_token ||= consumer.get_request_token(options)
+ end
+
+ # For web apps use params[:oauth_verifier], for desktop apps,
+ # use the verifier is the pin that twitter gives users.
+ def authorize_from_request(rtoken, rsecret, verifier_or_pin)
+ request_token = ::OAuth::RequestToken.new(consumer, rtoken, rsecret)
+ access_token = request_token.get_access_token(:oauth_verifier => verifier_or_pin)
+ @atoken, @asecret = access_token.token, access_token.secret
+ end
+
+ def access_token
+ @access_token ||= ::OAuth::AccessToken.new(consumer, @atoken, @asecret)
+ end
+
+ def authorize_from_access(atoken, asecret)
+ @atoken, @asecret = atoken, asecret
+ end
+
+ def get(path, options={})
+ path = "/v1#{path}"
+ puts path
+ response = access_token.get(path, options)
+ raise_errors(response)
+ parse(response)
+ end
+
+
+ def profile(options={})
+
+ path = person_path(options)
+
+ unless options[:fields].nil?
+ if options[:public]
+ path +=":public"
+ else
+ path +=":(#{options[:fields].map{|f| f.to_s}.join(',')})"
+ end
+ end
+ data = Hashie::Mash.new(get(path))
+
+ if data.errors.nil?
+ data.person
+ else
+ data
+ end
+
+ end
+
+ def connections(options={})
+ path = "#{person_path(options)}/connections"
+
+ unless options[:fields].nil?
+ if options[:public]
+ path +=":public"
+ else
+ path +=":(#{options[:fields].map{|f| f.to_s}.join(',')})"
+ end
+ end
+
+ data = Hashie::Mash.new(get(path))
+
+ if data.errors.nil?
+ data.connections
+ else
+ data
+ end
+
+ end
+
+ private
+ def clear_request_token
+ @request_token = nil
+ end
+
+ def raise_errors(response)
+ case response.code.to_i
+ when 502..503
+ raise Unavailable, "(#{response.code}): #{response.message}"
+ end
+ end
+
+ def parse(response)
+ Crack::XML.parse(response.body)
+ end
+
+ def person_path(options)
+ path = "/people/"
+ if options[:id]
+ path += "id=#{options[:id]}"
+ elsif options[:email]
+ path += "email=#{options[:email]}"
+ elsif options[:url]
+ path += "url=#{CGI.escape(options[:url])}"
+ else
+ path += "~"
+ end
+ end
+
+
+
+ end
+end
View
17 lib/linkedin.rb
@@ -0,0 +1,17 @@
+require 'forwardable'
+require 'rubygems'
+
+gem 'oauth', '~> 0.3.5'
+require 'oauth'
+
+gem 'hashie', '~> 0.1.3'
+require 'hashie'
+
+gem 'crack', '~> 0.1.4'
+require 'crack'
+
+require 'cgi'
+
+directory = File.expand_path(File.dirname(__FILE__))
+
+require File.join(directory, 'linked_in', 'client')
View
106 test/oauth_test.rb
@@ -0,0 +1,106 @@
+require 'test_helper'
+
+class OAuthTest < Test::Unit::TestCase
+ should "initialize with consumer token and secret" do
+ linkedin = LinkedIn::Client.new('token', 'secret')
+
+ linkedin.ctoken.should == 'token'
+ linkedin.csecret.should == 'secret'
+ end
+
+ should "set authorization path to '/uas/oauth/authorize' by default" do
+ linkedin = LinkedIn::Client.new('token', 'secret')
+ linkedin.consumer.options[:authorize_path].should == '/uas/oauth/authorize'
+ end
+
+ should "have a consumer" do
+ consumer = mock('oauth consumer')
+ options = {
+ :request_token_path => "/uas/oauth/requestToken",
+ :access_token_path => "/uas/oauth/accessToken",
+ :authorize_path => "/uas/oauth/authorize",
+ :site => 'https://api.linkedin.com'
+ }
+ OAuth::Consumer.expects(:new).with('token', 'secret', options).returns(consumer)
+ linkedin = LinkedIn::Client.new('token', 'secret')
+
+ linkedin.consumer.should == consumer
+ end
+
+ should "have a request token from the consumer" do
+ options = {
+ :request_token_path => "/uas/oauth/requestToken",
+ :access_token_path => "/uas/oauth/accessToken",
+ :authorize_path => "/uas/oauth/authorize",
+ :site => 'https://api.linkedin.com'
+ }
+ consumer = mock('oauth consumer')
+ request_token = mock('request token')
+ consumer.expects(:get_request_token).returns(request_token)
+ OAuth::Consumer.expects(:new).with('token', 'secret', options).returns(consumer)
+ linkedin = LinkedIn::Client.new('token', 'secret')
+
+ linkedin.request_token.should == request_token
+ end
+
+ context "set_callback_url" do
+ should "clear request token and set the callback url" do
+ consumer = mock('oauth consumer')
+ request_token = mock('request token')
+ options = {
+ :request_token_path => "/uas/oauth/requestToken",
+ :access_token_path => "/uas/oauth/accessToken",
+ :authorize_path => "/uas/oauth/authorize",
+ :site => 'https://api.linkedin.com'
+ }
+ OAuth::Consumer.
+ expects(:new).
+ with('token', 'secret', options).
+ returns(consumer)
+
+ linkedin = LinkedIn::Client.new('token', 'secret')
+
+ consumer.
+ expects(:get_request_token).
+ with({:oauth_callback => 'http://myapp.com/oauth_callback'})
+
+ linkedin.set_callback_url('http://myapp.com/oauth_callback')
+ end
+ end
+
+ should "be able to create access token from request token, request secret and verifier" do
+ linkedin = LinkedIn::Client.new('token', 'secret')
+ consumer = OAuth::Consumer.new('token', 'secret', {:site => 'https://api.linkedin.com'})
+ linkedin.stubs(:consumer).returns(consumer)
+
+ access_token = mock('access token', :token => 'atoken', :secret => 'asecret')
+ request_token = mock('request token')
+ request_token.
+ expects(:get_access_token).
+ with(:oauth_verifier => 'verifier').
+ returns(access_token)
+
+ OAuth::RequestToken.
+ expects(:new).
+ with(consumer, 'rtoken', 'rsecret').
+ returns(request_token)
+
+ linkedin.authorize_from_request('rtoken', 'rsecret', 'verifier')
+ linkedin.access_token.class.should be(OAuth::AccessToken)
+ linkedin.access_token.token.should == 'atoken'
+ linkedin.access_token.secret.should == 'asecret'
+ end
+
+ should "be able to create access token from access token and secret" do
+ linkedin = LinkedIn::Client.new('token', 'secret')
+ consumer = OAuth::Consumer.new('token', 'secret', {:site => 'https://api.linkedin.com'})
+ linkedin.stubs(:consumer).returns(consumer)
+
+ linkedin.authorize_from_access('atoken', 'asecret')
+ linkedin.access_token.class.should be(OAuth::AccessToken)
+ linkedin.access_token.token.should == 'atoken'
+ linkedin.access_token.secret.should == 'asecret'
+ end
+
+
+end
View
51 test/test_helper.rb
@@ -0,0 +1,51 @@
+require 'test/unit'
+require 'pathname'
+require 'rubygems'
+
+gem 'thoughtbot-shoulda', '>= 2.10.1'
+gem 'jnunemaker-matchy', '0.4.0'
+gem 'mocha', '0.9.4'
+gem 'fakeweb', '>= 1.2.5'
+
+require 'shoulda'
+require 'matchy'
+require 'mocha'
+require 'fakeweb'
+
+FakeWeb.allow_net_connect = false
+
+dir = (Pathname(__FILE__).dirname + '../lib').expand_path
+require dir + 'linkedin'
+
+class Test::Unit::TestCase
+end
+
+def fixture_file(filename)
+ return '' if filename == ''
+ file_path = File.expand_path(File.dirname(__FILE__) + '/fixtures/' + filename)
+ File.read(file_path)
+end
+
+def linkedin_url(url)
+ url =~ /^http/ ? url : "https://api.linkedin.com:80#{url}"
+end
+
+def stub_get(url, filename, status=nil)
+ options = {:body => fixture_file(filename)}
+ options.merge!({:status => status}) unless status.nil?
+
+ FakeWeb.register_uri(:get, linkedin_url(url), options)
+end
+
+def stub_post(url, filename)
+ FakeWeb.register_uri(:post, linkedin_url(url), :body => fixture_file(filename))
+end
+
+def stub_put(url, filename)
+ FakeWeb.register_uri(:put, linkedin_url(url), :body => fixture_file(filename))
+end
+
+def stub_delete(url, filename)
+ FakeWeb.register_uri(:delete, linkedin_url(url), :body => fixture_file(filename))
+
+end
Please sign in to comment.
Something went wrong with that request. Please try again.