rave 0.1.1 → 0.1.2
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 +27 -23
- data/lib/commands/appcfg.rb +9 -0
- data/lib/commands/create.rb +153 -147
- data/lib/commands/server.rb +7 -7
- data/lib/commands/task.rb +156 -0
- data/lib/commands/usage.rb +18 -12
- data/lib/commands/war.rb +27 -50
- data/lib/exceptions.rb +19 -5
- data/lib/ext/logger.rb +7 -0
- data/lib/gems.yaml +9 -0
- data/lib/jars/{appengine-api-1.0-sdk-1.2.1.jar → appengine-api-1.0-sdk-1.3.0.jar} +0 -0
- data/lib/mixins/controller.rb +72 -40
- data/lib/mixins/data_format.rb +206 -168
- 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 -18
- data/lib/models/blip.rb +305 -61
- data/lib/models/component.rb +42 -0
- data/lib/models/context.rb +174 -45
- data/lib/models/document.rb +8 -8
- data/lib/models/element.rb +113 -0
- data/lib/models/event.rb +230 -48
- data/lib/models/operation.rb +79 -89
- data/lib/models/range.rb +14 -0
- data/lib/models/robot.rb +78 -60
- data/lib/models/user.rb +62 -0
- data/lib/models/wave.rb +45 -19
- data/lib/models/wavelet.rb +269 -69
- data/lib/ops/blip_ops.rb +233 -134
- data/lib/rave.rb +27 -22
- metadata +96 -77
- data/lib/jars/jruby-core.jar +0 -0
- data/lib/jars/ruby-stdlib.jar +0 -0
data/lib/commands/usage.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
|
-
#Display usage for rave command
|
2
|
-
def display_usage
|
3
|
-
puts "Useage: rave [create | server | war] [robot_name] [options]"
|
4
|
-
puts "'create' generates a Google Wave robot client stub application."
|
5
|
-
puts "e.g."
|
6
|
-
puts "rave create my_robot image_url=http://my_robot.appspot.com/image.png profile_url=http://my_robot.appspot.com/"
|
7
|
-
puts "'server' launches the robot"
|
8
|
-
puts "e.g."
|
9
|
-
puts "rave server"
|
10
|
-
puts "'war' creates a war file suitable for deploying to Google AppEngine"
|
11
|
-
puts "e.g."
|
12
|
-
puts "rave war"
|
1
|
+
#Display usage for rave command
|
2
|
+
def display_usage
|
3
|
+
puts "Useage: rave [create | server | war] [robot_name] [options]"
|
4
|
+
puts "'create' generates a Google Wave robot client stub application."
|
5
|
+
puts "e.g."
|
6
|
+
puts "rave create my_robot image_url=http://my_robot.appspot.com/image.png profile_url=http://my_robot.appspot.com/"
|
7
|
+
puts "'server' launches the robot"
|
8
|
+
puts "e.g."
|
9
|
+
puts "rave server"
|
10
|
+
puts "'war' creates a war file suitable for deploying to Google AppEngine"
|
11
|
+
puts "e.g."
|
12
|
+
puts "rave war"
|
13
|
+
puts "'appengine_deploy' deploys the tmp/war folder to Google AppEngine"
|
14
|
+
puts "e.g."
|
15
|
+
puts "rave appengine_deploy"
|
16
|
+
puts "'cleanup' removes the .war file and the tmp/war staging directory"
|
17
|
+
puts "e.g."
|
18
|
+
puts "rave cleanup"
|
13
19
|
end
|
data/lib/commands/war.rb
CHANGED
@@ -1,51 +1,28 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
def delete_jruby_from_warbler(web_inf_gems)
|
29
|
-
jar = Dir[File.join(web_inf_gems, "warbler-*", "lib", "jruby-complete-*.jar")].first
|
30
|
-
puts "Deleting #{jar}"
|
31
|
-
File.delete(jar) if jar
|
32
|
-
end
|
33
|
-
|
34
|
-
def copy_jruby_chunks_to_warbler(rave_jar_dir, warbler_jar_dir)
|
35
|
-
puts "Copying jruby chunks"
|
36
|
-
%w( jruby-core.jar ruby-stdlib.jar ).each do |jar|
|
37
|
-
File.copy(File.join(rave_jar_dir, jar), File.join(warbler_jar_dir, jar))
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def fix_json_jruby_paths(web_inf_gems)
|
42
|
-
#TODO: Why is this necessary? Is this an appengine issue?
|
43
|
-
puts "Fixing paths in json-jruby"
|
44
|
-
ext = Dir[File.join(web_inf_gems, "json-jruby-*", "lib", "json", "ext.rb")].first
|
45
|
-
if ext
|
46
|
-
text = File.open(ext, "r") { |f| f.read }
|
47
|
-
text.gsub!("require 'json/ext/parser'", "require 'ext/parser'")
|
48
|
-
text.gsub!("require 'json/ext/generator'", "require 'ext/generator'")
|
49
|
-
File.open(ext, "w") { |f| f.write(text) }
|
50
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require File.join(File.dirname(__FILE__), 'task.rb')
|
4
|
+
|
5
|
+
#Runs warbler to package up the robot
|
6
|
+
# then does some cleanup that is specific to App Engine:
|
7
|
+
# => Deletes the complete JRuby jar from both the app's lib folder and
|
8
|
+
# the frozen warbler gem, and replaces them with a broken up version
|
9
|
+
# => Changes the file path json-jruby
|
10
|
+
# TODO: Not sure why this is necessary, but it doesn't run on appengine without it
|
11
|
+
def create_war(args)
|
12
|
+
Rake.application.standard_exception_handling do
|
13
|
+
Rake.application.init
|
14
|
+
Rave::Task.new
|
15
|
+
task(:default => "rave:create_war")
|
16
|
+
Rake.application.top_level
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#Runs warbler's cleanup to get rid of the .war file and the tmp/war folder
|
21
|
+
def cleanup_war(args)
|
22
|
+
Rake.application.standard_exception_handling do
|
23
|
+
Rake.application.init
|
24
|
+
Rave::Task.new
|
25
|
+
task(:default => "rave:clean")
|
26
|
+
Rake.application.top_level
|
27
|
+
end
|
51
28
|
end
|
data/lib/exceptions.rb
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
-
module Rave
|
2
|
-
#Exception raised when registering an invalid event
|
3
|
-
class InvalidEventException < Exception ; end
|
4
|
-
|
5
|
-
|
1
|
+
module Rave
|
2
|
+
#Exception raised when registering an invalid event
|
3
|
+
class InvalidEventException < Exception ; end
|
4
|
+
|
5
|
+
#Exception raised when registering an event with an invalid handler
|
6
|
+
class InvalidHandlerException < Exception ; end
|
7
|
+
|
8
|
+
# Raised when trying to create an object with the same ID as one that already exists.
|
9
|
+
class DuplicatedIDError < Exception; end
|
10
|
+
|
11
|
+
# Raised if an unimplemented method is called.
|
12
|
+
class NotImplementedError < Exception; end
|
13
|
+
|
14
|
+
# A method option was not one of the values allowed.
|
15
|
+
class BadOptionError < ArgumentError
|
16
|
+
def initialize(option_name, valid_options, received) # :nodoc:
|
17
|
+
super("#{option_name.inspect} option must be one of #{valid_options.inspect}, not #{received.inspect}")
|
18
|
+
end
|
19
|
+
end
|
6
20
|
end
|
data/lib/ext/logger.rb
ADDED
data/lib/gems.yaml
ADDED
Binary file
|
data/lib/mixins/controller.rb
CHANGED
@@ -1,40 +1,72 @@
|
|
1
|
-
#Contains the Rack #call method - to be mixed in to the Robot class
|
2
|
-
module Rave
|
3
|
-
module Mixins
|
4
|
-
module Controller
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
method
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
1
|
+
#Contains the Rack #call method - to be mixed in to the Robot class
|
2
|
+
module Rave
|
3
|
+
module Mixins
|
4
|
+
module Controller
|
5
|
+
include Logger
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
request = Rack::Request.new(env)
|
9
|
+
path = request.path_info
|
10
|
+
method = request.request_method
|
11
|
+
logger.info("#{method}ing #{path}")
|
12
|
+
begin
|
13
|
+
#There are only 3 URLs that Wave can access:
|
14
|
+
# robot capabilities, robot profile, and event notification
|
15
|
+
if path == "/_wave/capabilities.xml" && method == "GET"
|
16
|
+
[ 200, { 'Content-Type' => 'text/xml' }, capabilities_xml ]
|
17
|
+
elsif path == "/_wave/robot/profile" && method == "GET"
|
18
|
+
[ 200, { 'Content-Type' => 'application/json' }, profile_json ]
|
19
|
+
elsif path == "/_wave/robot/jsonrpc" && method == "POST"
|
20
|
+
body = request.body.read
|
21
|
+
context, events = parse_json_body(body)
|
22
|
+
events.each do |event|
|
23
|
+
handle_event(event, context)
|
24
|
+
end
|
25
|
+
response = context.to_json
|
26
|
+
logger.info("Structure (after):\n#{context.print_structure}")
|
27
|
+
logger.info("Response:\n#{response}")
|
28
|
+
[ 200, { 'Content-Type' => 'application/json' }, response ]
|
29
|
+
elsif cron_job = @cron_jobs.find { |job| job[:path] == path }
|
30
|
+
body = request.body.read
|
31
|
+
context, events = parse_json_body(body)
|
32
|
+
self.send(cron_job[:handler], context)
|
33
|
+
[ 200, { 'Content-Type' => 'application/json' }, context.to_json ]
|
34
|
+
elsif File.exist?(file = File.join(".", "public", *(path.split("/"))))
|
35
|
+
#Static resource
|
36
|
+
[ 200, { 'Content-Type' => static_resource_content_type(file) }, File.open(file) { |f| f.read } ]
|
37
|
+
elsif self.respond_to?(:custom_routes)
|
38
|
+
#Let the custom route method defined in the robot take care of the call
|
39
|
+
self.custom_routes(request, path, method)
|
40
|
+
else
|
41
|
+
logger.warning("404 - Not Found: #{path}")
|
42
|
+
[ 404, { 'Content-Type' => 'text/html' }, "404 - Not Found" ]
|
43
|
+
end
|
44
|
+
rescue Exception => e
|
45
|
+
logger.warning("500 - Internal Server Error: #{path}")
|
46
|
+
logger.warning("#{e.class}: #{e.message}\n\n#{e.backtrace.join("\n")}")
|
47
|
+
[ 500, { 'Content-Type' => 'text/html' }, "500 - Internal Server Error"]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
def static_resource_content_type(path)
|
53
|
+
case (ext = File.extname(path))
|
54
|
+
when '.html', '.htm'
|
55
|
+
'text/html'
|
56
|
+
when '.xml'
|
57
|
+
'text/xml'
|
58
|
+
when '.gif'
|
59
|
+
'image/gif'
|
60
|
+
when '.jpeg', '.jpg'
|
61
|
+
'image/jpeg'
|
62
|
+
when '.tif', '.tiff'
|
63
|
+
'image/tiff'
|
64
|
+
when '.txt', ''
|
65
|
+
'text/plain'
|
66
|
+
else
|
67
|
+
"application/#{ext}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/mixins/data_format.rb
CHANGED
@@ -1,168 +1,206 @@
|
|
1
|
-
#This mixin provides methods for robots to deal with parsing and presenting JSON and XML
|
2
|
-
module Rave
|
3
|
-
module Mixins
|
4
|
-
module DataFormat
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
xml.
|
12
|
-
xml.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
attrs
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
#
|
47
|
-
|
48
|
-
#Create
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
else
|
125
|
-
[]
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
]
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
1
|
+
#This mixin provides methods for robots to deal with parsing and presenting JSON and XML
|
2
|
+
module Rave
|
3
|
+
module Mixins
|
4
|
+
module DataFormat
|
5
|
+
include Logger
|
6
|
+
|
7
|
+
PROFILE_JAVA_CLASS = 'com.google.wave.api.ParticipantProfile'
|
8
|
+
|
9
|
+
#Returns this robot's capabilities in XML
|
10
|
+
def capabilities_xml
|
11
|
+
xml = Builder::XmlMarkup.new
|
12
|
+
xml.instruct!
|
13
|
+
xml.tag!("w:robot", "xmlns:w" => "http://wave.google.com/extensions/robots/1.0") do
|
14
|
+
xml.tag!("w:version", @version)
|
15
|
+
xml.tag!("w:capabilities") do
|
16
|
+
@handlers.keys.each do |capability|
|
17
|
+
xml.tag!("w:capability", "name" => capability)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
unless @cron_jobs.empty?
|
21
|
+
xml.tag!("w:crons") do
|
22
|
+
@cron_jobs.each do |job|
|
23
|
+
xml.tag!("w:cron", "path" => job[:path], "timerinseconds" => job[:seconds])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
attrs = { "name" => @name }
|
28
|
+
attrs["imageurl"] = @image_url if @image_url
|
29
|
+
attrs["profileurl"] = @profile_url if @profile_url
|
30
|
+
xml.tag!("w:profile", attrs)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#Returns the robot's profile in json format
|
35
|
+
def profile_json
|
36
|
+
{
|
37
|
+
'name' => @name,
|
38
|
+
'imageUrl' => @image_url,
|
39
|
+
'profileUrl' => @profile_url,
|
40
|
+
'javaClass' => PROFILE_JAVA_CLASS,
|
41
|
+
}.to_json.gsub('\/','/')
|
42
|
+
end
|
43
|
+
|
44
|
+
#Parses context and event info from JSON input
|
45
|
+
def parse_json_body(json)
|
46
|
+
logger.info("Received:\n#{json.to_s}")
|
47
|
+
data = JSON.parse(json)
|
48
|
+
#Create Context
|
49
|
+
context = context_from_json(data)
|
50
|
+
#Create events
|
51
|
+
events = events_from_json(data, context)
|
52
|
+
logger.info("Structure (before):\n#{context.print_structure}")
|
53
|
+
logger.info("Events: #{events.map { |e| e.type }.join(', ')}")
|
54
|
+
return context, events
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
def context_from_json(json)
|
59
|
+
blips = {}
|
60
|
+
blips_from_json(json).each do |blip|
|
61
|
+
blips[blip.id] = blip
|
62
|
+
end
|
63
|
+
wavelets = {}
|
64
|
+
wavelets_from_json(json).each do |wavelet|
|
65
|
+
wavelets[wavelet.id] = wavelet
|
66
|
+
end
|
67
|
+
waves = {}
|
68
|
+
#Waves aren't sent back, but we can reconstruct them from the wavelets
|
69
|
+
waves_from_wavelets(wavelets).each do |wave|
|
70
|
+
waves[wave.id] = wave
|
71
|
+
end
|
72
|
+
Rave::Models::Context.new(
|
73
|
+
:waves => waves,
|
74
|
+
:wavelets => wavelets,
|
75
|
+
:blips => blips,
|
76
|
+
:robot => self
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def blips_from_json(json)
|
81
|
+
map_to_hash(json['blips']).values.collect do |blip_data|
|
82
|
+
Rave::Models::Blip.new(
|
83
|
+
:id => blip_data['blipId'],
|
84
|
+
:annotations => annotations_from_json(blip_data),
|
85
|
+
:child_blip_ids => list_to_array(blip_data['childBlipIds']),
|
86
|
+
:content => blip_data['content'],
|
87
|
+
:contributors => list_to_array(blip_data['contributors']),
|
88
|
+
:creator => blip_data['creator'],
|
89
|
+
:elements => elements_from_json(blip_data['elements']),
|
90
|
+
:last_modified_time => blip_data['lastModifiedTime'],
|
91
|
+
:parent_blip_id => blip_data['parentBlipId'],
|
92
|
+
:version => blip_data['version'],
|
93
|
+
:wave_id => blip_data['waveId'],
|
94
|
+
:wavelet_id => blip_data['waveletId']
|
95
|
+
)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def elements_from_json(elements_map)
|
100
|
+
elements = {}
|
101
|
+
|
102
|
+
map_to_hash(elements_map).each_pair do |position, data|
|
103
|
+
elements[position.to_i] = Element.create(data['type'], map_to_hash(data['properties']))
|
104
|
+
end
|
105
|
+
|
106
|
+
elements
|
107
|
+
end
|
108
|
+
|
109
|
+
# Convert a json-java list (which may not be defined) into an array.
|
110
|
+
# Defaults to an empty array.
|
111
|
+
def list_to_array(list)
|
112
|
+
if list.nil?
|
113
|
+
[]
|
114
|
+
else
|
115
|
+
list['list'] || []
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Convert a json-java map (which may not be defined) into a hash. Defaults
|
120
|
+
# to an empty hash.
|
121
|
+
def map_to_hash(map)
|
122
|
+
if map.nil?
|
123
|
+
{}
|
124
|
+
else
|
125
|
+
map['map'] || {}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def annotations_from_json(json)
|
130
|
+
list_to_array(json['annotation']).collect do |annotation|
|
131
|
+
Rave::Models::Annotation.create(
|
132
|
+
annotation['name'],
|
133
|
+
annotation['value'],
|
134
|
+
range_from_json(annotation['range'])
|
135
|
+
)
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def range_from_json(json)
|
141
|
+
Range.new(json['start'], json['end'])
|
142
|
+
end
|
143
|
+
|
144
|
+
def events_from_json(json, context)
|
145
|
+
list_to_array(json['events']).collect do |event|
|
146
|
+
properties = {}
|
147
|
+
event['properties']['map'].each do |key, value|
|
148
|
+
properties[key] = case value
|
149
|
+
when String # Just a string, as in blipId.
|
150
|
+
value
|
151
|
+
when Hash # Serialised array, such as in participantsAdded.
|
152
|
+
value['list']
|
153
|
+
else
|
154
|
+
raise "Unrecognised property #{value} #{value.class}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
Rave::Models::Event.create(event['type'],
|
158
|
+
:timestamp => event['timestamp'],
|
159
|
+
:modified_by => event['modifiedBy'],
|
160
|
+
:properties => properties,
|
161
|
+
:context => context,
|
162
|
+
:robot => self
|
163
|
+
)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def wavelets_from_json(json)
|
168
|
+
#Currently only one wavelet is sent back
|
169
|
+
#TODO: should this look at the wavelet's children too?
|
170
|
+
wavelet = json['wavelet']
|
171
|
+
if wavelet
|
172
|
+
[
|
173
|
+
Rave::Models::Wavelet.new(
|
174
|
+
:creator => wavelet['creator'],
|
175
|
+
:creation_time => wavelet['creationTime'],
|
176
|
+
:data_documents => map_to_hash(wavelet['dataDocuments']),
|
177
|
+
:last_modifed_time => wavelet['lastModifiedTime'],
|
178
|
+
:participants => list_to_array(wavelet['participants']),
|
179
|
+
:root_blip_id => wavelet['rootBlipId'],
|
180
|
+
:title => wavelet['title'],
|
181
|
+
:version => wavelet['version'],
|
182
|
+
:wave_id => wavelet['waveId'],
|
183
|
+
:id => wavelet['waveletId']
|
184
|
+
)
|
185
|
+
]
|
186
|
+
else
|
187
|
+
[]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def waves_from_wavelets(wavelets)
|
192
|
+
wave_wavelet_map = {}
|
193
|
+
if wavelets
|
194
|
+
wavelets.values.each do |wavelet|
|
195
|
+
wave_wavelet_map[wavelet.wave_id] ||= []
|
196
|
+
wave_wavelet_map[wavelet.wave_id] << wavelet.id
|
197
|
+
end
|
198
|
+
end
|
199
|
+
wave_wavelet_map.collect do |wave_id, wavelet_ids|
|
200
|
+
Rave::Models::Wave.new(:id => wave_id, :wavelet_ids => wavelet_ids)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|