rave 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,45 +1,174 @@
1
- #Contains server request information including current waves and operations
2
- module Rave
3
- module Models
4
- class Context
5
- attr_reader :waves, :wavelets, :blips, :operations
6
-
7
- #Options include:
8
- # - :waves
9
- # - :wavelets
10
- # - :blips
11
- # - :operations
12
- def initialize(options = {})
13
- @waves = options[:waves] || {}
14
- @waves.values.each { |wave| wave.context = self } #Set up self as this wave's context
15
- @wavelets = options[:wavelets] || {}
16
- @wavelets.values.each { |wavelet| wavelet.context = self } #Set up self as this wavelet's context
17
- @blips = options[:blips] || {}
18
- @blips.values.each { |blip| blip.context = self } #Set up self as this blip's context
19
- @operations = options[:operations] || []
20
- end
21
-
22
- #Find the root wavelet if it exists in this context
23
- def root_wavelet
24
- @wavelets.values.find { |wavelet| wavelet.id =~ Regexp.new(Rave::Models::Wavelet::ROOT_ID_REGEXP) }
25
- end
26
-
27
- #Serializes the context to JSON format
28
- def to_json
29
- self.to_hash.to_json
30
- end
31
-
32
- #Serialize the context to a hash map
33
- def to_hash
34
- hash = {
35
- 'operations' => { 'javaClass' => 'java.util.ArrayList', 'list' => [] },
36
- 'javaClass' => 'com.google.wave.api.impl.OperationMessageBundle'
37
- }
38
- @operations.each do |op|
39
- hash['operations']['list'] << op.to_hash
40
- end
41
- hash
42
- end
43
- end
44
- end
45
- end
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
@@ -1,9 +1,9 @@
1
- module Rave
2
- module Models
3
- class Document
4
-
5
- #TODO
6
-
7
- end
8
- end
1
+ module Rave
2
+ module Models
3
+ class Document # :nodoc:
4
+
5
+ #TODO
6
+
7
+ end
8
+ end
9
9
  end
