tumblr-rb 1.3.0 → 2.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.travis.yml +7 -0
  2. data/Gemfile +15 -8
  3. data/Gemfile.lock +65 -65
  4. data/LICENSE +4 -2
  5. data/README.md +31 -84
  6. data/Rakefile +8 -68
  7. data/bin/tumblr +3 -133
  8. data/lib/tumblr.rb +7 -184
  9. data/lib/tumblr/authentication.rb +71 -0
  10. data/lib/tumblr/client.rb +148 -0
  11. data/lib/tumblr/command_line_interface.rb +222 -0
  12. data/lib/tumblr/credentials.rb +31 -0
  13. data/lib/tumblr/post.rb +253 -171
  14. data/lib/tumblr/post/answer.rb +17 -0
  15. data/lib/tumblr/post/audio.rb +22 -10
  16. data/lib/tumblr/post/chat.rb +25 -0
  17. data/lib/tumblr/post/link.rb +22 -9
  18. data/lib/tumblr/post/photo.rb +29 -10
  19. data/lib/tumblr/post/quote.rb +17 -10
  20. data/lib/tumblr/post/text.rb +18 -0
  21. data/lib/tumblr/post/video.rb +26 -11
  22. data/lib/tumblr/version.rb +3 -0
  23. data/lib/tumblr/views/error.erb +6 -0
  24. data/lib/tumblr/views/form.erb +11 -0
  25. data/lib/tumblr/views/layout.erb +41 -0
  26. data/lib/tumblr/views/success.erb +6 -0
  27. data/man/tumblr.1 +67 -65
  28. data/man/tumblr.1.html +131 -108
  29. data/man/tumblr.1.ronn +76 -57
  30. data/man/tumblr.5 +48 -68
  31. data/man/tumblr.5.html +106 -114
  32. data/man/tumblr.5.ronn +38 -51
  33. data/spec/fixtures/posts.json +10 -0
  34. data/spec/fixtures/typical_animated_gif.gif +0 -0
  35. data/spec/spec_helper.rb +12 -0
  36. data/spec/tumblr/authentication_spec.rb +57 -0
  37. data/spec/tumblr/client_spec.rb +223 -0
  38. data/spec/tumblr/credentials_spec.rb +63 -0
  39. data/spec/tumblr/post_spec.rb +125 -0
  40. data/tumblr-rb.gemspec +16 -89
  41. metadata +101 -102
  42. data/lib/tumblr/authenticator.rb +0 -18
  43. data/lib/tumblr/post/conversation.rb +0 -15
  44. data/lib/tumblr/post/regular.rb +0 -14
  45. data/lib/tumblr/reader.rb +0 -191
  46. data/lib/tumblr/writer.rb +0 -39
  47. data/test/fixtures/vcr_cassettes/authenticate/authenticate.yml +0 -39
  48. data/test/fixtures/vcr_cassettes/read/all_pages.yml +0 -34
  49. data/test/fixtures/vcr_cassettes/read/authenticated.yml +0 -40
  50. data/test/fixtures/vcr_cassettes/read/authentication_failure.yml +0 -33
  51. data/test/fixtures/vcr_cassettes/read/like.yml +0 -31
  52. data/test/fixtures/vcr_cassettes/read/mwunsch.yml +0 -101
  53. data/test/fixtures/vcr_cassettes/read/optional.yml +0 -48
  54. data/test/fixtures/vcr_cassettes/read/pages.yml +0 -36
  55. data/test/fixtures/vcr_cassettes/read/tumblrgemtest.yml +0 -42
  56. data/test/fixtures/vcr_cassettes/read/unlike.yml +0 -31
  57. data/test/fixtures/vcr_cassettes/write/delete.yml +0 -31
  58. data/test/fixtures/vcr_cassettes/write/edit.yml +0 -31
  59. data/test/fixtures/vcr_cassettes/write/reblog.yml +0 -31
  60. data/test/fixtures/vcr_cassettes/write/write.yml +0 -31
  61. data/test/helper.rb +0 -44
  62. data/test/test_tumblr.rb +0 -710
