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
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rave
|
2
|
+
module Mixins
|
3
|
+
module Logger
|
4
|
+
|
5
|
+
def logger
|
6
|
+
if @logger.nil?
|
7
|
+
if RUBY_PLATFORM == 'java'
|
8
|
+
@logger = java.util.logging.Logger.getLogger(self.class.to_s)
|
9
|
+
else
|
10
|
+
#TODO: Need to be able to configure output
|
11
|
+
@logger = ::Logger.new(STDOUT)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
@logger
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Rave
|
2
|
+
module Mixins
|
3
|
+
# Abstract object that allows you to create instances of the classes inside
|
4
|
+
# it based on providing a type name.
|
5
|
+
module ObjectFactory
|
6
|
+
WILDCARD = '*' unless defined? WILDCARD
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
# Store the registered classes in a class instance variable.
|
11
|
+
class << self
|
12
|
+
attr_reader :class_by_type_mapping
|
13
|
+
attr_reader :class_by_pattern_mapping
|
14
|
+
end
|
15
|
+
|
16
|
+
@class_by_type_mapping = {}
|
17
|
+
@class_by_pattern_mapping = {}
|
18
|
+
|
19
|
+
class_eval(<<-END, __FILE__, __LINE__)
|
20
|
+
def self.classes_by_type
|
21
|
+
::#{self.name}.class_by_type_mapping
|
22
|
+
end
|
23
|
+
def self.classes_by_pattern
|
24
|
+
::#{self.name}.class_by_pattern_mapping
|
25
|
+
end
|
26
|
+
END
|
27
|
+
|
28
|
+
# Object factory method.
|
29
|
+
#
|
30
|
+
# :type - Type of object to create [String]
|
31
|
+
def self.create(type, *args, &block)
|
32
|
+
if classes_by_type.has_key? type
|
33
|
+
return classes_by_type[type].new(*args, &block)
|
34
|
+
elsif
|
35
|
+
# Check for pattern-based types. Check for longer matches before shorter ones.
|
36
|
+
patterns = classes_by_pattern.keys.sort { |a, b| b.to_s.length <=> a.to_s.length }
|
37
|
+
patterns.each do |pattern|
|
38
|
+
if type =~ pattern
|
39
|
+
return classes_by_pattern[pattern].new($1, *args, &block)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
raise ArgumentError.new("Unknown #{self} type #{type}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Is this type able to be created?
|
47
|
+
def self.valid_type?(type)
|
48
|
+
classes_by_type.has_key? type
|
49
|
+
end
|
50
|
+
|
51
|
+
# Register this class with its factory.
|
52
|
+
def self.factory_register(type)
|
53
|
+
classes_by_type[type] = self
|
54
|
+
|
55
|
+
# * in a type indicates a wildcard.
|
56
|
+
if type[WILDCARD]
|
57
|
+
classes_by_pattern[/^#{type.sub(WILDCARD, '(.*)')}$/] = self
|
58
|
+
end
|
59
|
+
|
60
|
+
class << self
|
61
|
+
def type; @type.dup; end
|
62
|
+
end
|
63
|
+
|
64
|
+
@type = type
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
# Classes that can be generated by the factory [Array of Class]
|
69
|
+
def self.classes
|
70
|
+
classes_by_type.values
|
71
|
+
end
|
72
|
+
|
73
|
+
# Types that can be generated by the factory [Array of String]
|
74
|
+
def self.types
|
75
|
+
classes_by_type.keys
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Type name for this class [String]
|
81
|
+
attr_reader :type
|
82
|
+
def type # :nodoc:
|
83
|
+
self.class.type
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rave
|
2
|
+
module Mixins
|
3
|
+
module TimeUtils
|
4
|
+
|
5
|
+
def time_from_json(time)
|
6
|
+
if time
|
7
|
+
time_s = time.to_s
|
8
|
+
epoch = if time_s.length > 10
|
9
|
+
"#{time_s[0, 10]}.#{time_s[10..-1]}".to_f
|
10
|
+
else
|
11
|
+
time.to_i
|
12
|
+
end
|
13
|
+
Time.at(epoch)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/models/annotation.rb
CHANGED
@@ -1,18 +1,148 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
1
|
+
require 'mixins/object_factory'
|
2
|
+
|
3
|
+
module Rave
|
4
|
+
module Models
|
5
|
+
# An annotation applying styling or other meta-data to a section of text.
|
6
|
+
class Annotation
|
7
|
+
include Rave::Mixins::ObjectFactory
|
8
|
+
|
9
|
+
JAVA_CLASS = "com.google.wave.api.Annotation"
|
10
|
+
|
11
|
+
# Name of the annotation type [String]
|
12
|
+
def name # :nodoc:
|
13
|
+
# If @id is defined, then put that into the type, otherwise just the type is fine.
|
14
|
+
@id ? type.sub(WILDCARD, @id) : type
|
15
|
+
end
|
16
|
+
|
17
|
+
# Value of the annotation [String]
|
18
|
+
def value # :nodoc:
|
19
|
+
@value.dup
|
20
|
+
end
|
21
|
+
|
22
|
+
# Range of characters over which the annotation applies [Range]
|
23
|
+
def range # :nodoc:
|
24
|
+
@range.dup
|
25
|
+
end
|
26
|
+
|
27
|
+
# +value+:: Value of the annotation [String]
|
28
|
+
# +range+:: Range of characters that the annotation applies to [Range]
|
29
|
+
def initialize(value, range); end
|
30
|
+
# +id+:: The non-class-dependent part of the name [String]
|
31
|
+
# +value+:: Value of the annotation [String]
|
32
|
+
# +range+:: Range of characters that the annotation applies to [Range]
|
33
|
+
def initialize(id, value, range); end
|
34
|
+
def initialize(*args) # :nodoc:
|
35
|
+
case args.length
|
36
|
+
when 3
|
37
|
+
@id, @value, @range = args
|
38
|
+
when 2
|
39
|
+
@value, @range = args
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_json # :nodoc:
|
44
|
+
{
|
45
|
+
'javaClass' => JAVA_CLASS,
|
46
|
+
'name' => name,
|
47
|
+
'value' => value,
|
48
|
+
'range' => range,
|
49
|
+
}.to_json
|
50
|
+
end
|
51
|
+
|
52
|
+
factory_register '*' # Accept all unrecognised annotations.
|
53
|
+
|
54
|
+
# Annotation classes:
|
55
|
+
|
56
|
+
# Language selected, such as "en", "de", etc.
|
57
|
+
class Language < Annotation
|
58
|
+
factory_register 'lang'
|
59
|
+
end
|
60
|
+
|
61
|
+
# Style, acting the same as the similarly named CSS properties.
|
62
|
+
class Style < Annotation
|
63
|
+
|
64
|
+
factory_register 'style/*' # Accept all unrecognised style annotations.
|
65
|
+
|
66
|
+
class BackgroundColor < Style
|
67
|
+
factory_register 'style/backgroundColor'
|
68
|
+
end
|
69
|
+
|
70
|
+
class Color < Style
|
71
|
+
factory_register 'style/color'
|
72
|
+
end
|
73
|
+
|
74
|
+
class FontFamily < Style
|
75
|
+
factory_register 'style/fontFamily'
|
76
|
+
end
|
77
|
+
|
78
|
+
class FontSize < Style
|
79
|
+
factory_register 'style/fontSize'
|
80
|
+
end
|
81
|
+
|
82
|
+
class FontWeight < Style
|
83
|
+
factory_register 'style/fontWeight'
|
84
|
+
end
|
85
|
+
|
86
|
+
class TextDecoration < Style
|
87
|
+
factory_register 'style/textDecoration'
|
88
|
+
end
|
89
|
+
|
90
|
+
class VerticalAlign < Style
|
91
|
+
factory_register 'style/verticalAlign'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Conversation < Annotation
|
96
|
+
factory_register 'conv/*' # Accept all unrecognised conv annotations.
|
97
|
+
|
98
|
+
class Title < Conversation
|
99
|
+
factory_register "conv/title"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# (Abstract)
|
104
|
+
class Link < Annotation
|
105
|
+
factory_register 'link/*' # Accept all unrecognised link annotations.
|
106
|
+
|
107
|
+
class Manual < Link
|
108
|
+
factory_register "link/manual"
|
109
|
+
end
|
110
|
+
|
111
|
+
class Auto < Link
|
112
|
+
factory_register "link/autoA"
|
113
|
+
end
|
114
|
+
|
115
|
+
class Wave < Link
|
116
|
+
factory_register "link/waveA"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# (Abstract)
|
121
|
+
class User < Annotation
|
122
|
+
factory_register 'user/*' # Accept all unrecognised user annotations.
|
123
|
+
|
124
|
+
# Session ID for the user annotation.
|
125
|
+
def session_id # :nodoc:
|
126
|
+
name =~ %r!/([^/]+)$!
|
127
|
+
$1
|
128
|
+
end
|
129
|
+
|
130
|
+
def initialize(session_id, value, range)
|
131
|
+
super
|
132
|
+
end
|
133
|
+
|
134
|
+
class Document < User
|
135
|
+
factory_register "user/d/*"
|
136
|
+
end
|
137
|
+
|
138
|
+
class Selection < User
|
139
|
+
factory_register "user/r/*"
|
140
|
+
end
|
141
|
+
|
142
|
+
class Focus < User
|
143
|
+
factory_register "user/e/*"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
data/lib/models/blip.rb
CHANGED
@@ -1,61 +1,305 @@
|
|
1
|
-
|
2
|
-
module
|
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
|
-
@
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|