ezlinkedin 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fd3bc787edf277267d4ecdf564c7afddabb8398a
4
+ data.tar.gz: f9e5b890bfdd7ec4aa283c67e47e2b2371e36bca
5
+ SHA512:
6
+ metadata.gz: 595165aee0f3d837399c8aef7ec38f1982f31d8620fb2cae076c1bcd434b83ae863dd87e5aa2cc09e5fc740c3849b11314a181b50773dfc65ad76895340c614a
7
+ data.tar.gz: 7cccd7d271e2f0b7601b9f42c60fa48cebf097358103031e2d378a96d87b750331daa498c77a424cde888c0e1ee07c5fb43a5026453b301ab3be00bfaae8c1a1
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *~
2
+ *.*~
3
+ *.gem
4
+ *.rbc
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ezlinkedin.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 akonwi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # Ezlinkedin
2
+
3
+ A simple way to make calls on Linkedin's API. NOTE: It is not yet completed and does not encompass all of the api at this time. It serves the purpose I made it for but I will continue to develop it.
4
+
5
+ This is heavily inspired and influenced by pengwynn's linkedin gem. I was having issues with his gem though and there is very little documentation for using it so I decided to redo it myself in order to:
6
+ * Make it work for what I needed
7
+ * Add precise and useful documentation
8
+ * contribute a bit more robust ruby wrapper for Linkedin's API
9
+
10
+ Most of the tests are from pengwynn's gem
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'ezlinkedin'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install ezlinkedin
25
+
26
+ ## Usage
27
+
28
+ This is meant to be used alongside omniauth. Obtain access tokens from omniauth authentication and then use them to make api calls.
29
+
30
+ require 'ezlinkedin'
31
+
32
+ # Create a client
33
+ linkedin = EzLinkedin::Client.new("API KEY", "SECRET KEY", options) # options are the typical OAuth consumer options
34
+ linkedin.authorize("access_token", "access_token_secret") # tokens obtained from omniauth
35
+
36
+ Currently, one can post shares, retrieve updates, user profile, and connections.
37
+
38
+ ## Contributing
39
+
40
+ 1. Fork it
41
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
42
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
43
+ 4. Push to the branch (`git push origin my-new-feature`)
44
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ezlinkedin/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ezlinkedin"
8
+ spec.version = Ezlinkedin::VERSION
9
+ spec.authors = ["akonwi"]
10
+ spec.email = ["akonwi@gmail.com"]
11
+ spec.description = "A simple way to make calls on Linkedin's API"
12
+ spec.summary = %q{It's a simple way to access Linkedin and it's coupled well will omniauth}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency 'oauth', '~> 0.4.7'
22
+ spec.add_runtime_dependency 'hashie', '~> 2.0.5'
23
+ spec.add_runtime_dependency 'json', '~> 1.8.0'
24
+ spec.add_runtime_dependency 'multi_json', '~> 1.7.3'
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec", '~> 2.6'
28
+ spec.add_development_dependency 'guard'
29
+ spec.add_development_dependency 'guard-rspec'
30
+ spec.add_development_dependency 'libnotify'
31
+ spec.add_development_dependency "webmock", '~> 1.11.0'
32
+ end
@@ -0,0 +1,115 @@
1
+ module EzLinkedin
2
+ module Api
3
+
4
+ module QueryMethods
5
+
6
+ #
7
+ # Retrieve a certain profile depending on the options passed in.
8
+ # @param options={} [Hash] can be an array of fields as strings and an id,
9
+ # and a url to a public profile. This can also contain request
10
+ # headers
11
+ #
12
+ # @return [Mash] a Mash hash representing the found profile
13
+ def profile(options={})
14
+ path = person_path(options)
15
+ make_query(path, options, true)
16
+ end
17
+
18
+
19
+ #
20
+ # Retrieve the authenticated user's connections
21
+ # @param options={} [Hash] pass in fields and/or a count
22
+ #
23
+ # @return [Mash] Mash hash of connections
24
+ def connections(options={})
25
+ path = "#{person_path(options)}/connections"
26
+ make_query(path, options, true)
27
+ end
28
+
29
+ #
30
+ # Retrieve the user's social feed
31
+ # @param options={} [Hash] visit Linkedin's api to
32
+ # see possible options. it will default to an
33
+ # aggregated feed unless :scope => 'self'.
34
+ # :types => [:shar, :recu, :apps]
35
+ # :count => 5
36
+ #
37
+ # @return [Mash] Mash hash of updates
38
+ def network_updates(options={})
39
+ path = "#{person_path(options)}/network/updates"
40
+ make_query(path, options, false)
41
+ end
42
+
43
+ private
44
+
45
+ def person_path(options)
46
+ path = "/people/"
47
+ if id = options.delete(:id)
48
+ path += "id=#{id}"
49
+ elsif url = options.delete(:url)
50
+ path += "url=#{CGI.escape(url)}"
51
+ else
52
+ path += '~'
53
+ end
54
+ end
55
+
56
+ #
57
+ # create a valid path to make a restful request
58
+ # @param path [String] current path
59
+ # @param options [Hash] set of options
60
+ # @param use_fields |boolean| does request need fields?
61
+ #
62
+ # @return [Mash] hash object with results
63
+ def make_query(path, options, use_fields)
64
+
65
+ fields = options.delete(:fields) || EzLinkedin.default_profile_fields if use_fields
66
+ if fields
67
+ path += ":(#{fields.join(',')})"
68
+ elsif path.end_with? "network/updates"
69
+ path += network_options(options).to_s # if getting updates, add relevant options to the path
70
+ elsif count = options.delete(:count)
71
+ path += "?count=#{count}"
72
+ end
73
+
74
+ Mash.from_json(get(path, options))
75
+ end
76
+
77
+ # handle the options passed in pertaining to network updates
78
+ def network_options(options)
79
+ path = "?"
80
+ options_path = nil
81
+
82
+ if types = options.delete(:types)
83
+ types = types.map { |type| "type=#{type.to_s.upcase}" }
84
+ options_path = types.join('&')
85
+ end
86
+
87
+ if count = options.delete(:count)
88
+ string = "count=#{count}"
89
+ options_path = add_to_path(string, options_path)
90
+ end
91
+
92
+ if scope = options.delete(:scope)
93
+ string = "scope=self"
94
+ options_path = add_to_path(string, options_path)
95
+ end
96
+
97
+ if options_path.nil?
98
+ ""
99
+ else
100
+ "#{path}#{options_path}"
101
+ end
102
+ end
103
+
104
+ # helper for previous method
105
+ def add_to_path(option, options_path)
106
+ if options_path.nil?
107
+ options_path = option
108
+ else
109
+ options_path += "&#{option}"
110
+ end
111
+ end
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,27 @@
1
+ module EzLinkedin
2
+ module Api
3
+
4
+ module UpdateMethods
5
+
6
+ #
7
+ # post a share to Linkedin
8
+ # @param share [Hash] a hash containing at least the required
9
+ # attributes for a share.
10
+ # post_share({:comment => "I'm a comment",
11
+ # :content => { :title => "A title!",
12
+ # :description => "A description",
13
+ # :submitted_url => "http...",
14
+ # :submitted_image_url => "http..."
15
+ # }
16
+ # :visibility => { :code => "anyone"}
17
+ # })
18
+ #
19
+ # @return [HTTP::Response?] response of post call
20
+ def post_share(share)
21
+ path = "/people/~/shares"
22
+ defaults = { visibility: { code: 'anyone' } }
23
+ post(path, defaults.merge(share).to_json, "Content-Type" => "application/json")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,6 @@
1
+ module EzLinkedin
2
+ module Api
3
+ autoload :QueryMethods, 'ezlinkedin/api/query_methods'
4
+ autoload :UpdateMethods, 'ezlinkedin/api/update_methods'
5
+ end
6
+ end
@@ -0,0 +1,31 @@
1
+ require "cgi"
2
+
3
+ module EzLinkedin
4
+ class Client
5
+ include Request
6
+ include Api::QueryMethods
7
+ include Api::UpdateMethods
8
+
9
+ attr_reader :consumer_key, :consumer_secret, :access_token, :client
10
+ attr_accessor :consumer_options
11
+
12
+ def initialize(c_key=EzLinkedin.token, c_secret=EzLinkedin.secret, options={})
13
+ @consumer_key = c_key
14
+ @consumer_secret = c_secret
15
+ @consumer_options = { site: 'https://api.linkedin.com',
16
+ request_token_path: '/uas/oauth/requestToken',
17
+ access_token_path: '/uas/oauth/accessToken',
18
+ authorize_path: '/uas/oauth/authorize' }
19
+ @consumer_options.merge(options)
20
+ @client = OAuth::Consumer.new(c_key, c_secret, @consumer_options)
21
+ end
22
+
23
+ # Create and outh access token to make api calls with
24
+ # param: token - the access token obtained from omniauth
25
+ # param: token_secret - the access token secret obtained from omniauth
26
+ def authorize(token, token_secret)
27
+ @access_token = OAuth::AccessToken.new(@client, token, token_secret)
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module EzLinkedin
2
+ module Errors
3
+ class LinkedInError < StandardError
4
+ attr_reader :data
5
+ def initialize(data)
6
+ @data = data
7
+ super
8
+ end
9
+ end
10
+
11
+ class UnauthorizedError < LinkedInError; end
12
+ class GeneralError < LinkedInError; end
13
+ class AccessDeniedError < LinkedInError; end
14
+
15
+ class UnavailableError < StandardError; end
16
+ class InformLinkedInError < StandardError; end
17
+ class NotFoundError < StandardError; end
18
+ end
19
+ end
@@ -0,0 +1,68 @@
1
+ require 'hashie'
2
+ require 'multi_json'
3
+
4
+ module EzLinkedin
5
+ class Mash < ::Hashie::Mash
6
+
7
+ # a simple helper to convert a json string to a Mash
8
+ def self.from_json(json_string)
9
+ result_hash = ::MultiJson.decode(json_string)
10
+ new(result_hash)
11
+ end
12
+
13
+ # returns a Date if we have year, month and day, and no conflicting key
14
+ def to_date
15
+ if !self.has_key?('to_date') && contains_date_fields?
16
+ Date.civil(self.year, self.month, self.day)
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def timestamp
23
+ value = self['timestamp']
24
+ if value.kind_of? Integer
25
+ value = value / 1000 if value > 9999999999
26
+ Time.at(value)
27
+ else
28
+ value
29
+ end
30
+ end
31
+
32
+ protected
33
+
34
+ def contains_date_fields?
35
+ self.year? && self.month? && self.day?
36
+ end
37
+
38
+ # overload the convert_key mash method so that the LinkedIn
39
+ # keys are made a little more ruby-ish
40
+ def convert_key(key)
41
+ case key.to_s
42
+ when '_key'
43
+ 'id'
44
+ when '_total'
45
+ 'total'
46
+ when 'values'
47
+ 'all'
48
+ when 'numResults'
49
+ 'total_results'
50
+ else
51
+ underscore(key)
52
+ end
53
+ end
54
+
55
+ # borrowed from ActiveSupport
56
+ # no need require an entire lib when we only need one method
57
+ def underscore(camel_cased_word)
58
+ word = camel_cased_word.to_s.dup
59
+ word.gsub!(/::/, '/')
60
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
61
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
62
+ word.tr!("-", "_")
63
+ word.downcase!
64
+ word
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,50 @@
1
+ module EzLinkedin
2
+
3
+ module Request
4
+ DEFAULT_HEADERS = {
5
+ 'x-li-format' => 'json'
6
+ }
7
+
8
+ API_PATH = "https://api.linkedin.com/v1"
9
+
10
+ protected
11
+
12
+ def get(path, options={})
13
+ response = access_token.get("#{API_PATH}#{path}", DEFAULT_HEADERS.merge(options))
14
+ raise_errors(response)
15
+ response.body
16
+ end
17
+
18
+ def post(path, body='', options={})
19
+ response = access_token.post("#{API_PATH}#{path}", body, DEFAULT_HEADERS.merge(options))
20
+ raise_errors(response)
21
+ response
22
+ end
23
+
24
+ private
25
+
26
+ def raise_errors(response)
27
+ # Even if the json answer contains the HTTP status code, LinkedIn also sets this code
28
+ # in the HTTP answer (thankfully).
29
+ case response.code.to_i
30
+ when 401
31
+ data = Mash.from_json(response.body)
32
+ raise EzLinkedin::Errors::UnauthorizedError.new(data), "(#{data.status}): #{data.message}"
33
+ when 400
34
+ data = Mash.from_json(response.body)
35
+ raise EzLinkedin::Errors::GeneralError.new(data), "(#{data.status}): #{data.message}"
36
+ when 403
37
+ data = Mash.from_json(response.body)
38
+ raise EzLinkedin::Errors::AccessDeniedError.new(data), "(#{data.status}): #{data.message}"
39
+ when 404
40
+ raise EzLinkedin::Errors::NotFoundError, "(#{response.code}): #{response.message}"
41
+ when 500
42
+ raise EzLinkedin::Errors::InformLinkedInError, "LinkedIn had an internal error. Please let them know in the forum. (#{response.code}): #{response.message}"
43
+ when 502..503
44
+ raise EzLinkedin::Errors::UnavailableError, "(#{response.code}): #{response.message}"
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,3 @@
1
+ module Ezlinkedin
2
+ VERSION = "0.0.1"
3
+ end
data/lib/ezlinkedin.rb ADDED
@@ -0,0 +1,27 @@
1
+ require "ezlinkedin/version"
2
+ require 'ezlinkedin/request'
3
+ require 'ezlinkedin/api'
4
+ require 'ezlinkedin/mash'
5
+ require 'ezlinkedin/client'
6
+ require 'ezlinkedin/errors'
7
+ require 'oauth'
8
+
9
+ module EzLinkedin
10
+ class << self
11
+ attr_accessor :token, :secret, :default_profile_fields
12
+
13
+ # EzLinkedin.configure do |config|
14
+ # config.token = 'consumer_token'
15
+ # config.secret = 'consumer_secret'
16
+ # config.default_profile_fields = ['education', 'positions']
17
+ # end
18
+ #
19
+ # elsewhere
20
+ #
21
+ # client = EzLinkedin::Client.new
22
+ def configure
23
+ yield self
24
+ true
25
+ end
26
+ end
27
+ end
data/spec/api_spec.rb ADDED
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ describe EzLinkedin::Api do
4
+ before do
5
+ EzLinkedin.default_profile_fields = nil
6
+ client.stub(:consumer).and_return(consumer)
7
+ client.authorize('atoken', 'asecret')
8
+ end
9
+
10
+ let(:client){EzLinkedin::Client.new('token', 'secret')}
11
+ let(:consumer){OAuth::Consumer.new('token', 'secret', {:site => 'https://api.linkedin.com'})}
12
+
13
+ it "should be able to view the account profile" do
14
+ stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}")
15
+ client.profile.should be_an_instance_of(EzLinkedin::Mash)
16
+ end
17
+
18
+ it "should be able to view public profiles" do
19
+ stub_request(:get, "https://api.linkedin.com/v1/people/id=123").to_return(:body => "{}")
20
+ client.profile(:id => 123).should be_an_instance_of(EzLinkedin::Mash)
21
+ end
22
+
23
+ it "should be able to view connections" do
24
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/connections").to_return(:body => "{}")
25
+ client.connections.should be_an_instance_of(EzLinkedin::Mash)
26
+ end
27
+
28
+ it "should be able to view network_updates" do
29
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates").to_return(:body => "{}")
30
+ client.network_updates.should be_an_instance_of(EzLinkedin::Mash)
31
+ end
32
+
33
+ it "should be able to view network_updates with options" do
34
+ stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates?type=SHAR&count=5&scope=self").to_return(:body => "{}")
35
+ client.network_updates(types: [:shar], count: 5, scope: 'self').should be_an_instance_of(EzLinkedin::Mash)
36
+ end
37
+
38
+ # it "should be able to view network_update's comments" do
39
+ # stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates/key=network_update_key/update-comments").to_return(:body => "{}")
40
+ # client.share_comments("network_update_key").should be_an_instance_of(EzLinkedin::Mash)
41
+ # end
42
+
43
+ # it "should be able to view network_update's likes" do
44
+ # stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates/key=network_update_key/likes").to_return(:body => "{}")
45
+ # client.share_likes("network_update_key").should be_an_instance_of(EzLinkedin::Mash)
46
+ # end
47
+ #
48
+ # it "should be able to search with a keyword if given a String" do
49
+ # stub_request(:get, "https://api.linkedin.com/v1/people-search?keywords=business").to_return(:body => "{}")
50
+ # client.search("business").should be_an_instance_of(EzLinkedin::Mash)
51
+ # end
52
+ #
53
+ # it "should be able to search with an option" do
54
+ # stub_request(:get, "https://api.linkedin.com/v1/people-search?first-name=Javan").to_return(:body => "{}")
55
+ # client.search(:first_name => "Javan").should be_an_instance_of(EzLinkedin::Mash)
56
+ # end
57
+ #
58
+ # it "should be able to search with an option and fetch specific fields" do
59
+ # stub_request(:get, "https://api.linkedin.com/v1/people-search:(num-results,total)?first-name=Javan").to_return(
60
+ # :body => "{}")
61
+ # client.search(:first_name => "Javan", :fields => ["num_results", "total"]).should be_an_instance_of(EzLinkedin::Mash)
62
+ # end
63
+ #
64
+ it "should be able to post a share" do
65
+ stub_request(:post, "https://api.linkedin.com/v1/people/~/shares").to_return(:body => "", :status => 201)
66
+ response = client.post_share({:comment => "Testing, 1, 2, 3"})
67
+ response.body.should == nil
68
+ response.code.should == "201"
69
+ end
70
+ #
71
+ # it "should be able to comment on network update" do
72
+ # stub_request(:post, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/update-comments").to_return(
73
+ # :body => "", :status => 201)
74
+ # response = client.update_comment('SOMEKEY', "Testing, 1, 2, 3")
75
+ # response.body.should == nil
76
+ # response.code.should == "201"
77
+ # end
78
+ #
79
+ # it "should be able to send a message" do
80
+ # stub_request(:post, "https://api.linkedin.com/v1/people/~/mailbox").to_return(:body => "", :status => 201)
81
+ # response = client.send_message("subject", "body", ["recip1", "recip2"])
82
+ # response.body.should == nil
83
+ # response.code.should == "201"
84
+ # end
85
+ #
86
+ # it "should be able to like a network update" do
87
+ # stub_request(:put, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/is-liked").
88
+ # with(:body => "true").to_return(:body => "", :status => 201)
89
+ # response = client.like_share('SOMEKEY')
90
+ # response.body.should == nil
91
+ # response.code.should == "201"
92
+ # end
93
+ #
94
+ # it "should be able to unlike a network update" do
95
+ # stub_request(:put, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/is-liked").
96
+ # with(:body => "false").to_return(:body => "", :status => 201)
97
+ # response = client.unlike_share('SOMEKEY')
98
+ # response.body.should == nil
99
+ # response.code.should == "201"
100
+ # end
101
+ #
102
+ # context "Company API" do
103
+ # # use_vcr_cassette
104
+ #
105
+ # it "should be able to view a company profile" do
106
+ # stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586").to_return(:body => "{}")
107
+ # client.company(:id => 1586).should be_an_instance_of(EzLinkedin::Mash)
108
+ # end
109
+ #
110
+ # it "should be able to view a company by universal name" do
111
+ # stub_request(:get, "https://api.linkedin.com/v1/companies/universal-name=acme").to_return(:body => "{}")
112
+ # client.company(:name => 'acme').should be_an_instance_of(EzLinkedin::Mash)
113
+ # end
114
+ #
115
+ # it "should be able to view a company by e-mail domain" do
116
+ # stub_request(:get, "https://api.linkedin.com/v1/companies/email-domain=acme.com").to_return(:body => "{}")
117
+ # client.company(:domain => 'acme.com').should be_an_instance_of(EzLinkedin::Mash)
118
+ # end
119
+ #
120
+ # it "should load correct company data" do
121
+ # client.company(:id => 1586).name.should == "Amazon"
122
+ #
123
+ # data = client.company(:id => 1586, :fields => %w{ id name industry locations:(address:(city state country-code) is-headquarters) employee-count-range })
124
+ # data.id.should == 1586
125
+ # data.name.should == "Amazon"
126
+ # data.employee_count_range.name.should == "10001+"
127
+ # data.industry.should == "Internet"
128
+ # data.locations.all[0].address.city.should == "Seattle"
129
+ # data.locations.all[0].is_headquarters.should == true
130
+ # end
131
+ # end
132
+
133
+ # context "Group API" do
134
+ #
135
+ # it "should be able to list group memberships for a profile" do
136
+ # stub_request(:get, "https://api.linkedin.com/v1/people/~/group-memberships").to_return(:body => "{}")
137
+ # client.group_memberships.should be_an_instance_of(EzLinkedin::Mash)
138
+ # end
139
+ #
140
+ # it "should be able to join a group" do
141
+ # stub_request(:put, "https://api.linkedin.com/v1/people/~/group-memberships/123").to_return(:body => "", :status => 201)
142
+ #
143
+ # response = client.join_group(123)
144
+ # response.body.should == nil
145
+ # response.code.should == "201"
146
+ # end
147
+ #
148
+ # end
149
+
150
+ context "Errors" do
151
+ it "should raise AccessDeniedError when EzLinkedin returns 403 status code" do
152
+ stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 403)
153
+ expect{ client.profile }.to raise_error(EzLinkedin::Errors::AccessDeniedError)
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'ezlinkedin'
3
+
4
+ describe EzLinkedin::Client do
5
+ let(:client) { EzLinkedin::Client.new('api_key', 'secret_key') }
6
+
7
+ it "client initializes" do
8
+ client.nil?.should_not be_true
9
+ client.consumer_key.should eql('api_key')
10
+ client.consumer_secret.should eql('secret_key')
11
+ client.client.should be_a_kind_of OAuth::Consumer
12
+ end
13
+
14
+ it 'creates an access token' do
15
+ client.authorize('token', 'token_secret')
16
+ access_token = client.access_token
17
+ access_token.should be_a_kind_of OAuth::AccessToken
18
+ end
19
+
20
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'ezlinkedin'
3
+
4
+ describe EzLinkedin do
5
+ before(:each) do
6
+ EzLinkedin.token = nil
7
+ EzLinkedin.secret = nil
8
+ EzLinkedin.default_profile_fields = nil
9
+ end
10
+
11
+ it "should be able to set the consumer token and consumer secret" do
12
+ EzLinkedin.token = 'consumer_token'
13
+ EzLinkedin.secret = 'consumer_secret'
14
+
15
+ EzLinkedin.token.should == 'consumer_token'
16
+ EzLinkedin.secret.should == 'consumer_secret'
17
+ end
18
+
19
+ it "should be able to set the default profile fields" do
20
+ EzLinkedin.default_profile_fields = ['education', 'positions']
21
+
22
+ EzLinkedin.default_profile_fields.should == ['education', 'positions']
23
+ end
24
+
25
+ it "should be able to set the consumer token and consumer secret via a configure block" do
26
+ EzLinkedin.configure do |config|
27
+ config.token = 'consumer_token'
28
+ config.secret = 'consumer_secret'
29
+ config.default_profile_fields = ['education', 'positions']
30
+ end
31
+
32
+ EzLinkedin.token.should == 'consumer_token'
33
+ EzLinkedin.secret.should == 'consumer_secret'
34
+ EzLinkedin.default_profile_fields.should == ['education', 'positions']
35
+ end
36
+
37
+ end
data/spec/mash_spec.rb ADDED
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe EzLinkedin::Mash do
4
+
5
+ describe ".from_json" do
6
+ it "should convert a json string to a Mash" do
7
+ json_string = "{\"name\":\"Akonwi Ngoh\"}"
8
+ mash = EzLinkedin::Mash.from_json(json_string)
9
+
10
+ mash.should have_key('name')
11
+ mash.name.should == 'Akonwi Ngoh'
12
+ end
13
+ end
14
+
15
+ describe "#convert_keys" do
16
+ let(:mash) do
17
+ EzLinkedin::Mash.new({
18
+ 'firstName' => 'Josh',
19
+ 'LastName' => 'Kalderimis',
20
+ '_key' => 1234,
21
+ '_total' => 1234,
22
+ 'values' => {},
23
+ 'numResults' => 'total_results'
24
+ })
25
+ end
26
+
27
+ it "should convert camal cased hash keys to underscores" do
28
+ mash.should have_key('first_name')
29
+ mash.should have_key('last_name')
30
+ end
31
+
32
+ it "should convert the key _key to id" do
33
+ mash.should have_key('id')
34
+ end
35
+
36
+ it "should convert the key _total to total" do
37
+ mash.should have_key('total')
38
+ end
39
+
40
+ it "should convert the key values to all" do
41
+ mash.should have_key('all')
42
+ end
43
+
44
+ it "should convert the key numResults to total_results" do
45
+ mash.should have_key('total_results')
46
+ end
47
+ end
48
+
49
+ describe '#timestamp' do
50
+ it "should return a valid Time if a key of timestamp exists and the value is an int" do
51
+ time_mash = EzLinkedin::Mash.new({ 'timestamp' => 1297083249 })
52
+
53
+ time_mash.timestamp.should be_a_kind_of(Time)
54
+ time_mash.timestamp.to_i.should == 1297083249
55
+ end
56
+
57
+ it "should return a valid Time if a key of timestamp exists and the value is an int which is greater than 9999999999" do
58
+ time_mash = EzLinkedin::Mash.new({ 'timestamp' => 1297083249 * 1000 })
59
+
60
+ time_mash.timestamp.should be_a_kind_of(Time)
61
+ time_mash.timestamp.to_i.should == 1297083249
62
+ end
63
+
64
+ it "should not try to convert to a Time object if the value isn't an Integer" do
65
+ time_mash = EzLinkedin::Mash.new({ 'timestamp' => 'Foo' })
66
+
67
+ time_mash.timestamp.class.should be String
68
+ end
69
+ end
70
+
71
+ describe "#to_date" do
72
+ let(:date_mash) do
73
+ EzLinkedin::Mash.new({
74
+ 'year' => 2010,
75
+ 'month' => 06,
76
+ 'day' => 23
77
+ })
78
+ end
79
+
80
+ it "should return a valid Date if the keys year, month, day all exist" do
81
+ date_mash.to_date.should == Date.civil(2010, 06, 23)
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,16 @@
1
+ require 'webmock/rspec'
2
+ require 'ezlinkedin'
3
+ require 'ezlinkedin/errors'
4
+
5
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.run_all_when_everything_filtered = true
9
+ config.filter_run :focus
10
+
11
+ # Run specs in random order to surface order dependencies. If you find an
12
+ # order dependency and want to debug it, you can fix the order by providing
13
+ # the seed, which is printed after each run.
14
+ # --seed 1234
15
+ config.order = 'random'
16
+ end
metadata ADDED
@@ -0,0 +1,225 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ezlinkedin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - akonwi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: oauth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.4.7
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.4.7
27
+ - !ruby/object:Gem::Dependency
28
+ name: hashie
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.8.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.8.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: multi_json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.7.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.7.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '2.6'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '2.6'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: guard-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: libnotify
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: webmock
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ~>
158
+ - !ruby/object:Gem::Version
159
+ version: 1.11.0
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ version: 1.11.0
167
+ description: A simple way to make calls on Linkedin's API
168
+ email:
169
+ - akonwi@gmail.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - .gitignore
175
+ - .rspec
176
+ - Gemfile
177
+ - Guardfile
178
+ - LICENSE.txt
179
+ - README.md
180
+ - Rakefile
181
+ - ezlinkedin.gemspec
182
+ - lib/ezlinkedin.rb
183
+ - lib/ezlinkedin/api.rb
184
+ - lib/ezlinkedin/api/query_methods.rb
185
+ - lib/ezlinkedin/api/update_methods.rb
186
+ - lib/ezlinkedin/client.rb
187
+ - lib/ezlinkedin/errors.rb
188
+ - lib/ezlinkedin/mash.rb
189
+ - lib/ezlinkedin/request.rb
190
+ - lib/ezlinkedin/version.rb
191
+ - spec/api_spec.rb
192
+ - spec/client_spec.rb
193
+ - spec/ezlinkedin_spec.rb
194
+ - spec/mash_spec.rb
195
+ - spec/spec_helper.rb
196
+ homepage: ''
197
+ licenses:
198
+ - MIT
199
+ metadata: {}
200
+ post_install_message:
201
+ rdoc_options: []
202
+ require_paths:
203
+ - lib
204
+ required_ruby_version: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - '>='
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ required_rubygems_version: !ruby/object:Gem::Requirement
210
+ requirements:
211
+ - - '>='
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ requirements: []
215
+ rubyforge_project:
216
+ rubygems_version: 2.0.3
217
+ signing_key:
218
+ specification_version: 4
219
+ summary: It's a simple way to access Linkedin and it's coupled well will omniauth
220
+ test_files:
221
+ - spec/api_spec.rb
222
+ - spec/client_spec.rb
223
+ - spec/ezlinkedin_spec.rb
224
+ - spec/mash_spec.rb
225
+ - spec/spec_helper.rb