adaptation 0.0.6 → 0.0.7
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/CHANGELOG +2 -0
- data/README +3 -2
- data/lib/adaptation/adaptor.rb +1 -1
- data/lib/adaptation/message.rb +150 -158
- data/lib/adaptation/validateable.rb +33 -1
- metadata +3 -3
data/CHANGELOG
CHANGED
data/README
CHANGED
@@ -36,14 +36,15 @@ adapting a database-backed application.
|
|
36
36
|
By default this will try to subscribe to a mom listening on localhost:8080, using port
|
37
37
|
8081 to subscribe. These values can be changed editing <tt>config/mom.yml</tt>. In mom.yml
|
38
38
|
you can also specify wich topics your adaptor is interested in.
|
39
|
-
4. Start developing your adaptor, probably generating __Adaptors__, __Messages__
|
39
|
+
4. Start developing your adaptor, probably generating __Adaptors__[link:../rdoc/classes/Adaptation/Adaptor.html], __Messages__[link:../rdoc/classes/Adaptation/Message.html]
|
40
|
+
and __Models__[http://api.rubyonrails.org/classes/ActiveRecord/Base.html].
|
40
41
|
|
41
42
|
|
42
43
|
== Moms
|
43
44
|
|
44
45
|
By default, Adaptation will try to use druby to execute the built-in Ruby mom. This
|
45
46
|
mom is suitable for development, but not for production. For a production environment
|
46
|
-
a more stable solution like Xmlblaster should be chosen.
|
47
|
+
a more stable solution like Xmlblaster[http://www.xmlblaster.org] should be chosen.
|
47
48
|
|
48
49
|
|
49
50
|
== Description of contents
|
data/lib/adaptation/adaptor.rb
CHANGED
@@ -3,7 +3,7 @@ module Adaptation
|
|
3
3
|
#
|
4
4
|
#Adaptation::Adaptor is the base class for those classes containing the logic to be executed when a message is read through the mom.
|
5
5
|
#
|
6
|
-
#Each class extending Adaptation::Adaptor must implement the _process_ function, using it as the main entry point for the logic to be executed when a message arrives. The name of the class extending Adaptation::Message associates the class with the one to be executed when a message arrives. Ie. if a message is received with a root element named
|
6
|
+
#Each class extending Adaptation::Adaptor must implement the _process_ function, using it as the main entry point for the logic to be executed when a message arrives. The name of the class extending Adaptation::Message associates the class with the one to be executed when a message arrives. Ie. if a message is received with a root element named <hello>, adaptation will search for a class extending Adaptation::Adaptor named _HelloAdaptor_.
|
7
7
|
#
|
8
8
|
#<i>Adaptation::Adaptors</i> (classes extending Adaptation::Adaptor) must be stored under <i>app/adaptors_name</i> in the adaptation file tree. This is done automatically when an adaptor is generated using adaptation built-in generator:
|
9
9
|
# script/generate adaptor hello
|
data/lib/adaptation/message.rb
CHANGED
@@ -15,76 +15,83 @@ module Adaptation
|
|
15
15
|
#
|
16
16
|
#* Automated mapping between classes and xml attributes and elements.
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
18
|
+
# class Contact < Adaptation::Message
|
19
|
+
# has_one :text, :name
|
20
|
+
# end
|
21
21
|
#
|
22
|
-
#
|
22
|
+
# ...is automatically mapped to a xml structure with root element named "contact", such as:
|
23
23
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
24
|
+
# <contact>
|
25
|
+
# <name>Name</name>
|
26
|
+
# </contact>
|
27
27
|
#
|
28
|
-
#
|
28
|
+
# ...which gives Contact#name
|
29
29
|
#
|
30
30
|
#
|
31
31
|
#* Associations between objects controlled by simple meta-programming macros.
|
32
32
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
33
|
+
# class Agenda < Adaptation::Message
|
34
|
+
# has_one :attribute, :type
|
35
|
+
# has_one :text, :owner
|
36
|
+
# has_many :contacts
|
37
|
+
# end
|
38
38
|
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
39
|
+
# class Contact < Adaptation::Message
|
40
|
+
# has_one :text, :name
|
41
|
+
# end
|
42
42
|
#
|
43
|
-
#
|
43
|
+
# Agenda class would be mapping the following xml structure:
|
44
44
|
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
45
|
+
# <agenda type="...">
|
46
|
+
# <owner>...</owner>
|
47
|
+
# <contact>...</contact>
|
48
|
+
# <contact>...</contact>
|
49
|
+
# ...
|
50
|
+
# </agenda>
|
51
51
|
#
|
52
|
-
#
|
52
|
+
# while the _Contact_ class would map:
|
53
53
|
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
54
|
+
# <contact>
|
55
|
+
# <name>...</name>
|
56
|
+
# </contact>
|
57
57
|
#
|
58
|
-
#
|
59
|
-
#
|
58
|
+
# The Contact class is a partial, a structure included in a bigger structure, so its
|
59
|
+
# file name starts with an underscore: _contact.rb
|
60
60
|
#
|
61
|
-
#
|
61
|
+
# We could have wrote Agenda like this, to change the contacts container name:
|
62
62
|
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
63
|
+
# class Agenda < Adaptation::Message
|
64
|
+
# has_one :attribute, :type
|
65
|
+
# has_one :text, :owner
|
66
|
+
# has_many :contacts, :in => :contact_list
|
67
|
+
# end
|
68
68
|
#
|
69
|
-
#
|
69
|
+
# and Contact like:
|
70
70
|
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
# end
|
71
|
+
# class Contact < Adaptation::Message
|
72
|
+
# has_one :text, :name
|
73
|
+
# end
|
75
74
|
#
|
76
|
-
#
|
75
|
+
# Then the mapping in Agenda would be:
|
77
76
|
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
77
|
+
# <agenda type="...">
|
78
|
+
# <owner>...</owner>
|
79
|
+
# <contact_list>
|
80
|
+
# <contact>...</contact>
|
81
|
+
# </contact_list>
|
82
|
+
# </agenda>
|
84
83
|
#
|
85
84
|
#
|
86
85
|
#* Validation rules.
|
87
86
|
#
|
87
|
+
# Adaptation::Message uses {ActiveRecord::Validations}[http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html].
|
88
|
+
# This means that {ActiveRecord validations}[http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html]
|
89
|
+
# can be used in an Adaptation::Message object and that custom validations can be easily implemented.
|
90
|
+
#
|
91
|
+
# Adaptation::Message also defines some {custom validation methods}[link:../rdoc/classes/ActiveRecord/Validations/ClassMethods.html].
|
92
|
+
#
|
93
|
+
# Validations usage example:
|
94
|
+
#
|
88
95
|
# class Agenda < Adaptation::Message
|
89
96
|
# has_one :attribute, :type
|
90
97
|
# has_one :text, :owner
|
@@ -97,107 +104,46 @@ module Adaptation
|
|
97
104
|
|
98
105
|
@@classes_with_brothers = []
|
99
106
|
cattr_reader :classes_with_brothers
|
100
|
-
cattr_reader :validations
|
101
107
|
cattr_reader :objects
|
102
108
|
|
103
109
|
include Validateable
|
104
110
|
include ROXML
|
105
111
|
|
106
|
-
def to_hash
|
107
|
-
s = self.to_yaml
|
108
|
-
h = YAML::load s[4..s.length].downcase.gsub(/\!ruby\/object:.* /,"")
|
109
|
-
end
|
110
|
-
|
111
|
-
def has_son?(son)
|
112
|
-
search_symbol_in_hash self.to_hash, son
|
113
|
-
end
|
114
|
-
|
115
|
-
def search_symbol_in_hash hash, symbol
|
116
|
-
found = false
|
117
|
-
hash.each_pair do |k,v|
|
118
|
-
if (k.to_sym == symbol)
|
119
|
-
found = true
|
120
|
-
break
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
if !found
|
125
|
-
hash.each_pair do |k,v|
|
126
|
-
found = search_symbol_in_hash(v, symbol) if v.is_a?(Hash)
|
127
|
-
break if found
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
found
|
132
|
-
end
|
133
|
-
|
134
|
-
def search_paths(symbol)
|
135
|
-
get_paths_from_hash self.to_hash, symbol
|
136
|
-
end
|
137
|
-
|
138
|
-
def search_objects(symbol)
|
139
|
-
objects = []
|
140
|
-
paths = search_paths(symbol)
|
141
|
-
paths.each do |path|
|
142
|
-
objects << get_object(path)
|
143
|
-
end
|
144
|
-
objects.flatten
|
145
|
-
end
|
146
|
-
|
147
|
-
def get_paths_from_hash hash, symbol, root_path = ""
|
148
|
-
paths = []
|
149
|
-
hash.each_pair do |k,v|
|
150
|
-
if (k.to_sym == symbol)
|
151
|
-
paths << "#{root_path}.#{k}" unless paths.include?("#{root_path}.#{k}")
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
hash.each_pair do |k,v|
|
156
|
-
if v.is_a?(Hash)
|
157
|
-
son_paths = get_paths_from_hash(v, symbol, k)
|
158
|
-
son_paths.each do |sp|
|
159
|
-
paths << "#{root_path}.#{sp}" unless paths.include?("#{root_path}.#{sp}")
|
160
|
-
end
|
161
|
-
elsif v.is_a?(Array)
|
162
|
-
v.each do |h|
|
163
|
-
son_paths = get_paths_from_hash(h, symbol, k)
|
164
|
-
son_paths.each do |sp|
|
165
|
-
paths << "#{root_path}.#{sp}" unless paths.include?("#{root_path}.#{sp}")
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
paths.map!{|p|
|
172
|
-
if p.first == "."
|
173
|
-
p[1..p.length]
|
174
|
-
else
|
175
|
-
p
|
176
|
-
end
|
177
|
-
}
|
178
|
-
|
179
|
-
paths
|
180
|
-
end
|
181
|
-
|
182
|
-
def get_object path
|
183
|
-
subpaths = path.split(".")
|
184
|
-
objects = [self]
|
185
|
-
subpaths.each do |s|
|
186
|
-
array = []
|
187
|
-
objects.each do |o|
|
188
|
-
if o.is_a?(Array)
|
189
|
-
o.each do |os|
|
190
|
-
array << os.send(s.to_sym)
|
191
|
-
end
|
192
|
-
else
|
193
|
-
array << o.send(s.to_sym)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
objects = array
|
197
|
-
end
|
198
|
-
objects
|
199
|
-
end
|
200
112
|
|
113
|
+
# Maps an xml attribute or element.
|
114
|
+
#
|
115
|
+
# Example 1: Mapping an attribute:
|
116
|
+
# <xml attr="something"/>
|
117
|
+
#
|
118
|
+
# class Xml < Adaptation::Message
|
119
|
+
# has_one :attribute, :attr
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# Example 2: Mapping an xml element that contains text.
|
123
|
+
# <xml>
|
124
|
+
# <element>something</element>
|
125
|
+
# </xml>
|
126
|
+
#
|
127
|
+
# class Xml < Adaptation::Message
|
128
|
+
# has_one :text, :element
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
# Example 3: Mapping an xml element that contains xml data.
|
132
|
+
# <xml>
|
133
|
+
# <element>
|
134
|
+
# <subelement>something</subelement>
|
135
|
+
# </element>
|
136
|
+
# </xml>
|
137
|
+
#
|
138
|
+
# class Xml < Adaptation::Message
|
139
|
+
# has_one :object, :element
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# The element xml structure would be described in a separate partial file <em>_element.rb</em>:
|
143
|
+
# class Element < Adaptation::Message
|
144
|
+
# has_one :text, :subelement
|
145
|
+
# end
|
146
|
+
#
|
201
147
|
def self.has_one *symbols
|
202
148
|
xml_tag = symbols[0]
|
203
149
|
case xml_tag
|
@@ -233,6 +179,30 @@ module Adaptation
|
|
233
179
|
end
|
234
180
|
end
|
235
181
|
|
182
|
+
# Maps an xml element text.
|
183
|
+
#
|
184
|
+
# If an element contains plain text data and has not been declared in its parent element with
|
185
|
+
# <em>has_one :text</em>, it must declare itself with <em>has_text</em> to be able to contain text.
|
186
|
+
#
|
187
|
+
# Example:
|
188
|
+
#
|
189
|
+
# <xml>
|
190
|
+
# <element attr="something">something more</element>
|
191
|
+
# </xml>
|
192
|
+
#
|
193
|
+
# class Xml < Adaptation::Message
|
194
|
+
# has_one :object, :element
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# In this case element cannot be declared just like <em>has_one :text</em>, because it also has
|
198
|
+
# an attribute. It must be declared like <em>has_one :object</em>. Then the element declares itself
|
199
|
+
# in a file called <em>_element.rb</em> like this:
|
200
|
+
#
|
201
|
+
# class Element < Adaptation::Message
|
202
|
+
# has_one :attribute, :attr
|
203
|
+
# has_text
|
204
|
+
# end
|
205
|
+
#
|
236
206
|
def self.has_text
|
237
207
|
if @has_text.nil?
|
238
208
|
@has_text = true
|
@@ -240,20 +210,34 @@ module Adaptation
|
|
240
210
|
end
|
241
211
|
end
|
242
212
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
end
|
256
|
-
|
213
|
+
# Maps many xml subelements.
|
214
|
+
#
|
215
|
+
# Example 1:
|
216
|
+
#
|
217
|
+
# <xml>
|
218
|
+
# <subelement>...</subelement>
|
219
|
+
# <subelement>...</subelement>
|
220
|
+
# <subelement>...</subelement>
|
221
|
+
# </xml>
|
222
|
+
#
|
223
|
+
# class Xml < Adaptation::Message
|
224
|
+
# has_many :subelements
|
225
|
+
# end
|
226
|
+
#
|
227
|
+
# Example 2:
|
228
|
+
#
|
229
|
+
# <xml>
|
230
|
+
# <subelement_list>
|
231
|
+
# <subelement>...</subelement>
|
232
|
+
# <subelement>...</subelement>
|
233
|
+
# <subelement>...</subelement>
|
234
|
+
# </subelement_list>
|
235
|
+
# </xml>
|
236
|
+
#
|
237
|
+
# class Xml < Adaptation::Message
|
238
|
+
# has_many :subelements, :in => :subelement_list
|
239
|
+
# end
|
240
|
+
#
|
257
241
|
def self.has_many *options
|
258
242
|
configuration = {}
|
259
243
|
configuration.update(options.pop) if options.last.is_a?(Hash)
|
@@ -285,14 +269,22 @@ module Adaptation
|
|
285
269
|
end
|
286
270
|
end
|
287
271
|
|
288
|
-
def self.get_class_object(searched_class)
|
272
|
+
def self.get_class_object(searched_class) #:nodoc:
|
289
273
|
Object.const_get searched_class
|
290
274
|
end
|
291
|
-
|
275
|
+
|
276
|
+
# This is the constructor. Instead of <em>Adaptation::Message#new</em>, an <em>Adaptation::Message</em>
|
277
|
+
# instance is created like this:
|
278
|
+
#
|
279
|
+
# m = Adaptation::Message.to_object("<xml>valid xml</xml>")
|
280
|
+
#
|
292
281
|
def self.to_object xml_message
|
293
282
|
parse xml_message
|
294
283
|
end
|
295
284
|
|
285
|
+
# Checks if an Adaptation::Message object passes all validations.
|
286
|
+
#
|
287
|
+
# It is an alias for <em>Adaptation::Message#valid?</em>
|
296
288
|
def check
|
297
289
|
valid?
|
298
290
|
end
|
@@ -19,6 +19,27 @@ module ActiveRecord
|
|
19
19
|
module Validations
|
20
20
|
module ClassMethods
|
21
21
|
|
22
|
+
# Validates whether the value of the specified xml attribute/element is the expected one.
|
23
|
+
#
|
24
|
+
# Example 1:
|
25
|
+
#
|
26
|
+
# <leftwing side="left"/>
|
27
|
+
#
|
28
|
+
# class Leftwing < Adaptation::Message
|
29
|
+
# has_one :attribute, :side
|
30
|
+
#
|
31
|
+
# validates_value_of :side, "left"
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# Example 2:
|
35
|
+
# <bird><wings><wing side="left"/><wing side="right"/></wings></bird>
|
36
|
+
#
|
37
|
+
# class Bird < Adaptation::Message
|
38
|
+
# has_many :wings
|
39
|
+
#
|
40
|
+
# validates_value_of :side, "left", :in => :wings
|
41
|
+
# end
|
42
|
+
#
|
22
43
|
def validates_value_of(*attr_names)
|
23
44
|
configuration = {
|
24
45
|
:message => 'value doesn\'t exist'
|
@@ -44,7 +65,18 @@ module ActiveRecord
|
|
44
65
|
end
|
45
66
|
end
|
46
67
|
end
|
47
|
-
|
68
|
+
|
69
|
+
# Validates whether the value of the specified xml attribute/element has a valid email format.
|
70
|
+
#
|
71
|
+
# Example:
|
72
|
+
# <contact email="mail@xample.com">...</contact>
|
73
|
+
#
|
74
|
+
# class Contact < Adaptation::Message
|
75
|
+
# has_one :attribute, :email
|
76
|
+
#
|
77
|
+
# validates_as_email :email
|
78
|
+
# end
|
79
|
+
#
|
48
80
|
def validates_as_email(*attr_names)
|
49
81
|
configuration = {
|
50
82
|
:message => 'is an invalid email',
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: adaptation
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2008-
|
6
|
+
version: 0.0.7
|
7
|
+
date: 2008-11-24 00:00:00 +01:00
|
8
8
|
summary: Framework to facilitate web-application interaction.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -15,7 +15,7 @@ description: Adaptation is a framework for building "adaptors" for web-applicati
|
|
15
15
|
autorequire: adaptation
|
16
16
|
default_executable: adaptation
|
17
17
|
bindir: bin
|
18
|
-
has_rdoc:
|
18
|
+
has_rdoc: true
|
19
19
|
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
20
|
requirements:
|
21
21
|
- - ">"
|