JackDanger-wave 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|