adaptation 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
- - ">"
|