From 2c5f6cd1d121557d729d2f0689a509a847507488 Mon Sep 17 00:00:00 2001 From: AJ Kerrigan Date: Fri, 13 Dec 2013 02:20:31 -0500 Subject: [PATCH 1/3] Add attribute accessors for Updates Provide sequence number, title and body members. --- lib/kickscraper/client/update.rb | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/kickscraper/client/update.rb b/lib/kickscraper/client/update.rb index 1df961b..12118e1 100644 --- a/lib/kickscraper/client/update.rb +++ b/lib/kickscraper/client/update.rb @@ -1,5 +1,26 @@ module Kickscraper class Update < Api - + attr_accessor :sequence, :title, :body + + def reload! + @raw = Kickscraper.client.process_api_url("Update", self.urls.api.update, false) + Kickscraper::Update::do_coercion(self) + end + + def sequence + reload! unless @raw['sequence'] + @raw['sequence'] + end + + def title + reload! unless @raw['title'] + @raw['title'] + end + + def body + reload! unless @raw['body'] + @raw['body'] + end + end end \ No newline at end of file From 67641a92229f20dd8a0bcd2d1895ff8a306cf48d Mon Sep 17 00:00:00 2001 From: AJ Kerrigan Date: Thu, 19 Dec 2013 00:10:41 -0500 Subject: [PATCH 2/3] Add ability to load more Updates if present Add methods to check for the presence of "more updates" and load them if possible. Mirror the "more projects" functionality for the sake of consistency. --- lib/kickscraper/client.rb | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/kickscraper/client.rb b/lib/kickscraper/client.rb index 1c013ff..ce68d66 100644 --- a/lib/kickscraper/client.rb +++ b/lib/kickscraper/client.rb @@ -58,6 +58,20 @@ def load_more_projects end end + def more_updates_available? + !@more_updates_url.nil? + end + + alias_method :can_load_more_updates, :more_updates_available? + + def load_more_updates + if self::more_updates_available? + self::process_api_url "updates", @more_updates_url + else + [] + end + end + def categories self::process_api_call "categories", "" end @@ -159,8 +173,19 @@ def coerce_api_response(expected_type, response) when "updates" - return empty_response if body.updates.nil? - body.updates.map { |update| Update.coerce update } + # Return an empty result set if the body has no updates + if body.updates.nil? + + @more_updates_url = nil + return empty_response + + # Otherwise, set the url that holds the next batch of updates (if available) + # and return an array of updates + else + + @more_updates_url = (!body.urls.nil? && !body.urls.api.nil? && !body.urls.api.more_updates.nil? && !body.urls.api.more_updates.empty?) ? body.urls.api.more_updates : nil + return body.updates.map { |update| Update.coerce update } + end when "categories" From 3f962fb14e75f85d7848e49621fce85475354e8d Mon Sep 17 00:00:00 2001 From: AJ Kerrigan Date: Mon, 23 Dec 2013 02:51:15 -0500 Subject: [PATCH 3/3] Add tests for update functionality - Add an update spec to test operations that apply to individual updates - Add tests to the client spec for higher level operations that touch updates in bulk --- lib/kickscraper/client.rb | 4 ++++ lib/kickscraper/client/update.rb | 12 ++++++++++- spec/client_spec.rb | 21 ++++++++++++++++++++ spec/test_constants.rb | 3 ++- spec/update_spec.rb | 34 ++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 spec/update_spec.rb diff --git a/lib/kickscraper/client.rb b/lib/kickscraper/client.rb index ce68d66..8c7b2c9 100644 --- a/lib/kickscraper/client.rb +++ b/lib/kickscraper/client.rb @@ -170,6 +170,10 @@ def coerce_api_response(expected_type, response) return empty_response if body.comments.nil? body.comments.map { |comment| Comment.coerce comment } + + when "update" + + Update.coerce body when "updates" diff --git a/lib/kickscraper/client/update.rb b/lib/kickscraper/client/update.rb index 12118e1..baef089 100644 --- a/lib/kickscraper/client/update.rb +++ b/lib/kickscraper/client/update.rb @@ -2,8 +2,18 @@ module Kickscraper class Update < Api attr_accessor :sequence, :title, :body + def to_s + "Update \##{sequence}: #{title}" + end + + def inspect + "" + end + def reload! - @raw = Kickscraper.client.process_api_url("Update", self.urls.api.update, false) + # The API URL must be specified here as api['update'], because api.update refers to the + # update method inherited from Hashie + @raw = Kickscraper.client.process_api_url("Update", self.urls.api['update'], false) Kickscraper::Update::do_coercion(self) end diff --git a/spec/client_spec.rb b/spec/client_spec.rb index 3e8917d..6d76ffc 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -128,4 +128,25 @@ its(:name) { should eq TEST_CATEGORY_NAME } end + context "returns an array of updates when a valid project is loaded" do + subject { client.find_project(TEST_PROJECT_ID).updates } + it_returns "a collection", Kickscraper::Update + end + + context "loads more updates when available" do + before { client.find_project(TEST_PROJECT_ID) } + subject do + client.more_updates_available?.should be_true + client.load_more_updates + end + + it_returns "a collection", Kickscraper::Update + end + + it "throws an error when accessing updates without a valid project loaded" do + subject { client.find_project TEST_PROJECT_ID } + expect { subject.to be_nil } + expect { subject.updates }.to raise_error + end + end diff --git a/spec/test_constants.rb b/spec/test_constants.rb index 2991072..bb4bf58 100644 --- a/spec/test_constants.rb +++ b/spec/test_constants.rb @@ -15,4 +15,5 @@ TEST_PROJECT_SLUG = 'wish-i-was-here-1' TEST_PROJECT_NAME = "WISH I WAS HERE" TEST_CATEGORY_NAME = 'Design' -TEST_CATEGORY_ID = 7 \ No newline at end of file +TEST_CATEGORY_ID = 7 +TEST_PUBLIC_UPDATE_URL = 'https://api.kickstarter.com/v1/projects/1871494789/updates/462776' \ No newline at end of file diff --git a/spec/update_spec.rb b/spec/update_spec.rb new file mode 100644 index 0000000..e23a208 --- /dev/null +++ b/spec/update_spec.rb @@ -0,0 +1,34 @@ +describe Kickscraper::Update do + let(:client) { Kickscraper.client } + subject(:update) { client.find_project(TEST_PROJECT_ID).updates.first } + + context "loads basic update information" do + its(:id) { should be > 0 } + its(:project_id) { should be > 0 } + its(:sequence) { should be > 0 } + its(:public) { should satisfy { |s| [true,false].include?(s) } } + its(:visible) { should satisfy { |s| [true,false].include?(s) } } + its(:title) { should_not be_empty } + its(:published_at) { should be >= 1262304000 } + its(:updated_at) { should be >= 1262304000 } + its(:comments_count) { should be >= 0 } + its(:likes_count) { should be >= 0 } + end + + context "reloads" do + before { update.reload! } + + its(:sequence) { should be > 0 } + its(:title) { should_not be_empty } + end + + context "loads additional information for a visible update" do + # Ensure that this test runs on a public update, so its success does not + # depend on the user running the tests + subject { client.process_api_url("update", TEST_PUBLIC_UPDATE_URL) } + + its(:body) { should_not be_empty } + its(:images) { should have_at_least(0).items } + its(:sounds) { should have_at_least(0).items } + end +end \ No newline at end of file