linkedin-oauth2 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.autotest +14 -0
- data/.document +5 -0
- data/.gemtest +0 -0
- data/.gitignore +41 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.markdown +121 -0
- data/Rakefile +26 -0
- data/changelog.markdown +94 -0
- data/examples/authenticate.rb +16 -0
- data/examples/network.rb +12 -0
- data/examples/profile.rb +18 -0
- data/examples/sinatra.rb +69 -0
- data/examples/status.rb +6 -0
- data/lib/linked_in/api.rb +6 -0
- data/lib/linked_in/api/query_methods.rb +123 -0
- data/lib/linked_in/api/update_methods.rb +76 -0
- data/lib/linked_in/client.rb +31 -0
- data/lib/linked_in/errors.rb +19 -0
- data/lib/linked_in/helpers.rb +6 -0
- data/lib/linked_in/helpers/authorization.rb +106 -0
- data/lib/linked_in/helpers/request.rb +93 -0
- data/lib/linked_in/mash.rb +68 -0
- data/lib/linked_in/search.rb +55 -0
- data/lib/linked_in/version.rb +11 -0
- data/lib/linkedin-oauth2.rb +32 -0
- data/linkedin-oauth2.gemspec +25 -0
- data/spec/cases/api_spec.rb +192 -0
- data/spec/cases/linkedin_spec.rb +37 -0
- data/spec/cases/mash_spec.rb +85 -0
- data/spec/cases/oauth_spec.rb +130 -0
- data/spec/cases/search_spec.rb +190 -0
- data/spec/helper.rb +30 -0
- metadata +236 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module LinkedIn
|
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,55 @@
|
|
1
|
+
module LinkedIn
|
2
|
+
|
3
|
+
module Search
|
4
|
+
def search(options={}, type='people')
|
5
|
+
path = "/#{type.to_s}-search"
|
6
|
+
|
7
|
+
if options.is_a?(Hash)
|
8
|
+
fields = options.delete(:fields)
|
9
|
+
path += field_selector(fields) if fields
|
10
|
+
end
|
11
|
+
|
12
|
+
options = { :keywords => options } if options.is_a?(String)
|
13
|
+
options = format_options_for_query(options)
|
14
|
+
|
15
|
+
result_json = get(to_uri(path, options))
|
16
|
+
|
17
|
+
Mash.from_json(result_json)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def format_options_for_query(opts)
|
23
|
+
opts.inject({}) do |list, kv|
|
24
|
+
key, value = kv.first.to_s.gsub("_","-"), kv.last
|
25
|
+
list[key] = sanitize_value(value)
|
26
|
+
list
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def sanitize_value(value)
|
31
|
+
value = value.join("+") if value.is_a?(Array)
|
32
|
+
value = value.gsub(" ", "+") if value.is_a?(String)
|
33
|
+
value
|
34
|
+
end
|
35
|
+
|
36
|
+
def field_selector(fields)
|
37
|
+
result = ":("
|
38
|
+
fields = fields.to_a.map do |field|
|
39
|
+
if field.is_a?(Hash)
|
40
|
+
innerFields = []
|
41
|
+
field.each do |key, value|
|
42
|
+
innerFields << key.to_s.gsub("_","-") + field_selector(value)
|
43
|
+
end
|
44
|
+
innerFields.join(',')
|
45
|
+
else
|
46
|
+
field.to_s.gsub("_","-")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
result += fields.join(',')
|
50
|
+
result += ")"
|
51
|
+
result
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
|
3
|
+
module LinkedIn
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :client_id, :client_secret, :default_profile_fields
|
7
|
+
|
8
|
+
# config/initializers/linkedin.rb (for instance)
|
9
|
+
#
|
10
|
+
# LinkedIn.configure do |config|
|
11
|
+
# config.client_id = 'client_id'
|
12
|
+
# config.client_secret = 'client_secret'
|
13
|
+
# config.default_profile_fields = ['education', 'positions']
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# elsewhere
|
17
|
+
#
|
18
|
+
# client = LinkedIn::Client.new
|
19
|
+
def configure
|
20
|
+
yield self
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
autoload :Api, "linked_in/api"
|
26
|
+
autoload :Client, "linked_in/client"
|
27
|
+
autoload :Mash, "linked_in/mash"
|
28
|
+
autoload :Errors, "linked_in/errors"
|
29
|
+
autoload :Helpers, "linked_in/helpers"
|
30
|
+
autoload :Search, "linked_in/search"
|
31
|
+
autoload :Version, "linked_in/version"
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../lib/linked_in/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.add_dependency 'hashie', ['>= 1.2', '< 2.1']
|
6
|
+
gem.add_dependency 'multi_json', '~> 1.0'
|
7
|
+
gem.add_dependency 'oauth2', '~> 0.8'
|
8
|
+
gem.add_development_dependency 'json', '~> 1.6'
|
9
|
+
gem.add_development_dependency 'rake', '~> 0.9'
|
10
|
+
gem.add_development_dependency 'rdoc', '~> 3.8'
|
11
|
+
gem.add_development_dependency 'rspec', '~> 2.6'
|
12
|
+
gem.add_development_dependency 'simplecov', '~> 0.5'
|
13
|
+
gem.add_development_dependency 'vcr', '~> 1.10'
|
14
|
+
gem.add_development_dependency 'webmock', '~> 1.9'
|
15
|
+
gem.authors = ["Evan Morikawa", "Wynn Netherland", "Josh Kalderimis"]
|
16
|
+
gem.description = %q{Ruby wrapper for the LinkedIn OAuth 2.0 API}
|
17
|
+
gem.email = ['evan@evanmorikawa.com', 'wynn.netherland@gmail.com', 'josh.kalderimis@gmail.com']
|
18
|
+
gem.files = `git ls-files`.split("\n")
|
19
|
+
gem.homepage = 'http://github.com/emorikawa/linkedin-oauth2'
|
20
|
+
gem.name = 'linkedin-oauth2'
|
21
|
+
gem.require_paths = ['lib']
|
22
|
+
gem.summary = gem.description
|
23
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
gem.version = LinkedIn::VERSION::STRING
|
25
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe LinkedIn::Api do
|
4
|
+
before do
|
5
|
+
LinkedIn.default_profile_fields = nil
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:client){LinkedIn::Client.new('stub_client_id',
|
9
|
+
'stub_client_secret',
|
10
|
+
'stub_access_token')}
|
11
|
+
|
12
|
+
it "should be able to view the account profile" do
|
13
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/~?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
14
|
+
client.profile.should be_an_instance_of(LinkedIn::Mash)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be able to view public profiles" do
|
18
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/id=123?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
19
|
+
client.profile(:id => 123).should be_an_instance_of(LinkedIn::Mash)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be able to view connections" do
|
23
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/~/connections?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
24
|
+
client.connections.should be_an_instance_of(LinkedIn::Mash)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to view network_updates" do
|
28
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
29
|
+
client.network_updates.should be_an_instance_of(LinkedIn::Mash)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be able to view network_update's comments" do
|
33
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates/key=network_update_key/update-comments?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
34
|
+
client.share_comments("network_update_key").should be_an_instance_of(LinkedIn::Mash)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should be able to view network_update's likes" do
|
38
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/~/network/updates/key=network_update_key/likes?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
39
|
+
client.share_likes("network_update_key").should be_an_instance_of(LinkedIn::Mash)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should be able to search with a keyword if given a String" do
|
43
|
+
stub_request(:get, "https://api.linkedin.com/v1/people-search?keywords=business&oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
44
|
+
client.search("business").should be_an_instance_of(LinkedIn::Mash)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be able to search with an option" do
|
48
|
+
stub_request(:get, "https://api.linkedin.com/v1/people-search?first-name=Javan&oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
49
|
+
client.search(:first_name => "Javan").should be_an_instance_of(LinkedIn::Mash)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should be able to search with an option and fetch specific fields" do
|
53
|
+
stub_request(:get, "https://api.linkedin.com/v1/people-search:(num-results,total)?first-name=Javan&oauth2_access_token=#{client.access_token.token}").to_return(
|
54
|
+
:body => "{}")
|
55
|
+
client.search(:first_name => "Javan", :fields => ["num_results", "total"]).should be_an_instance_of(LinkedIn::Mash)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should be able to share a new status" do
|
59
|
+
stub_request(:post, "https://api.linkedin.com/v1/people/~/shares?oauth2_access_token=#{client.access_token.token}").to_return(:body => "", :status => 201)
|
60
|
+
response = client.add_share(:comment => "Testing, 1, 2, 3")
|
61
|
+
response.body.should == ""
|
62
|
+
response.status.should == 201
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be able to comment on network update" do
|
66
|
+
stub_request(:post, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/update-comments?oauth2_access_token=#{client.access_token.token}").to_return(
|
67
|
+
:body => "", :status => 201)
|
68
|
+
response = client.update_comment('SOMEKEY', "Testing, 1, 2, 3")
|
69
|
+
response.body.should == ""
|
70
|
+
response.status.should == 201
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should be able to send a message" do
|
74
|
+
stub_request(:post, "https://api.linkedin.com/v1/people/~/mailbox?oauth2_access_token=#{client.access_token.token}").to_return(:body => "", :status => 201)
|
75
|
+
response = client.send_message("subject", "body", ["recip1", "recip2"])
|
76
|
+
response.body.should == ""
|
77
|
+
response.status.should == 201
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should be able to like a network update" do
|
81
|
+
stub_request(:put, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/is-liked?oauth2_access_token=#{client.access_token.token}").
|
82
|
+
with(:body => "true").to_return(:body => "", :status => 201)
|
83
|
+
response = client.like_share('SOMEKEY')
|
84
|
+
response.body.should == ""
|
85
|
+
response.status.should == 201
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should be able to unlike a network update" do
|
89
|
+
stub_request(:put, "https://api.linkedin.com/v1/people/~/network/updates/key=SOMEKEY/is-liked?oauth2_access_token=#{client.access_token.token}").
|
90
|
+
with(:body => "false").to_return(:body => "", :status => 201)
|
91
|
+
response = client.unlike_share('SOMEKEY')
|
92
|
+
response.body.should == ""
|
93
|
+
response.status.should == 201
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should be able to pass down the additional arguments to OAuth's request_access_token" do
|
97
|
+
#
|
98
|
+
# stub_request(:post, "https://www.linkedin.com/uas/oauth2/accessToken").with { |r| r.body == "grant_type=authorization_code&code=auth_code&client_id=stub_client_id&client_secret=stub_client_secret&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fcallback" }
|
99
|
+
#
|
100
|
+
# access_token = client.request_access_token("auth_code",
|
101
|
+
# {:redirect_uri => "http://localhost:3000/auth/callback"})
|
102
|
+
|
103
|
+
c = LinkedIn::Client.new('stub_client_id',
|
104
|
+
'stub_client_secret',
|
105
|
+
'stub_access_token',
|
106
|
+
{site: "some_other_site"})
|
107
|
+
|
108
|
+
c.oauth2_client.site == "some_other_site"
|
109
|
+
end
|
110
|
+
|
111
|
+
context "Company API" do
|
112
|
+
use_vcr_cassette
|
113
|
+
|
114
|
+
it "should be able to view a company profile" do
|
115
|
+
stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
116
|
+
client.company(:id => 1586).should be_an_instance_of(LinkedIn::Mash)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should be able to view a company by universal name" do
|
120
|
+
stub_request(:get, "https://api.linkedin.com/v1/companies/universal-name=acme?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
121
|
+
client.company(:name => 'acme').should be_an_instance_of(LinkedIn::Mash)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should be able to view a company by e-mail domain" do
|
125
|
+
stub_request(:get, "https://api.linkedin.com/v1/companies?email-domain=acme.com&oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
126
|
+
client.company(:domain => 'acme.com').should be_an_instance_of(LinkedIn::Mash)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should load correct company data" do
|
130
|
+
client.company(:id => 1586).name.should == "Amazon"
|
131
|
+
|
132
|
+
data = client.company(:id => 1586, :fields => %w{ id name industry locations:(address:(city state country-code) is-headquarters) employee-count-range })
|
133
|
+
data.id.should == 1586
|
134
|
+
data.name.should == "Amazon"
|
135
|
+
data.employee_count_range.name.should == "10001+"
|
136
|
+
data.industry.should == "Internet"
|
137
|
+
data.locations.all[0].address.city.should == "Seattle"
|
138
|
+
data.locations.all[0].is_headquarters.should == true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "Job API" do
|
143
|
+
use_vcr_cassette
|
144
|
+
|
145
|
+
it "should be able to view a job listing" do
|
146
|
+
stub_request(:get, "https://api.linkedin.com/v1/jobs/id=1586?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
147
|
+
client.job(:id => 1586).should be_an_instance_of(LinkedIn::Mash)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should be able to view its job bookmarks" do
|
151
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/~/job-bookmarks?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
152
|
+
client.job_bookmarks.should be_an_instance_of(LinkedIn::Mash)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should be able to view its job suggestion" do
|
156
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/~/suggestions/job-suggestions?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
157
|
+
client.job_suggestions.should be_an_instance_of(LinkedIn::Mash)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should be able to add a bookmark" do
|
161
|
+
stub_request(:post, "https://api.linkedin.com/v1/people/~/job-bookmarks?oauth2_access_token=#{client.access_token.token}").to_return(:body => "", :status => 201)
|
162
|
+
response = client.add_job_bookmark(:id => 1452577)
|
163
|
+
response.body.should == ""
|
164
|
+
response.status.should == 201
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "Group API" do
|
169
|
+
|
170
|
+
it "should be able to list group memberships for a profile" do
|
171
|
+
stub_request(:get, "https://api.linkedin.com/v1/people/~/group-memberships?oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}")
|
172
|
+
client.group_memberships.should be_an_instance_of(LinkedIn::Mash)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should be able to join a group" do
|
176
|
+
stub_request(:put, "https://api.linkedin.com/v1/people/~/group-memberships/123?oauth2_access_token=#{client.access_token.token}").to_return(:body => "", :status => 201)
|
177
|
+
|
178
|
+
response = client.join_group(123)
|
179
|
+
response.body.should == ""
|
180
|
+
response.status.should == 201
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
context "errors" do
|
186
|
+
it "should raise access denied error when linkedin returns 403 status code" do
|
187
|
+
stub_request(:get, "https://api.linkedin.com/v1/people-search?first-name=javan&oauth2_access_token=#{client.access_token.token}").to_return(:body => "{}", :status => 403)
|
188
|
+
|
189
|
+
expect{ client.search(:first_name => "javan") }.to raise_error(LinkedIn::Errors::AccessDeniedError)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe LinkedIn do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
LinkedIn.client_id = nil
|
7
|
+
LinkedIn.client_secret = nil
|
8
|
+
LinkedIn.default_profile_fields = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be able to set the client_id and client_secret" do
|
12
|
+
LinkedIn.client_id = 'client_id'
|
13
|
+
LinkedIn.client_secret = 'client_secret'
|
14
|
+
|
15
|
+
LinkedIn.client_id.should == 'client_id'
|
16
|
+
LinkedIn.client_secret.should == 'client_secret'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be able to set the default profile fields" do
|
20
|
+
LinkedIn.default_profile_fields = ['education', 'positions']
|
21
|
+
|
22
|
+
LinkedIn.default_profile_fields.should == ['education', 'positions']
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be able to set the client_id and client_secret via a configure block" do
|
26
|
+
LinkedIn.configure do |config|
|
27
|
+
config.client_id = 'client_id'
|
28
|
+
config.client_secret = 'client_secret'
|
29
|
+
config.default_profile_fields = ['education', 'positions']
|
30
|
+
end
|
31
|
+
|
32
|
+
LinkedIn.client_id.should == 'client_id'
|
33
|
+
LinkedIn.client_secret.should == 'client_secret'
|
34
|
+
LinkedIn.default_profile_fields.should == ['education', 'positions']
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe LinkedIn::Mash do
|
4
|
+
|
5
|
+
describe ".from_json" do
|
6
|
+
it "should convert a json string to a Mash" do
|
7
|
+
json_string = "{\"name\":\"Josh Kalderimis\"}"
|
8
|
+
mash = LinkedIn::Mash.from_json(json_string)
|
9
|
+
|
10
|
+
mash.should have_key('name')
|
11
|
+
mash.name.should == 'Josh Kalderimis'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#convert_keys" do
|
16
|
+
let(:mash) do
|
17
|
+
LinkedIn::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 = LinkedIn::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 = LinkedIn::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 = LinkedIn::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
|
+
LinkedIn::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
|