omf_common 6.0.0.pre.10 → 6.0.0.pre.11
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/monitor_topic.rb +80 -0
- data/bin/send_create.rb +94 -0
- data/bin/send_request.rb +58 -0
- data/example/engine_alt.rb +136 -0
- data/example/vm_alt.rb +65 -0
- data/lib/omf_common.rb +224 -3
- data/lib/omf_common/comm.rb +113 -46
- data/lib/omf_common/comm/amqp/amqp_communicator.rb +76 -0
- data/lib/omf_common/comm/amqp/amqp_topic.rb +91 -0
- data/lib/omf_common/comm/local/local_communicator.rb +64 -0
- data/lib/omf_common/comm/local/local_topic.rb +42 -0
- data/lib/omf_common/comm/topic.rb +190 -0
- data/lib/omf_common/{dsl/xmpp.rb → comm/xmpp/communicator.rb} +93 -53
- data/lib/omf_common/comm/xmpp/topic.rb +147 -0
- data/lib/omf_common/{dsl → comm/xmpp}/xmpp_mp.rb +2 -0
- data/lib/omf_common/eventloop.rb +94 -0
- data/lib/omf_common/eventloop/em.rb +57 -0
- data/lib/omf_common/eventloop/local_evl.rb +78 -0
- data/lib/omf_common/message.rb +112 -229
- data/lib/omf_common/message/json/json_message.rb +129 -0
- data/lib/omf_common/message/xml/message.rb +410 -0
- data/lib/omf_common/message/xml/relaxng_schema.rb +17 -0
- data/lib/omf_common/message/xml/topic_message.rb +20 -0
- data/lib/omf_common/protocol/6.0.rnc +11 -21
- data/lib/omf_common/protocol/6.0.rng +52 -119
- data/lib/omf_common/version.rb +1 -1
- data/omf_common.gemspec +4 -2
- data/test/fixture/pubsub.rb +19 -19
- data/test/omf_common/{dsl/xmpp_spec.rb → comm/xmpp/communicator_spec.rb} +47 -111
- data/test/omf_common/comm/xmpp/topic_spec.rb +113 -0
- data/test/omf_common/comm_spec.rb +1 -0
- data/test/omf_common/message/xml/message_spec.rb +136 -0
- data/test/omf_common/message_spec.rb +37 -131
- data/test/test_helper.rb +4 -1
- metadata +38 -28
- data/lib/omf_common/core_ext/object.rb +0 -21
- data/lib/omf_common/relaxng_schema.rb +0 -17
- data/lib/omf_common/topic.rb +0 -34
- data/lib/omf_common/topic_message.rb +0 -20
- data/test/omf_common/topic_message_spec.rb +0 -114
- data/test/omf_common/topic_spec.rb +0 -75
@@ -0,0 +1,94 @@
|
|
1
|
+
module OmfCommon
|
2
|
+
# Providing event loop support.
|
3
|
+
class Eventloop
|
4
|
+
|
5
|
+
@@providers = {
|
6
|
+
em: {
|
7
|
+
require: 'omf_common/eventloop/em',
|
8
|
+
constructor: 'OmfCommon::Eventloop::EventMachine'
|
9
|
+
},
|
10
|
+
local: {
|
11
|
+
require: 'omf_common/eventloop/local_evl',
|
12
|
+
constructor: 'OmfCommon::Eventloop::Local'
|
13
|
+
}
|
14
|
+
}
|
15
|
+
@@instance = nil
|
16
|
+
|
17
|
+
#
|
18
|
+
# opts:
|
19
|
+
# :type - eventloop provider
|
20
|
+
# :provider - custom provider (opts)
|
21
|
+
# :require - gem to load first (opts)
|
22
|
+
# :constructor - Class implementing provider
|
23
|
+
#
|
24
|
+
def self.init(opts, &block)
|
25
|
+
if @@instance
|
26
|
+
raise "Eventloop provider already iniitalised"
|
27
|
+
end
|
28
|
+
unless provider = opts[:provider]
|
29
|
+
provider = @@providers[opts[:type].to_sym]
|
30
|
+
end
|
31
|
+
unless provider
|
32
|
+
raise "Missing Eventloop provider declaration. Either define 'type' or 'provider'"
|
33
|
+
end
|
34
|
+
|
35
|
+
require provider[:require] if provider[:require]
|
36
|
+
|
37
|
+
if class_name = provider[:constructor]
|
38
|
+
provider_class = class_name.split('::').inject(Object) {|c,n| c.const_get(n) }
|
39
|
+
inst = provider_class.new(opts, &block)
|
40
|
+
else
|
41
|
+
raise "Missing provider creation info - :constructor"
|
42
|
+
end
|
43
|
+
@@instance = inst
|
44
|
+
inst
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.instance
|
48
|
+
@@instance
|
49
|
+
end
|
50
|
+
|
51
|
+
# Execute block after some time
|
52
|
+
#
|
53
|
+
# @param [float] delay in sec
|
54
|
+
# @param [block] block to execute
|
55
|
+
#
|
56
|
+
def after(delay_sec, &block)
|
57
|
+
raise "Missing implementation 'after'"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Periodically call block every interval_sec
|
61
|
+
#
|
62
|
+
# @param [float] interval in sec
|
63
|
+
# @param [block] block to execute
|
64
|
+
#
|
65
|
+
def every(interval_sec, &block)
|
66
|
+
raise "Missing implementation 'every'"
|
67
|
+
end
|
68
|
+
|
69
|
+
# Block calling thread until eventloop exits
|
70
|
+
def join()
|
71
|
+
raise "Missing implementation 'join'"
|
72
|
+
end
|
73
|
+
|
74
|
+
def run()
|
75
|
+
raise "Missing implementation 'run'"
|
76
|
+
end
|
77
|
+
|
78
|
+
def stop()
|
79
|
+
raise "Missing implementation 'stop'"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Calling 'block' before stopping eventloop
|
83
|
+
#
|
84
|
+
def on_stop(&block)
|
85
|
+
warn "Missing implementation 'on_stop'"
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
def initialize(opts = {}, &block)
|
90
|
+
#run(&block) if block
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
|
3
|
+
module OmfCommon
|
4
|
+
class Eventloop
|
5
|
+
# Implements a simple eventloop which only deals with timer events
|
6
|
+
#
|
7
|
+
class EventMachine < Eventloop
|
8
|
+
|
9
|
+
def initialize(opts = {}, &block)
|
10
|
+
super
|
11
|
+
@deferred = []
|
12
|
+
@deferred << block if block
|
13
|
+
end
|
14
|
+
|
15
|
+
# Execute block after some time
|
16
|
+
#
|
17
|
+
# @param [Float] delay in sec
|
18
|
+
def after(delay_sec, &block)
|
19
|
+
if EM.reactor_running?
|
20
|
+
EM.add_timer(delay_sec, &block)
|
21
|
+
else
|
22
|
+
@deferred << lambda do
|
23
|
+
EM.add_timer(delay_sec, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Periodically call block every interval_sec
|
29
|
+
#
|
30
|
+
# @param [Float] interval in sec
|
31
|
+
def every(interval_sec, &block)
|
32
|
+
if EM.reactor_running?
|
33
|
+
EM.add_periodic_timer(interval_sec, &block)
|
34
|
+
else
|
35
|
+
@deferred << lambda do
|
36
|
+
EM.add_periodic_timer(interval_sec, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def run(&block)
|
42
|
+
EM.run do
|
43
|
+
@deferred.each { |proc| proc.call }
|
44
|
+
@deferred = nil
|
45
|
+
if block
|
46
|
+
block.arity == 0 ? block.call : block.call(self)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def stop()
|
52
|
+
EM.stop
|
53
|
+
end
|
54
|
+
end # class
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module OmfCommon
|
4
|
+
class Eventloop
|
5
|
+
# Implements a simple eventloop which only deals with timer events
|
6
|
+
#
|
7
|
+
class Local < Eventloop
|
8
|
+
|
9
|
+
def initialize(opts = {}, &block)
|
10
|
+
super
|
11
|
+
@tasks = []
|
12
|
+
@running = false
|
13
|
+
after(0, &block) if block
|
14
|
+
end
|
15
|
+
|
16
|
+
# Execute block after some time
|
17
|
+
#
|
18
|
+
# @param [float] delay in sec
|
19
|
+
# @param [block] block to execute
|
20
|
+
#
|
21
|
+
def after(delay_sec, &block)
|
22
|
+
@tasks << [Time.now + delay_sec, block]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Periodically call block every interval_sec
|
26
|
+
#
|
27
|
+
# @param [float] interval in sec
|
28
|
+
# @param [block] block to execute
|
29
|
+
#
|
30
|
+
def every(interval_sec, &block)
|
31
|
+
@tasks << [Time.now + interval_sec, block, :periodic => interval_sec]
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop
|
35
|
+
@running = false
|
36
|
+
end
|
37
|
+
|
38
|
+
def run(&block)
|
39
|
+
after(0, &block) if block
|
40
|
+
return if @running
|
41
|
+
@running = true
|
42
|
+
|
43
|
+
while @running do
|
44
|
+
now = Time.now
|
45
|
+
@tasks = @tasks.sort
|
46
|
+
while @tasks[0] && @tasks[0][0] <= now
|
47
|
+
# execute
|
48
|
+
t = @tasks.shift
|
49
|
+
debug "Executing Task #{t}"
|
50
|
+
block = t[1]
|
51
|
+
block.arity == 0 ? block.call : block.call(self)
|
52
|
+
now = Time.now
|
53
|
+
# Check if periodic
|
54
|
+
if interval = ((t[2] || {})[:periodic])
|
55
|
+
if (next_time = t[0] + interval) < now
|
56
|
+
warn "Falling behind with periodic task #{t[1]}"
|
57
|
+
next_time = now + interval
|
58
|
+
end
|
59
|
+
@tasks << [next_time, t[1], :periodic => interval]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
# by now, there could have been a few more tasks added, so let's sort again
|
63
|
+
@tasks = @tasks.sort
|
64
|
+
if @tasks.empty?
|
65
|
+
# done
|
66
|
+
@running = false
|
67
|
+
else
|
68
|
+
if (delay = @tasks[0][0] - Time.now) > 0
|
69
|
+
debug "Sleeping #{delay}"
|
70
|
+
sleep delay
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end # class
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
data/lib/omf_common/message.rb
CHANGED
@@ -1,293 +1,176 @@
|
|
1
|
-
require 'niceogiri'
|
2
|
-
require 'hashie'
|
3
|
-
require 'securerandom'
|
4
|
-
require 'openssl'
|
5
|
-
require 'cgi'
|
6
|
-
require 'omf_common/relaxng_schema'
|
7
|
-
|
8
1
|
module OmfCommon
|
9
2
|
|
10
3
|
class MPMessage < OML4R::MPBase
|
11
4
|
name :message
|
12
5
|
param :time, :type => :double
|
13
6
|
param :operation, :type => :string
|
14
|
-
param :
|
15
|
-
param :
|
7
|
+
param :mid, :type => :string
|
8
|
+
param :cid, :type => :string
|
16
9
|
param :content, :type => :string
|
17
10
|
end
|
18
11
|
|
19
|
-
|
20
|
-
|
21
|
-
# @example To create a valid omf message, e.g. a 'configure' message:
|
22
|
-
#
|
23
|
-
# Message.request do |message|
|
24
|
-
# message.property('os', 'debian')
|
25
|
-
# message.property('memory', { value: 2, unit: 'gb' })
|
26
|
-
# end
|
27
|
-
#
|
28
|
-
class Message < Niceogiri::XML::Node
|
12
|
+
class Message
|
13
|
+
|
29
14
|
OMF_NAMESPACE = "http://schema.mytestbed.net/omf/#{OmfCommon::PROTOCOL_VERSION}/protocol"
|
30
|
-
|
31
|
-
|
32
|
-
# measurement twice, once when a message is created for publishing to T,
|
33
|
-
# and once when this message comes back (as we are also a subscriber of T)
|
34
|
-
# Thus we keep track of message IDs here (again only when OML is enabled)
|
35
|
-
@@msg_id_list = []
|
36
|
-
|
37
|
-
class << self
|
38
|
-
OPERATION.each do |operation|
|
39
|
-
define_method(operation) do |*args, &block|
|
40
|
-
xml = new(operation, nil, OMF_NAMESPACE)
|
41
|
-
if operation == 'inform'
|
42
|
-
xml.element('context_id', args[1]) if args[1]
|
43
|
-
xml.element('inform_type', args[0])
|
44
|
-
else
|
45
|
-
xml.element('publish_to', args[0]) if args[0]
|
46
|
-
end
|
47
|
-
block.call(xml) if block
|
48
|
-
xml.sign
|
49
|
-
end
|
50
|
-
end
|
15
|
+
OMF_CORE_READ = [:operation, :ts, :src, :mid, :replyto, :cid, :itype, :rtype, :guard, :res_id]
|
16
|
+
OMF_CORE_WRITE = [:replyto, :itype, :guard]
|
51
17
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
18
|
+
@@providers = {
|
19
|
+
xml: {
|
20
|
+
require: 'omf_common/message/xml/message',
|
21
|
+
constructor: 'OmfCommon::Message::XML::Message'
|
22
|
+
},
|
23
|
+
json: {
|
24
|
+
require: 'omf_common/message/json/json_message',
|
25
|
+
constructor: 'OmfCommon::Message::Json::Message'
|
26
|
+
}
|
27
|
+
}
|
28
|
+
@@message_class = nil
|
62
29
|
|
63
|
-
|
64
|
-
|
65
|
-
def property(key, value = nil)
|
66
|
-
key_node = Message.new('property')
|
67
|
-
key_node.write_attr('key', key)
|
68
|
-
|
69
|
-
unless value.nil?
|
70
|
-
key_node.write_attr('type', ruby_type_2_prop_type(value.class))
|
71
|
-
c_node = value_node_set(value)
|
72
|
-
|
73
|
-
if c_node.class == Array
|
74
|
-
c_node.each { |c_n| key_node.add_child(c_n) }
|
75
|
-
else
|
76
|
-
key_node.add_child(c_node)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
add_child(key_node)
|
80
|
-
key_node
|
30
|
+
def self.create(type, properties, body = {})
|
31
|
+
@@message_class.create(type, properties, body)
|
81
32
|
end
|
82
33
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
[].tap do |array|
|
87
|
-
value.each_pair do |k, v|
|
88
|
-
n = Message.new(k)
|
89
|
-
n.write_attr('type', ruby_type_2_prop_type(v.class))
|
90
|
-
|
91
|
-
c_node = value_node_set(v, k)
|
92
|
-
if c_node.class == Array
|
93
|
-
c_node.each { |c_n| n.add_child(c_n) }
|
94
|
-
else
|
95
|
-
n.add_child(c_node)
|
96
|
-
end
|
97
|
-
array << n
|
98
|
-
end
|
99
|
-
end
|
100
|
-
when Array
|
101
|
-
value.map do |v|
|
102
|
-
n = Message.new('item')
|
103
|
-
n.write_attr('type', ruby_type_2_prop_type(v.class))
|
104
|
-
|
105
|
-
c_node = value_node_set(v, 'item')
|
106
|
-
if c_node.class == Array
|
107
|
-
c_node.each { |c_n| n.add_child(c_n) }
|
108
|
-
else
|
109
|
-
n.add_child(c_node)
|
110
|
-
end
|
111
|
-
n
|
112
|
-
end
|
113
|
-
else
|
114
|
-
if key.nil?
|
115
|
-
string_value(value)
|
116
|
-
else
|
117
|
-
n = Message.new(key)
|
118
|
-
n.add_child(string_value(value))
|
119
|
-
end
|
120
|
-
end
|
34
|
+
def self.create_inform_message(itype = nil, properties = {}, body = {})
|
35
|
+
body[:itype] = itype if itype
|
36
|
+
create(:inform, properties, body)
|
121
37
|
end
|
122
38
|
|
123
|
-
#
|
39
|
+
# Create and return a message by parsing 'str'
|
124
40
|
#
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
canonical_msg = self.canonicalize
|
41
|
+
def self.parse(str)
|
42
|
+
@@message_class.parse(str)
|
43
|
+
end
|
129
44
|
|
130
|
-
|
131
|
-
|
45
|
+
def self.init(opts = {})
|
46
|
+
if @@message_class
|
47
|
+
raise "Message provider already iniitalised"
|
48
|
+
end
|
49
|
+
unless provider = opts[:provider]
|
50
|
+
provider = @@providers[opts[:type]]
|
51
|
+
end
|
52
|
+
unless provider
|
53
|
+
raise "Missing Message provider declaration. Either define 'type' or 'provider'"
|
54
|
+
end
|
132
55
|
|
133
|
-
|
134
|
-
write_attr('digest', digest)
|
135
|
-
write_attr('signature', signature) if signature
|
56
|
+
require provider[:require] if provider[:require]
|
136
57
|
|
137
|
-
if
|
138
|
-
|
139
|
-
|
58
|
+
if class_name = provider[:constructor]
|
59
|
+
@@message_class = class_name.split('::').inject(Object) {|c,n| c.const_get(n) }
|
60
|
+
else
|
61
|
+
raise "Missing provider class info - :constructor"
|
140
62
|
end
|
141
|
-
self
|
142
63
|
end
|
143
64
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
65
|
+
OMF_CORE_READ.each do |pname|
|
66
|
+
define_method(pname.to_s) do |*args|
|
67
|
+
_get_core(pname)
|
68
|
+
end
|
69
|
+
end
|
149
70
|
|
71
|
+
alias_method :type, :operation
|
150
72
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
validation = RelaxNGSchema.instance.schema.validate(self.document)
|
155
|
-
if validation.empty?
|
156
|
-
true
|
157
|
-
else
|
158
|
-
logger.error validation.map(&:message).join("\n")
|
159
|
-
logger.debug self.to_s
|
160
|
-
false
|
73
|
+
OMF_CORE_WRITE.each do |pname|
|
74
|
+
define_method("#{pname}=") do |val|
|
75
|
+
_set_core(pname.to_sym, val)
|
161
76
|
end
|
162
77
|
end
|
163
78
|
|
164
|
-
#
|
79
|
+
# To access properties
|
165
80
|
#
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
block.call(key_node)
|
171
|
-
else
|
172
|
-
key_node.content = value if value
|
173
|
-
end
|
81
|
+
# @param [String] name of the property
|
82
|
+
# @param [Hash] ns namespace of property
|
83
|
+
def [](name, ns = nil)
|
84
|
+
_get_property(name.to_sym, ns)
|
174
85
|
end
|
175
86
|
|
176
|
-
#
|
87
|
+
# To set properties
|
177
88
|
#
|
178
|
-
|
179
|
-
|
89
|
+
# @param [String] name of the property
|
90
|
+
# @param [Hash] ns namespace of property
|
91
|
+
def []=(name, ns = nil, value)
|
92
|
+
# TODO why itype cannot be set?
|
93
|
+
#raise if name.to_sym == :itype
|
94
|
+
if ns
|
95
|
+
@props_ns ||= {}
|
96
|
+
@props_ns.merge(ns)
|
97
|
+
end
|
98
|
+
_set_property(name.to_sym, value, ns)
|
180
99
|
end
|
181
100
|
|
182
|
-
|
183
|
-
|
184
|
-
xpath(xpath_without_ns.gsub(/(^|\/{1,2})(\w+)/, '\1xmlns:\2'), :xmlns => OMF_NAMESPACE)
|
101
|
+
def each_property(&block)
|
102
|
+
raise NotImplementedError
|
185
103
|
end
|
186
104
|
|
187
|
-
#
|
105
|
+
# Loop over all the unbound (sent without a value) properties
|
106
|
+
# of a request message.
|
188
107
|
#
|
189
|
-
|
108
|
+
def each_unbound_request_property(&block)
|
109
|
+
raise NotImplementedError
|
110
|
+
end
|
190
111
|
|
191
|
-
#
|
112
|
+
# Loop over all the bound (sent with a value) properties
|
113
|
+
# of a request message.
|
192
114
|
#
|
193
|
-
def
|
194
|
-
|
195
|
-
unless element_content.nil?
|
196
|
-
element_content.empty? ? nil : element_content
|
197
|
-
else
|
198
|
-
nil
|
199
|
-
end
|
115
|
+
def each_bound_request_property(&block)
|
116
|
+
raise NotImplementedError
|
200
117
|
end
|
201
118
|
|
202
|
-
|
203
|
-
|
204
|
-
read_property(:context_id) || read_content(:context_id)
|
119
|
+
def has_properties?
|
120
|
+
raise NotImplementedError
|
205
121
|
end
|
206
122
|
|
207
|
-
|
208
|
-
|
209
|
-
|
123
|
+
def resource
|
124
|
+
name = _get_property(:res_id)
|
125
|
+
OmfCommon.comm.create_topic(name)
|
210
126
|
end
|
211
127
|
|
212
|
-
def
|
213
|
-
|
128
|
+
def success?
|
129
|
+
! error?
|
214
130
|
end
|
215
131
|
|
216
|
-
def
|
217
|
-
|
132
|
+
def error?
|
133
|
+
(itype || '') =~ /(error|ERROR|FAILED)/
|
218
134
|
end
|
219
135
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
# @return [Object] the content of the property, as string, integer, float, or mash(hash with indifferent access)
|
224
|
-
#
|
225
|
-
def read_property(key, data_binding = nil)
|
226
|
-
key = key.to_s
|
227
|
-
e = read_element("property[@key='#{key}']").first
|
228
|
-
reconstruct_data(e, data_binding) if e
|
136
|
+
def create_inform_reply_message(itype = nil, properties = {}, body = {})
|
137
|
+
body[:cid] = self.mid
|
138
|
+
self.class.create_inform_message(itype, properties, body)
|
229
139
|
end
|
230
140
|
|
231
|
-
def
|
232
|
-
|
233
|
-
case node_type
|
234
|
-
when 'array'
|
235
|
-
node.element_children.map do |child|
|
236
|
-
reconstruct_data(child, data_binding)
|
237
|
-
end
|
238
|
-
when /hash/
|
239
|
-
mash ||= Hashie::Mash.new
|
240
|
-
node.element_children.each do |child|
|
241
|
-
mash[child.attr('key') || child.element_name] ||= reconstruct_data(child, data_binding)
|
242
|
-
end
|
243
|
-
mash
|
244
|
-
when /boolean/
|
245
|
-
node.content == "true"
|
246
|
-
else
|
247
|
-
if node.content.empty?
|
248
|
-
nil
|
249
|
-
elsif data_binding && node_type == 'string'
|
250
|
-
ERB.new(node.content).result(data_binding)
|
251
|
-
else
|
252
|
-
node.content.ducktype
|
253
|
-
end
|
254
|
-
end
|
141
|
+
def to_s
|
142
|
+
raise NotImplementedError
|
255
143
|
end
|
256
144
|
|
257
|
-
|
258
|
-
|
259
|
-
def each_property(&block)
|
260
|
-
read_element("property").each { |v| block.call(v) }
|
145
|
+
def marshall
|
146
|
+
raise NotImplementedError
|
261
147
|
end
|
262
148
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
149
|
+
def valid?
|
150
|
+
raise NotImplementedError
|
151
|
+
end
|
152
|
+
|
153
|
+
# Construct default namespace of the props from resource type
|
154
|
+
def default_props_ns
|
155
|
+
resource_type = _get_core(:rtype)
|
156
|
+
resource_type ? { resource_type.to_s => "#{OMF_NAMESPACE}/#{resource_type}" } : {}
|
157
|
+
end
|
158
|
+
|
159
|
+
# Get all property namespace defs
|
160
|
+
def props_ns
|
161
|
+
@props_ns ||= {}
|
162
|
+
default_props_ns.merge(@props_ns)
|
267
163
|
end
|
268
164
|
|
269
165
|
private
|
270
166
|
|
271
|
-
def
|
272
|
-
|
273
|
-
case v_type
|
274
|
-
when *%w(trueclass falseclass)
|
275
|
-
'boolean'
|
276
|
-
when *%w(fixnum bignum)
|
277
|
-
'integer'
|
278
|
-
else
|
279
|
-
v_type
|
280
|
-
end
|
167
|
+
def _get_property(name, ns = nil)
|
168
|
+
raise NotImplementedError
|
281
169
|
end
|
282
170
|
|
283
|
-
|
284
|
-
|
285
|
-
if value.kind_of? String
|
286
|
-
value = CGI::escape_html(value)
|
287
|
-
else
|
288
|
-
value = value.to_s
|
289
|
-
end
|
290
|
-
value
|
171
|
+
def _set_property(name, value, ns = nil)
|
172
|
+
raise NotImplementedError
|
291
173
|
end
|
292
174
|
end
|
175
|
+
|
293
176
|
end
|