From 73d54e48dde288d430c6ff56d5354fd009e060f5 Mon Sep 17 00:00:00 2001 From: Rob Sanheim Date: Sat, 26 Nov 2011 21:54:54 -0500 Subject: [PATCH 1/6] getting specs wired up --- Gemfile | 7 ++++++- Gemfile.lock | 7 +++++++ app.rb | 5 +---- spec/app_spec.rb | 29 +++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 spec/app_spec.rb diff --git a/Gemfile b/Gemfile index acf81a3..138e781 100644 --- a/Gemfile +++ b/Gemfile @@ -6,4 +6,9 @@ gem "sinatra-static-assets" gem "maruku" gem "swish" gem "twitter" -gem "heroku" \ No newline at end of file +gem "heroku" + +group :test do + gem "rack-test" + gem "mocha" +end diff --git a/Gemfile.lock b/Gemfile.lock index 30c87c3..8d48a82 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -25,11 +25,16 @@ GEM addressable (~> 2.2.6) maruku (0.6.0) syntax (>= 1.0.0) + metaclass (0.0.1) mime-types (1.17.2) + mocha (0.10.0) + metaclass (~> 0.0.1) multi_json (1.0.3) multi_xml (0.4.1) multipart-post (1.1.3) rack (1.2.1) + rack-test (0.6.1) + rack (>= 1.0) rest-client (1.6.7) mime-types (>= 1.16) rubyzip (0.9.4) @@ -62,7 +67,9 @@ DEPENDENCIES haml heroku maruku + mocha rack + rack-test sinatra (= 1.1.2) sinatra-static-assets swish diff --git a/app.rb b/app.rb index 7bebcf5..1a86d87 100644 --- a/app.rb +++ b/app.rb @@ -6,7 +6,6 @@ require 'swish' require 'twitter' - # FOR BASIC AUTH USE BELOW, REPLACE ['username', 'password'] with actual credentials # use Rack::Auth::Basic do |username, password| # [username, password] == ['username', 'password'] @@ -15,12 +14,10 @@ set :haml, {:format => :html5} get '/' do - @page_title = "Artist & Designer at Relevance, Inc. in Durham, NC" # @tweet = Twitter.user_timeline("parenteau").first.text @player = Dribbble::Player.find('michaelparenteau') @shot = @player.shots.first haml :index - -end \ No newline at end of file +end diff --git a/spec/app_spec.rb b/spec/app_spec.rb new file mode 100644 index 0000000..9542bab --- /dev/null +++ b/spec/app_spec.rb @@ -0,0 +1,29 @@ +$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[..]) +Bundler.require(:test) +ENV['RACK_ENV'] = 'test' +require 'app' +require 'test/unit' +require 'mocha' +require 'rack/test' + +class AppTest < Test::Unit::TestCase + include Mocha::API + include Rack::Test::Methods + + def app + Sinatra::Application + end + + def test_good_response + get '/' + assert last_response.ok? + end + + def test_grabs_latest_tweet + foo = mock(:foo => "bar") + foo.bar + # app.expects(:last_tweet).returns("this is a tweet!") + get "/" + # assert last_response.body.include?("this is a tweet!") + end +end From 66d425b4338ecc6bfe5a816381e5e23727163452 Mon Sep 17 00:00:00 2001 From: Rob Sanheim Date: Sat, 26 Nov 2011 22:12:51 -0500 Subject: [PATCH 2/6] using rspec and stuff --- Gemfile | 2 ++ Gemfile.lock | 12 ++++++++++++ Rakefile | 10 ++++++++++ spec/app_spec.rb | 17 +++++++++-------- 4 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 Rakefile diff --git a/Gemfile b/Gemfile index 138e781..20071ea 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,5 @@ source "http://rubygems.org" +gem "rake" gem "rack" gem "sinatra", "1.1.2", :require => "sinatra" gem "haml" @@ -11,4 +12,5 @@ gem "heroku" group :test do gem "rack-test" gem "mocha" + gem "rspec" end diff --git a/Gemfile.lock b/Gemfile.lock index 8d48a82..7e92424 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,6 +3,7 @@ GEM specs: addressable (2.2.6) crack (0.3.1) + diff-lcs (1.1.3) emk-sinatra-url-for (0.2.1) sinatra (>= 0.9.1.1) faraday (0.7.5) @@ -35,8 +36,17 @@ GEM rack (1.2.1) rack-test (0.6.1) rack (>= 1.0) + rake (0.9.2.2) rest-client (1.6.7) mime-types (>= 1.16) + rspec (2.7.0) + rspec-core (~> 2.7.0) + rspec-expectations (~> 2.7.0) + rspec-mocks (~> 2.7.0) + rspec-core (2.7.1) + rspec-expectations (2.7.0) + diff-lcs (~> 1.1.2) + rspec-mocks (2.7.0) rubyzip (0.9.4) simple_oauth (0.1.5) sinatra (1.1.2) @@ -70,6 +80,8 @@ DEPENDENCIES mocha rack rack-test + rake + rspec sinatra (= 1.1.2) sinatra-static-assets swish diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d2e1cbb --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +require 'rubygems' +require "bundler/setup" +# require File.join(File.dirname(__FILE__), *%w[lib nachos version]) + +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) + +task :default => [:spec] + diff --git a/spec/app_spec.rb b/spec/app_spec.rb index 9542bab..efbdd74 100644 --- a/spec/app_spec.rb +++ b/spec/app_spec.rb @@ -2,26 +2,27 @@ Bundler.require(:test) ENV['RACK_ENV'] = 'test' require 'app' -require 'test/unit' +require 'rspec' require 'mocha' require 'rack/test' -class AppTest < Test::Unit::TestCase - include Mocha::API - include Rack::Test::Methods +RSpec.configure do |conf| + conf.include Rack::Test::Methods + conf.mock_with :mocha +end +describe "the App" do def app Sinatra::Application end - def test_good_response + it "has a good response" do get '/' - assert last_response.ok? + last_response.should be_ok end - def test_grabs_latest_tweet + it "grabs the latest tweet" do foo = mock(:foo => "bar") - foo.bar # app.expects(:last_tweet).returns("this is a tweet!") get "/" # assert last_response.body.include?("this is a tweet!") From e13447002909a362d4f622cb17540ac315150240 Mon Sep 17 00:00:00 2001 From: Rob Sanheim Date: Sat, 26 Nov 2011 22:15:03 -0500 Subject: [PATCH 3/6] document the specs --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 8dbf803..e74e2fa 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,16 @@ This is my playground. I will have a place to show my artwork, some of my user interface design and I will also start making some poster-like blog posts. I had a lot of fun making all of this so far and plan on continuing the theme. All art, design and development was done by me. You can see it all here, even the PSD. Enjoy +## Running Specs + +Simple spec suite using RSpec/Mocha can be run via: + + rake # the default task runs the whole suite + +Or + + bundle exec rspec + ## Tech Used: * [Sinatra](http://sinatrarb.com) (Ruby and Rubygems) From 80ed7aeec03e3daa24cdf3a10a914844f4955329 Mon Sep 17 00:00:00 2001 From: Rob Sanheim Date: Sat, 26 Nov 2011 23:06:30 -0500 Subject: [PATCH 4/6] Bring back the tweets... - using ActiveSupport Cache (in memory only) to store last tweets - last tweet will be stored for four hours by default - bring in guard to speed up dev with fast spec runs - show the time out message for tweets only if there wasn't a tweet found --- Gemfile | 5 +++++ Gemfile.lock | 14 ++++++++++++++ Guardfile | 13 +++++++++++++ Rakefile | 6 ++---- app.rb | 29 ++++++++++++++++++----------- spec/app_spec.rb | 23 +++++++++++++++++++---- views/index.haml | 8 +++++--- 7 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 Guardfile diff --git a/Gemfile b/Gemfile index 20071ea..8537fae 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,6 @@ source "http://rubygems.org" +gem "i18n" +gem "activesupport", "~> 3.1", :require => nil gem "rake" gem "rack" gem "sinatra", "1.1.2", :require => "sinatra" @@ -10,7 +12,10 @@ gem "twitter" gem "heroku" group :test do + gem "fakeweb" gem "rack-test" gem "mocha" gem "rspec" + gem "guard" + gem "guard-rspec" end diff --git a/Gemfile.lock b/Gemfile.lock index 7e92424..07f7f95 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,17 +1,24 @@ GEM remote: http://rubygems.org/ specs: + activesupport (3.1.3) + multi_json (~> 1.0) addressable (2.2.6) crack (0.3.1) diff-lcs (1.1.3) emk-sinatra-url-for (0.2.1) sinatra (>= 0.9.1.1) + fakeweb (1.3.0) faraday (0.7.5) addressable (~> 2.2.6) multipart-post (~> 1.1.3) rack (>= 1.1.0, < 2) faraday_middleware (0.7.0) faraday (~> 0.7.3) + guard (0.8.8) + thor (~> 0.14.6) + guard-rspec (0.5.7) + guard (>= 0.8.4) haml (3.0.25) hashie (1.1.0) heroku (2.11.0) @@ -22,6 +29,7 @@ GEM httparty (0.8.1) multi_json multi_xml + i18n (0.6.0) launchy (2.0.5) addressable (~> 2.2.6) maruku (0.6.0) @@ -61,6 +69,7 @@ GEM httparty (>= 0.6.1) syntax (1.0.0) term-ansicolor (1.0.7) + thor (0.14.6) tilt (1.2.2) twitter (1.7.2) faraday (~> 0.7.4) @@ -74,8 +83,13 @@ PLATFORMS ruby DEPENDENCIES + activesupport (~> 3.1) + fakeweb + guard + guard-rspec haml heroku + i18n maruku mocha rack diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..84d7101 --- /dev/null +++ b/Guardfile @@ -0,0 +1,13 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +guard 'rspec', :version => 2 do + watch(%r{^spec/.+_spec\.rb$}) + watch('spec/spec_helper.rb') { "spec" } + watch('app.rb') { "spec" } + watch(%r{^(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } + watch(%r{^spec/support/(.+)\.rb$}) { "spec" } + watch('spec/spec_helper.rb') { "spec" } +end + diff --git a/Rakefile b/Rakefile index d2e1cbb..0a7549b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,8 +1,6 @@ -require 'rubygems' +require "rubygems" require "bundler/setup" -# require File.join(File.dirname(__FILE__), *%w[lib nachos version]) - -require 'rspec/core/rake_task' +require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) diff --git a/app.rb b/app.rb index 1a86d87..19fdd2a 100644 --- a/app.rb +++ b/app.rb @@ -2,22 +2,29 @@ require "bundler/setup" require "rack" require "sinatra" -require 'sinatra/static_assets' -require 'swish' -require 'twitter' +require "sinatra/static_assets" +require "swish" +require "twitter" +require "active_support/cache" -# FOR BASIC AUTH USE BELOW, REPLACE ['username', 'password'] with actual credentials -# use Rack::Auth::Basic do |username, password| -# [username, password] == ['username', 'password'] -# end +DefaultCacheExpirationTime = 4.hours set :haml, {:format => :html5} +set :cache, ActiveSupport::Cache::MemoryStore.new(:expires_in => DefaultCacheExpirationTime) get '/' do @page_title = "Artist & Designer at Relevance, Inc. in Durham, NC" - # @tweet = Twitter.user_timeline("parenteau").first.text - @player = Dribbble::Player.find('michaelparenteau') - @shot = @player.shots.first - + @tweet = last_tweet + @shot = last_shot haml :index end + +def last_shot + Dribbble::Player.find('michaelparenteau').shots.first +end + +def last_tweet + settings.cache.fetch(:last_tweet) do + Twitter.user_timeline("parenteau").first.text + end +end diff --git a/spec/app_spec.rb b/spec/app_spec.rb index efbdd74..e915b96 100644 --- a/spec/app_spec.rb +++ b/spec/app_spec.rb @@ -16,15 +16,30 @@ def app Sinatra::Application end + before do + # Don't allow any real http requests -- we don't want Dribble or Twitter + # requests happening during test runs + FakeWeb.allow_net_connect = false + end + it "has a good response" do + app.any_instance.stubs(:last_shot).returns(stub_everything("dribble shot")) + app.any_instance.stubs(:last_tweet).returns("some tweet") get '/' last_response.should be_ok end - it "grabs the latest tweet" do - foo = mock(:foo => "bar") - # app.expects(:last_tweet).returns("this is a tweet!") + it "shows friendly error message if tweets can't be loaded" do + app.any_instance.stubs(:last_shot).returns(stub_everything("dribble shot")) + app.any_instance.expects(:last_tweet).returns(nil) + get "/" + last_response.body.should include("Twitter requests are timing out") + end + + it "shows the latest tweet" do + app.any_instance.stubs(:last_shot).returns(stub_everything("dribble shot")) + app.any_instance.expects(:last_tweet).returns("this is a tweet!") get "/" - # assert last_response.body.include?("this is a tweet!") + last_response.body.should include("this is a tweet!") end end diff --git a/views/index.haml b/views/index.haml index f73c5f6..038ce0b 100644 --- a/views/index.haml +++ b/views/index.haml @@ -13,8 +13,10 @@ %a{:href => 'http://twitter.com/michaelparenteau',:target => '_blank'} twitter .tweet %p - Twitter requests are timing out... sorry, this is not the tweet you are looking for. - / = @tweet + -if @tweet.nil? + Twitter requests are timing out... sorry, this is not the tweet you are looking for. + -else + = @tweet .four.columns.ampersand =image_tag("/images/ampersand.png", :alt => "Ampersand (&)") .six.columns.dribbble @@ -25,4 +27,4 @@ .clear .sixteen.columns.surfer-and-fish-water - =image_tag("/images/surfer-and-fish-water.png", :alt => "Cyclops alien on a surfboard chasing 3 flying fish") \ No newline at end of file + =image_tag("/images/surfer-and-fish-water.png", :alt => "Cyclops alien on a surfboard chasing 3 flying fish") From ac6e7846ef6bb0026910256a88bc35ca47d51d52 Mon Sep 17 00:00:00 2001 From: Rob Sanheim Date: Sat, 26 Nov 2011 23:10:35 -0500 Subject: [PATCH 5/6] make sure we don't die if Twitter blows up --- app.rb | 8 +++++++- spec/app_spec.rb | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app.rb b/app.rb index 19fdd2a..48dc70f 100644 --- a/app.rb +++ b/app.rb @@ -25,6 +25,12 @@ def last_shot def last_tweet settings.cache.fetch(:last_tweet) do - Twitter.user_timeline("parenteau").first.text + begin + Twitter.user_timeline("parenteau").first.text + rescue => e + $stderr.puts "Could not retrieve latest tweet!" + $stderr.puts e + nil + end end end diff --git a/spec/app_spec.rb b/spec/app_spec.rb index e915b96..78318d9 100644 --- a/spec/app_spec.rb +++ b/spec/app_spec.rb @@ -36,6 +36,13 @@ def app last_response.body.should include("Twitter requests are timing out") end + it "shows friendly error message if twitter raises an exception" do + app.any_instance.stubs(:last_shot).returns(stub_everything("dribble shot")) + Twitter.expects(:user_timeline).raises(RuntimeError) + get "/" + last_response.body.should include("Twitter requests are timing out") + end + it "shows the latest tweet" do app.any_instance.stubs(:last_shot).returns(stub_everything("dribble shot")) app.any_instance.expects(:last_tweet).returns("this is a tweet!") From 268243d720a90cdfc1852e1e68f633df03487a10 Mon Sep 17 00:00:00 2001 From: Rob Sanheim Date: Sat, 26 Nov 2011 23:11:08 -0500 Subject: [PATCH 6/6] document guard --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e74e2fa..df4eb05 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ Simple spec suite using RSpec/Mocha can be run via: rake # the default task runs the whole suite -Or +Or for automatic test runs while developing: - bundle exec rspec + bundle exec guard ## Tech Used: