tinder 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +3 -0
- data/README.txt +20 -4
- data/lib/tinder.rb +2 -0
- data/lib/tinder/campfire.rb +57 -30
- data/lib/tinder/room.rb +66 -24
- data/lib/tinder/version.rb +2 -2
- data/test/test_helper.rb +1 -0
- data/test/unit/campfire_test.rb +18 -0
- metadata +2 -2
data/CHANGELOG.txt
CHANGED
data/README.txt
CHANGED
@@ -1,14 +1,18 @@
|
|
1
|
-
= Tinder
|
1
|
+
= Tinder - get the Campfire started
|
2
2
|
|
3
|
-
Tinder is a library for interfacing with Campfire, the chat application from 37Signals.
|
3
|
+
Tinder is a library for interfacing with Campfire, the chat application from 37Signals. Unlike Marshmallow, it is designed to be a full-featured API (since 37Signals doesn't provide a real one), allowing you to programatically manage and speak/listen in chat rooms.
|
4
|
+
|
5
|
+
== Usage
|
4
6
|
|
5
7
|
campfire = Campfire.new 'mysubdomain'
|
6
8
|
campfire.login 'myemail@example.com', 'mypassword'
|
7
9
|
room = campfire.create_room 'New Room', 'My new campfire room to test tinder'
|
8
10
|
room.rename 'New Room Name'
|
9
11
|
room.speak 'Hello world!'
|
10
|
-
room.
|
12
|
+
room.paste "my pasted\ncode"
|
11
13
|
room.destroy
|
14
|
+
|
15
|
+
See the RDoc for more details.
|
12
16
|
|
13
17
|
== Requirements
|
14
18
|
|
@@ -16,9 +20,21 @@ Tinder is a library for interfacing with Campfire, the chat application from 37S
|
|
16
20
|
gem install activesupport
|
17
21
|
* Hpricot
|
18
22
|
gem install hpricot
|
23
|
+
|
24
|
+
== Installation
|
25
|
+
|
26
|
+
Tinder can be installed as a gem or a Rails plugin:
|
27
|
+
|
28
|
+
gem install tinder
|
29
|
+
|
30
|
+
script/plugin install http://source.collectiveidea.com/public/tinder/trunk
|
31
|
+
|
32
|
+
== Development
|
33
|
+
|
34
|
+
The source for Tinder is available at http://source.collectiveidea.com/public/tinder/trunk. Development can be followed at http://opensoul.org/tags/tinder. Contributions are welcome!
|
19
35
|
|
20
36
|
== ToDo
|
21
37
|
|
22
38
|
* Tests! (unit and remote)
|
23
39
|
* Log in via guest url
|
24
|
-
*
|
40
|
+
* Marshmallow-style integration scripts for exception notification and continuous integration
|
data/lib/tinder.rb
CHANGED
data/lib/tinder/campfire.rb
CHANGED
@@ -2,41 +2,52 @@ module Tinder
|
|
2
2
|
|
3
3
|
# == Usage
|
4
4
|
#
|
5
|
-
# campfire = Campfire.new 'mysubdomain'
|
5
|
+
# campfire = Tinder::Campfire.new 'mysubdomain'
|
6
6
|
# campfire.login 'myemail@example.com', 'mypassword'
|
7
7
|
# room = campfire.create_room 'New Room', 'My new campfire room to test tinder'
|
8
8
|
# room.speak 'Hello world!'
|
9
9
|
# room.destroy
|
10
10
|
class Campfire
|
11
|
-
|
11
|
+
attr_reader :subdomain, :uri
|
12
12
|
|
13
|
-
|
13
|
+
# Create a new connection to the campfire account with the given +subdomain+.
|
14
|
+
# There's an optional +:ssl+ option to use SSL for the connection.
|
15
|
+
#
|
16
|
+
# c = Tinder::Campfire.new("mysubdomain", :ssl => true)
|
17
|
+
def initialize(subdomain, options = {})
|
18
|
+
options = { :ssl => false }.merge(options)
|
14
19
|
@cookie = nil
|
15
|
-
|
16
|
-
|
20
|
+
@subdomain = subdomain
|
21
|
+
@uri = URI.parse("#{options[:ssl] ? 'https' : 'http' }://#{subdomain}.campfirenow.com")
|
17
22
|
end
|
18
|
-
|
23
|
+
|
24
|
+
# Log in to campfire using your +email+ and +password+
|
19
25
|
def login(email, password)
|
20
26
|
@logged_in = verify_response(post("login", :email_address => email, :password => password), :redirect_to => url_for)
|
21
27
|
end
|
22
|
-
|
28
|
+
|
23
29
|
def logged_in?
|
24
30
|
@logged_in
|
25
31
|
end
|
26
32
|
|
27
33
|
def logout
|
28
|
-
|
34
|
+
returning verify_response(get("logout"), :redirect) do |result|
|
35
|
+
@logged_in = !result
|
36
|
+
end
|
29
37
|
end
|
30
38
|
|
39
|
+
# Creates and returns a new Room with the given +name+ and optionally a +topic+
|
31
40
|
def create_room(name, topic = nil)
|
32
41
|
find_room_by_name(name) if verify_response(post("account/create/room?from=lobby", {:room => {:name => name, :topic => topic}}, :ajax => true), :success)
|
33
42
|
end
|
34
|
-
|
43
|
+
|
44
|
+
# Find a campfire room by name
|
35
45
|
def find_room_by_name(name)
|
36
46
|
link = Hpricot(get.body).search("//h2/a").detect { |a| a.inner_html == name }
|
37
47
|
link.blank? ? nil : Room.new(self, link.attributes['href'].scan(/room\/(\d*)$/).to_s, name)
|
38
48
|
end
|
39
|
-
|
49
|
+
|
50
|
+
# List the users that are currently chatting in any room
|
40
51
|
def users(*room_names)
|
41
52
|
users = Hpricot(get.body).search("div.room").collect do |room|
|
42
53
|
if room_names.empty? || room_names.include?((room/"h2/a").inner_html)
|
@@ -46,37 +57,52 @@ module Tinder
|
|
46
57
|
users.flatten.compact.uniq.sort
|
47
58
|
end
|
48
59
|
|
60
|
+
# Deprecated: only included for backwards compatability
|
61
|
+
def host #:nodoc:
|
62
|
+
uri.host
|
63
|
+
end
|
64
|
+
|
65
|
+
# Is the connection to campfire using ssl?
|
66
|
+
def ssl?
|
67
|
+
uri.scheme == 'https'
|
68
|
+
end
|
69
|
+
|
49
70
|
private
|
50
71
|
|
51
72
|
def url_for(path = "")
|
52
|
-
"
|
73
|
+
"#{uri}/#{path}"
|
53
74
|
end
|
54
75
|
|
55
76
|
def post(path, data = {}, options = {})
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
returning @response = Net::HTTP.new(host, 80).start { |http| http.request(@request) } do |response|
|
62
|
-
@cookie = response['set-cookie'] if response['set-cookie']
|
77
|
+
perform_request(options) do
|
78
|
+
returning Net::HTTP::Post.new(url_for(path)) do |request|
|
79
|
+
request.add_field 'Content-Type', 'application/x-www-form-urlencoded'
|
80
|
+
request.set_form_data flatten(data)
|
81
|
+
end
|
63
82
|
end
|
64
83
|
end
|
65
84
|
|
66
85
|
def get(path = nil, options = {})
|
67
|
-
|
68
|
-
prepare_request(request, options)
|
69
|
-
end
|
70
|
-
returning @response = Net::HTTP.new(host, 80).start { |http| http.request(@request) } do |response|
|
71
|
-
@cookie = response['set-cookie'] if response['set-cookie']
|
72
|
-
end
|
86
|
+
perform_request(options) { Net::HTTP::Get.new(url_for(path)) }
|
73
87
|
end
|
74
88
|
|
75
89
|
def prepare_request(request, options = {})
|
76
|
-
request
|
77
|
-
|
78
|
-
|
79
|
-
|
90
|
+
returning request do
|
91
|
+
request.add_field 'Cookie', @cookie if @cookie
|
92
|
+
if options[:ajax]
|
93
|
+
request.add_field 'X-Requested-With', 'XMLHttpRequest'
|
94
|
+
request.add_field 'X-Prototype-Version', '1.5.0_rc1'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def perform_request(options = {}, &block)
|
100
|
+
@request = prepare_request(yield, options)
|
101
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
102
|
+
http.use_ssl = ssl?
|
103
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ssl?
|
104
|
+
@response = returning http.request(@request) do |response|
|
105
|
+
@cookie = response['set-cookie'] if response['set-cookie']
|
80
106
|
end
|
81
107
|
end
|
82
108
|
|
@@ -93,11 +119,12 @@ module Tinder
|
|
93
119
|
|
94
120
|
def verify_response(response, options = {})
|
95
121
|
if options.is_a?(Symbol)
|
96
|
-
case options
|
122
|
+
codes = case options
|
97
123
|
when :success then [200]
|
98
124
|
when :redirect then 300..399
|
99
125
|
else raise ArgumentError.new("Unknown response #{options}")
|
100
|
-
end
|
126
|
+
end
|
127
|
+
codes.include?(response.code.to_i)
|
101
128
|
elsif options[:redirect_to]
|
102
129
|
verify_response(response, :redirect) && response['location'] == options[:redirect_to]
|
103
130
|
else
|
data/lib/tinder/room.rb
CHANGED
@@ -1,67 +1,110 @@
|
|
1
1
|
module Tinder
|
2
|
+
# A campfire room
|
2
3
|
class Room
|
3
|
-
|
4
|
+
attr_reader :id, :name
|
4
5
|
|
5
6
|
def initialize(campfire, id, name = nil)
|
6
7
|
@campfire = campfire
|
7
|
-
|
8
|
-
|
9
|
-
@room = get("room/#{self.id}")
|
10
|
-
@membership_key = @room.body.scan(/\"membershipKey\": \"([a-z0-9]+)\"/).to_s
|
11
|
-
@user_id = @room.body.scan(/\"userID\": (\d+)/).to_s
|
12
|
-
@last_cache_id = @room.body.scan(/\"lastCacheID\": (\d+)/).to_s
|
13
|
-
@timestamp = @room.body.scan(/\"timestamp\": (\d+)/).to_s
|
8
|
+
@id = id
|
9
|
+
@name = name
|
14
10
|
end
|
15
11
|
|
12
|
+
# Join the room. Pass +true+ to join even if you've already joined.
|
13
|
+
def join(force = false)
|
14
|
+
@room = returning(get("room/#{id}")) do |room|
|
15
|
+
return false unless verify_response(room, :success)
|
16
|
+
@membership_key = room.body.scan(/\"membershipKey\": \"([a-z0-9]+)\"/).to_s
|
17
|
+
@user_id = room.body.scan(/\"userID\": (\d+)/).to_s
|
18
|
+
@last_cache_id = room.body.scan(/\"lastCacheID\": (\d+)/).to_s
|
19
|
+
@timestamp = room.body.scan(/\"timestamp\": (\d+)/).to_s
|
20
|
+
end unless @room || force
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Leave a room
|
16
25
|
def leave
|
17
|
-
verify_response
|
26
|
+
returning verify_response(get("room/#{id}/leave"), :redirect) do
|
27
|
+
@room, @membership_key, @user_id, @last_cache_id, @timestamp = nil
|
28
|
+
end
|
18
29
|
end
|
19
30
|
|
31
|
+
# Toggle guest access on or off
|
20
32
|
def toggle_guest_access
|
21
|
-
verify_response(post("room/#{
|
33
|
+
verify_response(post("room/#{id}/toggle_guest_access"), :success)
|
22
34
|
end
|
23
35
|
|
36
|
+
# Get the url for guest access
|
24
37
|
def guest_url
|
25
|
-
|
38
|
+
join
|
39
|
+
(Hpricot(@room.body)/"#guest_access h4").first.inner_html
|
26
40
|
end
|
27
41
|
|
42
|
+
# The invite code use for guest
|
28
43
|
def guest_invite_code
|
29
|
-
guest_url.scan(
|
44
|
+
guest_url.scan(/\/(\w*)$/).to_s
|
30
45
|
end
|
31
46
|
|
32
|
-
|
33
|
-
|
47
|
+
# Change the name of the room
|
48
|
+
def name=(name)
|
49
|
+
@name = name if verify_response(post("account/edit/room/#{id}", { :room => { :name => name }}, :ajax => true), :success)
|
34
50
|
end
|
51
|
+
alias_method :rename, :name=
|
35
52
|
|
53
|
+
# Change the topic
|
36
54
|
def topic=(topic)
|
37
|
-
topic if verify_response(post("room/#{
|
55
|
+
topic if verify_response(post("room/#{id}/change_topic", { 'room' => { 'topic' => topic }}, :ajax => true), :success)
|
38
56
|
end
|
39
|
-
|
57
|
+
|
58
|
+
# Lock the room to prevent new users from entering and to disable logging
|
40
59
|
def lock
|
41
|
-
verify_response(post("room/#{
|
60
|
+
verify_response(post("room/#{id}/lock", {}, :ajax => true), :success)
|
42
61
|
end
|
43
62
|
|
63
|
+
# Unlock the room
|
44
64
|
def unlock
|
45
|
-
verify_response(post("room/#{
|
65
|
+
verify_response(post("room/#{id}/unlock", {}, :ajax => true), :success)
|
46
66
|
end
|
47
67
|
|
48
68
|
def destroy
|
49
|
-
verify_response(post("account/delete/room/#{
|
69
|
+
verify_response(post("account/delete/room/#{id}"), :success)
|
50
70
|
end
|
51
71
|
|
72
|
+
# Post a new message to the chat room
|
52
73
|
def speak(message)
|
74
|
+
join
|
53
75
|
send message
|
54
76
|
end
|
55
|
-
|
77
|
+
|
56
78
|
def paste(message)
|
79
|
+
join
|
57
80
|
send message, { :paste => true }
|
58
81
|
end
|
59
|
-
|
82
|
+
|
83
|
+
# Get the list of users currently chatting for this room
|
60
84
|
def users
|
61
|
-
|
85
|
+
@campfire.users name
|
62
86
|
end
|
63
87
|
|
88
|
+
# Get and array of the messages that have been posted to the room since you joined. Each
|
89
|
+
# messages is a hash with:
|
90
|
+
# * +:person+: the display name of the person that posted the message
|
91
|
+
# * +:message+: the body of the message
|
92
|
+
# * +:user_id+: Campfire user id
|
93
|
+
# * +:id+: Campfire message id
|
94
|
+
#
|
95
|
+
# room.listen
|
96
|
+
# #=> [{:person=>"Brandon", :message=>"I'm getting very sleepy", :user_id=>"148583", :id=>"16434003"}]
|
97
|
+
#
|
98
|
+
# listen also takes an optional block, which then polls for new messages every 5 seconds
|
99
|
+
# and calls the block for each message.
|
100
|
+
#
|
101
|
+
# room.listen do |m|
|
102
|
+
# room.speak "#{m[:person]}, Go away!" if m[:message] =~ /Java/i
|
103
|
+
# end
|
104
|
+
#
|
64
105
|
def listen
|
106
|
+
# FIXME: this method needs refactored!
|
107
|
+
join
|
65
108
|
continue = true
|
66
109
|
while(continue)
|
67
110
|
messages = []
|
@@ -93,7 +136,6 @@ module Tinder
|
|
93
136
|
end
|
94
137
|
messages
|
95
138
|
end
|
96
|
-
|
97
139
|
|
98
140
|
private
|
99
141
|
|
@@ -110,7 +152,7 @@ module Tinder
|
|
110
152
|
end
|
111
153
|
|
112
154
|
def send(message, options = {})
|
113
|
-
message if verify_response(post("room/#{
|
155
|
+
message if verify_response(post("room/#{id}/speak", { :message => message, :t => Time.now.to_i }.merge(options), :ajax => true), :success)
|
114
156
|
end
|
115
157
|
|
116
158
|
end
|
data/lib/tinder/version.rb
CHANGED
data/test/test_helper.rb
CHANGED
data/test/unit/campfire_test.rb
CHANGED
@@ -39,5 +39,23 @@ class CampfireTest < Test::Unit::TestCase
|
|
39
39
|
assert false === @campfire.send(:verify_response, @response, :redirect_to => '/foobar')
|
40
40
|
end
|
41
41
|
|
42
|
+
def test_prepare_request_returns_request
|
43
|
+
request = Net::HTTP::Get.new("does_not_matter")
|
44
|
+
assert_equal request, @campfire.send(:prepare_request, request)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_prepare_request_sets_cookie
|
48
|
+
request = Net::HTTP::Get.new("does_not_matter")
|
49
|
+
@campfire.instance_variable_set("@cookie", "foobar")
|
50
|
+
assert_equal "foobar", @campfire.send(:prepare_request, request)['Cookie']
|
51
|
+
end
|
42
52
|
|
53
|
+
def test_perform_request
|
54
|
+
response = mock("response")
|
55
|
+
Net::HTTP.any_instance.stubs(:request).returns(response)
|
56
|
+
request = Net::HTTP::Get.new("does_not_matter")
|
57
|
+
response.expects(:[]).with('set-cookie')
|
58
|
+
|
59
|
+
assert_equal response, @campfire.send(:perform_request) { request }
|
60
|
+
end
|
43
61
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: tinder
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.1.3
|
7
|
+
date: 2007-02-12 00:00:00 -05:00
|
8
8
|
summary: An (unofficial) Campfire API
|
9
9
|
require_paths:
|
10
10
|
- lib
|