@@ -0,0 +1,10 @@
1
+ HTTP/1.1 200 OK
2
+ P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"
3
+ Vary: Accept-Encoding
4
+ X-Tumblr-Usec: D=115445
5
+ Content-Type: application/json
6
+ Content-Length: 25091
7
+ Date: Sun, 23 Sep 2012 03:02:08 GMT
8
+ Connection: close
9
+
10
+ {"meta":{"status":200,"msg":"OK"},"response":{"blog":{"title":"M. Wunsch","posts":303,"name":"mwunsch","url":"http:\/\/mwunsch.tumblr.com\/","updated":1347989422,"description":"Chronicling the interests of <a href=\"http:\/\/markwunsch.com\" rel=\"me author\">Mark Wunsch<\/a>, engineer at <a href=\"http:\/\/www.gilt.com\">Gilt<\/a>.","ask":true,"ask_anon":false},"posts":[{"blog_name":"mwunsch","id":31803039364,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/31803039364\/weary-v1-1-0","slug":"weary-v1-1-0","type":"link","date":"2012-09-18 17:30:22 GMT","timestamp":1347989422,"state":"published","format":"markdown","reblog_key":"EDW3aiKr","tags":["Weary","gilt"],"featured_in_tag":["Tech"],"highlighted":[],"note_count":11,"title":"Weary v1.1.0","url":"https:\/\/rubygems.org\/gems\/weary\/versions\/1.1.0","description":"<p><a href=\"https:\/\/github.com\/mwunsch\/weary\">Weary<\/a>, the Ruby framework for making web service clients, got a late-night version bump.<\/p>\n\n<p><strong>What&#8217;s new in this version?<\/strong><\/p>\n\n<ul><li>Adapters for <a href=\"https:\/\/github.com\/typhoeus\/typhoeus\">Typhoeus<\/a> and <a href=\"https:\/\/github.com\/geemus\/excon\">Excon<\/a>.<\/li>\n<li>Updated dependencies on multi-json and addressable<\/li>\n<li><code>Response#parse<\/code> can now take a block for custom Response body parsing.<\/li>\n<li><code>Requestable<\/code> module to allow for configuration that cascades from Client -&gt; Resource -&gt; Request<\/li>\n<li><a href=\"https:\/\/github.com\/mwunsch\/weary\/issues\/21\">Issue #21<\/a> - now, Rack::Lint is run as part of the specs.<\/li>\n<\/ul><p>The code is cleaned up a bit as well, and is now getting <a href=\"https:\/\/codeclimate.com\/github\/mwunsch\/weary\">all A&#8217;s on Code Climate<\/a>.<\/p>\n\n<p>Along with this new version of Weary, a new version of the Ruby bindings to the Gilt public API has been released: <a href=\"https:\/\/rubygems.org\/gems\/gilt\/versions\/0.2.0\">0.2.0<\/a> with support for product categories.<\/p>\n\n<p><code>gem install weary<\/code> and make a thing.<\/p>"},{"blog_name":"mwunsch","id":31683541860,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/31683541860\/minus50dkp","slug":"minus50dkp","type":"video","date":"2012-09-16 21:01:00 GMT","timestamp":1347829260,"state":"published","format":"markdown","reblog_key":"ySCQPwfh","tags":[],"highlighted":[],"note_count":1,"caption":"<p>Blast from the past.<\/p>\n\n<blockquote>\n <p>That&#8217;s a fucking 50 DKP minus.<\/p>\n<\/blockquote>","permalink_url":"http:\/\/www.youtube.com\/watch?v=HtvIYRrgZ04","thumbnail_url":"http:\/\/img.youtube.com\/vi\/HtvIYRrgZ04\/hqdefault.jpg","thumbnail_width":480,"thumbnail_height":360,"html5_capable":true,"player":[{"width":250,"embed_code":"<iframe width=\"248\" height=\"185\" src=\"http:\/\/www.youtube.com\/embed\/HtvIYRrgZ04?wmode=transparent&autohide=1&egm=0&hd=1&iv_load_policy=3&modestbranding=1&rel=0&showinfo=0&showsearch=0\" frameborder=\"0\" allowfullscreen><\/iframe>"},{"width":400,"embed_code":"<iframe width=\"400\" height=\"299\" src=\"http:\/\/www.youtube.com\/embed\/HtvIYRrgZ04?wmode=transparent&autohide=1&egm=0&hd=1&iv_load_policy=3&modestbranding=1&rel=0&showinfo=0&showsearch=0\" frameborder=\"0\" allowfullscreen><\/iframe>"},{"width":500,"embed_code":"<iframe width=\"500\" height=\"374\" src=\"http:\/\/www.youtube.com\/embed\/HtvIYRrgZ04?wmode=transparent&autohide=1&egm=0&hd=1&iv_load_policy=3&modestbranding=1&rel=0&showinfo=0&showsearch=0\" frameborder=\"0\" allowfullscreen><\/iframe>"}]},{"blog_name":"mwunsch","id":30536763755,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/30536763755\/thornton-melon","slug":"thornton-melon","type":"audio","date":"2012-08-30 20:12:00 GMT","timestamp":1346357520,"state":"published","format":"markdown","reblog_key":"SOUeeBpm","tags":[],"highlighted":[],"note_count":0,"source_url":"http:\/\/open.spotify.com\/track\/1GgfXHQGEXH1Psc1SSC9Uy","source_title":"Spotify","artist":"Danny Elfman","album":"Music For A Darkened Theatre Volume One","year":1990,"track":"7","track_name":"Back To School - Study Montage","caption":"<blockquote>\n <p>Bring us a pitcher of beer every seven minutes until somebody passes out. And then bring one every ten minutes.<\/p>\n<\/blockquote>","player":"<iframe src=\"https:\/\/embed.spotify.com\/?uri=spotify:track:1GgfXHQGEXH1Psc1SSC9Uy&amp;view=coverart\" frameborder=\"0\" allowtransparency=\"true\" style=\"width:500px;height:580px;\"><\/iframe>","plays":0,"audio_url":"http:\/\/open.spotify.com\/track\/1GgfXHQGEXH1Psc1SSC9Uy"},{"blog_name":"mwunsch","id":28998006425,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/28998006425\/otherkin","slug":"otherkin","type":"link","date":"2012-08-08 19:50:34 GMT","timestamp":1344455434,"state":"published","format":"markdown","reblog_key":"PaoKukTM","tags":["wikipedia"],"highlighted":[],"note_count":1,"title":"Otherkin","url":"http:\/\/en.wikipedia.org\/wiki\/Otherkin","description":"<p>What I&#8217;m looking at on Wikipedia, right now.<\/p>\n\n<blockquote>\n <p>Otherkin are a community of people who see themselves as partially or entirely non-human.<\/p>\n<\/blockquote>\n\n<p>I learned of this term through the wonderful <a href=\"https:\/\/twitter.com\/TumblrTXT\/status\/231574946713849856\">@tumblrtxt<\/a> Twitter account.<\/p>\n\n<blockquote>\n <p>Otherkin largely identify as mythical creatures, with others identifying as creatures from fantasy or popular culture. Examples include: angels, demons, dragons, elves, fairies, sprites, aliens, and cartoon characters.<\/p>\n<\/blockquote>\n\n<p>Wait. <em>Cartoon characters<\/em>? Oh yes. Meet <a href=\"http:\/\/en.wiktionary.org\/wiki\/otakukin\"><em>otakukin<\/em><\/a>.<\/p>\n\n<blockquote>\n <p>Outside viewers may have varying opinions about people who identify as otherkin, ranging from considering them animal-human relationship pioneers, to psychologically dysfunctional. Reactions often range from disbelief to aggressive antagonism, especially online.<\/p>\n<\/blockquote>\n\n<p>I leave it as an exercise to the reader to guess my reaction.<\/p>"},{"blog_name":"mwunsch","id":28154452444,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/28154452444\/olympic-flame","slug":"olympic-flame","type":"link","date":"2012-07-27 22:36:35 GMT","timestamp":1343428595,"state":"published","format":"markdown","reblog_key":"eNErE3nN","tags":["wikipedia"],"highlighted":[],"note_count":0,"title":"Olympic Flame","url":"http:\/\/en.wikipedia.org\/wiki\/Olympic_Flame","description":"<p>What I\u2019m looking at on Wikipedia, right now.<\/p>\n\n<blockquote>\n <p>Commemorating the theft of fire from the Greek god Zeus by Prometheus, its origins lie in ancient Greece, where a fire was kept burning throughout the celebration of the ancient Olympics. The fire was reintroduced at the 1928 Summer Olympics in Amsterdam, and it has been part of the modern Olympic Games ever since. In contrast to the Olympic flame proper, the torch relay of modern times which transports the flame from Greece to the various designated sites of the games had no ancient precedent and was introduced by Carl Diem at the controversial 1936 Summer Olympics in Berlin.<\/p>\n<\/blockquote>\n\n<p>This Olympic Torch tradition was birthed out of the Nazi&#8217;s love for pageantry:<\/p>\n\n<blockquote>\n <p>Carl Diem devised the idea of the torch relay for the 1936 Summer Olympics in Berlin that was organized by the Nazis under the guidance of Joseph Goebbels &#8230;\n Hitler saw the link with the ancient Games as the perfect way to illustrate his belief that classical Greece was an Aryan forerunner of the modern German Reich.<\/p>\n<\/blockquote>\n\n<p><img src=\"http:\/\/f.cl.ly\/items\/2x0c0P363C010Q0W2p37\/abfab-olympics-ddd-main.jpg\" alt=\"Wonder what the Nazis would think of Patsy and Edina\"\/><\/p>\n\n<p><a href=\"http:\/\/mwunsch.tumblr.com\/tagged\/wikipedia\">Check out some of the other things I&#8217;ve looked at on Wikipedia.<\/a><\/p>"},{"blog_name":"mwunsch","id":28068072088,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/28068072088","slug":"","type":"photo","date":"2012-07-26 18:46:43 GMT","timestamp":1343328403,"state":"published","format":"markdown","reblog_key":"ZNiLGdWR","tags":[],"highlighted":[],"note_count":3,"caption":"","link_url":"https:\/\/twitter.com\/mattlanger","photos":[{"caption":"","alt_sizes":[{"width":441,"height":708,"url":"http:\/\/24.media.tumblr.com\/tumblr_m7s6tvQiBH1qzykueo1_500.png"},{"width":374,"height":600,"url":"http:\/\/25.media.tumblr.com\/tumblr_m7s6tvQiBH1qzykueo1_400.png"},{"width":249,"height":400,"url":"http:\/\/25.media.tumblr.com\/tumblr_m7s6tvQiBH1qzykueo1_250.png"},{"width":100,"height":161,"url":"http:\/\/25.media.tumblr.com\/tumblr_m7s6tvQiBH1qzykueo1_100.png"},{"width":75,"height":75,"url":"http:\/\/25.media.tumblr.com\/tumblr_m7s6tvQiBH1qzykueo1_75sq.png"}],"original_size":{"width":441,"height":708,"url":"http:\/\/24.media.tumblr.com\/tumblr_m7s6tvQiBH1qzykueo1_500.png"}}]},{"blog_name":"mwunsch","id":28058019488,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/28058019488\/in-my-head-i-pronounce-blingee-as-blinjee","slug":"in-my-head-i-pronounce-blingee-as-blinjee","type":"photo","date":"2012-07-26 15:56:03 GMT","timestamp":1343318163,"state":"published","format":"markdown","reblog_key":"U30iJ00H","tags":[],"highlighted":[],"note_count":10,"caption":"<p>In my head, I pronounce &#8220;Blingee&#8221; as &#8220;Blinjee&#8221;, with a soft \u27e8g\u27e9.<\/p>","photos":[{"caption":"","alt_sizes":[{"width":400,"height":400,"url":"http:\/\/25.media.tumblr.com\/tumblr_m7ryofu1a41qz8omxo1_400.gif"},{"width":250,"height":250,"url":"http:\/\/25.media.tumblr.com\/tumblr_m7ryofu1a41qz8omxo1_250.gif"},{"width":100,"height":100,"url":"http:\/\/24.media.tumblr.com\/tumblr_m7ryofu1a41qz8omxo1_100.gif"},{"width":75,"height":75,"url":"http:\/\/25.media.tumblr.com\/tumblr_m7ryofu1a41qz8omxo1_75sq.gif"}],"original_size":{"width":400,"height":400,"url":"http:\/\/25.media.tumblr.com\/tumblr_m7ryofu1a41qz8omxo1_400.gif"}}]},{"blog_name":"mwunsch","id":26855473247,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/26855473247\/ical","slug":"ical","type":"chat","date":"2012-07-09 21:18:00 GMT","timestamp":1341868680,"state":"published","format":"markdown","reblog_key":"mYzXIa3g","tags":["ical","irc"],"highlighted":[],"note_count":1,"title":null,"body":"inky:\tmy calendar strategy is skeumorphism can eat a dick","dialogue":[{"name":"inky","label":"inky:","phrase":"my calendar strategy is skeumorphism can eat a dick"}]},{"blog_name":"mwunsch","id":26838846920,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/26838846920\/gilt-technologie-gilt-live-a-new-way-to-shop","slug":"gilt-technologie-gilt-live-a-new-way-to-shop","type":"link","date":"2012-07-09 16:55:58 GMT","timestamp":1341852958,"state":"published","format":"markdown","reblog_key":"zG8IIKtz","tags":["gilt","playframework","scala","web-sockets"],"highlighted":[],"note_count":7,"title":"Gilt Technologie: Gilt Live: A New Way to Shop","url":"http:\/\/tech.gilt.com\/post\/26801428997\/gilt-live-a-new-way-to-shop","description":"<p>Big rollout of Web Sockets for Gilt, starting today.<\/p>\n\n<p><a href=\"http:\/\/tech.gilt.com\/post\/26801428997\/gilt-live-a-new-way-to-shop\" class=\"tumblr_blog\">gilt-tech<\/a>:<\/p>\n\n<blockquote><p class=\"MsoNormal\"><a href=\"http:\/\/live.gilt.com\">http:\/\/live.gilt.com<\/a> is a new way to shop on Gilt. \u00a0It gives you the chance to see what our members are buying on Gilt - right now. \u00a0We are excited because it gives you a way to discover new products that you might never have seen. \u00a0And since it is updating in real-time you can see something sell out right before your eyes \u2013- or not if you are quick enough to jump on it.<\/p>\n<\/blockquote>\n\n<p>Includes real-time inventory updates for items going fast.<\/p>\n\n<p>The first of a series of new projects at gilt using the fantastic <a href=\"http:\/\/www.playframework.org\/\">Play! 2.0.1<\/a> web framework.<\/p>"},{"blog_name":"mwunsch","id":25509354648,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/25509354648\/fakemarkwunsch-is-a-better-mark-wunsch-than-i-am","slug":"fakemarkwunsch-is-a-better-mark-wunsch-than-i-am","type":"photo","date":"2012-06-20 16:12:44 GMT","timestamp":1340208764,"state":"published","format":"markdown","reblog_key":"tbhpUfBL","tags":[],"highlighted":[],"note_count":1,"caption":"<p><a href=\"https:\/\/twitter.com\/#!\/fakemarkwunsch\">@FakeMarkWunsch<\/a> is a better Mark Wunsch than I am. Who are you, Fake Mark Wunsch?<\/p>","link_url":"https:\/\/twitter.com\/#!\/fakemarkwunsch","photos":[{"caption":"","alt_sizes":[{"width":550,"height":290,"url":"http:\/\/25.media.tumblr.com\/tumblr_m5xbp86ApO1qzykueo1_1280.png"},{"width":500,"height":264,"url":"http:\/\/25.media.tumblr.com\/tumblr_m5xbp86ApO1qzykueo1_500.png"},{"width":400,"height":211,"url":"http:\/\/24.media.tumblr.com\/tumblr_m5xbp86ApO1qzykueo1_400.png"},{"width":250,"height":132,"url":"http:\/\/24.media.tumblr.com\/tumblr_m5xbp86ApO1qzykueo1_250.png"},{"width":100,"height":53,"url":"http:\/\/24.media.tumblr.com\/tumblr_m5xbp86ApO1qzykueo1_100.png"},{"width":75,"height":75,"url":"http:\/\/25.media.tumblr.com\/tumblr_m5xbp86ApO1qzykueo1_75sq.png"}],"original_size":{"width":550,"height":290,"url":"http:\/\/25.media.tumblr.com\/tumblr_m5xbp86ApO1qzykueo1_1280.png"}}]},{"blog_name":"mwunsch","id":25290466084,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/25290466084\/tumblr-rb-edge","slug":"tumblr-rb-edge","type":"link","date":"2012-06-17 13:41:06 GMT","timestamp":1339940466,"state":"published","format":"markdown","reblog_key":"wR7wKtvn","tags":["tumblr"],"highlighted":[],"note_count":0,"title":"tumblr-rb edge","url":"https:\/\/github.com\/mwunsch\/tumblr\/tree\/v2","description":"<p>Being rewritten with the latest Weary library on the <code>v2<\/code> branch.<\/p>"},{"blog_name":"mwunsch","id":25258359641,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/25258359641\/i-posted-this-using-the-bleeding-edge-of-the-new","slug":"i-posted-this-using-the-bleeding-edge-of-the-new","type":"photo","date":"2012-06-17 00:30:59 GMT","timestamp":1339893059,"state":"published","format":"html","reblog_key":"6Egy3pX7","tags":[],"highlighted":[],"note_count":3,"caption":"<p>I posted this using the bleeding edge of the new Tumblr Command Line utility for #fashionhack day.<\/p>","photos":[{"caption":"","alt_sizes":[{"width":500,"height":252,"url":"http:\/\/25.media.tumblr.com\/tumblr_m5qk3pwU241qzykueo1_500.gif"},{"width":400,"height":202,"url":"http:\/\/24.media.tumblr.com\/tumblr_m5qk3pwU241qzykueo1_400.gif"},{"width":250,"height":126,"url":"http:\/\/25.media.tumblr.com\/tumblr_m5qk3pwU241qzykueo1_250.gif"},{"width":100,"height":50,"url":"http:\/\/25.media.tumblr.com\/tumblr_m5qk3pwU241qzykueo1_100.gif"},{"width":75,"height":75,"url":"http:\/\/24.media.tumblr.com\/tumblr_m5qk3pwU241qzykueo1_75sq.gif"}],"original_size":{"width":500,"height":252,"url":"http:\/\/25.media.tumblr.com\/tumblr_m5qk3pwU241qzykueo1_500.gif"}}]},{"blog_name":"mwunsch","id":24883482482,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/24883482482\/i-want-to-shoot-the-whole-day-down","slug":"i-want-to-shoot-the-whole-day-down","type":"audio","date":"2012-06-11 14:10:29 GMT","timestamp":1339423829,"state":"published","format":"markdown","reblog_key":"sZY5Tcb7","tags":[],"highlighted":[],"note_count":0,"source_url":"http:\/\/open.spotify.com\/track\/7JFoeg0arawADjGcz9gBnq","source_title":"Spotify","artist":"The Boomtown Rats","album":"The Fine Art Of Surfacing","year":2005,"track":"6","track_name":"I Don't Like Mondays","caption":"<p>I want to shoot the whole day down.<\/p>","player":"<iframe src=\"https:\/\/embed.spotify.com\/?uri=spotify:track:7JFoeg0arawADjGcz9gBnq&amp;view=coverart\" frameborder=\"0\" allowtransparency=\"true\" style=\"width:500px;height:580px;\"><\/iframe>","plays":0,"audio_url":"http:\/\/open.spotify.com\/track\/7JFoeg0arawADjGcz9gBnq"},{"blog_name":"mwunsch","id":23870305629,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/23870305629\/list-of-pre-1920-jazz-standards","slug":"list-of-pre-1920-jazz-standards","type":"link","date":"2012-05-27 17:07:24 GMT","timestamp":1338138444,"state":"published","format":"markdown","reblog_key":"GTOMsW8E","tags":["wikipedia"],"highlighted":[],"note_count":3,"title":"List of pre-1920 jazz standards","url":"http:\/\/en.wikipedia.org\/wiki\/List_of_pre-1920_jazz_standards","description":"<p>What I&#8217;m looking at on Wikipedia, right now.<\/p>\n\n<blockquote>\n <p>This list includes compositions written before 1920 that are considered standards by at least one major fake book publication or reference work. Some of the tunes listed were instant hits and quickly became well-known standards, while others were popularized later.<\/p>\n<\/blockquote>"},{"blog_name":"mwunsch","id":23493020232,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/23493020232\/gilt-technologie-nyc-fashion-hack-day-2012-june-16","slug":"gilt-technologie-nyc-fashion-hack-day-2012-june-16","type":"link","date":"2012-05-21 19:35:00 GMT","timestamp":1337628900,"state":"published","format":"markdown","reblog_key":"KEhqylIz","tags":["gilt"],"highlighted":[],"note_count":3,"title":"Gilt Technologie: NYC Fashion Hack Day 2012: June 16","url":"http:\/\/tech.gilt.com\/post\/23490365999\/nyc-fashion-hack-day-2012-june-16","description":"<blockquote>\n<p><a href=\"http:\/\/nycfashionhackday.eventbrite.com\/\"><img src=\"http:\/\/media.tumblr.com\/tumblr_m4dxxmd9Xt1qzuc2n.png\" alt=\"\"\/><\/a><\/p> <p>On Saturday, June 16, 2012, Gilt Tech is joining forces with two giants of their respective industries: <a href=\"http:\/\/www.apigee.com\">Apigee<\/a>, in the business of <a href=\"http:\/\/apigee.com\/about\/products\/enterprise\">APIs<\/a> and <a href=\"http:\/\/apigee.com\/about\/products\/usergrid\">cloud platforms<\/a>, and <a href=\"http:\/\/www.tumblr.com\">Tumblr<\/a>, in the business of <a href=\"http:\/\/www.tumblr.com\/about\">hosting and spreading the word about art and creativity<\/a> and <a href=\"http:\/\/www.maddieonthings.com\/\"> blogs about dogs on top of things<\/a>.<\/p><\/blockquote>"},{"blog_name":"mwunsch","id":21091697655,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/21091697655\/how-is-weary-asynchronous","slug":"how-is-weary-asynchronous","type":"link","date":"2012-04-14 17:22:07 GMT","timestamp":1334424127,"state":"published","format":"markdown","reblog_key":"zwoh3AGI","tags":["Weary"],"highlighted":[],"note_count":0,"title":"How is Weary asynchronous?","url":"https:\/\/github.com\/mwunsch\/weary\/issues\/11","description":"<p>Great question in GitHub issues, I hope this helps others:<\/p>\n\n<blockquote>\n <p>I&#8217;m curious about how asynchronicity is implemented compared to Typhoeus.<\/p>\n<\/blockquote>\n\n<p>When you call <code>Request#perform<\/code>, that computation is performed independently of the main program flow. This action is always non-blocking. Consider this example:<\/p>\n\n<pre><code>require 'weary\/request'\n\nrequest = Weary::Request.new \"https:\/\/api.github.com\/repos\/mwunsch\/weary\"\n\nrequest.perform do |response|\n puts response.body\nend\n<\/code><\/pre>\n\n<p>Remember that <code>perform<\/code> takes a block that accepts a response and executes once the response has completed. When you execute this file as is you will <em>not<\/em> see the response&#8217;s body. Why? Because the main thread completes before the request has completed. Changing this to<\/p>\n\n<pre><code>require 'weary\/request'\n\nrequest = Weary::Request.new \"https:\/\/api.github.com\/repos\/mwunsch\/weary\"\n\nresponse = request.perform\nputs response.body\n<\/code><\/pre>\n\n<p>will produce the desired results, and here&#8217;s why: <code>Request#perform<\/code> returns a Future &#8212; a lightweight proxy object wrapping the Response (Weary uses the <a href=\"https:\/\/rubygems.org\/gems\/promise\">promise<\/a> gem under the hood). <strong>The main thread is only blocked when you call a method on the response.<\/strong> This is all done with plain ol&#8217; Ruby Threads (of which there is a lot of FUD in the Ruby community because of the GIL, but this is a perfect use case for them).<\/p>\n\n<p>I haven&#8217;t investigated <a href=\"https:\/\/github.com\/dbalatero\/typhoeus\">Typhoeus<\/a>&#8217;s source code too deeply, but I believe it implements concurrency using an extension to <a href=\"http:\/\/curl.haxx.se\/libcurl\/c\/libcurl-multi.html\">libcurl-multi<\/a>. Not sure what that means in practice compared to using a Thread.<\/p>\n\n<p>Unlike Typhoeous, Weary does not provide a queue mechanism. But you could just do something like:<\/p>\n\n<pre><code>responses = [req1, req2].map(&amp;:perform)\n<\/code><\/pre>\n\n<p>It might be helpful to look at how <a href=\"https:\/\/github.com\/mwunsch\/gilt\/blob\/0bd79329f9e5a1ecc9b8bf0ed9246a644b7e518a\/lib\/gilt\/sale.rb#L86-93\">my Gilt gem<\/a> performs multiple requests in parallel to get a sale&#8217;s products.<\/p>\n\n<p>Also unlike Typhoueus, Weary provides no internal mechanisms for memoization or caching, but you can use Rack middleware to achieve the desired result. Hope that answers your question.<\/p>"},{"blog_name":"mwunsch","id":20355238408,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/20355238408\/heres-a-brief-screencast-on-the-basics-of-the-new","slug":"heres-a-brief-screencast-on-the-basics-of-the-new","type":"video","date":"2012-04-02 17:18:20 GMT","timestamp":1333387100,"state":"published","format":"markdown","reblog_key":"UhaVbgPe","tags":[],"highlighted":{"message":"Watch this!","icon":"http:\/\/assets.tumblr.com\/images\/highlighted_posts\/icons\/unicorn_white.png","color":"#6c9141"},"note_count":3,"caption":"<p>Here&#8217;s a brief screencast on the basics of the new Weary API and how it integrates with Rack.<\/p>\n\n<p><a href=\"http:\/\/rubygems.org\/gems\/weary\">Weary v1.0.0<\/a> was released yesterday.<\/p>","permalink_url":"http:\/\/vimeo.com\/39610693","thumbnail_url":"http:\/\/b.vimeocdn.com\/ts\/273\/258\/273258714_200.jpg","thumbnail_width":200,"thumbnail_height":150,"html5_capable":true,"player":[{"width":250,"embed_code":"<iframe src=\"http:\/\/player.vimeo.com\/video\/39610693\" width=\"250\" height=\"156\" frameborder=\"0\"><\/iframe>"},{"width":400,"embed_code":"<iframe src=\"http:\/\/player.vimeo.com\/video\/39610693\" width=\"400\" height=\"250\" frameborder=\"0\"><\/iframe>"},{"width":500,"embed_code":"<iframe src=\"http:\/\/player.vimeo.com\/video\/39610693\" width=\"500\" height=\"312\" frameborder=\"0\"><\/iframe>"}]},{"blog_name":"mwunsch","id":20307428326,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/20307428326\/weary-v1-0-0","slug":"weary-v1-0-0","type":"link","date":"2012-04-01 20:57:47 GMT","timestamp":1333313867,"state":"published","format":"markdown","reblog_key":"DvrwMyuJ","tags":["Weary"],"highlighted":{"message":"Now presenting...","icon":"http:\/\/assets.tumblr.com\/images\/highlighted_posts\/icons\/megaphone_white.png","color":"#bb3434"},"note_count":7,"title":"Weary v1.0.0","url":"https:\/\/github.com\/mwunsch\/weary\/wiki","description":"<p>April Fools jokes are for chumps. I&#8217;ll choose today to ship software.<\/p>\n\n<p><strong>Weary v1.0.0 is released<\/strong><\/p>\n\n<p>Much more documentation forthcoming. Keep an eye on the wiki and this blog.<\/p>"},{"blog_name":"mwunsch","id":19164961171,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/19164961171\/weary-1-0-0-rc1","slug":"weary-1-0-0-rc1","type":"link","date":"2012-03-12 04:05:17 GMT","timestamp":1331525117,"state":"published","format":"markdown","reblog_key":"AJSThGFZ","tags":["weary","ruby"],"highlighted":{"message":"For Science!","icon":"http:\/\/assets.tumblr.com\/images\/highlighted_posts\/icons\/bolt_white.png","color":"#9c5faf"},"note_count":2,"title":"weary 1.0.0.rc1","url":"https:\/\/rubygems.org\/gems\/weary\/versions\/1.0.0.rc1","description":"<p><code>gem install weary --pre<\/code><\/p>"},{"blog_name":"mwunsch","id":18946326036,"post_url":"http:\/\/mwunsch.tumblr.com\/post\/18946326036\/gilt-technologie-summerqamp-introducing-qa-as-a","slug":"gilt-technologie-summerqamp-introducing-qa-as-a","type":"link","date":"2012-03-08 13:10:43 GMT","timestamp":1331212243,"state":"published","format":"markdown","reblog_key":"IAbIcziG","tags":[],"highlighted":[],"note_count":10,"title":"Gilt Technologie: SummerQAmp: introducing QA as a career opportunity","url":"http:\/\/tech.gilt.com\/post\/18915833538\/summerqamp-introducing-qa-as-a-career-opportunity","description":"<blockquote>\n<p>The tech team at Gilt is excited to launch <strong>SummerQAmp<\/strong> (summer-kamp) with Bon Jovi, the White House, GroupMe and Onswipe. This is a great initiative that is launching as a part of the White House\u2019s Summer Jobs+ program to introduce Quality Assurance as a career path to youth in the U.S.<\/p>\n<p><img align=\"middle\" height=\"238\" src=\"http:\/\/blog.onswipe.com\/wp-content\/uploads\/2012\/03\/summer_qamp_logo.png\" width=\"500\"\/><\/p>\n<\/blockquote>\n\n<p><em>with Bon Jovi<\/em><\/p>"}],"total_posts":303}}
@@ -0,0 +1,12 @@
1
+ require 'tumblr'
2
+ require 'webmock/rspec'
3
+
4
+ WebMock.disable_net_connect!
5
+
6
+ def fixture_path
7
+ File.expand_path("../fixtures", __FILE__)
8
+ end
9
+
10
+ def fixture(filename)
11
+ File.new("#{fixture_path}/#{filename}")
12
+ end
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ describe Tumblr::Authentication do
4
+ require "rack/test"
5
+ include Rack::Test::Methods
6
+
7
+ before do
8
+ stub_request :any, /www\.tumblr.com\/oauth\/.*/
9
+ @tempfile = Tempfile.new("tumblr_credentials")
10
+ described_class.set :credential_path, @tempfile.path
11
+ end
12
+
13
+ after do
14
+ @tempfile.close
15
+ @tempfile.unlink
16
+ end
17
+
18
+ def app
19
+ described_class
20
+ end
21
+
22
+ describe "/" do
23
+ it "returns a 400 when no key or secret is given" do
24
+ get "/"
25
+ last_response.status.should eql 400
26
+ end
27
+
28
+ it "redirects to tumblr for user authorization" do
29
+ get "/", :key => "consumer-key", :secret => "consumer-secret"
30
+ last_response.status.should eql 302
31
+ end
32
+
33
+ it "redirects to tumblr's authorize endpoint" do
34
+ get "/", :key => "consumer-key", :secret => "consumer-secret"
35
+ last_response.location.should match /oauth\/authorize.*/
36
+ end
37
+ end
38
+
39
+ describe "/auth" do
40
+ it "returns a 401 when no params are passed (meaning the user denied)" do
41
+ get "/auth"
42
+ last_response.status.should eql 401
43
+ end
44
+
45
+ it "posts to tumblr to exchange tokens" do
46
+ get "/auth", :oauth_token => "token", :oauth_verifier => "verifier"
47
+ a_request(:post, /oauth\/access_token/).should have_been_made
48
+ end
49
+
50
+ it "writes credentials to the correct path" do
51
+ get "/auth", :oauth_token => "token", :oauth_verifier => "verifier"
52
+ YAML.load(@tempfile.read).should have_key "consumer_key"
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,223 @@
1
+ require "spec_helper"
2
+
3
+ describe Tumblr::Client do
4
+ before do
5
+ @client = described_class.new
6
+ @domain = described_class.domain
7
+ @oauth = {
8
+ :consumer_key => "consumer-key",
9
+ :consumer_secret => "consumer-secret",
10
+ :token => "auth-token",
11
+ :token_secret => "token-secret"
12
+ }
13
+ stub_request :any, /api\.tumblr\.com\/.*/
14
+ end
15
+
16
+ describe "::headers" do
17
+ it "includes the Tumblr client user agent string" do
18
+ described_class.headers["User-Agent"].should match /Tumblr API Client/
19
+ end
20
+ end
21
+
22
+ describe "#info" do
23
+ it "gets the info for a particular blog" do
24
+ api_key = @oauth[:consumer_key]
25
+ hostname = "mwunsch.tumblr.com"
26
+ req = @client.info :api_key => api_key, :hostname => hostname
27
+ req.perform.force
28
+ a_request(:get, "#{@domain}/blog/#{hostname}/info").with(:query => {
29
+ "api_key" => api_key
30
+ }).should have_been_made
31
+ end
32
+ end
33
+
34
+ describe "#avatar" do
35
+ it "gets the avatar for a particular blog" do
36
+ hostname = "mwunsch.tumblr.com"
37
+ req = @client.avatar :hostname => hostname
38
+ req.perform.force
39
+ a_request(:get, "#{@domain}/blog/#{hostname}/avatar").should have_been_made
40
+ end
41
+ end
42
+
43
+ describe "#followers" do
44
+ it "gets the followers for an authorized blog" do
45
+ hostname = "mwunsch.tumblr.com"
46
+ req = @client.followers @oauth.merge(:hostname => hostname)
47
+ req.perform.force
48
+ a_request(:get, "#{@domain}/blog/#{hostname}/followers").with {|request|
49
+ request.headers.has_key? "Authorization"
50
+ }.should have_been_made
51
+ end
52
+ end
53
+
54
+ describe "#posts" do
55
+ it "gets the posts for a particular blog" do
56
+ api_key = @oauth[:consumer_key]
57
+ hostname = "mwunsch.tumblr.com"
58
+ req = @client.posts :api_key => api_key, :hostname => hostname
59
+ req.perform.force
60
+ a_request(:get, "#{@domain}/blog/#{hostname}/posts").with(:query => {
61
+ "api_key" => api_key
62
+ }).should have_been_made
63
+ end
64
+ end
65
+
66
+ describe "#queue" do
67
+ it "gets the contents of a queue for an authorized blog" do
68
+ hostname = "mwunsch.tumblr.com"
69
+ req = @client.queue @oauth.merge(:hostname => hostname)
70
+ req.perform.force
71
+ a_request(:get, "#{@domain}/blog/#{hostname}/posts/queue").with {|request|
72
+ request.headers.has_key? "Authorization"
73
+ }.should have_been_made
74
+ end
75
+ end
76
+
77
+ describe "#draft" do
78
+ it "gets the draft posts for an authorized blog" do
79
+ hostname = "mwunsch.tumblr.com"
80
+ req = @client.draft @oauth.merge(:hostname => hostname)
81
+ req.perform.force
82
+ a_request(:get, "#{@domain}/blog/#{hostname}/posts/draft").with {|request|
83
+ request.headers.has_key? "Authorization"
84
+ }.should have_been_made
85
+ end
86
+ end
87
+
88
+ describe "#submission" do
89
+ it "gets the submission posts for an authorized blog" do
90
+ hostname = "mwunsch.tumblr.com"
91
+ req = @client.submission @oauth.merge(:hostname => hostname)
92
+ req.perform.force
93
+ a_request(:get, "#{@domain}/blog/#{hostname}/posts/submission").with {|request|
94
+ request.headers.has_key? "Authorization"
95
+ }.should have_been_made
96
+ end
97
+ end
98
+
99
+ describe "#post" do
100
+ it "posts to the authorized blog" do
101
+ hostname = "mwunsch.tumblr.com"
102
+ req = @client.post @oauth.merge(:hostname => hostname, :type => "text", :body => "Hello, world.")
103
+ req.perform.force
104
+ a_request(:post, "#{@domain}/blog/#{hostname}/post").with {|request|
105
+ request.headers.has_key? "Authorization" and !request.body.empty?
106
+ }.should have_been_made
107
+ end
108
+ end
109
+
110
+ describe "#edit" do
111
+ it "edits a post of the authorized blog" do
112
+ hostname = "mwunsch.tumblr.com"
113
+ req = @client.edit @oauth.merge(:hostname => hostname, :id => "my-text-post", :body => "Hello, world.")
114
+ req.perform.force
115
+ a_request(:post, "#{@domain}/blog/#{hostname}/post/edit").with {|request|
116
+ request.headers.has_key? "Authorization" and !request.body.empty?
117
+ }.should have_been_made
118
+ end
119
+ end
120
+
121
+ describe "#reblog" do
122
+ it "reblogs a post to the authorized blog" do
123
+ hostname = "mwunsch.tumblr.com"
124
+ req = @client.reblog @oauth.merge(:hostname => hostname, :id => "my-text-post", :reblog_key => "rebloggable")
125
+ req.perform.force
126
+ a_request(:post, "#{@domain}/blog/#{hostname}/post/reblog").with {|request|
127
+ request.headers.has_key? "Authorization" and !request.body.empty?
128
+ }.should have_been_made
129
+ end
130
+ end
131
+
132
+ describe "#user" do
133
+ it "gets the authorized user's account information" do
134
+ req = @client.user @oauth
135
+ req.perform.force
136
+ a_request(:get, "#{@domain}/user/info").with {|request|
137
+ request.headers.has_key? "Authorization"
138
+ }.should have_been_made
139
+ end
140
+ end
141
+
142
+ describe "#dashboard" do
143
+ it "gets the authorized user's dashboard" do
144
+ req = @client.dashboard @oauth
145
+ req.perform.force
146
+ a_request(:get, "#{@domain}/user/dashboard").with {|request|
147
+ request.headers.has_key? "Authorization"
148
+ }.should have_been_made
149
+ end
150
+ end
151
+
152
+ describe "#likes" do
153
+ it "gets the authorized user's likes" do
154
+ req = @client.likes @oauth
155
+ req.perform.force
156
+ a_request(:get, "#{@domain}/user/likes").with {|request|
157
+ request.headers.has_key? "Authorization"
158
+ }.should have_been_made
159
+ end
160
+ end
161
+
162
+ describe "#following" do
163
+ it "gets the authorized user's list of followed users" do
164
+ req = @client.following @oauth
165
+ req.perform.force
166
+ a_request(:get, "#{@domain}/user/following").with {|request|
167
+ request.headers.has_key? "Authorization"
168
+ }.should have_been_made
169
+ end
170
+ end
171
+
172
+ describe "#follow" do
173
+ it "follows a blog" do
174
+ req = @client.follow @oauth.merge(:url => "www.davidslog.com")
175
+ req.perform.force
176
+ a_request(:post, "#{@domain}/user/follow").with {|request|
177
+ request.headers.has_key? "Authorization" and !request.body.empty?
178
+ }.should have_been_made
179
+ end
180
+ end
181
+
182
+ describe "#unfollow" do
183
+ it "unfollows a blog" do
184
+ req = @client.unfollow @oauth.merge(:url => "www.davidslog.com")
185
+ req.perform.force
186
+ a_request(:post, "#{@domain}/user/unfollow").with {|request|
187
+ request.headers.has_key? "Authorization" and !request.body.empty?
188
+ }.should have_been_made
189
+ end
190
+ end
191
+
192
+ describe "#like" do
193
+ it "likes a post" do
194
+ req = @client.like @oauth.merge(:id => "a-post", :reblog_key => "rebloggable")
195
+ req.perform.force
196
+ a_request(:post, "#{@domain}/user/like").with {|request|
197
+ request.headers.has_key? "Authorization" and !request.body.empty?
198
+ }.should have_been_made
199
+ end
200
+ end
201
+
202
+ describe "#unlike" do
203
+ it "unlikes a post" do
204
+ req = @client.unlike @oauth.merge(:id => "a-post", :reblog_key => "rebloggable")
205
+ req.perform.force
206
+ a_request(:post, "#{@domain}/user/unlike").with {|request|
207
+ request.headers.has_key? "Authorization" and !request.body.empty?
208
+ }.should have_been_made
209
+ end
210
+ end
211
+
212
+ describe "#tagged" do
213
+ it "gets posts with a tag" do
214
+ api_key = @oauth[:consumer_key]
215
+ req = @client.tagged :api_key => api_key, :tag => "gif"
216
+ req.perform.force
217
+ a_request(:get, "#{@domain}/tagged").with(:query => {
218
+ "api_key" => api_key,
219
+ "tag" => "gif"
220
+ }).should have_been_made
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+ require 'tumblr/credentials'
3
+
4
+ describe Tumblr::Credentials do
5
+
6
+ describe "#path" do
7
+ it "has a default path of ~/.tumblr" do
8
+ credentials = described_class.new
9
+ credentials.path.should eql File.expand_path("~/.tumblr")
10
+ end
11
+
12
+ it "can be overriden at initialization" do
13
+ credentials = described_class.new("~/.tumblr_oauth")
14
+ credentials.path.should eql File.expand_path("~/.tumblr_oauth")
15
+ end
16
+ end
17
+
18
+ describe "#write" do
19
+ before do
20
+ @tempfile = Tempfile.new("tumblr_credentials")
21
+ @credentials = described_class.new(@tempfile.path)
22
+ @oauth = {
23
+ "consumer_key" => "consumer-key",
24
+ "consumer_secret" => "consumer-secret",
25
+ "token" => "access-token",
26
+ "token_secret" => "token-secret"
27
+ }
28
+ end
29
+
30
+ after do
31
+ @tempfile.close
32
+ @tempfile.unlink
33
+ end
34
+
35
+ it "writes oauth credentials to the path" do
36
+ @credentials.write @oauth["consumer_key"], @oauth["consumer_secret"], @oauth["token"], @oauth["token_secret"]
37
+ @tempfile.read.should eql YAML.dump(@oauth)
38
+ end
39
+ end
40
+
41
+ describe "#read" do
42
+ before do
43
+ @oauth = {
44
+ "consumer_key" => "consumer-key",
45
+ "consumer_secret" => "consumer-secret",
46
+ "token" => "access-token",
47
+ "token_secret" => "token-secret"
48
+ }
49
+ @tempfile = Tempfile.new("tumblr_credentials")
50
+ @tempfile.write YAML.dump(@oauth)
51
+ @tempfile.rewind
52
+ end
53
+
54
+ after do
55
+ @tempfile.close
56
+ @tempfile.unlink
57
+ end
58
+
59
+ it "reads credentials out of the path" do
60
+ described_class.new(@tempfile.path).read.should eql @oauth
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,125 @@
1
+ require "spec_helper"
2
+
3
+ describe Tumblr::Post do
4
+ before do
5
+ @client = Tumblr::Client.new("mwunsch.tumblr.com")
6
+ @request = @client.posts :api_key => "my-consumer-key"
7
+ stub_request(:get, /api\.tumblr\.com\/.+\/posts.+/).to_return fixture('posts.json')
8
+
9
+ end
10
+
11
+ describe "::perform" do
12
+ it "creates a set of Post objects given a request" do
13
+ posts = described_class.perform(@request)
14
+ posts.should be_all {|post| post.is_a? described_class }
15
+ end
16
+ end
17
+
18
+ describe "::create" do
19
+ it "creates a subclass of Post from a post_response" do
20
+ first_post = @request.perform.parse["response"]["posts"].first
21
+ post = described_class.create(first_post)
22
+ post.should be_kind_of Tumblr::Post::Link
23
+ end
24
+ end
25
+
26
+ describe "::load" do
27
+ it "loads a post from a serialized, YAML front-matter format" do
28
+ first_post = @request.perform.parse["response"]["posts"].first
29
+ post = described_class.create(first_post)
30
+
31
+ loaded_post = described_class.load(post.serialize)
32
+ loaded_post.serialize.should eql post.serialize
33
+ end
34
+ end
35
+
36
+ describe "::load_from_path" do
37
+ # The typical_animated_gif.gif c/o topherchris.com
38
+ it "determines post type based on file" do
39
+ post = described_class.load_from_path "#{fixture_path}/typical_animated_gif.gif"
40
+ post.should be_kind_of Tumblr::Post::Photo
41
+ end
42
+
43
+ it "raises an exception when the path is not a file" do
44
+ expect { described_class.load_from_path("#{fixture_path}/foo_bazzy.png") }.to raise_error(ArgumentError)
45
+ end
46
+ end
47
+
48
+ describe "::infer_post_type_from_string" do
49
+ it "infers a video post from youtube" do
50
+ type = described_class.infer_post_type_from_string("http://www.youtube.com/watch?v=9bZkp7q19f0")
51
+ type.should eql :video
52
+ end
53
+
54
+ it "infers a video post from vimeo" do
55
+ type = described_class.infer_post_type_from_string("https://vimeo.com/39610693")
56
+ type.should eql :video
57
+ end
58
+
59
+ it "infers a video post from youtube short url" do
60
+ type = described_class.infer_post_type_from_string("http://youtu.be/9bZkp7q19f0")
61
+ type.should eql :video
62
+ end
63
+
64
+ it "infers a link post from a generic url" do
65
+ type = described_class.infer_post_type_from_string("http://mwunsch.tumblr.com")
66
+ type.should eql :link
67
+ end
68
+
69
+ it "infers an audio post from a spotify url" do
70
+ type = described_class.infer_post_type_from_string("http://open.spotify.com/track/6tGtBvK6DezcjbtUxXGyxe")
71
+ type.should eql :audio
72
+ end
73
+
74
+ it "infers an audio post from a soundcloud url" do
75
+ type = described_class.infer_post_type_from_string("http://soundcloud.com/novasolus/bach-goldberg-variations-1-3")
76
+ type.should eql :audio
77
+ end
78
+
79
+ it "infers an audio post from a soundcloud short url" do
80
+ type = described_class.infer_post_type_from_string("http://snd.sc/YbrmBi")
81
+ type.should eql :audio
82
+ end
83
+
84
+ it "infers an audio post from a spotify direct link" do
85
+ type = described_class.infer_post_type_from_string("spotify:track:6tGtBvK6DezcjbtUxXGyxe")
86
+ type.should eql :audio
87
+ end
88
+
89
+ it "infers a text post from anything else" do
90
+ type = described_class.infer_post_type_from_string("Hi, hows it going?")
91
+ type.should eql :text
92
+ end
93
+
94
+ end
95
+
96
+ describe "#request_parameters" do
97
+ it "transforms a post into a hash for the request" do
98
+ first_post = @request.perform.parse["response"]["posts"].first
99
+ post = described_class.create(first_post)
100
+ post.request_parameters.keys.should be_all do |key|
101
+ (Tumblr::Client::POST_OPTIONS).map(&:to_s).include? key
102
+ end
103
+ end
104
+ end
105
+
106
+ describe "#meta_data" do
107
+ it "excludes post body data from the request parameters" do
108
+ first_post = @request.perform.parse["response"]["posts"].first
109
+ post = described_class.create(first_post)
110
+ post.meta_data.keys.should_not include("description")
111
+ end
112
+ end
113
+
114
+ describe "#serialize" do
115
+ it "transforms the post into a string w/ YAML frontmatter" do
116
+ first_post = @request.perform.parse["response"]["posts"].first
117
+ post = described_class.create(first_post)
118
+ post.serialize =~ /^(\s*---(.*?)---\s*)/m
119
+ YAML.load(Regexp.last_match[2]).should eql post.meta_data
120
+ end
121
+ end
122
+
123
+
124
+
125
+ end