diff --git a/Rakefile b/Rakefile index cc758dcd..fba29305 100644 --- a/Rakefile +++ b/Rakefile @@ -15,6 +15,7 @@ begin gem.add_dependency('oauth', '~> 0.3.5') gem.add_dependency('roxml', '~> 3.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') diff --git a/changelog.markdown b/changelog.markdown index 0b9b6661..e1438284 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -1,6 +1,16 @@ ## Changelog + +### 0.1.0 - November 25, 2009 + +* Network updates API support +* Search API support +* Updates API support + ### 0.0.2 - November 25, 2009 + * Swapped out Crack for ROXML for prettier object access * Added more tests for Profile API + ### 0.0.1 - November 24, 2009 + * Initial release \ No newline at end of file diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index 128b894d..cd8873ba 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -51,6 +51,20 @@ def get(path, options={}) response.body end + def put(path, options={}) + path = "/v1#{path}" + response = access_token.put(path, options) + raise_errors(response) + response + end + + def delete(path, options={}) + path = "/v1#{path}" + response = access_token.delete(path, options) + raise_errors(response) + response + end + def profile(options={}) @@ -81,6 +95,42 @@ def connections(options={}) Connections.from_xml(get(path)).profiles end + def search(options={}) + path = "/people" + options = {:keywords => options} if options.is_a?(String) + options = format_options_for_query(options) + + People.from_xml(get(to_uri(path, options))) + end + + def current_status + path = "/people/~/current-status" + Crack::XML.parse(get(path))['current_status'] + end + + def update_status(text) + path = "/people/~/current-status" + put(path, status_to_xml(text)) + end + + def clear_status + path = "/people/~/current-status" + delete(path).code + end + + def network_statuses(options={}) + options[:type] = 'STAT' + network_updates(options) + end + + def network_updates(options={}) + path = "/people/~/network" + Network.from_xml(get(to_uri(path, options))) + end + + + + # helpful in making authenticated calls and writing the # raw xml to a fixture file def write_fixture(path, filename) @@ -100,15 +150,37 @@ def raise_errors(response) raise Unavailable, "(#{response.code}): #{response.message}" end - if response.body.include?("") + if response.body && response.body.include?("") error = LinkedIn::Error.from_xml(response.body) - case error.status - when 404 - Raise LinkedInError, "(#{error.status}): #{error.code} - #{error.message}" - end + Raise LinkedInError, "(#{error.status}): #{error.code} - #{error.message}" + end + end + + def format_options_for_query(opts) + opts.keys.each do |key| + value = opts.delete(key) + value = value.join("+") if value.is_a?(Array) + value = value.gsub(" ", "+") if value.is_a?(String) + opts[key.to_s.gsub("_","-")] = value end + opts + end + + def to_query(options) + options.inject([]) do |collection, opt| + collection << "#{opt[0]}=#{opt[1]}" + collection + end * '&' end + + def to_uri(path, options) + uri = URI.parse(path) + if options && options != {} + uri.query = to_query(options) + end + uri.to_s + end def person_path(options) path = "/people/" @@ -123,6 +195,10 @@ def person_path(options) end end + def status_to_xml(status) + %Q{ + #{status}} + end end diff --git a/lib/linked_in/network.rb b/lib/linked_in/network.rb new file mode 100644 index 00000000..7b6a3eb3 --- /dev/null +++ b/lib/linked_in/network.rb @@ -0,0 +1,7 @@ +module LinkedIn + class Network + include ROXML + xml_convention {|val| val.gsub("_","-") } + xml_reader :updates, :as => [Update] + end +end \ No newline at end of file diff --git a/lib/linked_in/people.rb b/lib/linked_in/people.rb new file mode 100644 index 00000000..f07aceb7 --- /dev/null +++ b/lib/linked_in/people.rb @@ -0,0 +1,10 @@ +module LinkedIn + class People + include ROXML + xml_convention {|val| val.gsub("_","-") } + xml_reader :total, :as => Integer, :from => "@total" + xml_reader :start, :as => Integer, :from => "@start" + xml_reader :count, :as => Integer, :from => "@count" + xml_reader :profiles, :as => [Profile], :from => 'person' + end +end \ No newline at end of file diff --git a/lib/linked_in/update.rb b/lib/linked_in/update.rb new file mode 100644 index 00000000..b58c74c8 --- /dev/null +++ b/lib/linked_in/update.rb @@ -0,0 +1,11 @@ +module LinkedIn + class Update + include ROXML + xml_convention {|val| val.gsub("_","-") } + xml_reader :timestamp, :as => Integer + xml_reader :update_key + xml_reader :update_type + xml_reader :profile, :as => Profile, :from => 'update-content/person' + xml_reader :is_commentable? + end +end diff --git a/lib/linkedin.rb b/lib/linkedin.rb index 7129c597..3e850eb7 100644 --- a/lib/linkedin.rb +++ b/lib/linkedin.rb @@ -7,6 +7,9 @@ gem 'roxml', '~> 3.1.3' require 'roxml' +gem 'crack', '~> 0.1.4' +require 'crack' + require 'cgi' module LinkedIn @@ -38,5 +41,8 @@ class NotFound < StandardError; end require File.join(directory, 'linked_in', 'location') require File.join(directory, 'linked_in', 'position') require File.join(directory, 'linked_in', 'profile') +require File.join(directory, 'linked_in', 'update') +require File.join(directory, 'linked_in', 'network') +require File.join(directory, 'linked_in', 'people') require File.join(directory, 'linked_in', 'connections') require File.join(directory, 'linked_in', 'client') \ No newline at end of file diff --git a/test/client_test.rb b/test/client_test.rb index adbdf764..64daada2 100644 --- a/test/client_test.rb +++ b/test/client_test.rb @@ -44,6 +44,61 @@ class ClientTest < Test::Unit::TestCase cons.size.should == 146 cons.last.last_name.should == 'Yuchnewicz' end + + should "perform a search by keyword" do + stub_get("/v1/people?keywords=github", "search.xml") + results = @linkedin.search(:keywords => 'github') + results.start == 0 + results.count == 10 + results.profiles.first.first_name.should == 'Zach' + results.profiles.first.last_name.should == 'Inglis' + end + + should "perform a search by multiple keywords" do + stub_get("/v1/people?keywords=ruby+rails", "search.xml") + results = @linkedin.search(:keywords => ["ruby", "rails"]) + results.start == 0 + results.count == 10 + results.profiles.first.first_name.should == 'Zach' + results.profiles.first.last_name.should == 'Inglis' + end + + should "perform a search by name" do + stub_get("/v1/people?name=Zach+Inglis", "search.xml") + results = @linkedin.search(:name => "Zach Inglis") + results.start == 0 + results.count == 10 + results.profiles.first.first_name.should == 'Zach' + results.profiles.first.last_name.should == 'Inglis' + end + + should "update a user's current status" do + stub_put("/v1/people/~/current-status", "blank.xml") + @linkedin.update_status("Testing out the LinkedIn API") + end + + should "clear a user's current status" do + stub_delete("/v1/people/~/current-status", "blank.xml") + @linkedin.clear_status + end + + should "retrieve the authenticated user's current status" do + stub_get("/v1/people/~/current-status", "status.xml") + @linkedin.current_status.should == "New blog post: What makes a good API wrapper? http://wynnnetherland.com/2009/11/what-makes-a-good-api-wrapper/" + end + + should "retrieve status updates for the authenticated user's network" do + stub_get("/v1/people/~/network?type=STAT", "network_statuses.xml") + stats = @linkedin.network_statuses + stats.updates.first.profile.first_name.should == 'Vahid' + end + + should "retrieve network updates" do + stub_get("/v1/people/~/network?type=PICT", "picture_updates.xml") + stats = @linkedin.network_updates(:type => "PICT") + stats.updates.size.should == 4 + stats.updates.last.profile.headline.should == "Creative Director for Intridea" + end end diff --git a/test/fixtures/blank.xml b/test/fixtures/blank.xml new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/network_statuses.xml b/test/fixtures/network_statuses.xml new file mode 100644 index 00000000..94524326 --- /dev/null +++ b/test/fixtures/network_statuses.xml @@ -0,0 +1,279 @@ + + + + 146 + 16998 + + + + 1259179809524 + STAT-19408512-118-*1 + STAT + + + 19408512 + Vahid + Behzadi (vahid@cybercoders.com) + Executive Recruiter at CyberCoders - Recruiting Manager + said: Etsy Dallas Jingle Bash – Shop local for the Holidays http://ping.fm/0P80n(I+live+in+Dallas) + + http://api.linkedin.com/v1/people/Hz_9mRaUxh:full + + + x-li-auth-token + name:EPo9 + + + + + http://www.linkedin.com/profile?viewProfile=&key=19408512&authToken=EPo9&authType=name + + + + true + + + 1259134444850 + STAT-10801267-18-*1 + STAT + + + 10801267 + Michael + Bleigh + Creative Director for Intridea + Hate it when I get the ideas for four or five lengthy blog posts but don't have time to write any of them. + + http://api.linkedin.com/v1/people/zIVkLLOYia:full + + + x-li-auth-token + name:BcLL + + + + + http://www.linkedin.com/profile?viewProfile=&key=10801267&authToken=BcLL&authType=name + + + + true + + + 1259118559812 + STAT-10801267-17-*1 + STAT + + + 10801267 + Michael + Bleigh + Creative Director for Intridea + If you aren't exposing it to change in your app's UI, why do you need it in the database at all? Ex. currencies, roles, countries... + + http://api.linkedin.com/v1/people/zIVkLLOYia:full + + + x-li-auth-token + name:BcLL + + + + + http://www.linkedin.com/profile?viewProfile=&key=10801267&authToken=BcLL&authType=name + + + + true + + + 1259104574686 + STAT-19408512-116-*1 + STAT + + + 19408512 + Vahid + Behzadi (vahid@cybercoders.com) + Executive Recruiter at CyberCoders - Recruiting Manager + said: Nokia – The story of an Awesomely Innovative Company getting Out-innovated http://ping.fm/yTGmL + + http://api.linkedin.com/v1/people/Hz_9mRaUxh:full + + + x-li-auth-token + name:EPo9 + + + + + http://www.linkedin.com/profile?viewProfile=&key=19408512&authToken=EPo9&authType=name + + + + true + + + 1259094708174 + STAT-16571819-52-*1 + STAT + + + 16571819 + Brian + Blankenship + Interactive Creative Director at Balcom Agency + Thanks @consuro for keeping @balcomagency humming today! + + http://api.linkedin.com/v1/people/-5o6E7ti32:full + + + x-li-auth-token + name:NZ8c + + + + + http://www.linkedin.com/profile?viewProfile=&key=16571819&authToken=NZ8c&authType=name + + + + true + + + 1259094344698 + STAT-16571819-50-*1 + STAT + + + 16571819 + Brian + Blankenship + Interactive Creative Director at Balcom Agency + Balcomites @balcomagency @chiphanna @sanichols etc buzz me via dm on Twit. Can't access anything else. Net still down? + + http://api.linkedin.com/v1/people/-5o6E7ti32:full + + + x-li-auth-token + name:NZ8c + + + + + http://www.linkedin.com/profile?viewProfile=&key=16571819&authToken=NZ8c&authType=name + + + + true + + + 1259083650707 + STAT-3429308-40-*1 + STAT + + + 3429308 + Daniel + Lathrop + Digital Strategist at InvestigateWest + My niece texted so much she broke her phone's keyboard. Now she has to text 'the old fashioned way. + + http://api.linkedin.com/v1/people/1bJ9lghNE-:full + + + x-li-auth-token + name:FBW_ + + + + + http://www.linkedin.com/profile?viewProfile=&key=3429308&authToken=FBW_&authType=name + + + + true + + + 1259080455770 + STAT-19408512-114-*1 + STAT + + + 19408512 + Vahid + Behzadi (vahid@cybercoders.com) + Executive Recruiter at CyberCoders - Recruiting Manager + said: Eliot Spitzer, Now More Than Ever http://ping.fm/vUB3V + + http://api.linkedin.com/v1/people/Hz_9mRaUxh:full + + + x-li-auth-token + name:EPo9 + + + + + http://www.linkedin.com/profile?viewProfile=&key=19408512&authToken=EPo9&authType=name + + + + true + + + 1259042672786 + STAT-10801267-16-*1 + STAT + + + 10801267 + Michael + Bleigh + Creative Director for Intridea + Anyone have an available couch.io or mongohq invite or code? + + http://api.linkedin.com/v1/people/zIVkLLOYia:full + + + x-li-auth-token + name:BcLL + + + + + http://www.linkedin.com/profile?viewProfile=&key=10801267&authToken=BcLL&authType=name + + + + true + + + 1259019816599 + STAT-16571819-49-*1 + STAT + + + 16571819 + Brian + Blankenship + Interactive Creative Director at Balcom Agency + RT @ULTRACEPT Many businesses unprepared for flu-related absences | Top Stories | Star-Telegram.com: http://bit.ly/6CqJ6T via @addthis + + http://api.linkedin.com/v1/people/-5o6E7ti32:full + + + x-li-auth-token + name:NZ8c + + + + + http://www.linkedin.com/profile?viewProfile=&key=16571819&authToken=NZ8c&authType=name + + + + true + + + diff --git a/test/fixtures/picture_updates.xml b/test/fixtures/picture_updates.xml new file mode 100644 index 00000000..1b13d82e --- /dev/null +++ b/test/fixtures/picture_updates.xml @@ -0,0 +1,117 @@ + + + + 146 + 17000 + + + + 1258714582136 + PICU-6043885-ffe88342*3bee0*3453f*38ffb*3460fde2eb011-*1 + PICU + + + 6043885 + Darrin + Tvrdy, PMP + Project Manager / Business Systems Analyst IV at Hewlett-Packard + http://media.linkedin.com/mpr/mpr/shrink_80_80/p/1/000/03d/0d8/2c32744.jpg + + http://api.linkedin.com/v1/people/xNOObJb-yZ:full + + + x-li-auth-token + name:5DNj + + + + + http://www.linkedin.com/profile?viewProfile=&key=6043885&authToken=5DNj&authType=name + + + + true + + + 1258476132751 + PICU-6043885-070638e9*36873*34b5f*3ae0e*38317a0b7f845-*1 + PICU + + + 6043885 + Darrin + Tvrdy, PMP + Project Manager / Business Systems Analyst IV at Hewlett-Packard + http://media.linkedin.com/mpr/mpr/shrink_80_80/p/1/000/03c/2b2/32dd2ae.jpg + + http://api.linkedin.com/v1/people/xNOObJb-yZ:full + + + x-li-auth-token + name:5DNj + + + + + http://www.linkedin.com/profile?viewProfile=&key=6043885&authToken=5DNj&authType=name + + + + true + + + 1257874533025 + PICU-58354393-3ce71c91*32ae4*349e4*39292*3fe67cf5f53e3-*1 + PICU + + + 58354393 + Paula + Netherland + Owner, TreeFrog Studios + http://media.linkedin.com/mpr/mpr/shrink_80_80/p/3/000/03b/1fd/191b80c.jpg + + http://api.linkedin.com/v1/people/Wg56CgmrNZ:full + + + x-li-auth-token + name:ykZL + + + + + http://www.linkedin.com/profile?viewProfile=&key=58354393&authToken=ykZL&authType=name + + + + true + + + 1257862249721 + PICU-10801267-44155327*3e1a1*340bf*38507*313d4f654b91f-*1 + PICU + + + 10801267 + Michael + Bleigh + Creative Director for Intridea + http://media.linkedin.com/mpr/mpr/shrink_80_80/p/2/000/03b/1d6/1ae8bb6.jpg + + http://api.linkedin.com/v1/people/zIVkLLOYia:full + + + x-li-auth-token + name:BcLL + + + + + http://www.linkedin.com/profile?viewProfile=&key=10801267&authToken=BcLL&authType=name + + + + true + + + diff --git a/test/fixtures/search.xml b/test/fixtures/search.xml new file mode 100644 index 00000000..8f343f08 --- /dev/null +++ b/test/fixtures/search.xml @@ -0,0 +1,538 @@ + + + + U6YB1O2bqv + Zach + Inglis + Partner at London Made + + United Kingdom + + gb + + + Online Media + + 0 + 1 + + + 54820459 + Owner + London Made is a development and design shop. We also offer training and recruitment. + + 2008 + 11 + + true + + London Made + + + + 47016515 + Writer + + 2008 + 8 + + true + + Ruby Inside + + + + 30985289 + Partner + Clipgarden allows you to earn money by recording the things you do best. We’re still in the early stages of development but continue to hear positive things. + + 2007 + 8 + + true + + Clipgarden + + + + + http://api.linkedin.com/v1/people/U6YB1O2bqv:full + + + x-li-auth-token + OUT_OF_NETWORK:h0Rc + + + + + http://www.linkedin.com/profile?viewProfile=&key=3669630&authToken=h0Rc&authType=OUT_OF_NETWORK + + + + OVeaSymWcX + Zach + Moazeni + Founder at Downstream + + Greater Grand Rapids, Michigan Area + + Computer Software + + 0 + 2 + + + 78139799 + Founder + As a co-founder of Downstream, I am tasked with the development in order to bring the product to launch. I am also responsible for the Application Scaling plans as well as helping give language to the other founders as they communicate to investors. + + 2009 + 5 + + true + + Downstream + + + + 14106883 + Software Developer + I've taken the technical lead on many of Elevator Up's projects from decision, design, and the implementation. Beyond the codebase itself, I have also been tasked to train junior developers to become productive contributors to the team. These projects have exposed me to many leading edge open source technologies surrounding the Rails stack. + +Though my role is primarily as a developer, I've also taken responsibility in a wide variety of non-software areas. Business Planning, Business/Revenue Modeling, Interviewing/Hiring, Proposals, Estimating, Project Management, Server and Network Engineering/Administration, User Interface Design. My role(s) have consistently required me to distill technical knowledge and translate it into business terms. + + 2007 + 1 + + true + + Elevator Up + + + + + http://api.linkedin.com/v1/people/OVeaSymWcX:full + + + x-li-auth-token + OUT_OF_NETWORK:-TzE + + + + + http://www.linkedin.com/profile?viewProfile=&key=10342418&authToken=-TzE&authType=OUT_OF_NETWORK + + + + HbUhpG4QBG + Kyle + Neath + Designer for GitHub + + San Francisco Bay Area + + Internet + + 0 + 2 + + + 91660562 + Designer + I make shiny things for http://github.com and other Logical Awesome offerings. + + 2009 + 10 + + true + + Logical Awesome + + + + + http://api.linkedin.com/v1/people/HbUhpG4QBG:full + + + x-li-auth-token + OUT_OF_NETWORK:Tia4 + + + + + http://www.linkedin.com/profile?viewProfile=&key=5178019&authToken=Tia4&authType=OUT_OF_NETWORK + + + + YDJZU3B5E- + Rizwan + Reza + Freelance Web Developer & Interaction Designer + + Saudi Arabia + + Computer Software + + 0 + 2 + + + 83027482 + Freelance Web Developer & Interaction Designer + + + 2009 + 8 + + true + + Rizwan Reza + + + + + http://api.linkedin.com/v1/people/YDJZU3B5E-:full + + + x-li-auth-token + OUT_OF_NETWORK:y2-T + + + + + http://www.linkedin.com/profile?viewProfile=&key=26468354&authToken=y2-T&authType=OUT_OF_NETWORK + + + + MUidFvxKQ6 + Lance + Ennen + Software Consultant at Obtiva + + Greater Chicago Area + + Computer Software + + 0 + 2 + + + 82862186 + Software Consultant + + + 2009 + 5 + + true + + Obtiva + + + + + http://api.linkedin.com/v1/people/MUidFvxKQ6:full + + + x-li-auth-token + OUT_OF_NETWORK:etcX + + + + + http://www.linkedin.com/profile?viewProfile=&key=19558926&authToken=etcX&authType=OUT_OF_NETWORK + + + + KH1gMc_rDG + Dominic + Da Silva + Enterprise Application Developer specilizing in Java, .NET and Ruby technologies + + Orlando, Florida Area + + Information Technology and Services + + 0 + 2 + + + 71614339 + Software Engineer + Develop .NET applications using Microsoft and ALT.NET technologies, Service Oriented Architecture, and proven enterprise and software design patterns. + +Follow the SCRUM agile development methodology. + + 2009 + 4 + + true + + Aptitude Solutions + + + + 18897619 + President / Technical Architect / Lead Developer + Owner, technical architect and lead developer for an independent software development consultancy. + +SilvaSoft has built numerous customer facing business web sites using Java web technologies that integrate with existing web service, shipping and secure credit card processing APIs. + +We use technologies such as Java (1.4, 5, 6), Struts, JBoss Seam, Tomcat (5, 6), XFire, Apache Axis, Apache CXF and Sun Metro. + +We have integrated with third party web services such as: +1. Amazon S3 +2. PayPal credit card payment API +3. Authorize.net credit card / check payment API +4. UPS shipping API. + +Clients include Intellavia LLC, Amazon Web Services, Chenoa Information Services, adaptiveblue and Developer.com. + +Client work includes: + +JVI Inspection - http://www.jviinspection.com/ + +Coolaroo USA - http://www.coolaroousa.com/ + +IAPP - http://www.iappnet.org/ + +BMS Biowrap - http://biometricwrap.com/ + +Building a Struts-Based Web Application on Amazon S3 - http://tinyurl.com/d596b6 + +Building a Web Application with Ruby on Rails and Amazon S3 - http://tinyurl.com/236yk4 + + 2003 + 9 + + true + + SilvaSoft, Inc. + + + + + http://api.linkedin.com/v1/people/KH1gMc_rDG:full + + + x-li-auth-token + OUT_OF_NETWORK:VunB + + + + + http://www.linkedin.com/profile?viewProfile=&key=13457424&authToken=VunB&authType=OUT_OF_NETWORK + + + + k8ASaj0HMi + Barry + Hess + Independent consultant in the web world + + Rochester, Minnesota Area + + Internet + + 0 + 2 + + + 17303961 + Prime Hacker + Helping Harvest be all that it can be. Primary developer on Co-op. Manage Iridesco programmer outreach. + +http://getharvest.com +http://coopapp.com +http://github.com/iridesco + + 2007 + + true + + Iridesco + + + + 16038108 + Prime Hacker + Backend programming in Ruby on Rails, I also have a sense of design and interface. Live projects: + +http://followcost.com +http://scrawlers.com +http://ventorium.com +http://gethoffed.com + + 2007 + 2 + + true + + bjhess.com + + + + + http://api.linkedin.com/v1/people/k8ASaj0HMi:full + + + x-li-auth-token + OUT_OF_NETWORK:WcpW + + + + + http://www.linkedin.com/profile?viewProfile=&key=9202576&authToken=WcpW&authType=OUT_OF_NETWORK + + + + SvKzNaGjHa + Sukhchander + Khanna + Software Manufacturer, Plumber, and Mechanic + + Greater New York City Area + + Internet + + 0 + 2 + + + 95304666 + Software Manufacturer, Plumber, and Mechanic + + + 2009 + 11 + + true + + 16012 + + + + + http://api.linkedin.com/v1/people/SvKzNaGjHa:full + + + x-li-auth-token + OUT_OF_NETWORK:_YOz + + + + + http://www.linkedin.com/profile?viewProfile=&key=7452363&authToken=_YOz&authType=OUT_OF_NETWORK + + + + qpgZ6hzBr7 + John + Griffiths + Web / Media / iPhone + + Colchester, United Kingdom + + Internet + + 0 + 2 + + + 16016691 + Owner + Personal site, now 7 years & going strong. Technical tutorials, code snippets & research. Ported from Typo to my own RoR CMS. + + 2000 + 1 + + true + + Red91.com + + + + + http://api.linkedin.com/v1/people/qpgZ6hzBr7:full + + + x-li-auth-token + OUT_OF_NETWORK:VtL8 + + + + + http://www.linkedin.com/profile?viewProfile=&key=7104192&authToken=VtL8&authType=OUT_OF_NETWORK + + + + 6Vt1KQjwGB + Matt + Aimonetti + Senior Software Engineer + + Greater San Diego Area + + Computer Software + + 0 + 2 + + + 59051476 + Evangelist/Developer Relation Engineer + + + 2008 + 12 + + true + + Ruby on Rails + + + + 49599478 + Lead Evangelist/ Developer + Build a critical mass of support and awareness around Merb, a flexible yet powerful Ruby framework. + + 2008 + 9 + + true + + Merb + + + + 17113878 + Owner and Lead Developer + - Help the customer evaluate and define their IT needs using Agile Methodologies + - Develop Ruby on Rails / Merb based solutions + - Evaluate effectiveness of provided solutions + - Audit on existing project + - Provide training/coaching for on-site teams + + 2005 + 6 + + true + + m|a agile consulting, inc. + + + + + http://api.linkedin.com/v1/people/6Vt1KQjwGB:full + + + x-li-auth-token + OUT_OF_NETWORK:1QZs + + + + + http://www.linkedin.com/profile?viewProfile=&key=6347192&authToken=1QZs&authType=OUT_OF_NETWORK + + + diff --git a/test/fixtures/status.xml b/test/fixtures/status.xml new file mode 100644 index 00000000..7e520e08 --- /dev/null +++ b/test/fixtures/status.xml @@ -0,0 +1,2 @@ + +New blog post: What makes a good API wrapper? http://wynnnetherland.com/2009/11/what-makes-a-good-api-wrapper/