JackDanger-wave 0.0.4
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 +20 -0
- data/README.markdown +9 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/lib/wave.rb +39 -0
- data/lib/wave/annotation.rb +23 -0
- data/lib/wave/blip.rb +42 -0
- data/lib/wave/document.rb +38 -0
- data/lib/wave/events.rb +39 -0
- data/lib/wave/participant.rb +23 -0
- data/lib/wave/robot.rb +52 -0
- data/lib/wave/wavelet.rb +29 -0
- data/test/annotation_test.rb +23 -0
- data/test/blip_test.rb +47 -0
- data/test/document_test.rb +26 -0
- data/test/participant_test.rb +24 -0
- data/test/robot_test.rb +77 -0
- data/test/test_helper.rb +70 -0
- data/test/wave_test.rb +17 -0
- data/test/wavelet_test.rb +25 -0
- data/wave.gemspec +63 -0
- metadata +81 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jack Danger Canty
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Wave
|
2
|
+
|
3
|
+
Ruby client for the Google Wave Federation Protocol
|
4
|
+
|
5
|
+
based on the [whitepapers](http://www.waveprotocol.org/whitepapers)
|
6
|
+
for use in building [robots](http://code.google.com/intl/it/apis/wave/extensions/robots/index.html) or
|
7
|
+
Ruby clients for human interaction.
|
8
|
+
|
9
|
+
Author: [Jack Danger Canty](http://jackcanty.com)
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "wave"
|
8
|
+
gem.summary = %Q{Ruby client for the Google Wave Federation Protocol}
|
9
|
+
gem.email = "google-wave@jackcanty.com"
|
10
|
+
gem.homepage = "http://github.com/JackDanger/wave"
|
11
|
+
gem.authors = ["Jack Danger Canty"]
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
13
|
+
end
|
14
|
+
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
21
|
+
test.libs << 'lib' << 'test'
|
22
|
+
test.pattern = 'test/**/*_test.rb'
|
23
|
+
test.verbose = true
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'rcov/rcovtask'
|
28
|
+
Rcov::RcovTask.new do |test|
|
29
|
+
test.libs << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
rescue LoadError
|
34
|
+
task :rcov do
|
35
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
task :default => :test
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
if File.exist?('VERSION.yml')
|
45
|
+
config = YAML.load(File.read('VERSION.yml'))
|
46
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
47
|
+
else
|
48
|
+
version = ""
|
49
|
+
end
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "wave #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
56
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.4
|
data/lib/wave.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Wave
|
2
|
+
#
|
3
|
+
# A wave is identified by a globally unique wave id, which is
|
4
|
+
# a pair of a domain name and an id string. The domain names
|
5
|
+
# the wave provider where the wave originated.
|
6
|
+
# So if you're accessing a wave initiated by wave.google.com
|
7
|
+
# the Wave id may look like the following:
|
8
|
+
#
|
9
|
+
# a12f4d@wave.google.com
|
10
|
+
#
|
11
|
+
# A wave contains a collection of wavelets which each have a distinct
|
12
|
+
# list of participants and a historical set of operations (blips)
|
13
|
+
# which contain documents
|
14
|
+
|
15
|
+
|
16
|
+
class Wave
|
17
|
+
VERSION = File.read(File.dirname(__FILE__) + "/../VERSION").chomp
|
18
|
+
|
19
|
+
class WaveError < StandardError; end
|
20
|
+
|
21
|
+
|
22
|
+
attr_reader :id, :wavelets, :options
|
23
|
+
|
24
|
+
def initialize(id, options = {})
|
25
|
+
@id = id
|
26
|
+
@options = options
|
27
|
+
@wavelets = []
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
$:.unshift File.dirname(__FILE__)
|
33
|
+
|
34
|
+
require "wave/wavelet"
|
35
|
+
require "wave/participant"
|
36
|
+
require "wave/blip"
|
37
|
+
require "wave/document"
|
38
|
+
require "wave/annotation"
|
39
|
+
require "wave/robot"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Annotation
|
2
|
+
#
|
3
|
+
# Documents have annotations that span a range of the
|
4
|
+
# document's length. An annotation is a key/value pair
|
5
|
+
# applied to some portion of the document.
|
6
|
+
#
|
7
|
+
#
|
8
|
+
|
9
|
+
class Wave
|
10
|
+
class Annotation
|
11
|
+
|
12
|
+
attr_reader :document, :name, :value, :range
|
13
|
+
|
14
|
+
def initialize(document, name, value, range = 0..0)
|
15
|
+
@document = document
|
16
|
+
@name = name
|
17
|
+
@value = value
|
18
|
+
@range = range
|
19
|
+
raise Wave::WaveError, "Annotation has no document" unless document
|
20
|
+
document.annotations << self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/wave/blip.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Blip
|
2
|
+
#
|
3
|
+
# A blip is a historical operation performed on a wavelet. If the
|
4
|
+
# wavelet is a conversation then this is the smallest meaningful
|
5
|
+
# element of that conversation. Blips can be arranged in a tree
|
6
|
+
# structure with parent/child relationships and each wavelet has
|
7
|
+
# a 'root' blip that is considered the first element of the wavelet.
|
8
|
+
#
|
9
|
+
# Each blip contains a document which holds all the interesting
|
10
|
+
# content of the blip.
|
11
|
+
#
|
12
|
+
|
13
|
+
class Wave
|
14
|
+
class Blip
|
15
|
+
|
16
|
+
attr_reader :wavelet, :parent, :children, :creator
|
17
|
+
attr_accessor :document
|
18
|
+
|
19
|
+
def initialize(options = {})
|
20
|
+
if options[:parent]
|
21
|
+
@parent = options[:parent]
|
22
|
+
@parent.children << self
|
23
|
+
@wavelet = @parent.wavelet
|
24
|
+
end
|
25
|
+
@wavelet ||= options[:wavelet]
|
26
|
+
raise Wave::WaveError, "Blip has no wavelet" unless @wavelet
|
27
|
+
@creator = options[:creator]
|
28
|
+
raise Wave::WaveError, "Blip has no creator" unless @creator
|
29
|
+
@wavelet.blips << self
|
30
|
+
@children ||= []
|
31
|
+
end
|
32
|
+
|
33
|
+
def root?
|
34
|
+
self == wavelet.blips.first
|
35
|
+
end
|
36
|
+
|
37
|
+
def wave
|
38
|
+
wavelet.wave
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Document
|
2
|
+
#
|
3
|
+
# A document is attached to a blip and contains the interesting
|
4
|
+
# data for this element of the conversation.
|
5
|
+
#
|
6
|
+
# Documents contain annotations, elements and a serialized
|
7
|
+
#
|
8
|
+
#
|
9
|
+
|
10
|
+
class Wave
|
11
|
+
class Document
|
12
|
+
|
13
|
+
ELEMENT_TYPES = ['INLINE_BLIP', 'INPUT', 'CHECK', 'LABEL',
|
14
|
+
'BUTTON', 'RADIO_BUTTON', 'RADIO_BUTTON_GROUP',
|
15
|
+
'PASSWORD', 'GADGET', 'IMAGE']
|
16
|
+
|
17
|
+
attr_reader :blip, :elements, :annotations
|
18
|
+
|
19
|
+
def initialize(type, options = {})
|
20
|
+
@type = type
|
21
|
+
@blip = options.delete(:blip)
|
22
|
+
@options = options
|
23
|
+
@elements = []
|
24
|
+
@annotations = []
|
25
|
+
raise Wave::WaveError, "Document has no blip" unless blip
|
26
|
+
blip.document = self
|
27
|
+
end
|
28
|
+
|
29
|
+
def wavelet
|
30
|
+
blip.wavelet
|
31
|
+
end
|
32
|
+
|
33
|
+
def wave
|
34
|
+
wavelet.wave
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/wave/events.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
class Wave
|
2
|
+
module Events
|
3
|
+
|
4
|
+
attr_reader :events
|
5
|
+
|
6
|
+
EVENTS = [
|
7
|
+
'WAVELET_BLIP_CREATED',
|
8
|
+
'WAVELET_BLIP_REMOVED',
|
9
|
+
'WAVELET_PARTICIPANTS_CHANGED',
|
10
|
+
'WAVELET_TIMESTAMP_CHANGED',
|
11
|
+
'WAVELET_TITLE_CHANGED',
|
12
|
+
'WAVELET_VERSION_CHANGED',
|
13
|
+
'BLIP_CONTRIBUTORS_CHANGED',
|
14
|
+
'BLIP_DELETED',
|
15
|
+
'BLIP_SUBMITTED',
|
16
|
+
'BLIP_TIMESTAMP_CHANGED',
|
17
|
+
'BLIP_VERSION_CHANGED',
|
18
|
+
'DOCUMENT_CHANGED',
|
19
|
+
'FORM_BUTTON_CLICKED'
|
20
|
+
]
|
21
|
+
|
22
|
+
EVENTS.each do |event|
|
23
|
+
eval <<-EOMETHOD
|
24
|
+
def #{event.downcase}(&block)
|
25
|
+
raise "No callback action defined for #{event}" unless block
|
26
|
+
add_callback_for(:#{event.downcase}, block)
|
27
|
+
end
|
28
|
+
EOMETHOD
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def add_callback_for(event, block)
|
34
|
+
@events ||= {}
|
35
|
+
@events[event] ||= []
|
36
|
+
@events[event] << block
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Participant
|
2
|
+
#
|
3
|
+
# A participant is one of the humans or robots that have full
|
4
|
+
# read/write access to a wavelet. Participants are identified
|
5
|
+
# by a unique id that (conveniently) is in the exact format of
|
6
|
+
# an email address.
|
7
|
+
#
|
8
|
+
|
9
|
+
class Wave
|
10
|
+
class Participant
|
11
|
+
|
12
|
+
attr_reader :wavelet, :id
|
13
|
+
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
@wavelet = options[:wavelet]
|
17
|
+
raise Wave::WaveError, "Participant requires wavelet" unless @wavelet
|
18
|
+
@wavelet.participants << self
|
19
|
+
@id = options[:id]
|
20
|
+
raise Wave::WaveError, "Participant requires id" unless @id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/wave/robot.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#
|
2
|
+
# Wave Robot
|
3
|
+
#
|
4
|
+
# A wave robot is created by giving the robot a name
|
5
|
+
# and a set of options and then definining callbacks
|
6
|
+
# for the various operations it might receive from the
|
7
|
+
# wave server.
|
8
|
+
#
|
9
|
+
# For example:
|
10
|
+
# Robot.define "Terminator",
|
11
|
+
# :image_url => 'http://www.sky.net/models/t800.png',
|
12
|
+
# :profile_url => 'http://www.sky.net/models/t800.html'
|
13
|
+
# do |robot|
|
14
|
+
# robot.wavelet_participants_changed do |wavelet|
|
15
|
+
# wavelet.kill_participant
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Required options:
|
20
|
+
# image_url: the location of the avatar graphic to identify the robot
|
21
|
+
# profile_url: the URI of the html description of the robot.
|
22
|
+
# Available options:
|
23
|
+
# debug: Optional variable that defaults to False and is passed through
|
24
|
+
# to the webapp application to determine if it should show debug info.
|
25
|
+
#
|
26
|
+
|
27
|
+
require "wave/events"
|
28
|
+
|
29
|
+
class Wave
|
30
|
+
class Robot
|
31
|
+
|
32
|
+
class Error < StandardError; end
|
33
|
+
|
34
|
+
include Wave::Events
|
35
|
+
|
36
|
+
def self.define(name, options = {}, &block)
|
37
|
+
instance = new(name, options)
|
38
|
+
yield instance if block_given?
|
39
|
+
instance
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :name, :options
|
43
|
+
|
44
|
+
def initialize(name, options = {})
|
45
|
+
raise Error, "Each Robot requires a name" if name.empty?
|
46
|
+
raise Error, "Each Robot requires an image_url" unless options[:image_url]
|
47
|
+
raise Error, "Each Robot requires a profile_url" unless options[:profile_url]
|
48
|
+
@name = name
|
49
|
+
@options = options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/wave/wavelet.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Wavelet
|
2
|
+
#
|
3
|
+
# A wavelet has a list of participants that can be any mixture
|
4
|
+
# of humans or robots. This set of participants is distinct from
|
5
|
+
# the participants of any other wavelet in the wave.
|
6
|
+
# A wavelet also contains a set of 'blips' which are an ordered
|
7
|
+
# set of operations serving to create a history for the wavelet.
|
8
|
+
# These blips contain the documents that make up the real content
|
9
|
+
# of the wavelet.
|
10
|
+
#
|
11
|
+
|
12
|
+
|
13
|
+
class Wave
|
14
|
+
class Wavelet
|
15
|
+
|
16
|
+
attr_reader :wave, :options, :participants, :blips
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
raise Wave::WaveError,
|
20
|
+
"Wavelets must be instantiated with a wave option" unless
|
21
|
+
options[:wave] && options[:wave].is_a?(Wave)
|
22
|
+
|
23
|
+
@wave = options.delete(:wave)
|
24
|
+
@participants = options.delete(:participants) || []
|
25
|
+
@blips = options.delete(:blips) || []
|
26
|
+
@wave.wavelets << self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class AnnotationTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "a annotation" do
|
6
|
+
setup { @annotation = Factory.annotation }
|
7
|
+
should "have a document" do
|
8
|
+
assert @annotation.document
|
9
|
+
end
|
10
|
+
should "have a name" do
|
11
|
+
assert @annotation.name
|
12
|
+
end
|
13
|
+
should "have a value" do
|
14
|
+
assert @annotation.value
|
15
|
+
end
|
16
|
+
should "have a range" do
|
17
|
+
assert @annotation.range
|
18
|
+
end
|
19
|
+
should "register itself as an annotation in its document" do
|
20
|
+
assert @annotation.document.annotations.include?(@annotation)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/test/blip_test.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class BlipTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "a blip" do
|
6
|
+
setup { @blip = Factory.blip }
|
7
|
+
should "have a wavelet" do
|
8
|
+
assert @blip.wavelet
|
9
|
+
end
|
10
|
+
should "have a wave" do
|
11
|
+
assert @blip.wave
|
12
|
+
end
|
13
|
+
should "have a creator" do
|
14
|
+
assert @blip.creator
|
15
|
+
end
|
16
|
+
should "have a collection of child blips" do
|
17
|
+
assert @blip.children
|
18
|
+
end
|
19
|
+
should "be root if it's the first blip in the wavelet" do
|
20
|
+
assert @blip.root?
|
21
|
+
end
|
22
|
+
should "not have a parent if it's the root blip" do
|
23
|
+
assert !@blip.parent
|
24
|
+
end
|
25
|
+
should "register itself in its wavelet's blip collection" do
|
26
|
+
assert @blip.wavelet.blips.include?(@blip)
|
27
|
+
end
|
28
|
+
context "made second" do
|
29
|
+
setup { @second_blip = Factory.blip(:wavelet => @blip.wavelet) }
|
30
|
+
should "not be root" do
|
31
|
+
assert !@second_blip.root?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
context "made as a child to another blip" do
|
35
|
+
setup { @child_blip = Factory.blip(:parent => @blip) }
|
36
|
+
should "not be root" do
|
37
|
+
assert !@child_blip.root?
|
38
|
+
end
|
39
|
+
should "have a proper parent blip" do
|
40
|
+
assert_equal @blip, @child_blip.parent
|
41
|
+
end
|
42
|
+
should "be in the parent blip's collection of children" do
|
43
|
+
assert @blip.children.include?(@child_blip)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class DocumentTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "a document" do
|
6
|
+
setup { @document = Factory.document }
|
7
|
+
should "have a blip" do
|
8
|
+
assert @document.blip
|
9
|
+
end
|
10
|
+
should "have a wavelet" do
|
11
|
+
assert @document.wavelet
|
12
|
+
end
|
13
|
+
should "have a wave" do
|
14
|
+
assert @document.wave
|
15
|
+
end
|
16
|
+
should "have a collection of annotations" do
|
17
|
+
assert @document.annotations
|
18
|
+
end
|
19
|
+
should "have a collection of non-text elements" do
|
20
|
+
assert @document.elements
|
21
|
+
end
|
22
|
+
should "register itself as its blip's document" do
|
23
|
+
assert_equal @document, @document.blip.document
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class ParticipantTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "a participant" do
|
6
|
+
setup { @blip = Factory.participant }
|
7
|
+
should "have a wavelet" do
|
8
|
+
assert @blip.wavelet
|
9
|
+
end
|
10
|
+
should "have an id" do
|
11
|
+
assert @blip.id
|
12
|
+
end
|
13
|
+
should "require an id" do
|
14
|
+
assert_raises Wave::WaveError do
|
15
|
+
Wave::Participant.new(:wavelet => Factory.wavelet)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
should "require a wavelet" do
|
19
|
+
assert_raises Wave::WaveError do
|
20
|
+
Wave::Participant.new(:id => 'user@email.com')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/test/robot_test.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class RobotTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "defining a robot" do
|
6
|
+
context "with no name" do
|
7
|
+
should "raise error" do
|
8
|
+
assert_raises(Wave::Robot::Error) { Wave::Robot.define '' }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
context "with no options" do
|
12
|
+
should "raise error" do
|
13
|
+
assert_raises(Wave::Robot::Error) { Wave::Robot.define('PoorlyDefined') }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
context "with name and options" do
|
17
|
+
setup {
|
18
|
+
@robot = Wave::Robot.define("ValidName", :image_url => '/img.jpg',
|
19
|
+
:profile_url => '/profile.html')
|
20
|
+
}
|
21
|
+
should "return a robot instance" do
|
22
|
+
assert_kind_of Wave::Robot, @robot
|
23
|
+
end
|
24
|
+
should "set the name on the robot" do
|
25
|
+
assert_equal 'ValidName', @robot.name
|
26
|
+
end
|
27
|
+
should "set the options on the robot" do
|
28
|
+
assert_equal '/img.jpg', @robot.options[:image_url]
|
29
|
+
assert_equal '/profile.html', @robot.options[:profile_url]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "Robot events" do
|
35
|
+
context "specified via .define block" do
|
36
|
+
setup {
|
37
|
+
@robot =
|
38
|
+
Wave::Robot.define "ValidName",
|
39
|
+
:image_url => '/img.jpg',
|
40
|
+
:profile_url => '/prof.html' do |r|
|
41
|
+
r.wavelet_blip_created do |content|
|
42
|
+
"create a new blip"
|
43
|
+
end
|
44
|
+
r.wavelet_blip_removed do |content|
|
45
|
+
"remove the blip locally"
|
46
|
+
end
|
47
|
+
r.wavelet_blip_removed do |content|
|
48
|
+
"do something else after a blip is removed"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
}
|
52
|
+
should "save the specified events into an event callback" do
|
53
|
+
assert_equal 1, @robot.events[:wavelet_blip_created].size
|
54
|
+
end
|
55
|
+
should "have no callbacks for events that weren't supplied" do
|
56
|
+
assert !@robot.events[:document_changed]
|
57
|
+
end
|
58
|
+
should "support multiple callbacks of the same type" do
|
59
|
+
assert_equal 2, @robot.events[:wavelet_blip_removed].size
|
60
|
+
end
|
61
|
+
should "catch typos on event names" do
|
62
|
+
assert_raises NoMethodError do
|
63
|
+
Wave::Robot.define "ValidName",
|
64
|
+
:image_url => '/img.jpg',
|
65
|
+
:profile_url => '/prof.html' do |r|
|
66
|
+
r.wildly_invalid_event_name {}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
should "allow more events to be added after the initial block" do
|
71
|
+
@robot.wavelet_blip_created {|c| "freak out about the new blip" }
|
72
|
+
assert_equal 2, @robot.events[:wavelet_blip_created].size
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
require 'wave'
|
9
|
+
class Test::Unit::TestCase
|
10
|
+
module Factory
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def wave(options = {})
|
14
|
+
Wave.new(
|
15
|
+
options[:id] || "id#{sequence}@wave.google.com",
|
16
|
+
options
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def wavelet(options = {})
|
21
|
+
Wave::Wavelet.new(
|
22
|
+
{ :wave => options[:wave] || Factory.wave
|
23
|
+
}.merge(options)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def participant(options = {})
|
28
|
+
Wave::Participant.new(
|
29
|
+
{ :id => "id#{sequence}@email.com",
|
30
|
+
:wavelet => options[:wavelet] || Factory.wavelet
|
31
|
+
}.merge(options)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def blip(options = {})
|
36
|
+
wavelet = options[:wavelet] || Factory.wavelet
|
37
|
+
Wave::Blip.new(
|
38
|
+
{ :wavelet => wavelet,
|
39
|
+
:creator => Factory.participant(:wavelet => wavelet)
|
40
|
+
}.merge(options)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def document(options = {})
|
45
|
+
Wave::Document.new(
|
46
|
+
'IMAGE',
|
47
|
+
{ :wavelet => wavelet,
|
48
|
+
:blip => Factory.blip,
|
49
|
+
:creator => Factory.participant(:wavelet => wavelet)
|
50
|
+
}.merge(options)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def annotation(options = {})
|
55
|
+
Wave::Annotation.new(
|
56
|
+
options[:document] || Factory.document,
|
57
|
+
options[:name] || "Annotation#{sequence}",
|
58
|
+
options[:value] || "content number #{sequence}",
|
59
|
+
options[:range] || 4..11
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
def sequence
|
65
|
+
@sequence ||= 0
|
66
|
+
@sequence += 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/test/wave_test.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class WaveTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "instantiating a wave" do
|
6
|
+
context "without any id" do
|
7
|
+
should "raise an error" do
|
8
|
+
assert_raises(ArgumentError) { @wave = Wave.new }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
should "set the wave id" do
|
12
|
+
assert Factory.wave.id =~
|
13
|
+
/^[\w\d]+@[\w\d]+\.[\w\d]+/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class WaveletTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "a wavelet" do
|
6
|
+
setup { @wavelet = Factory.wavelet }
|
7
|
+
should "have a wave" do
|
8
|
+
assert @wavelet.wave
|
9
|
+
end
|
10
|
+
should "require a wave" do
|
11
|
+
assert_raises Wave::WaveError do
|
12
|
+
Wave::Wavelet.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
should "have a participant list" do
|
16
|
+
assert @wavelet.participants
|
17
|
+
end
|
18
|
+
should "have a collection of blips" do
|
19
|
+
assert @wavelet.blips
|
20
|
+
end
|
21
|
+
should "register itself in it's wave's wavelet collection" do
|
22
|
+
assert @wavelet.wave.wavelets.include?(@wavelet)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/wave.gemspec
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{wave}
|
5
|
+
s.version = "0.0.4"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Jack Danger Canty"]
|
9
|
+
s.date = %q{2009-05-30}
|
10
|
+
s.email = %q{google-wave@jackcanty.com}
|
11
|
+
s.extra_rdoc_files = [
|
12
|
+
"LICENSE",
|
13
|
+
"README.markdown"
|
14
|
+
]
|
15
|
+
s.files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.markdown",
|
18
|
+
"Rakefile",
|
19
|
+
"VERSION",
|
20
|
+
"lib/wave.rb",
|
21
|
+
"lib/wave/annotation.rb",
|
22
|
+
"lib/wave/blip.rb",
|
23
|
+
"lib/wave/document.rb",
|
24
|
+
"lib/wave/events.rb",
|
25
|
+
"lib/wave/participant.rb",
|
26
|
+
"lib/wave/robot.rb",
|
27
|
+
"lib/wave/wavelet.rb",
|
28
|
+
"test/annotation_test.rb",
|
29
|
+
"test/blip_test.rb",
|
30
|
+
"test/document_test.rb",
|
31
|
+
"test/participant_test.rb",
|
32
|
+
"test/robot_test.rb",
|
33
|
+
"test/test_helper.rb",
|
34
|
+
"test/wave_test.rb",
|
35
|
+
"test/wavelet_test.rb",
|
36
|
+
"wave.gemspec"
|
37
|
+
]
|
38
|
+
s.homepage = %q{http://github.com/JackDanger/wave}
|
39
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
40
|
+
s.require_paths = ["lib"]
|
41
|
+
s.rubygems_version = %q{1.3.3}
|
42
|
+
s.summary = %q{Ruby client for the Google Wave Federation Protocol}
|
43
|
+
s.test_files = [
|
44
|
+
"test/annotation_test.rb",
|
45
|
+
"test/blip_test.rb",
|
46
|
+
"test/document_test.rb",
|
47
|
+
"test/participant_test.rb",
|
48
|
+
"test/robot_test.rb",
|
49
|
+
"test/test_helper.rb",
|
50
|
+
"test/wave_test.rb",
|
51
|
+
"test/wavelet_test.rb"
|
52
|
+
]
|
53
|
+
|
54
|
+
if s.respond_to? :specification_version then
|
55
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
56
|
+
s.specification_version = 3
|
57
|
+
|
58
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
59
|
+
else
|
60
|
+
end
|
61
|
+
else
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: JackDanger-wave
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jack Danger Canty
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-30 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: google-wave@jackcanty.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.markdown
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README.markdown
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- lib/wave.rb
|
31
|
+
- lib/wave/annotation.rb
|
32
|
+
- lib/wave/blip.rb
|
33
|
+
- lib/wave/document.rb
|
34
|
+
- lib/wave/events.rb
|
35
|
+
- lib/wave/participant.rb
|
36
|
+
- lib/wave/robot.rb
|
37
|
+
- lib/wave/wavelet.rb
|
38
|
+
- test/annotation_test.rb
|
39
|
+
- test/blip_test.rb
|
40
|
+
- test/document_test.rb
|
41
|
+
- test/participant_test.rb
|
42
|
+
- test/robot_test.rb
|
43
|
+
- test/test_helper.rb
|
44
|
+
- test/wave_test.rb
|
45
|
+
- test/wavelet_test.rb
|
46
|
+
- wave.gemspec
|
47
|
+
has_rdoc: false
|
48
|
+
homepage: http://github.com/JackDanger/wave
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --charset=UTF-8
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.2.0
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Ruby client for the Google Wave Federation Protocol
|
73
|
+
test_files:
|
74
|
+
- test/annotation_test.rb
|
75
|
+
- test/blip_test.rb
|
76
|
+
- test/document_test.rb
|
77
|
+
- test/participant_test.rb
|
78
|
+
- test/robot_test.rb
|
79
|
+
- test/test_helper.rb
|
80
|
+
- test/wave_test.rb
|
81
|
+
- test/wavelet_test.rb
|