@@ -0,0 +1,113 @@
1
+ module Rave
2
+ module Models
3
+ # An element within a document.
4
+ # (abstract factory)
5
+ class Element < Component
6
+ include Rave::Mixins::ObjectFactory
7
+
8
+ JAVA_CLASS = "com.google.wave.api.FormElement"
9
+
10
+ def initialize(properties = {})
11
+ super(:id => '') # TODO: Don't actually have IDs, as such. Bad inheritance from Component?
12
+ @properties = properties
13
+ end
14
+
15
+ # Gets the value of an element property.
16
+ def get(key, default = nil)
17
+ if @properties.has_key? key
18
+ @properties[key]
19
+ else
20
+ default
21
+ end
22
+ end
23
+
24
+ # Sets the value of an element property.
25
+ def set(key, value)
26
+ @properties[key] = value
27
+ end
28
+
29
+ # Alias for #set(key, value)
30
+ alias_method :[]=, :set
31
+
32
+ # Alias for #get(key)
33
+ alias_method :[], :get
34
+
35
+ def to_json # :nodoc:
36
+ {
37
+ 'javaClass' => JAVA_CLASS,
38
+ 'properties' => @properties,
39
+ 'type' => type,
40
+ }.to_json
41
+ end
42
+
43
+ # A Google Gadget element within a document.
44
+ class Gadget < Element
45
+ factory_register 'GADGET'
46
+
47
+ def initialize(fields = {})
48
+ # Gadget has 'fields' rather than 'properties'.
49
+ super(fields)
50
+ end
51
+ end
52
+
53
+ # An image element within a document.
54
+ class Image < Element
55
+ factory_register 'IMAGE'
56
+ end
57
+
58
+ # An inline blip within a document.
59
+ class InlineBlip < Element
60
+ factory_register 'INLINE_BLIP'
61
+
62
+ # The blip contained within the element [Blip].
63
+ def blip # :nodoc:
64
+ @context.blips[@properties['blipId']]
65
+ end
66
+ end
67
+
68
+ # A form element within a document.
69
+ # (Abstract)
70
+ class Form < Element
71
+ # A button form element within a document.
72
+ class Button < Form
73
+ factory_register 'BUTTON'
74
+ end
75
+
76
+ # A check form element within a document.
77
+ class Check < Form
78
+ factory_register 'CHECK'
79
+ end
80
+
81
+ # A input form element within a document.
82
+ class Input < Form
83
+ factory_register 'INPUT'
84
+ end
85
+
86
+ # A password form element within a document.
87
+ class Password < Form
88
+ factory_register 'PASSWORD'
89
+ end
90
+
91
+ # A label form element within a document.
92
+ class Label < Form
93
+ factory_register 'LABEL'
94
+ end
95
+
96
+ # A radio button form element within a document.
97
+ class RadioButton < Form
98
+ factory_register 'RADIO_BUTTON'
99
+ end
100
+
101
+ # A radio button group form element within a document.
102
+ class RadioButtonGroup < Form
103
+ factory_register 'RADIO_BUTTON_GROUP'
104
+ end
105
+
106
+ # A text-area form element within a document.
107
+ class TextArea < Form
108
+ factory_register 'TEXTAREA'
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
data/lib/models/event.rb CHANGED
@@ -1,48 +1,230 @@
1
- #Represents and event
2
- module Rave
3
- module Models
4
- class Event
5
- attr_reader :type, :timestamp, :modified_by, :properties
6
-
7
- #Event types:
8
- WAVELET_BLIP_CREATED = 'WAVELET_BLIP_CREATED'
9
- WAVELET_BLIP_REMOVED = 'WAVELET_BLIP_REMOVED'
10
- WAVELET_PARTICIPANTS_CHANGED = 'WAVELET_PARTICIPANTS_CHANGED'
11
- WAVELET_TIMESTAMP_CHANGED = 'WAVELET_TIMESTAMP_CHANGED'
12
- WAVELET_TITLE_CHANGED = 'WAVELET_TITLE_CHANGED'
13
- WAVELET_VERSION_CHANGED = 'WAVELET_VERSION_CHANGED'
14
- BLIP_CONTRIBUTORS_CHANGED = 'BLIP_CONTRIBUTORS_CHANGED'
15
- BLIP_DELETED = 'BLIP_DELETED'
16
- BLIP_SUBMITTED = 'BLIP_SUBMITTED'
17
- BLIP_TIMESTAMP_CHANGED = 'BLIP_TIMESTAMP_CHANGED'
18
- BLIP_VERSION_CHANGED = 'BLIP_VERSION_CHANGED'
19
- DOCUMENT_CHANGED = 'DOCUMENT_CHANGED'
20
- FORM_BUTTON_CLICKED = 'FORM_BUTTON_CLICKED'
21
-
22
- VALID_EVENTS = [
23
- WAVELET_BLIP_CREATED, WAVELET_BLIP_REMOVED, WAVELET_PARTICIPANTS_CHANGED,
24
- WAVELET_TIMESTAMP_CHANGED, WAVELET_TITLE_CHANGED, WAVELET_VERSION_CHANGED,
25
- BLIP_CONTRIBUTORS_CHANGED, BLIP_DELETED, BLIP_SUBMITTED, BLIP_TIMESTAMP_CHANGED,
26
- BLIP_VERSION_CHANGED, DOCUMENT_CHANGED, FORM_BUTTON_CLICKED
27
- ]
28
-
29
- #Options include:
30
- # - :type
31
- # - :timestamp
32
- # - :modified_by
33
- # - :properties
34
- def initialize(options = {})
35
- @type = options[:type]
36
- @timestamp = options[:timestamp] || Time.now
37
- @modified_by = options[:modified_by]
38
- @properties = options[:properties] || {}
39
- end
40
-
41
- #Returns true if the event_type is a possible event type, and false if not
42
- def self.valid_event_type?(event_type)
43
- VALID_EVENTS.include?(event_type)
44
- end
45
-
46
- end
47
- end
48
- end
1
+ module Rave
2
+ module Models
3
+ # Represents an event received from the server.
4
+ class Event
5
+ include Rave::Mixins::TimeUtils
6
+ include Rave::Mixins::ObjectFactory
7
+
8
+ BLIP_ID = 'blipId' # :nodoc:
9
+
10
+ # Time at which the event was created [Time]
11
+ def timestamp # :nodoc:
12
+ @timestamp.dup
13
+ end
14
+
15
+ # ID of the blip that caused the event, or root blip of the wavelet that caused the event [String]
16
+ def blip_id # :nodoc:
17
+ @properties[BLIP_ID].dup
18
+ end
19
+
20
+ # Wavelet that caused the event, or wavelet containing the blip that caused the event [Wavelet]
21
+ def wavelet # :nodoc:
22
+ @context.primary_wavelet
23
+ end
24
+
25
+ # The user that caused this event to be generated [User]
26
+ def modified_by # :nodoc:
27
+ @context.users[@modified_by_id]
28
+ end
29
+
30
+ # Blip that caused the event, or wavelet's root blip for wavelet events [Blip]
31
+ def blip # :nodoc:
32
+ @context.blips[@properties[BLIP_ID]]
33
+ end
34
+
35
+ #Options include:
36
+ # - :timestamp
37
+ # - :modified_by
38
+ # - :properties
39
+ # - :context
40
+ # Do not use Event.new from outside; instead use Event.create
41
+ def initialize(options = {}) # :nodoc:
42
+ @timestamp = time_from_json(options[:timestamp]) || Time.now
43
+ @modified_by_id = options[:modified_by] || User::NOBODY_ID
44
+ @properties = options[:properties] || {}
45
+ @context = options[:context]
46
+
47
+ raise ArgumentError.new(":context option required") if @context.nil?
48
+
49
+ add_user_ids([@modified_by_id])
50
+ end
51
+
52
+ protected
53
+ # Add a series of user ids to the context, if they don't already exist.
54
+ def add_user_ids(user_ids) # :nodoc:
55
+ user_ids.each do |id|
56
+ @context.add_user(:id => id) unless @context.users[id]
57
+ end
58
+ end
59
+
60
+ # Wavelet events
61
+
62
+ public
63
+ class WaveletBlipCreated < Event
64
+ factory_register 'WAVELET_BLIP_CREATED'
65
+
66
+ # Newly created blip [Blip]
67
+ def new_blip # :nodoc:
68
+ @context.blips[@properties['newBlipId']]
69
+ end
70
+ end
71
+
72
+ class WaveletBlipRemoved < Event
73
+ factory_register 'WAVELET_BLIP_REMOVED'
74
+
75
+ # ID for blip which has now been removed [String]
76
+ def removed_blip_id # :nodoc:
77
+ @properties['removedBlipId'].dup
78
+ end
79
+ end
80
+
81
+ class WaveletParticipantsChanged < Event
82
+ factory_register 'WAVELET_PARTICIPANTS_CHANGED'
83
+
84
+ ADDED = 'participantsAdded' # :nodoc:
85
+ REMOVED = 'participantsRemoved' # :nodoc:
86
+
87
+ def initialize(options = {}) # :nodoc:
88
+ super(options)
89
+
90
+ add_user_ids(@properties[ADDED]) if @properties[ADDED]
91
+ add_user_ids(@properties[REMOVED]) if @properties[REMOVED]
92
+ end
93
+
94
+ # Array of participants added to the wavelet [Array of User]
95
+ def participants_added # :nodoc:
96
+ @properties[ADDED].map { |id| @context.users[id] }
97
+ end
98
+
99
+ # Array of participants removed from the wavelet [Array of User].
100
+ def participants_removed # :nodoc:
101
+ @properties[REMOVED].map { |id| @context.users[id] }
102
+ end
103
+ end
104
+
105
+ class WaveletSelfAdded < Event
106
+ factory_register 'WAVELET_SELF_ADDED'
107
+ end
108
+
109
+ class WaveletSelfRemoved < Event
110
+ factory_register 'WAVELET_SELF_REMOVED'
111
+ end
112
+
113
+ class WaveletTimestampChanged < Event
114
+ factory_register 'WAVELET_TIMESTAMP_CHANGED'
115
+
116
+ # Time that the wavelet was changed [Time]
117
+ def new_timestamp # :nodoc:
118
+ @properties['timestamp'].dup
119
+ end
120
+ end
121
+
122
+ class WaveletTitleChanged < Event
123
+ factory_register 'WAVELET_TITLE_CHANGED'
124
+
125
+ def new_title # :nodoc:
126
+ @properties['title'].dup
127
+ end
128
+ end
129
+
130
+ class WaveletVersionChanged < Event
131
+ factory_register 'WAVELET_VERSION_CHANGED'
132
+
133
+ def new_version # :nodoc:
134
+ @properties['version'].dup
135
+ end
136
+ end
137
+
138
+ # Blip events
139
+
140
+ class BlipContributorsChanged < Event
141
+ factory_register 'BLIP_CONTRIBUTORS_CHANGED'
142
+
143
+ ADDED = 'contributorsAdded' # :nodoc:
144
+ REMOVED = 'contributorsRemoved' # :nodoc:
145
+
146
+ def initialize(options = {}) # :nodoc:
147
+ super(options)
148
+
149
+ add_user_ids(@properties[ADDED]) if @properties[ADDED]
150
+ add_user_ids(@properties[REMOVED]) if @properties[REMOVED]
151
+ end
152
+
153
+ # Array of contributors added to the wavelet [Array of User].
154
+ def contributors_added # :nodoc:
155
+ @properties[ADDED].map { |id| @context.users[id] }
156
+ end
157
+
158
+ # Array of contributors removed from the wavelet [Array of User].
159
+ def contributors_removed # :nodoc:
160
+ @properties[REMOVED].map { |id| @context.users[id] }
161
+ end
162
+ end
163
+
164
+ class BlipSubmitted < Event
165
+ factory_register 'BLIP_SUBMITTED'
166
+ end
167
+
168
+ # #blip will be nil, but #blip_id will give a sensible value.
169
+ class BlipDeleted < Event
170
+ factory_register 'BLIP_DELETED'
171
+
172
+ # ID of the blip that was deleted [String]
173
+ #-- This dummy method just added for the purposes of rdoc.
174
+ def blip_id # :nodoc:
175
+ super
176
+ end
177
+
178
+ def initialize(options = {}) # :nodoc:
179
+ super(options)
180
+
181
+ # Ensure a referenced blip is properly deleted. Destroyed blip won't exist.
182
+ blip.delete_me(false) if @properties[BLIP_ID] and blip
183
+ end
184
+ end
185
+
186
+ # General events.
187
+
188
+ class DocumentChanged < Event
189
+ factory_register 'DOCUMENT_CHANGED'
190
+ end
191
+
192
+ class FormButtonClicked < Event
193
+ factory_register 'FORM_BUTTON_CLICKED'
194
+
195
+ # Name of button that was clicked.
196
+ def button # :nodoc:
197
+ @properties['button'].dup
198
+ end
199
+ end
200
+
201
+ # Generated when someone in the current wave creates a new wavelet (in a new wave).
202
+ class WaveletCreated < Event
203
+ factory_register 'WAVELET_CREATED'
204
+ end
205
+
206
+ class OperationError < Event
207
+ factory_register 'OPERATION_ERROR'
208
+
209
+ # Message describing what caused the error [String]
210
+ def message # :nodoc:
211
+ @properties['errorMessage'].dup
212
+ end
213
+
214
+ # Operation type that caused the error [String]
215
+ def operation_type # :nodoc:
216
+ # Format is "document.appendMarkup1260632282946" (number is timestamp)
217
+ @properties['operationId'] =~ /^(.+?)\d+$/
218
+ "#{$1.split(/(?=[A-Z])|\./).join('_').upcase}"
219
+ end
220
+
221
+ # Time of the err [String]
222
+ def operation_timestamp # :nodoc:
223
+ # Format is "document.appendMarkup1260632282946" (number is timestamp)
224
+ @properties['operationId'] =~ /(\d+)$/
225
+ time_from_json($1)
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end