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.
@@ -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