kickscraper 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ module Kickscraper
2
+ class Category < Api
3
+ attr_accessor :projects
4
+
5
+ def to_s
6
+ name
7
+ end
8
+
9
+ def inspect
10
+ "<Category: '#{to_s}'>"
11
+ end
12
+
13
+ def projects
14
+ return [] unless @projects || self.urls.web.discover
15
+ @projects ||= Kickscraper.client.process_api_url("Projects", self.urls.web.discover)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module Kickscraper
2
+ class Comment < Api
3
+
4
+ end
5
+ end
File without changes
File without changes
@@ -0,0 +1,71 @@
1
+ require_relative 'user.rb'
2
+ require_relative 'category.rb'
3
+
4
+ module Kickscraper
5
+ class Project < Api
6
+ coerce_key :creator, Kickscraper::User
7
+ coerce_key :category, Kickscraper::Category
8
+
9
+ attr_accessor :comments, :updates, :rewards
10
+
11
+ def to_s
12
+ name
13
+ end
14
+
15
+ def inspect
16
+ "<Project: '#{to_s}'>"
17
+ end
18
+
19
+ def reload!
20
+ if self.urls.api.nil?
21
+ the_full_project = Kickscraper.client.find_project(self.id)
22
+ project_api_url = the_full_project.nil? ? nil : the_full_project.urls.api.project
23
+ else
24
+ project_api_url = self.urls.api.project
25
+ end
26
+ @raw = Kickscraper.client.process_api_url("Project", project_api_url, false) unless project_api_url.nil?
27
+ Kickscraper::Project::do_coercion(self)
28
+ end
29
+
30
+ def successful?
31
+ pledged >= goal
32
+ end
33
+
34
+ def active?
35
+ state == "live"
36
+ end
37
+
38
+ def comments
39
+ return @comments if @comments
40
+
41
+ # must reload to get urls.api, not returned in public discover search
42
+ reload! unless (self.urls.api && self.urls.api.comments)
43
+
44
+ # if logged in and can use private API, self.urls.api.updates should now be defined
45
+ if (self.urls.api && self.urls.api.updates)
46
+ @comments = Kickscraper.client.process_api_url("Comments", self.urls.api.comments)
47
+ else
48
+ @comments= []
49
+ end
50
+ end
51
+
52
+ def updates
53
+ return @updates if @updates
54
+
55
+ # must reload to get urls.api, not returned in public discover search
56
+ reload! unless (self.urls.api && self.urls.api.updates)
57
+
58
+ # if logged in and can use private API, self.urls.api.updates should now be defined
59
+ if (self.urls.api && self.urls.api.updates)
60
+ @updates = Kickscraper.client.process_api_url("Updates", self.urls.api.updates)
61
+ else
62
+ @updates = []
63
+ end
64
+ end
65
+
66
+ def rewards
67
+ reload! unless @raw['rewards']
68
+ @raw['rewards']
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,5 @@
1
+ module Kickscraper
2
+ class Update < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,34 @@
1
+ module Kickscraper
2
+ class User < Api
3
+ attr_accessor :backed_projects, :starred_projects
4
+
5
+ def to_s
6
+ name
7
+ end
8
+
9
+ def reload!
10
+ @raw = Kickscraper.client.process_api_url("User", self.urls.api.user, false)
11
+ Kickscraper::User::do_coercion(self)
12
+ end
13
+
14
+ def biography
15
+ reload! unless @raw['biography']
16
+ @raw['biography']
17
+ end
18
+
19
+ def backed_projects
20
+ return [] unless self.urls.api.backed_projects
21
+ @backed_projects ||= Kickscraper.client.process_api_url("Projects", self.urls.api.backed_projects)
22
+ end
23
+
24
+ def starred_projects
25
+ return [] unless self.urls.api.starred_projects
26
+ @starred_projects ||= Kickscraper.client.process_api_url("Projects", self.urls.api.starred_projects)
27
+ end
28
+
29
+ def created_projects
30
+ return [] unless self.urls.api.created_projects
31
+ @created_projects ||= Kickscraper.client.process_api_url("Projects", self.urls.api.created_projects)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ module Kickscraper
2
+ module Configure
3
+
4
+ attr_accessor :email, :password, :token, :proxy
5
+
6
+ def configure
7
+ yield self
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,63 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'uri/query_params'
4
+
5
+ class KSToken < Faraday::Middleware
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ # replace '+' symbols in the query params with their original spaces, because there
12
+ # seems to be a bug in the way some versions of Fararay escape parameters with spaces
13
+ env[:url].query_params.each { |key, value|
14
+ env[:url].query_params[key] = value.tr('+', ' ')
15
+ }
16
+
17
+ # add format=json to all public search requests, or add the oauth_token to all api requests once we have it
18
+ if env[:url].to_s.index('https://api.kickstarter.com').nil?
19
+ env[:url].query_params['format'] = 'json'
20
+ else
21
+ env[:url].query_params['oauth_token'] = Kickscraper.token unless Kickscraper.token.nil?
22
+ end
23
+
24
+ # make the call
25
+ @app.call(env)
26
+ end
27
+ end
28
+
29
+ module Kickscraper
30
+ module Connection
31
+
32
+ private
33
+
34
+ def connection(api_or_search = "api")
35
+ options = {
36
+ :headers => {'Accept' => "application/json; charset=utf-8", 'User-Agent' => "Kickscraper/XXX"},
37
+ :ssl => {:verify => false},
38
+ :url => api_or_search == "api" ? "https://api.kickstarter.com" : "https://www.kickstarter.com",
39
+ :proxy => Kickscraper.proxy.nil? ? "" : Kickscraper.proxy
40
+ }
41
+
42
+ if api_or_search == "api"
43
+ @api_connection ||= Faraday::Connection.new(options) do |connection|
44
+ connection.use Faraday::Request::UrlEncoded
45
+ connection.use FaradayMiddleware::Mashify
46
+ connection.use FaradayMiddleware::FollowRedirects
47
+ connection.use Faraday::Response::ParseJson
48
+ connection.use ::KSToken
49
+ connection.adapter(Faraday.default_adapter)
50
+ end
51
+ else
52
+ @search_connection ||= Faraday::Connection.new(options) do |connection|
53
+ connection.use Faraday::Request::UrlEncoded
54
+ connection.use FaradayMiddleware::Mashify
55
+ connection.use FaradayMiddleware::FollowRedirects
56
+ connection.use Faraday::Response::ParseJson
57
+ connection.use ::KSToken
58
+ connection.adapter(Faraday.default_adapter)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,15 @@
1
+ module Kickscraper
2
+ class Response
3
+
4
+ attr_accessor :body
5
+
6
+ def initialize(res)
7
+ @body = res.body
8
+ return res.body
9
+ end
10
+
11
+ def error?
12
+ return false
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Kickscraper
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,26 @@
1
+ describe Kickscraper::Category do
2
+ let(:client) { Kickscraper.client }
3
+ let(:category) { client.categories.first }
4
+
5
+ context "loading category info" do
6
+ subject { category }
7
+
8
+ it { should be_a Kickscraper::Category }
9
+ its(:name) { should_not be_empty }
10
+ its(:projects_count) { should be > 0 }
11
+ end
12
+
13
+ context "urls" do
14
+ subject { category.urls }
15
+
16
+ it { should_not be_empty }
17
+ its(:web) { should_not be_empty }
18
+ end
19
+
20
+
21
+ context "projects" do
22
+ subject { category.projects }
23
+ it_returns "a collection", Kickscraper::Project
24
+ end
25
+ end
26
+
@@ -0,0 +1,84 @@
1
+ describe Kickscraper::Client do
2
+ let(:client) { Kickscraper.client }
3
+
4
+ context "finds a user by id" do
5
+ subject(:user) { client.find_user TEST_USER_ID }
6
+
7
+ its(:id) { should == TEST_USER_ID }
8
+ its(:name) { should == 'Zach Braff' }
9
+ end
10
+
11
+ context "returns nil when finding a non-existent user" do
12
+ subject { client.find_user 9999 }
13
+
14
+ it { should be_nil }
15
+ end
16
+
17
+ context "finds a project by id" do
18
+ subject(:project) { client.find_project TEST_PROJECT_ID }
19
+
20
+ its(:id) { should == TEST_PROJECT_ID }
21
+ its(:slug) { should == TEST_PROJECT_SLUG }
22
+ its(:name) { should == TEST_PROJECT_NAME }
23
+ end
24
+
25
+ context "finds a project by slug" do
26
+ subject(:project) { client.find_project TEST_PROJECT_SLUG }
27
+
28
+ its(:id) { should == TEST_PROJECT_ID }
29
+ its(:slug) { should == TEST_PROJECT_SLUG }
30
+ its(:name) { should == TEST_PROJECT_NAME }
31
+ end
32
+
33
+ context "returns nil when finding a non-existent project" do
34
+ subject { client.find_project 9999 }
35
+ it { should be_nil }
36
+ end
37
+
38
+ describe ".ending_soon_projects" do
39
+ it_behaves_like "ending_soon projects"
40
+ end
41
+
42
+ describe ".recently_launched_project" do
43
+ it_behaves_like "recently_launched projects"
44
+ end
45
+
46
+ # findes recently launched projects with the 'newest_projects' method for backwards compatibility
47
+ describe ".newest_projects" do
48
+ it_behaves_like "newest_projects projects"
49
+ end
50
+
51
+ describe ".popular_projects" do
52
+ it_behaves_like "popular projects"
53
+ end
54
+
55
+ describe ".search_project" do
56
+ it_behaves_like "search projects"
57
+ end
58
+
59
+ # context "loads recently launched projects starting at a specific timestamp" do
60
+ # subject { client.recently_launched_projects((Time.now - (2 * 24 * 60 * 60)).to_i) }
61
+ # it_returns "a collection", Kickscraper::Project
62
+ # end
63
+
64
+ # context "loads projects ending soon starting at a specific deadline" do
65
+ # subject { client.ending_soon_projects((Time.now + (2 * 24 * 60 * 60)).to_i) }
66
+ # it_returns "a collection", Kickscraper::Project
67
+ # end
68
+
69
+ context "lists all categories" do
70
+ subject { client.categories }
71
+ it_returns "a collection", Kickscraper::Category
72
+ end
73
+
74
+ context "loads a category from string" do
75
+ subject { client.category(TEST_CATEGORY_NAME) }
76
+ its(:name) { should eq TEST_CATEGORY_NAME }
77
+ end
78
+
79
+ context "loads a category from an id" do
80
+ subject { client.category(TEST_CATEGORY_ID) }
81
+ its(:name) { should eq TEST_CATEGORY_NAME }
82
+ end
83
+
84
+ end
@@ -0,0 +1,16 @@
1
+ describe Kickscraper do
2
+ subject { Kickscraper.client }
3
+
4
+ it "accepts configuration" do
5
+ Kickscraper.email.should == KICKSCRAPER_TEST_API_EMAIL
6
+ end
7
+
8
+ context "connects to the kickstarter api" do
9
+ it { should_not be_nil }
10
+ it { should be_a Kickscraper::Client }
11
+
12
+ its(:user) { should_not be_nil }
13
+ its(:user) { should be_a Kickscraper::User }
14
+ end
15
+
16
+ end
@@ -0,0 +1,73 @@
1
+ describe Kickscraper::Client do
2
+ context "no email no password client" do
3
+ before(:all) do
4
+ @save_token = Kickscraper.token
5
+ Kickscraper.token=nil
6
+ end
7
+
8
+ after (:all) do
9
+ Kickscraper.token=@save_token
10
+ end
11
+
12
+ let(:client) do
13
+ Kickscraper.configure do |config|
14
+ config.email = nil
15
+ config.password = nil
16
+ end
17
+ Kickscraper::Client.new
18
+ end
19
+
20
+ describe ".find_user" do
21
+ subject(:user) { client.find_user TEST_USER_ID }
22
+
23
+ it { should be_nil } # don't know how to do on purely Public API
24
+ end
25
+
26
+ describe ".find_product" do
27
+ subject(:project) { client.find_project TEST_PROJECT_ID }
28
+
29
+ it { should be_nil } # don't know how to do on purely Public API
30
+ end
31
+
32
+ describe ".categories" do
33
+ subject { client.categories }
34
+
35
+ it { should eq [] } # don't know how to do on purely Public API
36
+ end
37
+
38
+ describe ".category" do
39
+ context "loads a category from string" do
40
+ subject { client.category(TEST_CATEGORY_NAME) }
41
+
42
+ it { should be_nil } # don't know how to do on purely Public API
43
+ end
44
+
45
+ context "loads a category from an id" do
46
+ subject { client.category(TEST_CATEGORY_ID) }
47
+
48
+ it { should be_nil } # don't know how to do on purely Public API
49
+ end
50
+ end
51
+
52
+ describe ".ending_soon_projects" do
53
+ it_behaves_like "ending_soon projects"
54
+ end
55
+
56
+ describe ".recently_launched_project" do
57
+ it_behaves_like "recently_launched projects"
58
+ end
59
+
60
+ # findes recently launched projects with the 'newest_projects' method for backwards compatibility
61
+ describe ".newest_projects" do
62
+ it_behaves_like "newest_projects projects"
63
+ end
64
+
65
+ describe ".popular_projects" do
66
+ it_behaves_like "popular projects"
67
+ end
68
+
69
+ describe ".search_project" do
70
+ it_behaves_like "search projects"
71
+ end
72
+ end
73
+ end