etherpad-lite 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/LICENSE +13 -0
- data/README.rdoc +58 -0
- data/lib/etherpad-lite.rb +2 -0
- data/lib/etherpad-lite/client.rb +229 -0
- data/lib/etherpad-lite/models.rb +6 -0
- data/lib/etherpad-lite/models/author.rb +53 -0
- data/lib/etherpad-lite/models/group.rb +97 -0
- data/lib/etherpad-lite/models/instance.rb +94 -0
- data/lib/etherpad-lite/models/pad.rb +135 -0
- data/lib/etherpad-lite/models/padded.rb +26 -0
- data/lib/etherpad-lite/models/session.rb +65 -0
- data/spec/author_spec.rb +24 -0
- data/spec/config.yml +9 -0
- data/spec/config.yml.example +9 -0
- data/spec/group_spec.rb +102 -0
- data/spec/instance_spec.rb +15 -0
- data/spec/pad_spec.rb +81 -0
- data/spec/session_spec.rb +45 -0
- data/spec/spec_helper.rb +18 -0
- metadata +82 -0
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2011 Jordan Hollinger
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.rdoc
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
= Etherpad Lite Ruby Client
|
2
|
+
|
3
|
+
etherpad-lite is a Ruby client for Etherpad Lite's HTTP JSON API. Etherpad Lite is a collaborative editor provided by the Etherpad Foundation (http://etherpad.org).
|
4
|
+
|
5
|
+
See https://github.com/Pita/etherpad-lite for information on how to install and configure your own Etherpad Lite instance, and read https://github.com/Pita/etherpad-lite/wiki/HTTP-API for an in-depth description of Etherpad Lite's HTTP API.
|
6
|
+
|
7
|
+
== 1 Installation
|
8
|
+
gem install etherpad-lite
|
9
|
+
|
10
|
+
== 2 Basic usage
|
11
|
+
require 'etherpad-lite'
|
12
|
+
|
13
|
+
# Connect to your Etherpad Lite instance (passing no arguments will connect you to beta.etherpad.org)
|
14
|
+
ether = EtherpadLite.connect('http://etherpad-lite.example.com', 'your api key')
|
15
|
+
|
16
|
+
# Get a Pad (or create one if it doesn't exist)
|
17
|
+
pad = ether.pad('my first etherpad lite pad')
|
18
|
+
|
19
|
+
puts pad.text
|
20
|
+
=> "Welcome to Etherpad Lite!\n\nThis pad text is synchronized as you type, so that everyone viewing..."
|
21
|
+
|
22
|
+
# Write your the changes to the Pad
|
23
|
+
pad.text = "What hath God wrought?"
|
24
|
+
|
25
|
+
# There are now 2 revisions!
|
26
|
+
puts pad.revison_numbers.size
|
27
|
+
=> 2
|
28
|
+
|
29
|
+
# Iterate through each revision
|
30
|
+
pad.revisions.each do |pad_rev|
|
31
|
+
puts pad_rev.rev
|
32
|
+
puts pad_rev.text
|
33
|
+
end
|
34
|
+
|
35
|
+
For advanced functionality (i.e. Groups, Authors, Sessions), read the full docs at http://jordanhollinger.com/docs/ruby-etherpad-lite/. Also, the RSpec tests under /spec may provide some pointers.
|
36
|
+
|
37
|
+
== 3 Why is the Ruby client so different from the others? What gives you the right?!?
|
38
|
+
The PHP and Python clients are extremely thin wrappers of the HTTP API; their method names map directly to urls. The Ruby client offers a slightly higher level of abstration,
|
39
|
+
with the goal of making Etherpad Lite integration in Ruby projects as simple, poweful, and dare I say fun, as possible.
|
40
|
+
|
41
|
+
That said, there is certainly value in supporting the defacto standard set by the PHP and Python clients. With that in mind, the Ruby client is written in two layers,
|
42
|
+
one conforming to the other clients, and a higher-level "models" API riding on top of it.
|
43
|
+
|
44
|
+
In the examples above, the "traditional" client can be accessed with
|
45
|
+
client = ether.client
|
46
|
+
client.getText('my first etherpad lite pad')
|
47
|
+
=> {:text => "What hath God wrought?"}
|
48
|
+
|
49
|
+
Or you can explicitly load only the standard client
|
50
|
+
require 'etherpad-lite/client'
|
51
|
+
client = EtherpadLite::Client.new('api key', 'http://beta.etherpad.org/api')
|
52
|
+
|
53
|
+
== 4 License
|
54
|
+
Copyright 2011 Jordan Hollinger
|
55
|
+
Licensed under the Apache License
|
56
|
+
|
57
|
+
== 5 Credit
|
58
|
+
This Ruby client was inspired by TomNomNom's and devjones's PHP and Python clients, found at https://github.com/TomNomNom/etherpad-lite-client and https://github.com/devjones/PyEtherpadLite.
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/https'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module EtherpadLite
|
7
|
+
# A thin wrapper over Etherpad Lite's HTTP JSON API
|
8
|
+
class Client
|
9
|
+
API_VERSION = 1
|
10
|
+
|
11
|
+
CODE_OK = 0
|
12
|
+
CODE_INVALID_PARAMETERS = 1
|
13
|
+
CODE_INTERNAL_ERROR = 2
|
14
|
+
CODE_INVALID_METHOD = 3
|
15
|
+
CODE_INVALID_API_KEY = 4
|
16
|
+
|
17
|
+
attr_reader :uri, :api_key
|
18
|
+
|
19
|
+
# Path to the system's CA cert paths (for connecting over SSL)
|
20
|
+
@@ca_path = nil
|
21
|
+
|
22
|
+
# Get path to the system's CA certs
|
23
|
+
def self.ca_path; @@ca_path; end
|
24
|
+
|
25
|
+
# Manually set path to the system's CA certs. Use this if the location couldn't be determined automatically.
|
26
|
+
def self.ca_path=(path); @@ca_path = path; end
|
27
|
+
|
28
|
+
# Instantiate a new Etherpad Lite Instance. The url should include the protocol (i.e. http or https).
|
29
|
+
def initialize(api_key, url='http://localhost:9001/api')
|
30
|
+
@uri = URI.parse(url)
|
31
|
+
raise ArgumentError, "#{url} is not a valid url" unless @uri.host and @uri.port
|
32
|
+
@api_key = api_key
|
33
|
+
connect!
|
34
|
+
end
|
35
|
+
|
36
|
+
# Pad, Group, etc. all use this to send the HTTP API requests.
|
37
|
+
def call(method, params={})
|
38
|
+
# Build path
|
39
|
+
params[:apikey] = @api_key
|
40
|
+
params = params.map { |p| p.join('=') }.join('&').gsub(/\s/, '%20')
|
41
|
+
path = [@uri.path, API_VERSION, method].compact.join('/') << '?' << params
|
42
|
+
# Send request
|
43
|
+
get = Net::HTTP::Get.new(path)
|
44
|
+
response = @http.request(get)
|
45
|
+
handleResult response.body
|
46
|
+
end
|
47
|
+
|
48
|
+
# Groups
|
49
|
+
# Pads can belong to a group. There will always be public pads which don't belong to a group.
|
50
|
+
|
51
|
+
# Creates a new Group
|
52
|
+
def createGroup
|
53
|
+
call :createGroup
|
54
|
+
end
|
55
|
+
|
56
|
+
# Creates a new Group for groupMapper if one doesn't already exist. Helps you map your application's groups to Etherpad Lite's groups.
|
57
|
+
def createGroupIfNotExistsFor(groupMapper)
|
58
|
+
call :createGroupIfNotExistsFor, :groupMapper => groupMapper
|
59
|
+
end
|
60
|
+
|
61
|
+
# Deletes a group
|
62
|
+
def deleteGroup(groupID)
|
63
|
+
call :deleteGroup, :groupID => groupID
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns all the Pads in the given Group
|
67
|
+
def listPads(groupID)
|
68
|
+
call :listPads, :groupID => groupID
|
69
|
+
end
|
70
|
+
|
71
|
+
# Creates a new Pad in the given Group
|
72
|
+
def createGroupPad(groupID, padName, text=nil)
|
73
|
+
params = {:groupID => groupID, :padName => padName}
|
74
|
+
params[:text] = text unless text.nil?
|
75
|
+
call :createGroupPad, params
|
76
|
+
end
|
77
|
+
|
78
|
+
# Authors
|
79
|
+
# These authors are bound to the attributes the users choose (color and name).
|
80
|
+
|
81
|
+
# Create a new Author
|
82
|
+
def createAuthor(name=nil)
|
83
|
+
params = {}
|
84
|
+
params[:name] = name unless name.nil?
|
85
|
+
call :createAuthor, params
|
86
|
+
end
|
87
|
+
|
88
|
+
# Creates a new Author for authorMapper if one doesn't already exist. Helps you map your application's authors to Etherpad Lite's authors.
|
89
|
+
def createAuthorIfNotExistsFor(authorMapper, name=nil)
|
90
|
+
params = {:authorMapper => authorMapper}
|
91
|
+
params[:name] = name unless name.nil?
|
92
|
+
call :createAuthorIfNotExistsFor, params
|
93
|
+
end
|
94
|
+
|
95
|
+
# Sessions
|
96
|
+
# Sessions can be created between a group and an author. This allows
|
97
|
+
# an author to access more than one group. The sessionID will be set as
|
98
|
+
# a cookie to the client and is valid until a certian date.
|
99
|
+
|
100
|
+
# Creates a new Session for the given Author in the given Group
|
101
|
+
def createSession(groupID, authorID, validUntil)
|
102
|
+
call :createSession, :groupID => groupID, :authorID => authorID, :validUntil => validUntil
|
103
|
+
end
|
104
|
+
|
105
|
+
# Deletes the given Session
|
106
|
+
def deleteSession(sessionID)
|
107
|
+
call :deleteSession, :sessionID => sessionID
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns information about the Session
|
111
|
+
def getSessionInfo(sessionID)
|
112
|
+
call :getSessionInfo, :sessionID => sessionID
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns all Sessions in the given Group
|
116
|
+
def listSessionsOfGroup(groupID)
|
117
|
+
call :listSessionsOfGroup, :groupID => groupID
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns all Sessions belonging to the given Author
|
121
|
+
def listSessionsOfAuthor(authorID)
|
122
|
+
call :listSessionsOfAuthor, :authorID => authorID
|
123
|
+
end
|
124
|
+
|
125
|
+
# Pad content
|
126
|
+
# Pad content can be updated and retrieved through the API
|
127
|
+
|
128
|
+
# Returns the text of the given Pad. Optionally pass a revision number to get the text for that revision.
|
129
|
+
def getText(padID, rev=nil)
|
130
|
+
params = {:padID => padID}
|
131
|
+
params[:rev] = rev unless rev.nil?
|
132
|
+
call :getText, params
|
133
|
+
end
|
134
|
+
|
135
|
+
# Sets the text of the given Pad
|
136
|
+
def setText(padID, text)
|
137
|
+
call :setText, :padID => padID, :text => text
|
138
|
+
end
|
139
|
+
|
140
|
+
# Pad
|
141
|
+
# Group pads are normal pads, but with the name schema
|
142
|
+
# GROUPID$PADNAME. A security manager controls access of them and
|
143
|
+
# forbids normal pads from including a "$" in the name.
|
144
|
+
|
145
|
+
# Create a new Pad. Optionally specify the initial text.
|
146
|
+
def createPad(padID, text=nil)
|
147
|
+
params = {:padID => padID}
|
148
|
+
params[:text] = text unless text.nil?
|
149
|
+
call :createPad, params
|
150
|
+
end
|
151
|
+
|
152
|
+
# Returns the number of revisions the given Pad contains
|
153
|
+
def getRevisionsCount(padID)
|
154
|
+
call :getRevisionsCount, :padID => padID
|
155
|
+
end
|
156
|
+
|
157
|
+
# Delete the given Pad
|
158
|
+
def deletePad(padID)
|
159
|
+
call :deletePad, :padID => padID
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns the Pad's read-only id
|
163
|
+
def getReadOnlyID(padID)
|
164
|
+
call :getReadOnlyID, :padID => padID
|
165
|
+
end
|
166
|
+
|
167
|
+
# Sets a boolean for the public status of a Pad
|
168
|
+
def setPublicStatus(padID, publicStatus)
|
169
|
+
call :setPublicStatus, :padID => padID, :publicStatus => publicStatus
|
170
|
+
end
|
171
|
+
|
172
|
+
# Gets a boolean for the public status of a Pad
|
173
|
+
def getPublicStatus(padID)
|
174
|
+
call :getPublicStatus, :padID => padID
|
175
|
+
end
|
176
|
+
|
177
|
+
# Sets the password on a pad
|
178
|
+
def setPassword(padID, password)
|
179
|
+
call :setPassword, :padID => padID, :password => password
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns true if the Pad has a password, false if not
|
183
|
+
def isPasswordProtected(padID)
|
184
|
+
call :isPasswordProtected, :padID => padID
|
185
|
+
end
|
186
|
+
|
187
|
+
# Returns true if the connection to the Etherpad Lite instance is using SSL/HTTPS.
|
188
|
+
def secure?
|
189
|
+
@uri.port == 443
|
190
|
+
end
|
191
|
+
|
192
|
+
protected
|
193
|
+
|
194
|
+
# Parses the JSON response from the server, returning the data object as a Hash with symbolized keys.
|
195
|
+
# If the API response contains an error code, an exception is raised.
|
196
|
+
def handleResult(response)
|
197
|
+
response = JSON.parse(response, :symbolize_names => true)
|
198
|
+
case response[:code]
|
199
|
+
when CODE_OK then response[:data]
|
200
|
+
when CODE_INVALID_PARAMETERS, CODE_INVALID_API_KEY, CODE_INVALID_METHOD
|
201
|
+
raise ArgumentError, response[:message]
|
202
|
+
else
|
203
|
+
raise StandardError, "An unknown error ocurrced while handling the response: #{response.to_s}"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
# Initialize the HTTP connection object
|
210
|
+
def connect!
|
211
|
+
@http = Net::HTTP.new(@uri.host, @uri.port)
|
212
|
+
if secure?
|
213
|
+
@http.use_ssl = true
|
214
|
+
if @@ca_path
|
215
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
216
|
+
@http.ca_path = @@ca_path
|
217
|
+
else
|
218
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Try to find the system's CA certs
|
226
|
+
%w{/etc/ssl/certs /etc/ssl /usr/share/ssl /usr/lib/ssl /System/Library/OpenSSL /usr/local/ssl}.each do |path|
|
227
|
+
EtherpadLite::Client.ca_path = path and break if File.exists? path
|
228
|
+
end
|
229
|
+
$stderr.puts %q|WARNING Unable to find your CA Certificates; HTTPS connections will *not* be verified! You may remedy this with "EtherpadLite::Instance.ca_path = '/path/to/certs'"| unless EtherpadLite::Client.ca_path
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module EtherpadLite
|
2
|
+
# An Author of Pad content
|
3
|
+
class Author
|
4
|
+
attr_reader :id, :instance, :name, :mapper
|
5
|
+
|
6
|
+
# Creates a new Author. Optionally, you may pass the :mapper option your third party system's author id.
|
7
|
+
# This will allow you to find the Author again later using the same identifier as your foreign system.
|
8
|
+
# If you pass the mapper option, the method behaves like "create author for <mapper> if it doesn't already exist".
|
9
|
+
#
|
10
|
+
# Options:
|
11
|
+
#
|
12
|
+
# mapper => uid of Author from another system
|
13
|
+
#
|
14
|
+
# name => Author's name
|
15
|
+
def self.create(instance, options={})
|
16
|
+
result = options[:mapper] \
|
17
|
+
? instance.client.createAuthorIfNotExistsFor(options[:mapper], options[:name]) \
|
18
|
+
: instance.client.createAuthor(options[:name])
|
19
|
+
new instance, result[:authorID], options
|
20
|
+
end
|
21
|
+
|
22
|
+
# Instantiates an Author object (presumed it already exists)
|
23
|
+
#
|
24
|
+
# Options:
|
25
|
+
#
|
26
|
+
# mapper => the foreign author id it's mapped to
|
27
|
+
#
|
28
|
+
# name => the Author's name
|
29
|
+
def initialize(instance, id, options={})
|
30
|
+
@instance = instance
|
31
|
+
@id = id
|
32
|
+
@mapper = options[:mapper]
|
33
|
+
@name = options[:name]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a new session for group that will last length_in_minutes.
|
37
|
+
def create_session(group, length_in_min)
|
38
|
+
Session.create(@instance, group.id, @id, length_in_min)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns all session ids from this Author
|
42
|
+
def session_ids
|
43
|
+
s = @instance.client.listSessionsOfAuthor(@id) || {}
|
44
|
+
s.keys
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns all sessions from this Author
|
48
|
+
def sessions
|
49
|
+
s = @instance.client.listSessionsOfAuthor(@id) || {}
|
50
|
+
s.map { |id,info| Session.new(@instance, id, info) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module EtherpadLite
|
2
|
+
# A Group of Pads
|
3
|
+
class Group
|
4
|
+
GROUP_ID_REGEX = /^g\.[^\$]+/
|
5
|
+
include Padded
|
6
|
+
|
7
|
+
attr_reader :id, :instance, :mapper
|
8
|
+
|
9
|
+
# Creates a new Group. Optionally, you may pass the :mapper option your third party system's group id.
|
10
|
+
# This will allow you to find your Group again later using the same identifier as your foreign system.
|
11
|
+
# If you pass the mapper option, the method behaves like "create group for <mapper> if it doesn't already exist".
|
12
|
+
#
|
13
|
+
# Options:
|
14
|
+
#
|
15
|
+
# mapper => your foreign group id
|
16
|
+
def self.create(instance, options={})
|
17
|
+
result = options[:mapper] \
|
18
|
+
? instance.client.createGroupIfNotExistsFor(options[:mapper]) \
|
19
|
+
: instance.client.createGroup
|
20
|
+
new instance, result[:groupID], options
|
21
|
+
end
|
22
|
+
|
23
|
+
# Instantiates a Group object (presumed it already exists)
|
24
|
+
#
|
25
|
+
# Options:
|
26
|
+
#
|
27
|
+
# mapper => the foreign id it's mapped to
|
28
|
+
def initialize(instance, id, options={})
|
29
|
+
@instance = instance
|
30
|
+
@id = id
|
31
|
+
@mapper = options[:mapper]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the Pad with the given id, creating it if it doesn't already exist.
|
35
|
+
# This requires an HTTP request, so if you *know* the Pad already exists, use Group#get_pad instead.
|
36
|
+
def pad(id, options={})
|
37
|
+
options[:groupID] = @id
|
38
|
+
super groupify_pad_id(id), options
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the Pad with the given id (presumed to already exist).
|
42
|
+
# Use this instead of Group#pad when you *know* the Pad already exists; it will save an HTTP request.
|
43
|
+
def get_pad(id, options={})
|
44
|
+
options[:group] = self
|
45
|
+
super groupify_pad_id(id), options
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates and returns a Pad with the given id.
|
49
|
+
#
|
50
|
+
# Options:
|
51
|
+
#
|
52
|
+
# text => 'initial Pad text'
|
53
|
+
def create_pad(id, options={})
|
54
|
+
options[:groupID] = @id
|
55
|
+
super groupify_pad_id(id), options
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns an array of all the Pads in this Group.
|
59
|
+
def pads
|
60
|
+
pad_ids.map { |id| Pad.new(@instance, id, :group => self) }
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns an array of all the Pad ids in this Group.
|
64
|
+
def pad_ids
|
65
|
+
@instance.client.listPads(@id)[:padIDs].keys
|
66
|
+
end
|
67
|
+
|
68
|
+
# Create a new session for author that will last length_in_minutes.
|
69
|
+
def create_session(author, length_in_min)
|
70
|
+
Session.create(@instance, @id, author.id, length_in_min)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns all session ids in this Group
|
74
|
+
def session_ids
|
75
|
+
s = @instance.client.listSessionsOfGroup(@id) || {}
|
76
|
+
s.keys
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns all sessions in this Group
|
80
|
+
def sessions
|
81
|
+
s = @instance.client.listSessionsOfGroup(@id) || {}
|
82
|
+
s.map { |id,info| Session.new(@instance, id, info) }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Deletes the Group
|
86
|
+
def delete
|
87
|
+
@instance.client.deleteGroup(@id)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Prepend the group_id to the pad name
|
93
|
+
def groupify_pad_id(pad_id)
|
94
|
+
"#{@id}$#{pad_id}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module EtherpadLite
|
2
|
+
# Aliases to common Etherpad Lite hosts
|
3
|
+
HOST_ALIASES = {:local => 'http://localhost:9001',
|
4
|
+
:public => 'http://beta.etherpad.org'}
|
5
|
+
|
6
|
+
# Returns an EtherpadLite::Instance object.
|
7
|
+
#
|
8
|
+
# ether1 = EtherpadLite.connect('https://etherpad.yoursite.com[https://etherpad.yoursite.com]', 'your api key')
|
9
|
+
#
|
10
|
+
# ether2 = EtherpadLite.connect(:local, File.new('/file/path/to/APIKEY.txt'))
|
11
|
+
#
|
12
|
+
# ether3 = EtherpadLite.connect(:public, "beta.etherpad.org's api key")
|
13
|
+
def self.connect(host_or_alias, api_key_or_file)
|
14
|
+
# Parse the host
|
15
|
+
host = if host_or_alias.is_a? Symbol
|
16
|
+
raise ArgumentError, %Q|Unknown host alias "#{host_or_alias}"| unless HOST_ALIASES.has_key? host_or_alias
|
17
|
+
HOST_ALIASES[host_or_alias]
|
18
|
+
else
|
19
|
+
host_or_alias
|
20
|
+
end
|
21
|
+
|
22
|
+
# Parse the api key
|
23
|
+
if api_key_or_file.is_a? File
|
24
|
+
api_key = api_key_or_file.read
|
25
|
+
api_key_or_file.close
|
26
|
+
else
|
27
|
+
api_key = api_key_or_file
|
28
|
+
end
|
29
|
+
|
30
|
+
Instance.new(host, api_key)
|
31
|
+
end
|
32
|
+
|
33
|
+
# An EtherpadLite::Instance provides a hight-level interface to an Etherpad Lite system.
|
34
|
+
class Instance
|
35
|
+
include Padded
|
36
|
+
API_ROOT = 'api'
|
37
|
+
|
38
|
+
attr_reader :client
|
39
|
+
|
40
|
+
# Instantiate a new Etherpad Lite Instance. The url should include the protocol (i.e. http or https).
|
41
|
+
def initialize(url, api_key)
|
42
|
+
@client = Client.new(api_key, url + "/#{API_ROOT}")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns, creating if necessary, a Group mapped to your foreign system's group
|
46
|
+
def group(mapper)
|
47
|
+
create_group(:mapper => mapper)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns a Group with the given id (it is presumed to already exist).
|
51
|
+
def get_group(id)
|
52
|
+
Group.new self, id
|
53
|
+
end
|
54
|
+
|
55
|
+
# Creates a new Group. Optionally, you may pass the :mapper option your third party system's group id.
|
56
|
+
# This will allow you to find your Group again later using the same identifier as your foreign system.
|
57
|
+
#
|
58
|
+
# Options:
|
59
|
+
#
|
60
|
+
# mapper => your foreign group id
|
61
|
+
def create_group(options={})
|
62
|
+
Group.create self, options
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns, creating if necessary, a Author mapped to your foreign system's author
|
66
|
+
#
|
67
|
+
# Options:
|
68
|
+
#
|
69
|
+
# name => the Author's name
|
70
|
+
def author(mapper, options={})
|
71
|
+
options[:mapper] = mapper
|
72
|
+
create_author options
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns an Author with the given id (it is presumed to already exist).
|
76
|
+
def get_author(id)
|
77
|
+
Author.new self, id
|
78
|
+
end
|
79
|
+
|
80
|
+
# Creates a new Author. Optionally, you may pass the :mapper option your third party system's author id.
|
81
|
+
# This will allow you to find the Author again later using the same identifier as your foreign system.
|
82
|
+
#
|
83
|
+
# Options:
|
84
|
+
#
|
85
|
+
# mapper => your foreign author id
|
86
|
+
#
|
87
|
+
# name => the Author's name
|
88
|
+
def create_author(options={})
|
89
|
+
Author.create self, options
|
90
|
+
end
|
91
|
+
|
92
|
+
def instance; self; end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module EtherpadLite
|
2
|
+
# An Etherpad Lite Pad
|
3
|
+
class Pad
|
4
|
+
attr_reader :id, :instance, :rev
|
5
|
+
|
6
|
+
# Creates and returns a new Pad.
|
7
|
+
#
|
8
|
+
# Options:
|
9
|
+
#
|
10
|
+
# text => 'initial Pad text'
|
11
|
+
#
|
12
|
+
# groupID => group id of Group new Pad should belong to
|
13
|
+
def self.create(instance, id, options={})
|
14
|
+
if options[:groupID]
|
15
|
+
group = Group.new instance, options[:groupID]
|
16
|
+
instance.client.createGroupPad(group.id, degroupify_pad_id(id), options[:text])
|
17
|
+
else
|
18
|
+
group = nil
|
19
|
+
instance.client.createPad(id, options[:text])
|
20
|
+
end
|
21
|
+
new instance, id, :group => group
|
22
|
+
end
|
23
|
+
|
24
|
+
# Remove the group id portion of a Group Pad's id
|
25
|
+
def self.degroupify_pad_id(pad_id)
|
26
|
+
pad_id.to_s.sub(Group::GROUP_ID_REGEX, '').sub(/^\$/, '')
|
27
|
+
end
|
28
|
+
|
29
|
+
# Instantiate a Pad. It is presumed to already exist (via Pad.create).
|
30
|
+
#
|
31
|
+
# Options:
|
32
|
+
#
|
33
|
+
# group
|
34
|
+
#
|
35
|
+
# rev
|
36
|
+
def initialize(instance, id, options={})
|
37
|
+
@instance = instance
|
38
|
+
@id = id.to_s
|
39
|
+
@group = options[:group]
|
40
|
+
@rev = options[:rev]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the name of the Pad. For a normal pad, this is the same as it's id. But for a Group Pad,
|
44
|
+
# this strips away the group id part of the pad id.
|
45
|
+
def name
|
46
|
+
@name ||= self.class.degroupify_pad_id(@id)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns the group_id of this Pad, if any
|
50
|
+
def group_id
|
51
|
+
unless @group_id
|
52
|
+
match = Group::GROUP_ID_REGEX.match(@id)
|
53
|
+
@group_id = match ? match[0] : nil
|
54
|
+
end
|
55
|
+
@group_id
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns this Pad's group, if any
|
59
|
+
def group
|
60
|
+
return nil unless group_id
|
61
|
+
@group ||= Group.new(@instance, group_id)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the Pad's text. Unless you specified a :rev when instantiating the Pad, or specify one here, this will return the latest revision.
|
65
|
+
#
|
66
|
+
# Options:
|
67
|
+
#
|
68
|
+
# rev => revision_number
|
69
|
+
def text(options={})
|
70
|
+
@instance.client.getText(@id, options[:rev])[:text]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Writes txt to the Pad. There is no 'save' method; it is written immediately.
|
74
|
+
def text=(txt)
|
75
|
+
@instance.client.setText(@id, txt)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns a Range of all this Pad's revision numbers
|
79
|
+
def revision_numbers
|
80
|
+
max = @instance.client.getRevisionsCount(@id)[:revisions]
|
81
|
+
(0..max).to_a
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns an array of Pad objects, each with an increasing revision of the text.
|
85
|
+
def revisions
|
86
|
+
revision_numbers.map { |n| Pad.new(@instance, @id, :rev => n) }
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns the Pad's read-only id. This is cached.
|
90
|
+
def read_only_id
|
91
|
+
@read_only_id ||= @instance.client.getReadOnlyID(@id)[:readOnlyID]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns true if this is a public Pad (opposite of private).
|
95
|
+
# This only applies to Pads belonging to a Group.
|
96
|
+
def public?
|
97
|
+
@instance.client.getPublicStatus(@id)[:publicStatus]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Set the pad's public status to true or false (opposite of private=)
|
101
|
+
# This only applies to Pads belonging to a Group.
|
102
|
+
def public=(status)
|
103
|
+
@instance.client.setPublicStatus(@id, status)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns true if this is a private Pad (opposite of public)
|
107
|
+
# This only applies to Pads belonging to a Group.
|
108
|
+
def private?
|
109
|
+
not public?
|
110
|
+
end
|
111
|
+
|
112
|
+
# Set the pad's private status to true or false (opposite of public=)
|
113
|
+
# This only applies to Pads belonging to a Group.
|
114
|
+
def private=(status)
|
115
|
+
public = !status
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns true if this Pad has a password, false if not.
|
119
|
+
# This only applies to Pads belonging to a Group.
|
120
|
+
def password?
|
121
|
+
@instance.client.isPasswordProtected(@id)[:isPasswordProtected]
|
122
|
+
end
|
123
|
+
|
124
|
+
# Sets the Pad's password.
|
125
|
+
# This only applies to Pads belonging to a Group.
|
126
|
+
def password=(new_password)
|
127
|
+
@instance.client.setPassword(@id, new_password)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Deletes the Pad
|
131
|
+
def delete
|
132
|
+
@instance.client.deletePad(@id)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module EtherpadLite
|
2
|
+
# Methods for dealing with pads belonging to something. Both Instance and Group include this, as they each have pads.
|
3
|
+
# This will work with any object which has an instance method, returning an EtherpadLite Instance object.
|
4
|
+
module Padded
|
5
|
+
# Returns the Pad with the given id, creating it if it doesn't already exist.
|
6
|
+
# This requires an HTTP request, so if you *know* the Pad already exists, use Instance#get_pad instead.
|
7
|
+
def pad(id, options={})
|
8
|
+
Pad.create(instance, id, options) rescue Pad.new(instance, id, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns the Pad with the given id (presumed to already exist).
|
12
|
+
# Use this instead of Instance#pad when you *know* the Pad already exists; it will save an HTTP request.
|
13
|
+
def get_pad(id, options={})
|
14
|
+
Pad.new instance, id, options
|
15
|
+
end
|
16
|
+
|
17
|
+
# Creates and returns a Pad with the given id.
|
18
|
+
#
|
19
|
+
# Options:
|
20
|
+
#
|
21
|
+
# text => 'initial Pad text'
|
22
|
+
def create_pad(id, options={})
|
23
|
+
Pad.create instance, id, options
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module EtherpadLite
|
2
|
+
# An Etherpad Lite Session between a Group and an Author
|
3
|
+
class Session
|
4
|
+
attr_reader :id, :instance
|
5
|
+
|
6
|
+
# Creates a new Session between a Group and an Author. The session will expire after length_in_min.
|
7
|
+
def self.create(instance, group_id, author_id, length_in_min)
|
8
|
+
valid_until = Time.now.to_i + length_in_min * 60
|
9
|
+
result = instance.client.createSession(group_id, author_id, valid_until)
|
10
|
+
new instance, result[:sessionID]
|
11
|
+
end
|
12
|
+
|
13
|
+
# Instantiates a Session object (presumed to already exist)
|
14
|
+
def initialize(instance, id, info=nil)
|
15
|
+
@instance = instance
|
16
|
+
@id = id
|
17
|
+
@info = info
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the Session's group id
|
21
|
+
def group_id
|
22
|
+
get_info[:groupID]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the Session's group
|
26
|
+
def group
|
27
|
+
@group ||= Group.new @instance, group_id
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the Session's author id
|
31
|
+
def author_id
|
32
|
+
get_info[:authorID]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the Session's author
|
36
|
+
def author
|
37
|
+
@author ||= Author.new @instance, author_id
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the Session's expiration date is a Unix timestamp in seconds
|
41
|
+
def valid_until
|
42
|
+
get_info[:validUntil]
|
43
|
+
end
|
44
|
+
|
45
|
+
def valid?
|
46
|
+
valid_until < Time.now.to_i
|
47
|
+
end
|
48
|
+
|
49
|
+
def expired?
|
50
|
+
not valid?
|
51
|
+
end
|
52
|
+
|
53
|
+
# Deletes the Session
|
54
|
+
def delete
|
55
|
+
@instance.client.deleteSession(@id)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# Request and cache session info from the server
|
61
|
+
def get_info
|
62
|
+
@info ||= @instance.client.getSessionInfo(@id)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/spec/author_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe EtherpadLite::Author do
|
4
|
+
before do
|
5
|
+
@eth = EtherpadLite.connect TEST_CONFIG[:instances][:http][:url], TEST_CONFIG[:instances][:http][:api_key]
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be created" do
|
9
|
+
author = @eth.create_author
|
10
|
+
author.id.nil?.should == false
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be mapped to 'Author A'" do
|
14
|
+
author = @eth.create_author :mapper => 'Author A'
|
15
|
+
author.id.nil?.should == false
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be mapped to 'Author A'" do
|
19
|
+
author1 = @eth.create_author :mapper => 'Author A'
|
20
|
+
author2 = @eth.author 'Author A'
|
21
|
+
# They should be the same
|
22
|
+
author1.id.should == author2.id
|
23
|
+
end
|
24
|
+
end
|
data/spec/config.yml
ADDED
data/spec/group_spec.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe EtherpadLite::Group do
|
4
|
+
before do
|
5
|
+
@eth = EtherpadLite.connect TEST_CONFIG[:instances][:http][:url], TEST_CONFIG[:instances][:http][:api_key]
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be created" do
|
9
|
+
group = @eth.create_group
|
10
|
+
group.id.nil?.should == false
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be mapped to 'Group A'" do
|
14
|
+
group = @eth.create_group :mapper => 'Group A'
|
15
|
+
group.id.nil?.should == false
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be mapped to 'Group A'" do
|
19
|
+
group1 = @eth.create_group :mapper => 'Group A'
|
20
|
+
group2 = @eth.group 'Group A'
|
21
|
+
# They should be the same
|
22
|
+
group1.id.should == group2.id
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should create a Group Pad" do
|
26
|
+
group = @eth.group 'Group A'
|
27
|
+
pad = group.pad 'Important Group Stuff'
|
28
|
+
pad.id.should == "#{group.id}$Important Group Stuff"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should create a Group Pad with the right name" do
|
32
|
+
group = @eth.group 'Group A'
|
33
|
+
pad = group.pad 'Important Group Stuff'
|
34
|
+
pad.name.should == "Important Group Stuff"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should find a Group Pad with the right group" do
|
38
|
+
group = @eth.group 'Group A'
|
39
|
+
group.get_pad('Important Group Stuff').group_id.should == group.id
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should find a Group Pad with the right id" do
|
43
|
+
group = @eth.group 'Group A'
|
44
|
+
group.pad_ids.should == [:"#{group.id}$Important Group Stuff"]
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should find a Group Pad with the right name" do
|
48
|
+
group = @eth.group 'Group A'
|
49
|
+
group.pads.first.name.should == "Important Group Stuff"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should explicitly create a Group Pad" do
|
53
|
+
group = @eth.group 'Group A'
|
54
|
+
pad = group.create_pad 'new group pad', :text => 'abc'
|
55
|
+
pad.text.should == "abc\n"
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'Group Pad' do
|
59
|
+
context 'Privacy' do
|
60
|
+
it "should be private" do
|
61
|
+
group = @eth.group 'Group A'
|
62
|
+
pad = group.get_pad 'new group pad'
|
63
|
+
pad.private?.should == true
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not be public" do
|
67
|
+
group = @eth.group 'Group A'
|
68
|
+
pad = group.get_pad 'new group pad'
|
69
|
+
pad.public?.should == false
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should change to public" do
|
73
|
+
group = @eth.group 'Group A'
|
74
|
+
pad = group.get_pad 'new group pad'
|
75
|
+
pad.public = true
|
76
|
+
pad.public?.should == true
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should change to not private" do
|
80
|
+
group = @eth.group 'Group A'
|
81
|
+
pad = group.get_pad 'new group pad'
|
82
|
+
pad.private = false
|
83
|
+
pad.private?.should == false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'Password' do
|
88
|
+
it "should not have a password" do
|
89
|
+
group = @eth.group 'Group A'
|
90
|
+
pad = group.get_pad 'new group pad'
|
91
|
+
pad.password?.should == false
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should have a password set" do
|
95
|
+
group = @eth.group 'Group A'
|
96
|
+
pad = group.get_pad 'new group pad'
|
97
|
+
pad.password = 'correct horse battery staple'
|
98
|
+
pad.password?.should == true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe EtherpadLite::Instance do
|
4
|
+
before do
|
5
|
+
@eth = EtherpadLite.connect TEST_CONFIG[:instances][:http][:url], TEST_CONFIG[:instances][:http][:api_key]
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have the right API key" do
|
9
|
+
@eth.client.api_key.should == TEST_CONFIG[:instances][:http][:api_key]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "shouldn't be secure" do
|
13
|
+
@eth.client.secure?.should == false
|
14
|
+
end
|
15
|
+
end
|
data/spec/pad_spec.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe EtherpadLite::Pad do
|
4
|
+
before do
|
5
|
+
@eth = EtherpadLite.connect TEST_CONFIG[:instances][:http][:url], TEST_CONFIG[:instances][:http][:api_key]
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should blow up when querying a non-existing pad" do
|
9
|
+
pad = @eth.get_pad 'a non-existant pad'
|
10
|
+
begin
|
11
|
+
txt = pad.text
|
12
|
+
rescue ArgumentError => e
|
13
|
+
end
|
14
|
+
e.message.should == 'padID does not exist'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should create a new pad" do
|
18
|
+
pad = @eth.create_pad 'my new pad', :text => 'The initial text'
|
19
|
+
pad.text.should == "The initial text\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should blow up when creating a Pad that already exists" do
|
23
|
+
begin
|
24
|
+
pad = @eth.create_pad 'my new pad', :text => 'The initial text'
|
25
|
+
rescue ArgumentError => e
|
26
|
+
end
|
27
|
+
e.message.should == 'padID does already exist'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should automatically create a Pad" do
|
31
|
+
pad = @eth.pad 'another new pad'
|
32
|
+
pad.text = "The initial text"
|
33
|
+
pad.text.should == "The initial text\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should automatically find a Pad" do
|
37
|
+
pad = @eth.pad 'another new pad'
|
38
|
+
pad.text.should == "The initial text\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should find a Pad" do
|
42
|
+
pad = @eth.get_pad 'another new pad'
|
43
|
+
pad.text.should == "The initial text\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have a read-only id" do
|
47
|
+
pad = @eth.get_pad 'another new pad'
|
48
|
+
pad.read_only_id.should =~ /^r\.\w+/
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should add revisions" do
|
52
|
+
pad = @eth.get_pad 'another new pad'
|
53
|
+
pad.text == "New text"
|
54
|
+
pad.revision_numbers.last == 2
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should have the first revision" do
|
58
|
+
pad = @eth.get_pad 'another new pad'
|
59
|
+
pad.text(:rev => 1).should == "The initial text\n"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should have the first revision" do
|
63
|
+
pad = @eth.get_pad 'another new pad'
|
64
|
+
pad.revisions[1].text.should == "The initial text\n"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should have the same name and id" do
|
68
|
+
pad = @eth.get_pad 'another new pad'
|
69
|
+
pad.name.should == pad.id
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be initialized as revision 1" do
|
73
|
+
pad = @eth.get_pad 'another new pad', :rev => 1
|
74
|
+
pad.text.should == "The initial text\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should be deleted" do
|
78
|
+
@eth.get_pad('another new pad').delete
|
79
|
+
@eth.create_pad('another new pad').id.should_not == nil
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe EtherpadLite::Session do
|
4
|
+
before do
|
5
|
+
@eth = EtherpadLite.connect TEST_CONFIG[:instances][:http][:url], TEST_CONFIG[:instances][:http][:api_key]
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be created for a Group" do
|
9
|
+
group = @eth.group 'Maycomb'
|
10
|
+
author = @eth.author 'Atticus'
|
11
|
+
session = group.create_session(author, 20)
|
12
|
+
session.valid_until.should == Time.now.to_i + 20 * 60
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be created for an Author" do
|
16
|
+
group = @eth.group 'Maycomb'
|
17
|
+
author = @eth.author 'Scout'
|
18
|
+
session = author.create_session(group, 15)
|
19
|
+
session.valid_until.should == Time.now.to_i + 15 * 60
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be found in a Group" do
|
23
|
+
group = @eth.group 'Maycomb'
|
24
|
+
author = @eth.author 'Atticus'
|
25
|
+
group.sessions.map(&:author_id).include?(author.id).should == true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "shouldn be found in a Group" do
|
29
|
+
group = @eth.group 'Maycomb'
|
30
|
+
author = @eth.author 'Atticus'
|
31
|
+
author.sessions.map(&:group_id).include?(group.id).should == true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "shouldn't be found in the wrong Group" do
|
35
|
+
group = @eth.group 'Other group'
|
36
|
+
author = @eth.author 'Scout'
|
37
|
+
group.sessions.map(&:author_id).include?(author.id).should == false
|
38
|
+
end
|
39
|
+
|
40
|
+
it "shouldn't be found in the wrong Group" do
|
41
|
+
group = @eth.group 'Other group'
|
42
|
+
author = @eth.author 'Scout'
|
43
|
+
author.sessions.map(&:group_id).include?(group.id).should == false
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
# Load etherpad-lite
|
4
|
+
require File.dirname(__FILE__) + '/../lib/etherpad-lite/client'
|
5
|
+
require File.dirname(__FILE__) + '/../lib/etherpad-lite/models/padded'
|
6
|
+
require File.dirname(__FILE__) + '/../lib/etherpad-lite/models/instance'
|
7
|
+
require File.dirname(__FILE__) + '/../lib/etherpad-lite/models/pad'
|
8
|
+
require File.dirname(__FILE__) + '/../lib/etherpad-lite/models/group'
|
9
|
+
require File.dirname(__FILE__) + '/../lib/etherpad-lite/models/author'
|
10
|
+
require File.dirname(__FILE__) + '/../lib/etherpad-lite/models/session'
|
11
|
+
|
12
|
+
Rspec.configure do |c|
|
13
|
+
c.mock_with :rspec
|
14
|
+
end
|
15
|
+
|
16
|
+
# Load test config
|
17
|
+
require 'yaml'
|
18
|
+
TEST_CONFIG = YAML.load_file(File.dirname(__FILE__) + '/config.yml')
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: etherpad-lite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jordan Hollinger
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-08-30 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: etherpad-lite is a Ruby interface to Etherpad Lite's HTTP JSON API
|
22
|
+
email: jordan@jordanhollinger.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.rdoc
|
29
|
+
files:
|
30
|
+
- lib/etherpad-lite.rb
|
31
|
+
- lib/etherpad-lite/models.rb
|
32
|
+
- lib/etherpad-lite/models/session.rb
|
33
|
+
- lib/etherpad-lite/models/padded.rb
|
34
|
+
- lib/etherpad-lite/models/author.rb
|
35
|
+
- lib/etherpad-lite/models/instance.rb
|
36
|
+
- lib/etherpad-lite/models/pad.rb
|
37
|
+
- lib/etherpad-lite/models/group.rb
|
38
|
+
- lib/etherpad-lite/client.rb
|
39
|
+
- spec/spec_helper.rb
|
40
|
+
- spec/instance_spec.rb
|
41
|
+
- spec/session_spec.rb
|
42
|
+
- spec/group_spec.rb
|
43
|
+
- spec/config.yml
|
44
|
+
- spec/config.yml.example
|
45
|
+
- spec/author_spec.rb
|
46
|
+
- spec/pad_spec.rb
|
47
|
+
- README.rdoc
|
48
|
+
- LICENSE
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://github.com/jhollinger/etherpad-lite
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.3.7
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: A Ruby client library for Etherpad Lite
|
81
|
+
test_files: []
|
82
|
+
|