croudia 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/croudia.gemspec +21 -0
- data/lib/croudia/api.rb +5 -0
- data/lib/croudia/identity.rb +39 -0
- data/lib/croudia/scraper/friendships.rb +33 -0
- data/lib/croudia/scraper/login.rb +40 -0
- data/lib/croudia/scraper/parser/users.rb +53 -0
- data/lib/croudia/scraper/parser/voices.rb +32 -0
- data/lib/croudia/scraper/parser.rb +13 -0
- data/lib/croudia/scraper/users.rb +20 -0
- data/lib/croudia/scraper/voices.rb +27 -0
- data/lib/croudia/scraper.rb +62 -0
- data/lib/croudia/user.rb +43 -0
- data/lib/croudia/version.rb +3 -0
- data/lib/croudia/voice.rb +21 -0
- data/lib/croudia.rb +23 -0
- data/spec/croudia/api_spec.rb +7 -0
- data/spec/croudia/identity_spec.rb +65 -0
- data/spec/croudia/scraper/friendships_spec.rb +61 -0
- data/spec/croudia/scraper/login_spec.rb +135 -0
- data/spec/croudia/scraper/parser/users_spec.rb +256 -0
- data/spec/croudia/scraper/parser/voices_spec.rb +119 -0
- data/spec/croudia/scraper/users_spec.rb +74 -0
- data/spec/croudia/scraper/voices_spec.rb +92 -0
- data/spec/croudia/scraper_spec.rb +120 -0
- data/spec/croudia/user_spec.rb +43 -0
- data/spec/croudia/version_spec.rb +7 -0
- data/spec/croudia/voice_spec.rb +16 -0
- data/spec/croudia_spec.rb +49 -0
- data/spec/fixtures/follower_wktk.html +89 -0
- data/spec/fixtures/following_wktk.html +89 -0
- data/spec/fixtures/user_wktk1.html +72 -0
- data/spec/fixtures/user_wktk2.html +75 -0
- data/spec/fixtures/user_wktk3.html +83 -0
- data/spec/fixtures/voices_reply_list.html +55 -0
- data/spec/fixtures/voices_timeline.html +60 -0
- data/spec/fixtures/voices_written.html +20 -0
- data/spec/helper.rb +32 -0
- metadata +157 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 wktk
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Croudia
|
2
|
+
|
3
|
+
A Mechanize-based Ruby scraper for [Croudia](https://croudia.com)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'croudia'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install croudia
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/croudia.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/croudia/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['wktk']
|
6
|
+
gem.email = ['wktk@wktk.in']
|
7
|
+
gem.description = 'A Mechanize-based Ruby scraper for Croudia'
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.homepage = 'https://github.com/wktk/croudia-gem'
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = 'croudia'
|
15
|
+
gem.require_paths = ['lib']
|
16
|
+
gem.version = Croudia::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'mechanize', '~> 2.5.1'
|
19
|
+
gem.add_development_dependency 'rspec', '~> 2.10.1'
|
20
|
+
gem.add_development_dependency 'webmock', '~> 1.8.7'
|
21
|
+
end
|
data/lib/croudia/api.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Croudia
|
2
|
+
class Identity
|
3
|
+
attr_reader :id, :time
|
4
|
+
alias id_str id
|
5
|
+
alias created_at time
|
6
|
+
|
7
|
+
def initialize(attrs)
|
8
|
+
attrs.keys.each do |key|
|
9
|
+
if 'time' == key.to_s && !attrs[key].is_a?(Time)
|
10
|
+
if /^\d+$/ =~ attrs[key]
|
11
|
+
attrs[key] = Time.at(attrs[key].to_i)
|
12
|
+
else
|
13
|
+
attrs[key] = Time.new(*attrs[key].split(/\D/))
|
14
|
+
end
|
15
|
+
elsif /_count$/ =~ key.to_s
|
16
|
+
attrs[key] = attrs[key].to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
instance_variable_set(:"@#{key}", attrs[key])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
super || self.class == other.class && @id == other.id
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](name)
|
28
|
+
instance_variable_get(:"@#{name}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def id
|
32
|
+
@id
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(name, *args)
|
36
|
+
self[name]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Croudia
|
2
|
+
class Scraper
|
3
|
+
module Friendships
|
4
|
+
def follow(username)
|
5
|
+
require_login
|
6
|
+
post('/follows/target_follow',
|
7
|
+
:target_user_name => username,
|
8
|
+
:follow_action => 'enable',
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def unfollow(username)
|
13
|
+
require_login
|
14
|
+
post('/follows/target_follow',
|
15
|
+
:target_user_name => username,
|
16
|
+
:follow_action => 'diable', # Yes, it is!
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def following(username=nil, params={})
|
21
|
+
username = @current_user.username unless username
|
22
|
+
Parser.user_list(get("/follows/following/#{username}", params))
|
23
|
+
end
|
24
|
+
alias followings following
|
25
|
+
|
26
|
+
def follower(username=nil, params={})
|
27
|
+
username = @current_user.username unless username
|
28
|
+
Parser.user_list(get("/follows/follower/#{username}", params))
|
29
|
+
end
|
30
|
+
alias followers follower
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Croudia
|
2
|
+
class Scraper
|
3
|
+
module Login
|
4
|
+
def login(username, password)
|
5
|
+
get('/')
|
6
|
+
params = {
|
7
|
+
:username => username,
|
8
|
+
:password => password,
|
9
|
+
:auto_login => 'on',
|
10
|
+
}
|
11
|
+
post('/', params)
|
12
|
+
raise ArgumentError, 'Wrong ID or password' if not logged_in?
|
13
|
+
end
|
14
|
+
alias login! login
|
15
|
+
|
16
|
+
def logout
|
17
|
+
require_login
|
18
|
+
post('/login/logout', :method_name => 'logout')
|
19
|
+
@current_user = nil
|
20
|
+
@logged_in = false
|
21
|
+
end
|
22
|
+
alias logout! logout
|
23
|
+
|
24
|
+
def logged_in?(force=false)
|
25
|
+
@logged_in = nil if force
|
26
|
+
@logged_in = @logged_in.nil? ? '/' != get('/').uri.path : @logged_in
|
27
|
+
end
|
28
|
+
alias logged_in logged_in?
|
29
|
+
|
30
|
+
def logged_out?(force=false)
|
31
|
+
!logged_in?(force)
|
32
|
+
end
|
33
|
+
alias logged_out logged_out?
|
34
|
+
|
35
|
+
def require_login
|
36
|
+
raise 'Not logged in' if logged_out?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Croudia
|
2
|
+
class Scraper
|
3
|
+
module Parser
|
4
|
+
module Users
|
5
|
+
def user_page(page)
|
6
|
+
return nil if /on Croudia$/ !~ page.title
|
7
|
+
doc = page.parser
|
8
|
+
attrs = {
|
9
|
+
:username => doc.xpath('//a[contains(@href, "/voices/user/")]').first.attribute('href').content.sub(%r{^/voices/user/}, ''),
|
10
|
+
:nickname => doc.css('.avatar_l').first.attribute('alt').content,
|
11
|
+
:avatar => "#{page.uri.scheme}://#{page.uri.host}" + doc.css('.avatar_l').first.attribute('src').content,
|
12
|
+
:self_introduction => doc.css('.fontg').first.content.strip,
|
13
|
+
:voices_count => doc.xpath('//span[preceding-sibling::a[contains(@href,"/voices/user/")]]').first.content,
|
14
|
+
:following_count => doc.xpath('//span[preceding-sibling::a[contains(@href,"/following/")]]').first.content,
|
15
|
+
:followers_count => doc.xpath('//span[preceding-sibling::a[contains(@href,"/follower/")]]').first.content,
|
16
|
+
:album_count => doc.xpath('//span[preceding-sibling::a[contains(@href,"/album")]]').first.content,
|
17
|
+
:spreadia => doc.xpath('//span[preceding-sibling::a[contains(@href,"/spreadia/")]]').first.content,
|
18
|
+
:favodia => doc.xpath('//span[preceding-sibling::a[contains(@href,"/favodia/")]]').first.content,
|
19
|
+
}
|
20
|
+
if (location = doc.xpath('//a[contains(@href, "/users/google_maps")]')).size.nonzero?
|
21
|
+
attrs[:position] = location.first.content
|
22
|
+
end
|
23
|
+
if (url = doc.xpath('//a[@target="_blank"][name(..)="li"]')).size.nonzero?
|
24
|
+
attrs[:user_url] = url.first.content
|
25
|
+
end
|
26
|
+
if (friendships = doc.css('.font1')).size.nonzero?
|
27
|
+
attrs[:following] = /#e/i !~ friendships[0].attribute('style').value
|
28
|
+
attrs[:followed_by] = /#e/i !~ friendships[1].attribute('style').value
|
29
|
+
end
|
30
|
+
Croudia::User.new(attrs)
|
31
|
+
end
|
32
|
+
|
33
|
+
def user_list(page, klass=Croudia::User)
|
34
|
+
user_nodes = page.parser.xpath('//div[@data-role="content"]/ul[@data-role="listview"]/li[child::a]')
|
35
|
+
users = []
|
36
|
+
user_nodes.map do |user_node|
|
37
|
+
attrs = {
|
38
|
+
:username => user_node.css('a').first.attribute('href').value.sub(%r{^/}, ''),
|
39
|
+
:nickname => user_node.css('.bord').first.content,
|
40
|
+
:avatar => "#{page.uri.scheme}://#{page.uri.host}" + user_node.css('img').first.attribute('src').value,
|
41
|
+
:self_introduction => user_node.css('.fontg').first.content.strip,
|
42
|
+
}
|
43
|
+
if (following = user_node.css('.font1')).size.nonzero?
|
44
|
+
attrs[:following] = /#e/i !~ following.first.attribute('style').value
|
45
|
+
end
|
46
|
+
users << Croudia::User.new(attrs)
|
47
|
+
end
|
48
|
+
users
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Croudia
|
2
|
+
class Scraper
|
3
|
+
module Parser
|
4
|
+
module Voices
|
5
|
+
def voices(page)
|
6
|
+
voice_nodes = page.parser.xpath('//div[@data-role="content"]/ul[@data-role="listview"]/li[child::a]')
|
7
|
+
voices = []
|
8
|
+
voice_nodes.each do |voice|
|
9
|
+
user = Croudia::User.new(
|
10
|
+
:username => voice.xpath('//a[parent::span[@class="test_span"]]').first.attribute('href').value.gsub(/\W/, ''),
|
11
|
+
:nickname => voice.xpath('//span[@class="bord"][parent::p]').first.content,
|
12
|
+
:avatar => "#{page.uri.scheme}://#{page.uri.host}" + voice.xpath('//img[@class="avatar"]').attribute('src').value,
|
13
|
+
)
|
14
|
+
attrs = {
|
15
|
+
:id => voice.xpath('//a[contains(@href,"/voices/show/")]').first.attribute('href').value.gsub(/\D/, ''),
|
16
|
+
:user => user,
|
17
|
+
:voice_desc => voice.css('.voice_desc').first.content,
|
18
|
+
:spreaded_count => voice.xpath('//span[contains(@style,"#396")]').first.content.gsub(/\D/, ''),
|
19
|
+
:favorited_count => voice.xpath('//span[contains(@style,"520")]').first.content.gsub(/\D/, ''),
|
20
|
+
}
|
21
|
+
if (time = voice.xpath('//p[@data-time]')).size.nonzero?
|
22
|
+
# For timeline
|
23
|
+
attrs[:time] = time.first.attribute('data-time').value
|
24
|
+
end
|
25
|
+
voices << Croudia::Voice.new(attrs)
|
26
|
+
end
|
27
|
+
voices
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'croudia/scraper/parser/users'
|
2
|
+
require 'croudia/scraper/parser/voices'
|
3
|
+
|
4
|
+
module Croudia
|
5
|
+
class Scraper
|
6
|
+
module Parser
|
7
|
+
class << self
|
8
|
+
include Croudia::Scraper::Parser::Users
|
9
|
+
include Croudia::Scraper::Parser::Voices
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Croudia
|
2
|
+
class Scraper
|
3
|
+
module Users
|
4
|
+
def current_user(force=false)
|
5
|
+
require_login
|
6
|
+
@current_user = nil if force
|
7
|
+
@current_user ||= Parser.user_page(get('/users/redirect_user'))
|
8
|
+
end
|
9
|
+
alias verify_credentials current_user
|
10
|
+
|
11
|
+
def user(username=nil, params={})
|
12
|
+
if username
|
13
|
+
Parser.user_page(get("/#{username}", params))
|
14
|
+
else
|
15
|
+
current_user
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Croudia
|
2
|
+
class Scraper
|
3
|
+
module Voices
|
4
|
+
def timeline(params={})
|
5
|
+
require_login
|
6
|
+
Parser.voices(get('/voices/timeline', params))
|
7
|
+
end
|
8
|
+
alias home_timeline timeline
|
9
|
+
|
10
|
+
def reply_list(params={})
|
11
|
+
require_login
|
12
|
+
Parser.voices(get('/voices/reply_list', params))
|
13
|
+
end
|
14
|
+
alias mentions reply_list
|
15
|
+
alias mentions_timeline reply_list
|
16
|
+
|
17
|
+
def update(text)
|
18
|
+
require_login
|
19
|
+
page = get('/voices/written')
|
20
|
+
form = page.form_with(:action => '/voices/write')
|
21
|
+
form['voice[tweet]'] = text
|
22
|
+
result = form.submit
|
23
|
+
raise 'Update failed' if result.body.include? 'error_popup'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'croudia/scraper/friendships'
|
2
|
+
require 'croudia/scraper/login'
|
3
|
+
require 'croudia/scraper/parser'
|
4
|
+
require 'croudia/scraper/users'
|
5
|
+
require 'croudia/scraper/voices'
|
6
|
+
require 'croudia/user'
|
7
|
+
require 'croudia/version'
|
8
|
+
require 'croudia/voice'
|
9
|
+
require 'mechanize'
|
10
|
+
|
11
|
+
module Croudia
|
12
|
+
class Scraper
|
13
|
+
include Croudia::Scraper::Friendships
|
14
|
+
include Croudia::Scraper::Login
|
15
|
+
include Croudia::Scraper::Users
|
16
|
+
include Croudia::Scraper::Voices
|
17
|
+
|
18
|
+
attr_accessor :agent, :endpoint
|
19
|
+
|
20
|
+
def initialize(username=nil, password=nil)
|
21
|
+
yield self if block_given?
|
22
|
+
|
23
|
+
@endpoint ||= 'https://croudia.com'
|
24
|
+
@user_agent ||= "The Croudia Gem/#{Croudia::VERSION} (https://github.com/wktk/croudia-gem)"
|
25
|
+
@agent ||= Mechanize.new do |s|
|
26
|
+
s.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
27
|
+
end
|
28
|
+
self.user_agent = @user_agent
|
29
|
+
|
30
|
+
username && password && login(username, password)
|
31
|
+
end
|
32
|
+
|
33
|
+
def user_agent
|
34
|
+
@agent.user_agent
|
35
|
+
end
|
36
|
+
|
37
|
+
def user_agent=(ua)
|
38
|
+
unless @agent
|
39
|
+
@user_agent = ua
|
40
|
+
else
|
41
|
+
@agent.user_agent = ua
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def get(path, params={})
|
46
|
+
pick_token(@agent.get(@endpoint + path, params))
|
47
|
+
end
|
48
|
+
|
49
|
+
def post(path, params={})
|
50
|
+
params = { :authenticity_token => @authenticity_token }.merge(params)
|
51
|
+
pick_token(@agent.post(@endpoint + path, params))
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def pick_token(page)
|
56
|
+
page.respond_to?('parser') &&
|
57
|
+
(token = page.parser.xpath('//meta[@name="csrf-token"]')).size.nonzero? &&
|
58
|
+
@authenticity_token = token.first.attribute('content').content
|
59
|
+
page
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/croudia/user.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'croudia/identity'
|
2
|
+
|
3
|
+
module Croudia
|
4
|
+
class User < Croudia::Identity
|
5
|
+
attr_reader :username, :nickname, :avatar, :self_introduction,
|
6
|
+
:voices_count, :following_count, :followers_count, :album_count,
|
7
|
+
:position, :user_url, :spreadia, :favodia,
|
8
|
+
:following, :followed_by
|
9
|
+
alias handle username
|
10
|
+
alias screen_name username
|
11
|
+
alias user_name username
|
12
|
+
alias name nickname
|
13
|
+
alias profile_image avatar
|
14
|
+
alias description self_introduction
|
15
|
+
alias voice_count voices_count
|
16
|
+
alias statuses_count voices_count
|
17
|
+
alias status_count voices_count
|
18
|
+
alias updates_count voices_count
|
19
|
+
alias update_count voices_count
|
20
|
+
alias followings_count following_count
|
21
|
+
alias friends_count following_count
|
22
|
+
alias friend_count following_count
|
23
|
+
alias follower_count followers_count
|
24
|
+
alias location position
|
25
|
+
alias url user_url
|
26
|
+
alias favorited_count favodia
|
27
|
+
alias favourited_count favodia
|
28
|
+
alias spreaded_count spreadia
|
29
|
+
alias following? following
|
30
|
+
alias followed_by? followed_by
|
31
|
+
|
32
|
+
def initialize(*args)
|
33
|
+
super
|
34
|
+
@id = @username
|
35
|
+
@spreadia = @spreadia.to_i if @spreadia
|
36
|
+
@favodia = @favodia.to_i if @favodia
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
@username
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'croudia/identity'
|
2
|
+
|
3
|
+
module Croudia
|
4
|
+
class Voice < Croudia::Identity
|
5
|
+
attr_reader :user, :voice_desc, :spreaded_count, :favorited_count, :time
|
6
|
+
alias from_user user
|
7
|
+
alias text voice_desc
|
8
|
+
alias description voice_desc
|
9
|
+
alias desc voice_desc
|
10
|
+
alias spread_count spreaded_count
|
11
|
+
alias favorite_count favorited_count
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"@#{@user.username}: #{@desc}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_i
|
18
|
+
@id.to_i
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/croudia.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'croudia/scraper'
|
2
|
+
|
3
|
+
module Croudia
|
4
|
+
class << self
|
5
|
+
# Delegate to Croudia::Scraper.new
|
6
|
+
#
|
7
|
+
# @return [Croudia::Scraper]
|
8
|
+
def scraper(*args, &block)
|
9
|
+
Croudia::Scraper.new(*args, &block)
|
10
|
+
end
|
11
|
+
alias new scraper
|
12
|
+
alias client scraper
|
13
|
+
|
14
|
+
def method_missing(name, *args, &block)
|
15
|
+
return super unless scraper.respond_to?(name)
|
16
|
+
scraper.send(name, *args, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to?(name)
|
20
|
+
scraper.respond_to?(name) || super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Croudia::Identity do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'sets arguments as instance variables' do
|
6
|
+
Croudia::Identity.new(:hello => 'hi').instance_variable_get('@hello').should eq 'hi'
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'converts a Unix time attribution named time to a Time object' do
|
10
|
+
Croudia::Identity.new(:time => '1234567890').time.should be_a Time
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'converts a date string named time to a Time object' do
|
14
|
+
Croudia::Identity.new(:time => '2013-01-01 11:55').time.should be_a Time
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'converts *_count into an Integer' do
|
18
|
+
Croudia::Identity.new(:foo_count => '2012').foo_count.should eq 2012
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#==' do
|
23
|
+
it 'returns true when IDs match' do
|
24
|
+
obj1 = Croudia::Identity.new(:id => '1', :username => 'wktk')
|
25
|
+
obj2 = Croudia::Identity.new(:id => '1', :username => 'croudia')
|
26
|
+
(obj1 == obj2).should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns false when IDs do not match' do
|
30
|
+
obj1 = Croudia::Identity.new(:id => '1', :username => 'wktk')
|
31
|
+
obj2 = Croudia::Identity.new(:id => '2', :username => 'wktk')
|
32
|
+
(obj1 == obj2).should be_false
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns false when classes do not match' do
|
36
|
+
obj1 = Croudia::Identity.new(:id => '1')
|
37
|
+
obj2 = { :id => '1' }
|
38
|
+
(obj1 == obj2).should be_false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#[]' do
|
43
|
+
it 'returns the same name instance variable' do
|
44
|
+
Croudia::Identity.new(:foo => 'bar')[:foo].should eq 'bar'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#id' do
|
49
|
+
it 'returns @id, not object_id' do
|
50
|
+
identity = Croudia::Identity.new(:id => '1')
|
51
|
+
identity.id.should_not eq identity.object_id
|
52
|
+
identity.id.should eq identity.instance_variable_get('@id')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#method_missing' do
|
57
|
+
it 'returns the same name instance variable if set' do
|
58
|
+
Croudia::Identity.new(:foo => 'bar').foo.should eq 'bar'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns nil if not set' do
|
62
|
+
Croudia::Identity.new(:foo => 'bar').bar.should be_nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Croudia::Scraper::Friendships do
|
4
|
+
context 'when logged in' do
|
5
|
+
before do
|
6
|
+
@croudia = Croudia::Scraper.new
|
7
|
+
@croudia.instance_variable_set('@logged_in', true)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#follow' do
|
11
|
+
it 'posts to the correct resource' do
|
12
|
+
stub_post('/follows/target_follow').to_return(:headers => {:content_type => 'text/html'})
|
13
|
+
@croudia.follow('wktk')
|
14
|
+
a_post('/follows/target_follow').with(:body => /target_user_name=wktk/).should have_been_made
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#unfollow' do
|
19
|
+
it 'posts to the correct resource' do
|
20
|
+
stub_post('/follows/target_follow').to_return(:headers => {:content_type => 'text/html'})
|
21
|
+
@croudia.follow('wktk')
|
22
|
+
a_post('/follows/target_follow').with(:body => /target_user_name=wktk/).should have_been_made
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when not logged in' do
|
28
|
+
before do
|
29
|
+
@croudia = Croudia::Scraper.new
|
30
|
+
@croudia.instance_variable_set('@logged_in', true)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#follow' do
|
34
|
+
it 'should raise error' do
|
35
|
+
expect{ @croudia.follow('wktk') }.to raise_error
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#unfollow' do
|
40
|
+
it 'should raise error' do
|
41
|
+
expect{ @croudia.follow('wktk') }.to raise_error
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#follower' do
|
47
|
+
it 'gets the correct resource' do
|
48
|
+
stub_get('/follows/follower/wktk').to_return(:headers => {:content_type => 'text/html'})
|
49
|
+
Croudia.follower('wktk')
|
50
|
+
a_get('/follows/follower/wktk').should have_been_made
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#following' do
|
55
|
+
it 'gets the correct resource' do
|
56
|
+
stub_get('/follows/following/wktk').to_return(:headers => {:content_type => 'text/html'})
|
57
|
+
Croudia.following('wktk')
|
58
|
+
a_get('/follows/following/wktk').should have_been_made
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|