rave 0.1.2-java
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/bin/rave +28 -0
- data/lib/commands/appcfg.rb +9 -0
- data/lib/commands/create.rb +153 -0
- data/lib/commands/server.rb +8 -0
- data/lib/commands/task.rb +156 -0
- data/lib/commands/usage.rb +19 -0
- data/lib/commands/war.rb +28 -0
- data/lib/exceptions.rb +20 -0
- data/lib/ext/logger.rb +7 -0
- data/lib/gems.yaml +9 -0
- data/lib/jars/appengine-api-1.0-sdk-1.3.0.jar +0 -0
- data/lib/mixins/controller.rb +72 -0
- data/lib/mixins/data_format.rb +206 -0
- data/lib/mixins/logger.rb +19 -0
- data/lib/mixins/object_factory.rb +87 -0
- data/lib/mixins/time_utils.rb +19 -0
- data/lib/models/annotation.rb +148 -0
- data/lib/models/blip.rb +305 -0
- data/lib/models/component.rb +42 -0
- data/lib/models/context.rb +174 -0
- data/lib/models/document.rb +9 -0
- data/lib/models/element.rb +113 -0
- data/lib/models/event.rb +230 -0
- data/lib/models/operation.rb +79 -0
- data/lib/models/range.rb +14 -0
- data/lib/models/robot.rb +79 -0
- data/lib/models/user.rb +62 -0
- data/lib/models/wave.rb +45 -0
- data/lib/models/wavelet.rb +269 -0
- data/lib/ops/blip_ops.rb +233 -0
- data/lib/rave.rb +28 -0
- metadata +135 -0
data/lib/models/robot.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Rave
|
5
|
+
module Models
|
6
|
+
# Contains Robot data, event handlers and cron jobs.
|
7
|
+
class Robot < User
|
8
|
+
include Rave::Mixins::DataFormat
|
9
|
+
include Rave::Mixins::Controller
|
10
|
+
include Singleton
|
11
|
+
|
12
|
+
CONFIG_FILE = 'config.yaml' # :nodoc:
|
13
|
+
|
14
|
+
# Version of the robot, as in the yaml config [String]
|
15
|
+
def version # :nodoc:
|
16
|
+
@version.dup
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize() # :nodoc:
|
20
|
+
config = config_from_file
|
21
|
+
super(config)
|
22
|
+
@handlers = {}
|
23
|
+
@cron_jobs = []
|
24
|
+
@version = config[:version] || '1'
|
25
|
+
register_default_handlers
|
26
|
+
end
|
27
|
+
|
28
|
+
# Read options from user-edited yaml config file.
|
29
|
+
def config_from_file # :nodoc:
|
30
|
+
config = YAML::load(File.open(CONFIG_FILE))
|
31
|
+
hash = {}
|
32
|
+
config['robot'].each_pair { |k, v| hash[k.to_sym] = v }
|
33
|
+
hash
|
34
|
+
end
|
35
|
+
|
36
|
+
# Register a handler. Multiple handlers may be applied to a single event.
|
37
|
+
# +event_type+:: Must be one of Rave::Models::Event::*::TYPE [String]
|
38
|
+
def register_handler(event_type, handler)
|
39
|
+
raise Rave::InvalidEventException.new("Unknown event: #{event_type}") unless Rave::Models::Event.valid_type?(event_type)
|
40
|
+
raise Rave::InvalidHandlerException.new("Unknown handler: #{handler}") unless self.respond_to?(handler)
|
41
|
+
@handlers[event_type] ||= []
|
42
|
+
@handlers[event_type] << handler unless @handlers[event_type].include?(handler)
|
43
|
+
end
|
44
|
+
|
45
|
+
#Dispatches events to the appropriate handler
|
46
|
+
def handle_event(event, context) # :nodoc:
|
47
|
+
#Ignore unhandled events
|
48
|
+
if (handlers = @handlers[event.type])
|
49
|
+
handlers.each do |handler|
|
50
|
+
self.send(handler, event, context)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
#Registers a cron job
|
56
|
+
def register_cron_job(handler, seconds)
|
57
|
+
@cron_jobs << { :path => "/_wave/cron/#{handler}", :handler => handler, :seconds => seconds }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates a new wave with initial participants set.
|
61
|
+
# +participants+:: Humans and/or robots to start in the new wave [Array of String/User]
|
62
|
+
# Returns: The new wave, which contains a root wavelet which itself contains a root blip [Wave]
|
63
|
+
def create_wavelet(participants)
|
64
|
+
@context.create_wavelet(participants)
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
#Register any handlers that are defined through naming convention
|
69
|
+
def register_default_handlers # :nodoc:
|
70
|
+
Event.types.each do |type|
|
71
|
+
listener = type.downcase.to_sym
|
72
|
+
if respond_to?(listener)
|
73
|
+
register_handler(type, listener)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/models/user.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
module Rave
|
2
|
+
module Models
|
3
|
+
# A wave client, acting as a wave creator, blip contributor and/or a wavelet participant.
|
4
|
+
class User < Component
|
5
|
+
ROBOT_PATTERN = /@appspot\.com$/ # :nodoc:
|
6
|
+
NOBODY_ID = "@@@nobody@@@" # :nodoc: Used as a default in certain circumstances.
|
7
|
+
|
8
|
+
# Url link to the profile of the User [String].
|
9
|
+
# NOTE: Due to a limitation in Wave, for all users except the local robot
|
10
|
+
# the url will be empty.
|
11
|
+
def profile_url # :nodoc:
|
12
|
+
@profile_url.dup
|
13
|
+
end
|
14
|
+
|
15
|
+
# Url link to the image of the User [String].
|
16
|
+
# NOTE: Due to a limitation in Wave, for all users except the local robot
|
17
|
+
# the url will be empty.
|
18
|
+
def image_url # :nodoc:
|
19
|
+
@image_url.dup
|
20
|
+
end
|
21
|
+
|
22
|
+
# Unlike other components, Users are never generated [Boolean].
|
23
|
+
def generated? # :nodoc:
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
# - :id
|
28
|
+
# - :name
|
29
|
+
# - :profile_url
|
30
|
+
# - :image_url
|
31
|
+
# - :context
|
32
|
+
def initialize(options = {}) # :nodoc:
|
33
|
+
options[:id].downcase! if options[:id]
|
34
|
+
super(options)
|
35
|
+
@name = options[:name]
|
36
|
+
@profile_url = options[:profile_url] || ''
|
37
|
+
@image_url = options[:image_url] || ''
|
38
|
+
end
|
39
|
+
|
40
|
+
# Printable name of the User [String].
|
41
|
+
# NOTE: Due to a limitation in Wave, for all users except the local robot
|
42
|
+
# the name is the same as the @id.
|
43
|
+
def name # :nodoc:
|
44
|
+
@name || @id
|
45
|
+
end
|
46
|
+
|
47
|
+
# Is the User a robot client rather than a human client? [Boolean]
|
48
|
+
def robot? # :nodoc:
|
49
|
+
not (@id =~ ROBOT_PATTERN).nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
# Convert to string [String]
|
53
|
+
def to_s
|
54
|
+
@id
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_json # :nodoc:
|
58
|
+
@id.to_json
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/models/wave.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Rave
|
2
|
+
module Models
|
3
|
+
# Represents a Wave
|
4
|
+
class Wave < Component
|
5
|
+
# IDs for all wavelets that are part of the wave [Array of String]
|
6
|
+
def wavelet_ids # :nodoc:
|
7
|
+
@wavelet_ids.map { |id| id.dup }
|
8
|
+
end
|
9
|
+
|
10
|
+
#Options include:
|
11
|
+
# - :wavelet_ids
|
12
|
+
# - :id
|
13
|
+
def initialize(options = {}) # :nodoc:
|
14
|
+
if options[:id].nil? and options[:context]
|
15
|
+
super(:id => "#{GENERATED_PREFIX}_wave_#{unique_id}", :context => options[:context])
|
16
|
+
else
|
17
|
+
super(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
@wavelet_ids = options[:wavelet_ids] || []
|
21
|
+
end
|
22
|
+
|
23
|
+
# All wavelets that are part of the wave [Array of Wavelet]
|
24
|
+
def wavelets # :nodoc:
|
25
|
+
@wavelet_ids.map { |id| @context.wavelets[id] }
|
26
|
+
end
|
27
|
+
|
28
|
+
# The root wavelet (it will be nil if the event refers to a private subwavelet) [Wavelet]
|
29
|
+
def root_wavelet # :nodoc:
|
30
|
+
wavelets.find { |wavelet| wavelet and wavelet.root? }
|
31
|
+
end
|
32
|
+
|
33
|
+
def print_structure(indent = 0) # :nodoc:
|
34
|
+
str = ''
|
35
|
+
str << "#{' ' * indent}Wave:#{@id}\n"
|
36
|
+
|
37
|
+
wavelets.each do |wavelet|
|
38
|
+
str << wavelet.print_structure(indent + 1)
|
39
|
+
end
|
40
|
+
|
41
|
+
str
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,269 @@
|
|
1
|
+
module Rave
|
2
|
+
module Models
|
3
|
+
# Represents a Wavelet, owned by a Wave
|
4
|
+
class Wavelet < Component
|
5
|
+
include Rave::Mixins::TimeUtils
|
6
|
+
include Rave::Mixins::Logger
|
7
|
+
|
8
|
+
# Creator of the wavelet if it was generated via an operation.
|
9
|
+
GENERATED_CREATOR = "rusty@a.gwave.com" # :nodoc:
|
10
|
+
|
11
|
+
# Current version number of the wavelet [Integer]
|
12
|
+
attr_reader :version
|
13
|
+
|
14
|
+
# ID of the creator [String]
|
15
|
+
def creator_id # :nodoc:
|
16
|
+
@creator_id.dup
|
17
|
+
end
|
18
|
+
|
19
|
+
# Time the wavelet was created [Time]
|
20
|
+
def creation_time # :nodoc:
|
21
|
+
@creation_time.dup
|
22
|
+
end
|
23
|
+
|
24
|
+
# Documents contained within the wavelet [Array of Document]
|
25
|
+
def data_documents # :nodoc:
|
26
|
+
@data_documents.dup
|
27
|
+
end
|
28
|
+
|
29
|
+
# The last time the wavelet was modified [Time]
|
30
|
+
def last_modified_time # :nodoc:
|
31
|
+
@last_modified_time.dup
|
32
|
+
end
|
33
|
+
|
34
|
+
# ID for the root blip [String]
|
35
|
+
def root_blip_id # :nodoc:
|
36
|
+
@root_blip_id.dup
|
37
|
+
end
|
38
|
+
|
39
|
+
# Wavelet title [String]
|
40
|
+
def title # :nodoc:
|
41
|
+
@title.dup
|
42
|
+
end
|
43
|
+
|
44
|
+
# ID of the wave that the wavelet is a part of [String]
|
45
|
+
def wave_id # :nodoc:
|
46
|
+
@wave_id.dup
|
47
|
+
end
|
48
|
+
|
49
|
+
# IDs of all those who are currently members of the wavelet [Array of String]
|
50
|
+
def participant_ids # :nodoc:
|
51
|
+
@participant_ids.map { |id| id.dup }
|
52
|
+
end
|
53
|
+
|
54
|
+
JAVA_CLASS = 'com.google.wave.api.impl.WaveletData'
|
55
|
+
ROOT_ID_SUFFIX = "conv+root" #The suffix for the root wavelet in a wave]
|
56
|
+
ROOT_ID_REGEXP = /#{Regexp.escape(ROOT_ID_SUFFIX)}$/
|
57
|
+
|
58
|
+
#
|
59
|
+
# Options include:
|
60
|
+
# - :creator
|
61
|
+
# - :creation_time
|
62
|
+
# - :data_documents
|
63
|
+
# - :last_modifed_time
|
64
|
+
# - :participants
|
65
|
+
# - :root_blip_id
|
66
|
+
# - :title
|
67
|
+
# - :version
|
68
|
+
# - :wave_id
|
69
|
+
# - :context
|
70
|
+
# - :id
|
71
|
+
def initialize(options = {}) # :nodoc:
|
72
|
+
@participant_ids = options[:participants] || []
|
73
|
+
|
74
|
+
if options[:id].nil? and options[:context]
|
75
|
+
# Generate the wavelet from scratch.
|
76
|
+
super(:id => "#{GENERATED_PREFIX}_wavelet_#{unique_id}_#{ROOT_ID_SUFFIX}", :context => options[:context])
|
77
|
+
|
78
|
+
# Create a wave to live in.
|
79
|
+
wave = Wave.new(:wavelet_ids => [@id], :context => @context)
|
80
|
+
@wave_id = wave.id
|
81
|
+
@context.add_wave(wave)
|
82
|
+
|
83
|
+
# Ensure the newly created wavelet has a root blip.
|
84
|
+
blip = Blip.new(:wave_id => wave.id, :wavelet_id => @id,
|
85
|
+
:creator => @context.robot.id, :contributors => [@context.robot.id])
|
86
|
+
@context.add_blip(blip)
|
87
|
+
@root_blip_id = blip.id
|
88
|
+
|
89
|
+
@participant_ids.each do |id|
|
90
|
+
@context.add_user(:id => id) unless @context.users[id]
|
91
|
+
end
|
92
|
+
|
93
|
+
@creator_id = GENERATED_CREATOR
|
94
|
+
@context.add_user(:id => @creator_id) unless @context.users[@creator_id]
|
95
|
+
else
|
96
|
+
super(options)
|
97
|
+
@root_blip_id = options[:root_blip_id]
|
98
|
+
@creator_id = options[:creator] || User::NOBODY_ID
|
99
|
+
@wave_id = options[:wave_id]
|
100
|
+
end
|
101
|
+
|
102
|
+
@creation_time = time_from_json(options[:creation_time]) || Time.now
|
103
|
+
@data_documents = options[:data_documents] || {}
|
104
|
+
@last_modified_time = time_from_json(options[:last_modified_time]) || Time.now
|
105
|
+
@title = options[:title] || ''
|
106
|
+
@version = options[:version] || 0
|
107
|
+
end
|
108
|
+
|
109
|
+
# Users that are currently have access the wavelet [Array of User]
|
110
|
+
def participants # :nodoc:
|
111
|
+
@participant_ids.map { |p| @context.users[p] }
|
112
|
+
end
|
113
|
+
|
114
|
+
# Users that originally created the wavelet [User]
|
115
|
+
def creator # :nodoc:
|
116
|
+
@context.users[@creator_id]
|
117
|
+
end
|
118
|
+
|
119
|
+
# Is this the root wavelet for its wave? [Boolean]
|
120
|
+
def root? # :nodoc:
|
121
|
+
not (id =~ ROOT_ID_REGEXP).nil?
|
122
|
+
end
|
123
|
+
|
124
|
+
#Creates a blip for this wavelet
|
125
|
+
# Returns: Gererated blip [Blip]
|
126
|
+
def create_blip
|
127
|
+
parent = final_blip
|
128
|
+
blip = Blip.new(:wave_id => @wave_id, :parent_blip_id => parent.id,
|
129
|
+
:wavelet_id => @id, :context => @context)
|
130
|
+
parent.add_child_blip(blip)
|
131
|
+
|
132
|
+
@context.add_operation(:type => Operation::WAVELET_APPEND_BLIP, :wave_id => @wave_id, :wavelet_id => @id, :property => blip)
|
133
|
+
blip
|
134
|
+
end
|
135
|
+
|
136
|
+
# Find the last blip in the main thread [Blip]
|
137
|
+
def final_blip # :nodoc:
|
138
|
+
blip = @context.blips[@root_blip_id]
|
139
|
+
if blip
|
140
|
+
while blip
|
141
|
+
# Find the first blip that is defined, if at all.
|
142
|
+
child_blip = blip.child_blips.find { |b| not b.nil? }
|
143
|
+
break unless child_blip
|
144
|
+
blip = child_blip
|
145
|
+
end
|
146
|
+
end
|
147
|
+
blip
|
148
|
+
end
|
149
|
+
|
150
|
+
# Adds a participant (human or robot) to the wavelet
|
151
|
+
# +user+:: User to add, as ID or object [String or User]
|
152
|
+
# Returns: The user that was added [User or nil]
|
153
|
+
def add_participant(user) # :nodoc:
|
154
|
+
id = user.to_s.downcase
|
155
|
+
if @participant_ids.include?(id)
|
156
|
+
logger.warning("Attempted to add a participant who was already in the wavelet(#{@id}): #{id}")
|
157
|
+
return nil
|
158
|
+
end
|
159
|
+
|
160
|
+
# Allow string names to be used as participant.
|
161
|
+
user = if @context.users[id]
|
162
|
+
@context.users[id]
|
163
|
+
else
|
164
|
+
@context.add_user(:id => id)
|
165
|
+
end
|
166
|
+
|
167
|
+
@context.add_operation(:type => Operation::WAVELET_ADD_PARTICIPANT,
|
168
|
+
:wave_id => @wave_id, :wavelet_id => @id, :property => user)
|
169
|
+
@participant_ids << id
|
170
|
+
|
171
|
+
user
|
172
|
+
end
|
173
|
+
|
174
|
+
# Removes a participant (robot only) from the wavelet.
|
175
|
+
# +user+:: User to remove, as ID or object [String or User]
|
176
|
+
# Returns: The user that was removed [User or nil]
|
177
|
+
def remove_participant(user) # :nodoc:
|
178
|
+
id = user.to_s.downcase
|
179
|
+
unless @participant_ids.include?(id)
|
180
|
+
logger.warning("Attempted to remove a participant who was not in the wavelet(#{@id}): #{id}")
|
181
|
+
return nil
|
182
|
+
end
|
183
|
+
|
184
|
+
# Allow string names to be used as participant.
|
185
|
+
user = @context.users[id]
|
186
|
+
|
187
|
+
unless user.robot?
|
188
|
+
logger.warning("Attempted to remove a non-robot from wavelet(#{@id}): #{id}")
|
189
|
+
return nil
|
190
|
+
end
|
191
|
+
|
192
|
+
if user == @context.robot
|
193
|
+
return remove_robot
|
194
|
+
end
|
195
|
+
|
196
|
+
@context.add_operation(:type => Operation::WAVELET_REMOVE_PARTICIPANT,
|
197
|
+
:wave_id => @wave_id, :wavelet_id => @id, :property => user)
|
198
|
+
@participant_ids.delete id
|
199
|
+
|
200
|
+
user
|
201
|
+
end
|
202
|
+
|
203
|
+
# Removes the local robot from the wavelet.
|
204
|
+
# Returns: The local robot [Robot]
|
205
|
+
def remove_robot
|
206
|
+
robot = @context.robot
|
207
|
+
@context.add_operation(:type => Operation::WAVELET_REMOVE_SELF,
|
208
|
+
:wave_id => @wave_id, :wavelet_id => @id)
|
209
|
+
@participant_ids.delete robot.id
|
210
|
+
|
211
|
+
robot
|
212
|
+
end
|
213
|
+
|
214
|
+
#Sets the data document for the wavelet
|
215
|
+
#
|
216
|
+
# NOT IMPLEMENTED
|
217
|
+
def set_data_document(name, data)
|
218
|
+
raise NotImplementedError
|
219
|
+
end
|
220
|
+
|
221
|
+
#Set the title
|
222
|
+
#
|
223
|
+
def title=(title) # :nodoc: Documented by title() as accessor.
|
224
|
+
title = title.to_s
|
225
|
+
@context.add_operation(:type => Operation::WAVELET_SET_TITLE,
|
226
|
+
:wave_id => @wave_id, :wavelet_id => @id, :property => title)
|
227
|
+
@title = title
|
228
|
+
end
|
229
|
+
|
230
|
+
# First blip in the wavelet [Blip]
|
231
|
+
def root_blip # :nodoc:
|
232
|
+
@context.blips[@root_blip_id]
|
233
|
+
end
|
234
|
+
|
235
|
+
# Wave that the wavelet is contained within.
|
236
|
+
def wave# :nodoc:
|
237
|
+
@context.waves[@wave_id]
|
238
|
+
end
|
239
|
+
|
240
|
+
# *INTERNAL*
|
241
|
+
# Convert to json for sending in an operation.
|
242
|
+
def to_json # :nodoc:
|
243
|
+
{
|
244
|
+
'waveletId' => @id,
|
245
|
+
'javaClass' => JAVA_CLASS,
|
246
|
+
'waveId' => @wave_id,
|
247
|
+
'rootBlipId' => @root_blip_id,
|
248
|
+
'participants' => { "javaClass" => "java.util.ArrayList", "list" => @participant_ids }
|
249
|
+
}.to_json
|
250
|
+
end
|
251
|
+
|
252
|
+
# Convert to string.
|
253
|
+
def to_s
|
254
|
+
text = @title.length > 24 ? "#{@title[0..20]}..." : @title
|
255
|
+
"#{super}:#{participants.join(',')}:#{text}"
|
256
|
+
end
|
257
|
+
|
258
|
+
def print_structure(indent = 0) # :nodoc:
|
259
|
+
str = "#{' ' * indent}#{to_s}\n"
|
260
|
+
|
261
|
+
if root_blip
|
262
|
+
str << root_blip.print_structure(indent + 1)
|
263
|
+
end
|
264
|
+
|
265
|
+
str
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|