croudia 0.0.1
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.
- 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
|