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.
@@ -0,0 +1,305 @@
1
+ module Rave
2
+ module Models
3
+ # Represents a blip, containing formated text, gadgets and other elements.
4
+ # It is part of a Wavelet within a Wave.
5
+ class Blip < Component
6
+ include Rave::Mixins::TimeUtils
7
+ include Rave::Mixins::Logger
8
+
9
+ JAVA_CLASS = 'com.google.wave.api.impl.BlipData' # :nodoc:
10
+
11
+ # Version number of the contents of the blip [Integer]
12
+ def version
13
+ @version.dup
14
+ end
15
+
16
+ # Annotations on the blip [Array of Annotation]
17
+ def annotations # :nodoc:
18
+ @annotations.dup
19
+ end
20
+
21
+ # IDs of the children of this blip [Array of String]
22
+ def child_blip_ids # :nodoc:
23
+ @child_blip_ids.map { |id| id.dup }
24
+ end
25
+
26
+ # IDs (email addresses) of those who have altered this blip [Array of String]
27
+ def contributor_ids # :nodoc:
28
+ @contributor_ids.map { |id| id.dup }
29
+ end
30
+
31
+ # Elements contained within this blip [Array of Element]
32
+ def elements # :nodoc:
33
+ @elements.dup
34
+ end
35
+
36
+ # Last time the blip was altered [Time]
37
+ def last_modified_time # :nodoc:
38
+ @last_modified_time.dup
39
+ end
40
+
41
+ # ID of this blip's parent [String or nil for a root blip]
42
+ def parent_blip_id # :nodoc:
43
+ @parent_blip_id.nil? ? nil : @parent_blip_id.dup
44
+ end
45
+
46
+ # ID of the wave this blip belongs to [String]
47
+ def wave_id # :nodoc:
48
+ @wave_id.nil? ? nil : @wave_id.dup
49
+ end
50
+
51
+ # ID of the wavelet this blip belongs to [String]
52
+ def wavelet_id # :nodoc:
53
+ @wavelet_id.nil? ? nil : @wavelet_id.dup
54
+ end
55
+
56
+ # Wavelet that the blip is a part of [Wavelet]
57
+ def wavelet # :nodoc:
58
+ @context.wavelets[@wavelet_id]
59
+ end
60
+
61
+ # Wave that this blip is a part of [Wave]
62
+ def wave # :nodoc:
63
+ @context.waves[@wave_id]
64
+ end
65
+
66
+ # Blip that this Blip is a direct reply to. Will be nil if the root blip
67
+ # in a wavelet [Blip or nil for a root blip]
68
+ def parent_blip # :nodoc:
69
+ @context.blips[@parent_blip_id]
70
+ end
71
+
72
+ # Returns true if this is a root blip (no parent blip) [Boolean]
73
+ def root? # :nodoc:
74
+ @parent_blip_id.nil?
75
+ end
76
+
77
+ # Returns true if this is a leaf node (has no children). [Boolean]
78
+ def leaf? # :nodoc:
79
+ @child_blip_ids.empty?
80
+ end
81
+
82
+ # Has the blip been deleted? [Boolean]
83
+ def deleted? # :nodoc:
84
+ [:deleted, :null].include? @state
85
+ end
86
+
87
+ # Has the blip been completely destroyed? [Boolean]
88
+ def null? # :nodoc:
89
+ @state == :null
90
+ end
91
+
92
+ # Text contained in the blip [String]
93
+ def content # :nodoc:
94
+ @content.dup
95
+ end
96
+
97
+ # Users that have made a contribution to the blip [Array of User]
98
+ def contributors # :nodoc:
99
+ @contributor_ids.map { |c| @context.users[c] }
100
+ end
101
+
102
+ # Original creator of the blip [User]
103
+ def creator # :nodoc:
104
+ @context.users[@creator]
105
+ end
106
+
107
+ # List of direct children of this blip. The first one will be continuing
108
+ # the thread, others will be indented replies [Array of Blip]
109
+ def child_blips # :nodoc:
110
+ @child_blip_ids.map { |id| @context.blips[id] }
111
+ end
112
+
113
+ # Ensure that all elements within the blip are given a context.
114
+ def context=(value) # :nodoc:
115
+ super(value)
116
+ @elements.each_value { |e| e.context = value }
117
+ end
118
+
119
+ VALID_STATES = [:normal, :null, :deleted] # :nodoc: As passed to initializer in :state option.
120
+
121
+ #Options include:
122
+ # - :annotations
123
+ # - :child_blip_ids
124
+ # - :content
125
+ # - :contributors
126
+ # - :creator
127
+ # - :elements
128
+ # - :last_modified_time
129
+ # - :parent_blip_id
130
+ # - :version
131
+ # - :wave_id
132
+ # - :wavelet_id
133
+ # - :id
134
+ # - :context
135
+ # - :state
136
+ def initialize(options = {}) # :nodoc:
137
+ @annotations = options[:annotations] || []
138
+ @child_blip_ids = options[:child_blip_ids] || []
139
+ @content = options[:content] || ''
140
+ @contributor_ids = options[:contributors] || []
141
+ @creator = options[:creator] || User::NOBODY_ID
142
+ @elements = options[:elements] || {}
143
+ @last_modified_time = time_from_json(options[:last_modified_time]) || Time.now
144
+ @parent_blip_id = options[:parent_blip_id]
145
+ @version = options[:version] || -1
146
+ @wave_id = options[:wave_id]
147
+ @wavelet_id = options[:wavelet_id]
148
+ @state = options[:state] || :normal
149
+
150
+ unless VALID_STATES.include? @state
151
+ raise ArgumentError.new("Bad state #{options[:state]}. Should be one of #{VALID_STATES.join(', ')}")
152
+ end
153
+
154
+ # If the blip doesn't have a defined ID, since we just created it,
155
+ # assign a temporary, though unique, ID, based on the ID of the wavelet.
156
+ if options[:id].nil?
157
+ options[:id] = "#{GENERATED_PREFIX}_blip_#{unique_id}"
158
+ end
159
+
160
+ super(options)
161
+ end
162
+
163
+ #Returns true if an annotation with the given name exists in this blip
164
+ def has_annotation?(name)
165
+ @annotations.any? { |a| a.name == name }
166
+ end
167
+
168
+ # Adds an annotation to the Blip.
169
+ def add_annotation(annotation)
170
+ @annotations << annotation
171
+ self
172
+ end
173
+
174
+ #Creates a child blip under this blip
175
+ def create_child_blip
176
+ blip = Blip.new(:wave_id => @wave_id, :parent_blip_id => @id, :wavelet_id => @wavelet_id,
177
+ :context => @context, :contributors => [Robot.instance.id])
178
+ @context.add_operation(:type => Operation::BLIP_CREATE_CHILD, :blip_id => @id, :wave_id => @wave_id, :wavelet_id => @wavelet_id, :property => blip)
179
+ add_child_blip(blip)
180
+ blip
181
+ end
182
+
183
+ # Adds a created child blip to this blip.
184
+ def add_child_blip(blip) # :nodoc:
185
+ @child_blip_ids << blip.id
186
+ @context.add_blip(blip)
187
+ end
188
+
189
+ # INTERNAL
190
+ # Removed a child blip.
191
+ def remove_child_blip(blip) # :nodoc:
192
+ @child_blip_ids.delete(blip.id)
193
+
194
+ # Destroy oneself completely if you are no longer useful to structure.
195
+ destroy_me if deleted? and leaf? and not root?
196
+ end
197
+
198
+ # Delete this blip from its wavelet.
199
+ # Returns the blip id.
200
+ def delete
201
+ if deleted?
202
+ logger.warning("Attempt to delete blip that has already been deleted: #{id}")
203
+ elsif root?
204
+ logger.warning("Attempt to delete root blip: #{id}")
205
+ else
206
+ @context.add_operation(:type => Operation::BLIP_DELETE,
207
+ :blip_id => @id, :wave_id => @wave_id, :wavelet_id => @wavelet_id)
208
+ delete_me
209
+ end
210
+ end
211
+
212
+ # Convert to string.
213
+ def to_s
214
+ str = @content.gsub(/\n/, "\\n")
215
+ str = str.length > 24 ? "#{str[0..20]}..." : str
216
+
217
+ str = case @state
218
+ when :normal
219
+ "#{contributors.join(',')}:#{str}"
220
+ when :deleted
221
+ '<DELETED>'
222
+ when :null
223
+ '<NULL>'
224
+ end
225
+
226
+ "#{super}:#{str}"
227
+ end
228
+
229
+ # *INTERNAL*
230
+ # Write out a formatted block of text showing the blip and its descendants.
231
+ def print_structure(indent = 0) # :nodoc:
232
+ str = "#{' ' * indent}#{to_s}\n"
233
+
234
+ unless @child_blip_ids.empty?
235
+ # Move the first blip to the end, since it will be looked at last.
236
+ blip_ids = @child_blip_ids
237
+ blip_ids.push(blip_ids.shift)
238
+
239
+ # All children, except the first, should be indented.
240
+ blip_ids.each_with_index do |blip_id, index|
241
+ is_last_blip = (index == blip_ids.size - 1)
242
+
243
+ # All except the last one should be indented again.
244
+ ind = is_last_blip ? indent : indent + 1
245
+ blip = @context.blips[blip_id]
246
+ if blip
247
+ str << blip.print_structure(ind)
248
+ else
249
+ str << "#{' ' * ind}<undefined-blip>:#{blip_id}\n"
250
+ end
251
+
252
+ str << "\n" unless is_last_blip # Gap between reply chains.
253
+ end
254
+ end
255
+
256
+ str
257
+ end
258
+
259
+ # *INTERNAL*
260
+ # Convert to json for sending in an operation. We should never need to
261
+ # send more data than this, although blips we receive will have more data.
262
+ def to_json # :nodoc:
263
+ {
264
+ 'blipId' => @id,
265
+ 'javaClass' => JAVA_CLASS,
266
+ 'waveId' => @wave_id,
267
+ 'waveletId' => @wavelet_id
268
+ }.to_json
269
+ end
270
+
271
+ # *INTERNAL*
272
+ # Delete the blip or, if appropriate, destroy it instead.
273
+ def delete_me(allow_destroy = true) # :nodoc:
274
+ raise "Can't delete root blip" if root?
275
+
276
+ if leaf? and allow_destroy
277
+ destroy_me
278
+ else
279
+ # Blip is marked as deleted, but stays in place to maintain structure.
280
+ @state = :deleted
281
+ @content = ''
282
+ end
283
+
284
+ @id
285
+ end
286
+
287
+ protected
288
+ # *INTERNAL*
289
+ # Remove the blip entirely, leaving it null.
290
+ def destroy_me # :nodoc:
291
+ raise "Can't destroy root blip" if root?
292
+ raise "Can't destroy non-leaf blip" unless leaf?
293
+
294
+ # Remove the blip entirely to the realm of oblivion.
295
+ parent_blip.remove_child_blip(self)
296
+ @parent_blip_id = nil
297
+ @context.remove_blip(self)
298
+ @state = :null
299
+ @content = ''
300
+
301
+ @id
302
+ end
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,42 @@
1
+ module Rave
2
+ module Models
3
+ # A wave or wave component.
4
+ # This is an abstract class.
5
+ class Component
6
+ include Rave::Mixins::Logger
7
+
8
+ GENERATED_PREFIX = 'TBD' # :nodoc: Prefixes blips and wavelets that are created by the robot.
9
+ GENERATED_PATTERN = /^#{GENERATED_PREFIX}/ # :nodoc:
10
+
11
+ @@last_id = 0 # For generated components, this is a unique ID number for them.
12
+
13
+ attr_writer :context # :nodoc: Allow context to set link to it.
14
+
15
+ # Has this component been generated by the robot [Boolean]
16
+ def generated? # :nodoc:
17
+ # This is true for all components except Users, who would override this.
18
+ not (@id =~ /^#{GENERATED_PREFIX}/).nil?
19
+ end
20
+
21
+ # Generate a unique id number (from 1) [Integer]
22
+ def unique_id # :nodoc:
23
+ @@last_id += 1
24
+ end
25
+
26
+ # ID [String]
27
+ def id # :nodoc:
28
+ @id.dup
29
+ end
30
+
31
+ def initialize(options = {}) # :nodoc:
32
+ @id = options[:id] or raise ArgumentError.new(":id option is required for #{self.class.name}")
33
+ @context = options[:context]
34
+ end
35
+
36
+ # Convert to string.
37
+ def to_s
38
+ "#{self.class.name[/[^:]*$/]}:#{@id}"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,174 @@
1
+ module Rave
2
+ module Models
3
+ # Contains server request information including current waves and operations.
4
+ class Context
5
+
6
+ attr_reader :primary_wavelet # :nodoc: API users should use Event#wavelet
7
+ attr_reader :robot # The robot managing this context.
8
+
9
+ # All waves by ID [Hash of String => Wave]
10
+ def waves # :nodoc:
11
+ @waves.dup
12
+ end
13
+
14
+ # All wavelets by ID [Hash of String => Wavelet]
15
+ def wavelets # :nodoc:
16
+ @wavelets.dup
17
+ end
18
+
19
+ # All wavelets by ID [Hash of String => Wavelet]
20
+ def blips # :nodoc:
21
+ @blips.dup
22
+ end
23
+
24
+ # All operations [Array of Operation]
25
+ def operations # :nodoc:
26
+ @operations.dup
27
+ end
28
+
29
+ # All users by ID [Hash of String => User]
30
+ def users # :nodoc:
31
+ @users.dup
32
+ end
33
+
34
+ JAVA_CLASS = 'com.google.wave.api.impl.OperationMessageBundle' # :nodoc:
35
+
36
+ #Options include:
37
+ # - :waves
38
+ # - :wavelets
39
+ # - :blips
40
+ # - :operations
41
+ # - :users
42
+ def initialize(options = {}) # :nodoc:
43
+ @waves = options[:waves] || {}
44
+ @waves.values.each { |wave| wave.context = self } #Set up self as this wave's context
45
+
46
+ @wavelets = options[:wavelets] || {}
47
+ @wavelets.values.each { |wavelet| wavelet.context = self } #Set up self as this wavelet's context
48
+ @primary_wavelet = @wavelets.values[0] # As opposed to any that are created later.
49
+
50
+
51
+ @blips = options[:blips] || {}
52
+ @blips.values.each { |blip| blip.context = self } #Set up self as this blip's context
53
+
54
+ @operations = options[:operations] || []
55
+
56
+ @users = options[:users] || {}
57
+ @users.values.each { |user| user.context = self } #Set up self as this user's context
58
+
59
+ resolve_user_references(options[:robot])
60
+ end
61
+
62
+ protected
63
+ # Create users for every reference to one in the wave.
64
+ def resolve_user_references(robot) # :nodoc:
65
+ if robot
66
+ @users[robot.id] = robot
67
+ robot.context = self
68
+ @robot = robot
69
+ end
70
+
71
+ @wavelets.each_value do |wavelet|
72
+ wavelet.participant_ids.each do |id|
73
+ unless @users[id]
74
+ add_user(:id => id)
75
+ end
76
+ end
77
+
78
+ unless @users[wavelet.creator_id]
79
+ add_user(:id => wavelet.creator_id)
80
+ end
81
+ end
82
+
83
+ @blips.each_value do |blip|
84
+ blip.contributor_ids.each do |id|
85
+ unless @users[id]
86
+ add_user(:id => id)
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ public
93
+ # Add a blip to blips (Use an Operation to actually add the blip to the Wave).
94
+ # Returns: The blip [Blip].
95
+ def add_blip(blip) # :nodoc:
96
+ @blips[blip.id] = blip
97
+ blip.context = self
98
+ blip
99
+ end
100
+
101
+ # Add an operation to the list to be executed.
102
+ # Returns: self [Context]
103
+ def add_operation(options) # :nodoc:
104
+ @operations << Operation.new(options)
105
+ self
106
+ end
107
+
108
+ # Add a wavelet to wavelets (Use an Operation to actually add the blip to the Wave).
109
+ # Returns: The wavelet [Wavelet].
110
+ def add_wavelet(wavelet)# :nodoc:
111
+ @wavelets[wavelet.id] = wavelet
112
+ wavelet.context = self
113
+ wavelet
114
+ end
115
+
116
+ # Add a wave to waves (Use an Operation to actually add the wave).
117
+ # Returns: The wave [Wave].
118
+ def add_wave(wave)# :nodoc:
119
+ @waves[wave.id] = wave
120
+ wave.context = self
121
+ wave
122
+ end
123
+
124
+ # +participants+:: Participants to exist in the new wavelet, as IDs or objects [Array of String/User]
125
+ # Returns: Newly created wave [Wave]
126
+ def create_wavelet(participants) # :nodoc:
127
+ # Map participants to strings, since they could be Users.
128
+ participant_ids = participants.map {|p| p.to_s.downcase }
129
+ participant_ids << @robot.id unless participant_ids.include? @robot.id
130
+
131
+ wavelet = Wavelet.new(:context => self, :participants => participant_ids)
132
+ add_wavelet(wavelet)
133
+
134
+ # TODO: Get wave id from sensible place?
135
+ add_operation(:type => Operation::WAVELET_CREATE, :wave_id => @waves.keys[0],
136
+ :property => wavelet)
137
+
138
+ wavelet
139
+ end
140
+
141
+ # Remove a blip.
142
+ def remove_blip(blip) # :nodoc:
143
+ @blips.delete(blip.id)
144
+ end
145
+
146
+ # Add a user to users (Use an Operation to actually add the blip to the Wave).
147
+ def add_user(options) # :nodoc:
148
+ options[:id].downcase! if options[:id]
149
+ raise DuplicatedIDError.new("Can't add another User with id #{options[:id]}") if @users.has_key? options[:id].downcase
150
+ user = User.new(options)
151
+ @users[user.id] = user
152
+ user.context = self
153
+ user
154
+ end
155
+
156
+ #Serialize the context for use in the line protocol.
157
+ def to_json # :nodoc:
158
+ hash = {
159
+ 'operations' => { 'javaClass' => 'java.util.ArrayList', 'list' => @operations },
160
+ 'javaClass' => JAVA_CLASS
161
+ }
162
+ hash.to_json
163
+ end
164
+
165
+ def print_structure(indent = 0) # :nodoc:
166
+ str = ''
167
+ waves.each_value do |wave|
168
+ str << wave.print_structure(indent)
169
+ end
170
+ str
171
+ end
172
+ end
173
+ end
174
+ end