adaptation 0.1.10 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/README +90 -12
- data/helpers/publish.rb +1 -1
- data/helpers/test_helper.rb +4 -0
- data/lib/adaptation.rb +2 -1
- data/lib/adaptation/adaptor.rb +25 -8
- data/lib/adaptation/base.rb +4 -9
- data/lib/adaptation/message.rb +140 -244
- data/lib/adaptation/test/test_help.rb +28 -47
- data/lib/adaptation/validateable.rb +112 -12
- data/lib/adaptation/version.rb +3 -3
- data/lib/rails_generator/generators/components/adaptor/templates/functional_test.rb +3 -4
- data/lib/rails_generator/generators/components/message/templates/unit_test.rb +2 -10
- metadata +7 -7
data/CHANGELOG
CHANGED
@@ -65,3 +65,10 @@
|
|
65
65
|
- bug: test environment not set properly since 0.1.7
|
66
66
|
* 0.1.10
|
67
67
|
- generated mock publish.rb bug corrected
|
68
|
+
-------------------
|
69
|
+
* 1.0.0
|
70
|
+
- Migrated from ROXML to XmlSimple. Messages don't need to be defined any more, so
|
71
|
+
has_many, has_one... and partials are deprecated.
|
72
|
+
* 1.0.1
|
73
|
+
- Fixed problems with activerecord > 2.2.2
|
74
|
+
- Requires activerecord >= 2.3.3
|
data/README
CHANGED
@@ -40,8 +40,7 @@ Adaptation is available as a ruby gem, so the easiest way should be:
|
|
40
40
|
|
41
41
|
This will generate a an adaptor file tree under folder _myadaptor_.
|
42
42
|
|
43
|
-
2. If no message oriented middleware has been already set,
|
44
|
-
and start the <b>mom</b>:
|
43
|
+
2. If no message oriented middleware (mom) has been already set, you can start one typing:
|
45
44
|
|
46
45
|
> mom
|
47
46
|
|
@@ -50,14 +49,14 @@ Adaptation is available as a ruby gem, so the easiest way should be:
|
|
50
49
|
3. Subscribe your adaptor to the <b>mom</b>, so it will be executed when a message is received on
|
51
50
|
a topic your adaptor is interested in:
|
52
51
|
|
53
|
-
> script/subscribe
|
52
|
+
> ruby script/subscribe
|
54
53
|
|
55
54
|
By default this will try to subscribe to a *mom* listening on <em>localhost:8080</em>, using port
|
56
55
|
<em>8081</em> to subscribe (subscribing means starting a new server that listens for
|
57
56
|
message publication notifications). These values can be changed editing <em>config/mom.yml</em>. In <em>mom.yml</em>
|
58
57
|
you can also specify wich topics your adaptor is interested in.
|
59
58
|
|
60
|
-
4. Right now you should have a <b>mom</b>
|
59
|
+
4. Right now you should have a <b>mom</b> listening for messages on <em>localhost:8080</em>, and an _adaptor_
|
61
60
|
subscribed to that *mom* and listening on <em>localhost:8081</em>, and interested in all topics available.
|
62
61
|
|
63
62
|
This environment can be tested by executing the following from _myadaptor_ folder:
|
@@ -68,8 +67,8 @@ Adaptation is available as a ruby gem, so the easiest way should be:
|
|
68
67
|
This message should be displayed in the subscriber terminal when delivered by the *mom*.
|
69
68
|
Nothing would be executed, because a _Helloworld_ message[link:../rdoc/classes/Adaptation/Message.html] to
|
70
69
|
map this xml message and a _HelloworldAdaptor_[link:../rdoc/classes/Adaptation/Adaptor.html] to process it don't
|
71
|
-
exist yet. Since these classes aren't implemented, Adaptation will pass the message as
|
72
|
-
default _ApplicationAdaptor_ adaptor, but its _process_ method is still empty, so nothing will happen.
|
70
|
+
exist yet. Since these classes aren't implemented, Adaptation will pass the message as an Adaptation::Message object
|
71
|
+
to the default _ApplicationAdaptor_ adaptor, but its _process_ method is still empty, so nothing will happen.
|
73
72
|
|
74
73
|
To see something happening the _process_ method in the default _ApplicationAdaptor_ could be implemented,
|
75
74
|
editing file <em>myadaptor/app/adaptors/application.rb</em>:
|
@@ -109,8 +108,7 @@ Adaptation is available as a ruby gem, so the easiest way should be:
|
|
109
108
|
create app/adaptors/helloworld_adaptor.rb
|
110
109
|
create test/functional/helloworld_adaptor_test.rb
|
111
110
|
|
112
|
-
and to edit <em>app/adaptors/helloworld_adaptor</em> to make something happen
|
113
|
-
when a message is received:
|
111
|
+
and to edit <em>app/adaptors/helloworld_adaptor</em> to make something happen when a message is received:
|
114
112
|
|
115
113
|
class HelloworldAdaptor < ApplicationAdaptor
|
116
114
|
|
@@ -120,8 +118,8 @@ Adaptation is available as a ruby gem, so the easiest way should be:
|
|
120
118
|
|
121
119
|
end
|
122
120
|
|
123
|
-
We can notice that _helloworld_ variable is
|
124
|
-
has been able to map it to a Adaptation::Message object, and that the _HelloworldAdaptor_
|
121
|
+
We can notice that _helloworld_ variable is an instance of _Helloworld_ class (because Adaptation
|
122
|
+
has been able to map it to a subclass of Adaptation::Message object), and that the _HelloworldAdaptor_
|
125
123
|
inherits from _ApplicationAdaptor_, so functionality repeated in different _Adaptors_[link:../rdoc/classes/Adaptation/Adaptor.html]
|
126
124
|
can be placed in _ApplicationAdaptor_.
|
127
125
|
|
@@ -186,7 +184,87 @@ test
|
|
186
184
|
|
187
185
|
|
188
186
|
== Debugging
|
189
|
-
|
187
|
+
|
188
|
+
Adaptation includes a console from wich we can access Adaptation::Message and ActiveRecord classes defined in
|
189
|
+
the <em>adaptor</em> we are working on.
|
190
|
+
|
191
|
+
To open the console type:
|
192
|
+
|
193
|
+
> ruby script/console [environment]
|
194
|
+
|
195
|
+
From the command prompt that should appear, we can instantiate ActiveRecord objects defined in app/models and
|
196
|
+
Adaptation::Message objects defined in app/messages.
|
197
|
+
With the previous example, where an Adaptation::Message subclass called Helloworld was defined in app/messages,
|
198
|
+
we could do:
|
199
|
+
|
200
|
+
> ruby script/console test
|
201
|
+
$ >> Loading test environment (Adaptation X.X.X)
|
202
|
+
$ hw = HelloWorld.new("<helloworld>hello</helloworld>")
|
203
|
+
$ hw.content
|
204
|
+
$ >> "hello"
|
205
|
+
$ hw.to_xml
|
206
|
+
$ >> "<helloworld>hello</helloworld>"
|
207
|
+
|
208
|
+
We could edit app/messages/hellworld.rb to add a validation:
|
209
|
+
|
210
|
+
class Helloworld < Adaptation::Message
|
211
|
+
validates_presence_of :atr
|
212
|
+
end
|
213
|
+
|
214
|
+
and check if it works with the console:
|
215
|
+
|
216
|
+
> ruby script/console
|
217
|
+
$ >> Loading test environment (Adaptation X.X.X)
|
218
|
+
$ hw = HelloWorld.new("<helloworld>hello</helloworld>")
|
219
|
+
$ hw.valid?
|
220
|
+
$ >> false
|
221
|
+
$ hw = HelloWorld.new("<helloworld atr="something">hello</helloworld>")
|
222
|
+
$ hw.valid?
|
223
|
+
$ >> true
|
224
|
+
|
225
|
+
If we define ActiveRecord::Base subclasses in app/models we can do the same mapping
|
226
|
+
database rows instead of xml messages, if config/database.yml is properly configured
|
227
|
+
to access the database.
|
228
|
+
If we had a <em>users</em> table in our database, we could generate a model to access
|
229
|
+
it with ActiveRecord:
|
230
|
+
|
231
|
+
> ruby script/generate model user
|
232
|
+
exists app/models/
|
233
|
+
exists test/fixtures/
|
234
|
+
create app/models/user.rb
|
235
|
+
|
236
|
+
and use it from the console:
|
237
|
+
|
238
|
+
> ruby script/console
|
239
|
+
$ >> Loading test environment (Adaptation X.X.X)
|
240
|
+
$ u = User.find(:first)
|
241
|
+
|
190
242
|
|
191
243
|
== Testing
|
192
|
-
|
244
|
+
|
245
|
+
As it can be seen when generating adaptors and messages, adaptation automatically generates empty functional
|
246
|
+
tests for adaptors and empty unit tests for messages.
|
247
|
+
|
248
|
+
Tests can be run typing:
|
249
|
+
|
250
|
+
> ruby test.rb
|
251
|
+
|
252
|
+
Tests can use fixtures stored in <em>test/fixtures</em> folder. There are two kind of fixtures:
|
253
|
+
|
254
|
+
- <b>database fixtures</b>: the same database fixtures a {rails}[http://www.rubyonrails.org] application uses to fill its tables in tests. These fixtures are usually stored in <em>*.yml</em> files, and are used to reset database contents before each test, so it is important to configure the test database properly in config/database.yml. More about ActiveRecord fixtures {here}[http://api.rubyonrails.org/classes/Fixtures.html].
|
255
|
+
|
256
|
+
- <b>xml fixtures</b>: these fixtures are plain xml strored in <em>*.xml</em>, and are used to build Adaptation::Message objects and probably process them with our adaptor in the tests. These fixtures can also be created dynamically with Erb templetes. This is an example of a xml fixture built with Erb:
|
257
|
+
|
258
|
+
<20_people>
|
259
|
+
<% 20.times do |c| %>
|
260
|
+
<person num="<%= c %>"/>
|
261
|
+
<% end %>
|
262
|
+
</20_people>
|
263
|
+
|
264
|
+
For the _HellworldAdaptor_ in our example, we should find a functional test in <em>test/functional/helloworld_adaptor_test.rb</em>, and for the _Helloworld_ message a unit test in <em>test/unit/helloworld_test.rb</em>.
|
265
|
+
|
266
|
+
Tests usually perfrom {assertions}[link:../rdoc/classes/ActiveSupport/TestCase.html]. There are a couple of methods that may be useful when testing _adaptors_, {*get_message_form_fixture*}[link:../rdoc/classes/ActiveSupport/TestCase.html#M000044] and {*message*}[link:../rdoc/classes/ActiveSupport/TestCase.html#M000043]:
|
267
|
+
|
268
|
+
- *get_message_from_fixture*: Returns an Adaptation::Message object from a fixture, without processing it (or an instance of the corresponding subclass, if it's defined).
|
269
|
+
|
270
|
+
- *message*: Builds a message from a xml fixture file and processes it the same way messages from the mom are processed by Adaptation, but using the test environment. Messages published with {publish}[link:../rdoc/classes/Adaptation/Adaptor.html#M000170] will be published to a mocked MOM (and can be checked with _assert_message_published_).
|
data/helpers/publish.rb
CHANGED
@@ -9,7 +9,7 @@ class Adaptation::Adaptor
|
|
9
9
|
xml_message = options.first
|
10
10
|
message_type = xml_message[1..(xml_message.index(/(>| )/) - 1)]
|
11
11
|
message_class = Adaptation::Message.get_class_object(message_type.capitalize)
|
12
|
-
message_object = message_class.
|
12
|
+
message_object = message_class.new(xml_message)
|
13
13
|
end
|
14
14
|
|
15
15
|
mom = File.new(ADAPTOR_ROOT + '/test/mocks/test/mom.txt', "a")
|
data/helpers/test_helper.rb
CHANGED
data/lib/adaptation.rb
CHANGED
data/lib/adaptation/adaptor.rb
CHANGED
@@ -10,22 +10,39 @@ module Adaptation
|
|
10
10
|
#
|
11
11
|
class Adaptor
|
12
12
|
|
13
|
-
def process message
|
13
|
+
def process message #:nodoc:
|
14
14
|
end
|
15
15
|
|
16
|
+
# Returns the logger to output results in the current environment log file.
|
17
|
+
# Example:
|
18
|
+
# > logger.info "this is going to log/development.log"
|
16
19
|
def logger
|
17
20
|
Adaptation::Base.logger
|
18
21
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
|
23
|
+
# Publishes a message to the MOM. The message can be an instance of Adaptation::Message or a String.
|
24
|
+
#
|
25
|
+
# When executed in test environment messages are not published to the MOM. They are written to a mocked MOM
|
26
|
+
# and their publication can be asserted in tests with assert_message_published[link:/classes/ActiveSupport/TestCase.html#M000038].
|
27
|
+
#
|
28
|
+
# By default it uses <b>script/publish</b> ito publish. This can be overwritten specifying the
|
29
|
+
# <b>oappublish</b> instruction in configuration file <b>config/settings.yml</b>.
|
30
|
+
#
|
31
|
+
# By default it publishes in topic <b>ADAPTATION</b>. This can be overwritten specifying the <b>application</b> setting
|
32
|
+
# in <b>config/settings.yml</b> file.
|
33
|
+
#
|
34
|
+
# Example settings file:
|
35
|
+
# oappublish: /bin/echo
|
36
|
+
# application: MY_TOPIC
|
37
|
+
def publish *options
|
38
|
+
message_object = nil
|
39
|
+
if options.first.is_a?(Message)
|
40
|
+
message_object = options.first
|
24
41
|
elsif options.first.is_a?(String)
|
25
42
|
xml_message = options.first
|
26
43
|
message_type = xml_message[1..(xml_message.index(/(>| )/) - 1)]
|
27
44
|
message_class = Adaptation::Message.get_class_object(message_type.capitalize)
|
28
|
-
message_object = message_class.
|
45
|
+
message_object = message_class.new(xml_message)
|
29
46
|
end
|
30
47
|
|
31
48
|
xml = message_object.to_xml.to_s.gsub("'", "\"")
|
@@ -37,7 +54,7 @@ module Adaptation
|
|
37
54
|
|
38
55
|
end
|
39
56
|
|
40
|
-
def self.get_class_object(adaptor_class)
|
57
|
+
def self.get_class_object(adaptor_class) #:nodoc:
|
41
58
|
Object.const_get(adaptor_class) rescue nil
|
42
59
|
end
|
43
60
|
|
data/lib/adaptation/base.rb
CHANGED
@@ -61,19 +61,14 @@ module Adaptation
|
|
61
61
|
adaptor = message = nil
|
62
62
|
|
63
63
|
message_class = Adaptation::Message.get_class_object(message_type.capitalize)
|
64
|
-
message = message_class.nil? ? xml_message : message_class.
|
65
|
-
# TODO: the xml is returned as a String if a class to map it is not found;
|
66
|
-
# in future versions Adaptation may build a valid Adaptation::Message even
|
67
|
-
# without implementation for this type of message
|
64
|
+
message = message_class.nil? ? Adaptation::Message.new(xml_message) : message_class.new(xml_message)
|
68
65
|
|
69
66
|
adaptor_class = Adaptation::Adaptor.get_class_object("#{message_type.capitalize}Adaptor")
|
70
67
|
adaptor = adaptor_class.nil? ? ApplicationAdaptor.new : adaptor_class.new rescue Adaptation::Adaptor.new
|
71
68
|
|
72
|
-
unless message.
|
73
|
-
|
74
|
-
|
75
|
-
return
|
76
|
-
end
|
69
|
+
unless message.valid?
|
70
|
+
@@logger.info "WARNING:Message doesn't validate!"
|
71
|
+
return
|
77
72
|
end
|
78
73
|
|
79
74
|
adaptor.process message
|
data/lib/adaptation/message.rb
CHANGED
@@ -2,102 +2,44 @@ module Adaptation
|
|
2
2
|
|
3
3
|
#= Adaptation::Message -- XML to classes mapping.
|
4
4
|
#
|
5
|
-
#Adaptation::Message
|
6
|
-
#
|
7
|
-
#to
|
8
|
-
#management.
|
5
|
+
#Adaptation::Message maps xml data into a ruby object. It also provides validators
|
6
|
+
#(inspired by ActiveRecord[http://api.rubyonrails.org/classes/ActiveRecord/Validations.html] ORM)
|
7
|
+
#to check xml format.
|
9
8
|
#
|
10
|
-
#
|
11
|
-
#standalone classes. It offers a set of macros to specify wich structures are part of a bigger one and
|
12
|
-
#to allow validation of the different parts.
|
9
|
+
#Examples:
|
13
10
|
#
|
14
|
-
#
|
11
|
+
# contact = Adaptation::Message.new('<contact><name kind="surname">Name</name></contact>')
|
15
12
|
#
|
16
|
-
|
13
|
+
# contact.name.content # -> "Name"
|
14
|
+
# contact.names.first.content # -> "Name"
|
15
|
+
# contact.names.length # -> 1
|
16
|
+
# contact.name.kind # -> "surname"
|
17
17
|
#
|
18
|
-
#
|
19
|
-
# has_one :text, :name
|
20
|
-
# end
|
18
|
+
#Let's add some validations:
|
21
19
|
#
|
22
|
-
#
|
20
|
+
# class Contact < Adaptation::Message
|
21
|
+
# validates_presence_of :name
|
22
|
+
# end
|
23
23
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# </contact>
|
24
|
+
# contact = Contact.new('<contact><name kind="surname">Name</name></contact>')
|
25
|
+
# contact.valid? # -> true
|
27
26
|
#
|
28
|
-
#
|
27
|
+
# contact = Contact.new('<contact><phone>555</phone></contact>')
|
28
|
+
# contact.valid? # -> false
|
29
29
|
#
|
30
30
|
#
|
31
|
-
|
31
|
+
# class SeriousContact < Adaptation::Message
|
32
|
+
# maps_xml :contact # tell Adaptation that xml data like <contact>...</contact> is mapped by this class
|
33
|
+
# validates_value_of :kind, "surname", :in => :names
|
34
|
+
# end
|
32
35
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# has_one :text, :owner
|
36
|
-
# has_many :contacts
|
37
|
-
# end
|
36
|
+
# contact = SeriousContact.new('<contact><name kind="surname">Name</name></contact>')
|
37
|
+
# contact.valid? # -> true
|
38
38
|
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# end
|
42
|
-
#
|
43
|
-
# Agenda class would be mapping the following xml structure:
|
44
|
-
#
|
45
|
-
# <agenda type="...">
|
46
|
-
# <owner>...</owner>
|
47
|
-
# <contact>...</contact>
|
48
|
-
# <contact>...</contact>
|
49
|
-
# ...
|
50
|
-
# </agenda>
|
51
|
-
#
|
52
|
-
# while the _Contact_ class would map:
|
53
|
-
#
|
54
|
-
# <contact>
|
55
|
-
# <name>...</name>
|
56
|
-
# </contact>
|
57
|
-
#
|
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
|
-
#
|
61
|
-
# We could have wrote Agenda like this, to change the contacts container name:
|
62
|
-
#
|
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
|
-
#
|
69
|
-
# and Contact like:
|
70
|
-
#
|
71
|
-
# class Contact < Adaptation::Message
|
72
|
-
# has_one :text, :name
|
73
|
-
# end
|
74
|
-
#
|
75
|
-
# Then the mapping in Agenda would be:
|
76
|
-
#
|
77
|
-
# <agenda type="...">
|
78
|
-
# <owner>...</owner>
|
79
|
-
# <contact_list>
|
80
|
-
# <contact>...</contact>
|
81
|
-
# </contact_list>
|
82
|
-
# </agenda>
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#* Validation rules.
|
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.
|
39
|
+
# contact = SeriousContact.new('<contact><name kind="alias">Alias</name></contact>')
|
40
|
+
# contact.valid? # -> false
|
90
41
|
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
# Validations usage example:
|
94
|
-
#
|
95
|
-
# class Agenda < Adaptation::Message
|
96
|
-
# has_one :attribute, :type
|
97
|
-
# has_one :text, :owner
|
98
|
-
# validates_presence_of :owner, :type
|
99
|
-
# validates_value_of :type, "indexed"
|
100
|
-
# end
|
42
|
+
#More on validations here[link:../rdoc/classes/ActiveRecord/Validations/ClassMethods.html].
|
101
43
|
#
|
102
44
|
#
|
103
45
|
class Message
|
@@ -109,167 +51,86 @@ module Adaptation
|
|
109
51
|
cattr_reader :objects
|
110
52
|
|
111
53
|
include Validateable
|
112
|
-
include ROXML
|
113
54
|
|
55
|
+
# Constructor. Transforms xml passsed as a <em>String</em> to an object wich methods map the input xml elements and attributes.
|
56
|
+
def initialize xml_string
|
57
|
+
@hash_with_root = XmlSimple.xml_in("<adaptation_wrapper>" + xml_string + "</adaptation_wrapper>", 'ForceArray' => false, 'AttrPrefix' => true)
|
58
|
+
|
59
|
+
first_value = @hash_with_root.values.first
|
60
|
+
hash = first_value.is_a?(String) ? {"content" => first_value} : first_value
|
61
|
+
array = hash.is_a?(Array) ? hash : [hash]
|
114
62
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# class Xml < Adaptation::Message
|
141
|
-
# has_one :object, :element
|
142
|
-
# end
|
143
|
-
#
|
144
|
-
# The element xml structure would be described in a separate partial file <em>_element.rb</em>:
|
145
|
-
# class Element < Adaptation::Message
|
146
|
-
# has_one :text, :subelement
|
147
|
-
# end
|
148
|
-
#
|
149
|
-
def self.has_one *symbols
|
150
|
-
xml_tag = symbols[0]
|
151
|
-
case xml_tag
|
152
|
-
when :object
|
153
|
-
@objects = [] if @objects.nil?
|
154
|
-
unless @objects.include?(symbols[1])
|
155
|
-
@objects << symbols[1]
|
156
|
-
|
157
|
-
klass = get_class_object(symbols[1])
|
158
|
-
if klass.nil?
|
159
|
-
require "#{ADAPTOR_ROOT}/app/messages/_#{symbols[1].to_s}.rb"
|
160
|
-
klass = get_class_object(symbols[1])
|
63
|
+
array.each do |h|
|
64
|
+
if end_of_tree?(h)
|
65
|
+
h.each_pair do |k, v|
|
66
|
+
if !v.is_a?(Array)
|
67
|
+
is_attribute = k.include?("@") ? true : false
|
68
|
+
var = k.gsub("@","")
|
69
|
+
self.class_eval "attr_accessor :#{var}"
|
70
|
+
eval "@#{var} = v"
|
71
|
+
var2 = pluralize(var)
|
72
|
+
if !is_attribute and var != var2
|
73
|
+
self.class_eval "attr_accessor :#{var2}"
|
74
|
+
eval "@#{var2} = []; @#{var2} << '#{var}'"
|
75
|
+
end
|
76
|
+
else
|
77
|
+
var = pluralize(k.gsub("@",""))
|
78
|
+
self.class_eval "attr_accessor :#{var}"
|
79
|
+
eval "@#{var} = []"
|
80
|
+
v.each do |val|
|
81
|
+
if is_attribute?(val)
|
82
|
+
xml_substring = XmlSimple.xml_out(val, 'NoIndent' => true, 'RootName' => k, 'AttrPrefix' => true)
|
83
|
+
eval "@#{var} << Adaptation::Message.new('#{xml_substring}')"
|
84
|
+
else
|
85
|
+
eval "@#{var} << '#{val}'"
|
86
|
+
end
|
87
|
+
end
|
161
88
|
end
|
162
|
-
|
163
|
-
xml_object symbols[1], klass
|
164
|
-
validates_associated symbols[1]
|
165
89
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
90
|
+
else
|
91
|
+
h.each_pair do |k,v|
|
92
|
+
if k[0..0] == "@"
|
93
|
+
var = k.gsub("@","")
|
94
|
+
self.class_eval "attr_accessor :#{var}"
|
95
|
+
eval "@#{var} = '#{v}'"
|
96
|
+
else
|
97
|
+
self.class_eval "attr_accessor :#{k}"
|
98
|
+
xml_substring = ""
|
99
|
+
if !v.is_a?(Array)
|
100
|
+
xml_substring = XmlSimple.xml_out(v, 'NoIndent' => true, 'RootName' => k, 'AttrPrefix' => true)
|
101
|
+
eval "@#{k} = Adaptation::Message.new('#{xml_substring}')"
|
102
|
+
k2 = pluralize(k)
|
103
|
+
if k != k2
|
104
|
+
self.class_eval "attr_accessor :#{k2}"
|
105
|
+
eval "@#{k2} = []; @#{k2} << @#{k}"
|
106
|
+
end
|
107
|
+
else
|
108
|
+
k2 = pluralize(k)
|
109
|
+
self.class_eval "attr_accessor :#{k2}"
|
110
|
+
eval "@#{k2} = [];"
|
111
|
+
v.each do |val|
|
112
|
+
xml_substring = XmlSimple.xml_out(val, 'NoIndent' => true, 'RootName' => k, 'AttrPrefix' => true)
|
113
|
+
eval "@#{k} = Adaptation::Message.new('#{xml_substring}')"
|
114
|
+
eval "@#{k2} << @#{k}"
|
115
|
+
end
|
116
|
+
end
|
173
117
|
end
|
174
|
-
xml_attribute symbols[1]
|
175
|
-
end
|
176
|
-
when :text
|
177
|
-
@texts = [] if @texts.nil?
|
178
|
-
unless @texts.include?(symbols[1])
|
179
|
-
@texts << symbols[1]
|
180
|
-
xml_text symbols[1]
|
181
118
|
end
|
119
|
+
end
|
182
120
|
end
|
121
|
+
|
183
122
|
end
|
184
123
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
#
|
192
|
-
# <xml>
|
193
|
-
# <element attr="something">something more</element>
|
194
|
-
# </xml>
|
195
|
-
#
|
196
|
-
# class Xml < Adaptation::Message
|
197
|
-
# has_one :object, :element
|
198
|
-
# end
|
199
|
-
#
|
200
|
-
# In this case element cannot be declared just like <em>has_one :text</em>, because it also has
|
201
|
-
# an attribute. It must be declared like <em>has_one :object</em>. Then the element declares itself
|
202
|
-
# in a file called <em>_element.rb</em> like this:
|
203
|
-
#
|
204
|
-
# class Element < Adaptation::Message
|
205
|
-
# has_one :attribute, :attr
|
206
|
-
# has_text
|
207
|
-
# end
|
208
|
-
#
|
209
|
-
def self.has_text
|
210
|
-
if @has_text.nil?
|
211
|
-
@has_text = true
|
212
|
-
xml_text :text, nil, ROXML::TEXT_CONTENT
|
213
|
-
end
|
124
|
+
def self.has_one *symbols #:nodoc:
|
125
|
+
logger.info "has_one is deprecated and not necessary"
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.has_text #:nodoc:
|
129
|
+
logger.info "has_text is deprecated and not necessary"
|
214
130
|
end
|
215
131
|
|
216
|
-
|
217
|
-
|
218
|
-
# Example 1:
|
219
|
-
#
|
220
|
-
# <xml>
|
221
|
-
# <subelement>...</subelement>
|
222
|
-
# <subelement>...</subelement>
|
223
|
-
# <subelement>...</subelement>
|
224
|
-
# </xml>
|
225
|
-
#
|
226
|
-
# class Xml < Adaptation::Message
|
227
|
-
# has_many :subelements
|
228
|
-
# end
|
229
|
-
#
|
230
|
-
# Example 2:
|
231
|
-
#
|
232
|
-
# <xml>
|
233
|
-
# <subelement_list>
|
234
|
-
# <subelement>...</subelement>
|
235
|
-
# <subelement>...</subelement>
|
236
|
-
# <subelement>...</subelement>
|
237
|
-
# </subelement_list>
|
238
|
-
# </xml>
|
239
|
-
#
|
240
|
-
# class Xml < Adaptation::Message
|
241
|
-
# has_many :subelements, :in => :subelement_list
|
242
|
-
# end
|
243
|
-
#
|
244
|
-
def self.has_many *options
|
245
|
-
configuration = {}
|
246
|
-
configuration.update(options.pop) if options.last.is_a?(Hash)
|
247
|
-
|
248
|
-
class_with_container = nil
|
249
|
-
if configuration[:in]
|
250
|
-
class_with_container = options[0].to_s.capitalize[0..-2] + ":#{configuration[:in].to_s}"
|
251
|
-
else
|
252
|
-
class_with_container = options[0].to_s.capitalize[0..-2] + ":#{options[0].to_s}"
|
253
|
-
end
|
254
|
-
unless @@classes_with_brothers.include?(class_with_container)
|
255
|
-
@@classes_with_brothers << class_with_container
|
256
|
-
end
|
257
|
-
|
258
|
-
@has_many = [] if @has_many.nil?
|
259
|
-
unless @has_many.include?(options[0])
|
260
|
-
@has_many << options[0]
|
261
|
-
|
262
|
-
load "#{ADAPTOR_ROOT}/app/messages/_#{options[0].to_s[0..-2]}.rb"
|
263
|
-
klass = get_class_object(options[0].to_s.capitalize[0..-2])
|
264
|
-
|
265
|
-
if configuration[:in]
|
266
|
-
xml_object configuration[:in], klass, ROXML::TAG_ARRAY, configuration[:in].to_s
|
267
|
-
validates_associated configuration[:in]
|
268
|
-
else
|
269
|
-
xml_object options[0], klass, ROXML::TAG_ARRAY #, options[0].to_s
|
270
|
-
validates_associated options[0]
|
271
|
-
end
|
272
|
-
end
|
132
|
+
def self.has_many *options #:nodoc:
|
133
|
+
logger.info "has_many is deprecated and not necessary"
|
273
134
|
end
|
274
135
|
|
275
136
|
# Defines the xml element that this class is mapping. This is useful to avoid class
|
@@ -302,7 +163,6 @@ module Adaptation
|
|
302
163
|
#
|
303
164
|
def self.maps_xml element
|
304
165
|
@mapped_xml = element
|
305
|
-
xml_name element.to_s
|
306
166
|
end
|
307
167
|
|
308
168
|
# Returns the xml element this class is mapping
|
@@ -321,21 +181,57 @@ module Adaptation
|
|
321
181
|
klass
|
322
182
|
end
|
323
183
|
|
324
|
-
#
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
#
|
329
|
-
def self.to_object xml_message
|
330
|
-
parse xml_message
|
184
|
+
# <em>Deprecated</em>, use <em>new</em> instead.
|
185
|
+
def self.to_object xml_message #:nodoc:
|
186
|
+
logger.info "to_object is deprecated, use new instead"
|
187
|
+
self.new(xml_message)
|
331
188
|
end
|
332
189
|
|
333
|
-
# Alias for {Adaptation::Message#valid?}[http://api.rubyonrails.org/classes/ActiveRecord/Validations.html#M002099]
|
334
190
|
# <em>Deprecated</em>, use <em>valid?</em> instead.
|
335
|
-
def check
|
191
|
+
def check #:nodoc:
|
192
|
+
logger.info "check is deprecated, use valid? instead"
|
336
193
|
valid?
|
337
194
|
end
|
338
195
|
|
196
|
+
def self.logger#:nodoc:#
|
197
|
+
Adaptation::Base.logger rescue Logger.new(STDOUT)
|
198
|
+
end
|
199
|
+
|
200
|
+
def to_xml
|
201
|
+
xml_out(@hash_with_root).gsub("\"","'").gsub(/(<|<\/)content(>| *\/>)/,"")
|
202
|
+
end
|
203
|
+
|
204
|
+
def to_hash
|
205
|
+
@hash_with_root
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
|
210
|
+
def end_of_tree?(v) #:nodoc:
|
211
|
+
return true if v.has_key? "content"
|
212
|
+
return true if v.values.length == 1 and v.values.first.is_a?(Array) and v.values.first.reject{|val| val.is_a?(String) or is_attribute?(val)}.length == 0
|
213
|
+
false
|
214
|
+
end
|
215
|
+
|
216
|
+
def xml_in(xml_string)
|
217
|
+
XmlSimple.xml_in(xml_string, 'ForceArray' => false, 'AttrPrefix' => true, 'KeepRoot' => true)
|
218
|
+
end
|
219
|
+
|
220
|
+
def xml_out(xml_hash)
|
221
|
+
XmlSimple.xml_out(xml_hash, 'NoIndent' => true, 'RootName' => k, 'AttrPrefix' => true)
|
222
|
+
end
|
223
|
+
|
224
|
+
# TODO: improve this
|
225
|
+
def pluralize(v) #:nodoc:
|
226
|
+
v[(v.length - 1)..v.length] == "s" ? v : v + "s"
|
227
|
+
end
|
228
|
+
|
229
|
+
def is_attribute?(h) #:nodoc:
|
230
|
+
return false unless h.is_a?(Hash)
|
231
|
+
return true if h.length == 1 and h.values.first.is_a?(String)
|
232
|
+
false
|
233
|
+
end
|
234
|
+
|
339
235
|
end
|
340
236
|
|
341
237
|
end
|
@@ -5,58 +5,37 @@ require 'adaptation'
|
|
5
5
|
|
6
6
|
Adaptation::Initializer.run
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
Test::Unit::TestCase.fixture_path = 'test/fixtures'
|
8
|
+
begin
|
9
|
+
require 'active_record/test_case'
|
10
|
+
require 'active_record/fixtures'
|
11
|
+
rescue Exception => e
|
12
|
+
puts "Problem with database fixtures: #{e}"
|
13
|
+
raise e
|
15
14
|
end
|
16
15
|
|
17
16
|
require 'erb'
|
18
17
|
|
19
|
-
class
|
18
|
+
class ActiveSupport::TestCase
|
19
|
+
|
20
|
+
include ActiveRecord::TestFixtures
|
21
|
+
self.fixture_path = "#{ADAPTOR_ROOT}/test/fixtures/"
|
22
|
+
self.use_instantiated_fixtures = false
|
23
|
+
self.use_transactional_fixtures = false
|
20
24
|
|
21
25
|
# Asserts that a message[link:/classes/Adaptation/Message.html] in a xml
|
22
26
|
# fixture file is converted into an Adaptation::Message that if serialized
|
23
27
|
# again to xml is equivalent to the xml data in the initial fixture file.
|
24
|
-
# An Adaptation::Message object cretaed from a xml fixture, will only
|
25
|
-
# have the xml tags specified in its class definition (using has_one,
|
26
|
-
# has_many, has_text...) so this assertion can be useful to check that
|
27
|
-
# the class is defined correctly.
|
28
28
|
def assert_parsed message_symbol
|
29
29
|
data, message_object = load_message_fixture message_symbol
|
30
|
-
|
31
|
-
parsed_data =
|
30
|
+
|
31
|
+
#parsed_data = Adaptation::Message.new(data)
|
32
32
|
error = build_message error,
|
33
33
|
"? not parsed ok:\n initial: ?\n parsed: ?",
|
34
34
|
message_symbol.to_s,
|
35
|
-
|
36
|
-
message_object.to_xml
|
37
|
-
assert_block error do
|
38
|
-
compare_xml_elements parsed_data.root, message_object.to_xml
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Asserts that a message[link:/classes/Adaptation/Message.html] in a xml
|
43
|
-
# fixture file is converted into an Adaptation::Message that if serialized
|
44
|
-
# again to xml is not equivalent to the xml data in the initial fixture file.
|
45
|
-
# An Adaptation::Message object cretaed from a xml fixture, will only
|
46
|
-
# have the xml tags specified in its class definition (using has_one,
|
47
|
-
# has_many, has_text...) so this assertion can be useful to check that
|
48
|
-
# undesired xml tags are filtered.
|
49
|
-
def assert_not_parsed message_symbol
|
50
|
-
data, message_object = load_message_fixture message_symbol
|
51
|
-
|
52
|
-
parsed_data = REXML::Document.new data
|
53
|
-
error = build_message error,
|
54
|
-
"? shouldn't be parsed ok:\n data: ?\n real: ?",
|
55
|
-
message_symbol.to_s,
|
56
|
-
parsed_data.to_s,
|
57
|
-
message_object.to_xml.to_s
|
35
|
+
data,
|
36
|
+
message_object.to_xml
|
58
37
|
assert_block error do
|
59
|
-
|
38
|
+
compare_xml_elements data, message_object.to_xml
|
60
39
|
end
|
61
40
|
end
|
62
41
|
|
@@ -100,7 +79,7 @@ class Test::Unit::TestCase
|
|
100
79
|
# build Message object with xml_data
|
101
80
|
message_type = xml_message[1..(xml_message.index(/(>| )/) - 1)]
|
102
81
|
message_class = Adaptation::Message.get_class_object(message_type.capitalize)
|
103
|
-
message_object = message_class.
|
82
|
+
message_object = message_class.nil? ? Adaptation::Message.new(xml_message) : message_class.new(xml_message)
|
104
83
|
end
|
105
84
|
|
106
85
|
# check for all messages "published" in the mom (that's file /tmp/mom.txt),
|
@@ -108,10 +87,9 @@ class Test::Unit::TestCase
|
|
108
87
|
message_found = false
|
109
88
|
expected = published = ""
|
110
89
|
File.open(ADAPTOR_ROOT + '/test/mocks/test/mom.txt', 'r').each{ |line|
|
111
|
-
mom_message = REXML::Document.new line
|
112
90
|
published = line.chop
|
113
91
|
expected = message_object.to_xml.to_s
|
114
|
-
if compare_xml_elements
|
92
|
+
if compare_xml_elements published, message_object.to_xml
|
115
93
|
message_found = true
|
116
94
|
break
|
117
95
|
end
|
@@ -219,9 +197,10 @@ class Test::Unit::TestCase
|
|
219
197
|
end
|
220
198
|
|
221
199
|
# Builds a message[link:/classes/Adaptation/Message.html] from a xml fixture
|
222
|
-
# file and processes it the same way
|
223
|
-
# adaptation, but using a test environment.
|
224
|
-
#
|
200
|
+
# file and processes it the same way messages from the mom are processed by
|
201
|
+
# adaptation, but using a test environment. Messages published with
|
202
|
+
# {publish}[link:/classes/Adaptation/Adaptor.html#M000170] will be published
|
203
|
+
# to a mocked MOM (and can be checked with _assert_message_published_)
|
225
204
|
def message message_symbol
|
226
205
|
# build a message object from fixture
|
227
206
|
message_xml, message_object = load_message_fixture message_symbol
|
@@ -241,8 +220,8 @@ class Test::Unit::TestCase
|
|
241
220
|
|
242
221
|
end
|
243
222
|
|
244
|
-
#
|
245
|
-
#
|
223
|
+
# Returns an Adaptation::Message object from a fixture, without processing it
|
224
|
+
# (or an instance of the corresponding subclass, if it's defined).
|
246
225
|
def get_message_from_fixture message_symbol
|
247
226
|
load_message_fixture(message_symbol)[1]
|
248
227
|
end
|
@@ -264,11 +243,13 @@ class Test::Unit::TestCase
|
|
264
243
|
data = get_message_fixture(fixture_symbol.to_s)
|
265
244
|
class_name = data[1..(data.index(/(>| )/) - 1)].capitalize
|
266
245
|
message_class = Adaptation::Message.get_class_object(class_name)
|
267
|
-
message_object = message_class.nil? ? data : message_class.
|
246
|
+
message_object = message_class.nil? ? Adaptation::Message.new(data) : message_class.new(data)
|
268
247
|
[data, message_object]
|
269
248
|
end
|
270
249
|
|
271
250
|
def compare_xml_elements element1, element2 #:nodoc:
|
251
|
+
element1 = REXML::Document.new(element1) if element1.is_a?(String)
|
252
|
+
element2 = REXML::Document.new(element2) if element2.is_a?(String)
|
272
253
|
if element1.has_attributes?
|
273
254
|
if !element2.has_attributes?
|
274
255
|
return false
|
@@ -21,7 +21,7 @@ module Validateable
|
|
21
21
|
module ClassMethods
|
22
22
|
# Define class methods here.
|
23
23
|
|
24
|
-
def self_and_descendents_from_active_record#nodoc:
|
24
|
+
def self_and_descendents_from_active_record # :nodoc:
|
25
25
|
klass = self
|
26
26
|
classes = [klass]
|
27
27
|
while klass != klass.base_class
|
@@ -45,10 +45,97 @@ module Validateable
|
|
45
45
|
|
46
46
|
end
|
47
47
|
|
48
|
+
#= Adaptation::Message Validations
|
49
|
+
# {ActiveRecord validations}[http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html] should work
|
50
|
+
# the same way, except those that have been overwritten here.
|
51
|
+
#
|
48
52
|
module ActiveRecord
|
49
53
|
module Validations
|
50
54
|
module ClassMethods
|
51
55
|
|
56
|
+
# Validates whether the specified xml attribute/element is present (not nil or blank).
|
57
|
+
#
|
58
|
+
# Example 1:
|
59
|
+
#
|
60
|
+
# class Leftwing < Adaptation::Message
|
61
|
+
# validates_presence_of :side
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# lw = Leftwing.new("<leftwing side=\"left\"/>")
|
65
|
+
# lw.valid? # -> true
|
66
|
+
# lw = Leftwing.new("<leftwing noside=\"left\"/>")
|
67
|
+
# lw.valid? # -> false
|
68
|
+
#
|
69
|
+
# Example 2:
|
70
|
+
#
|
71
|
+
# class Bird < Adaptation::Message
|
72
|
+
# validates_presence_of :side, :in => "birds.wings"
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# b = Bired.new('<birds><bird><wings><wing side="left"/><wing side="right"/></wings></bird></birds>')
|
76
|
+
# b.valid? # -> true
|
77
|
+
# b = Bired.new('<birds><bird><wings><wing side="left"/><wing noside="right"/></wings></bird></birds>')
|
78
|
+
# b.valid? # -> false
|
79
|
+
#
|
80
|
+
def validates_presence_of(*attr_names)
|
81
|
+
configuration = {
|
82
|
+
:message => 'cannot be blank'
|
83
|
+
}
|
84
|
+
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
85
|
+
|
86
|
+
if configuration[:in].nil?
|
87
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
88
|
+
string = record.send(attr_names[0].to_sym)
|
89
|
+
unless string.nil?
|
90
|
+
string = string.content if string.is_a?(Adaptation::Message)
|
91
|
+
end
|
92
|
+
if string.blank?
|
93
|
+
record.errors.add(attr_name, configuration[:message])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
else
|
97
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
98
|
+
missing = false
|
99
|
+
configuration_in = configuration[:in].to_s
|
100
|
+
elements = configuration_in.to_s.split('.')
|
101
|
+
subelement = record
|
102
|
+
while elements.length > 1
|
103
|
+
subelement = record.send(elements[0].to_sym)
|
104
|
+
elements.slice!(0)
|
105
|
+
end
|
106
|
+
|
107
|
+
if !subelement.is_a?(Array)
|
108
|
+
subelement.send(elements[0].to_sym).each do |s|
|
109
|
+
string = s.send(attr_names[0].to_sym)
|
110
|
+
unless string.nil?
|
111
|
+
string = string.content unless string.is_a?(String)
|
112
|
+
end
|
113
|
+
if string.blank?
|
114
|
+
missing = true
|
115
|
+
break
|
116
|
+
end
|
117
|
+
end
|
118
|
+
else
|
119
|
+
subelement.each do |sub|
|
120
|
+
sub.send(elements[0].to_sym).each do |s|
|
121
|
+
string = s.send(attr_names[0].to_sym)
|
122
|
+
unless string.nil?
|
123
|
+
string = string.content unless string.is_a?(String)
|
124
|
+
end
|
125
|
+
if string.blank?
|
126
|
+
missing = true
|
127
|
+
break
|
128
|
+
end
|
129
|
+
end
|
130
|
+
break if missing
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
record.errors.add(attr_name, configuration[:message]) if missing
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
52
139
|
# Validates whether the value of the specified xml attribute/element is the expected one.
|
53
140
|
#
|
54
141
|
# Example 1:
|
@@ -56,8 +143,6 @@ module ActiveRecord
|
|
56
143
|
# <leftwing side="left"/>
|
57
144
|
#
|
58
145
|
# class Leftwing < Adaptation::Message
|
59
|
-
# has_one :attribute, :side
|
60
|
-
#
|
61
146
|
# validates_value_of :side, "left"
|
62
147
|
# end
|
63
148
|
#
|
@@ -65,8 +150,6 @@ module ActiveRecord
|
|
65
150
|
# <bird><wings><wing side="left"/><wing side="right"/></wings></bird>
|
66
151
|
#
|
67
152
|
# class Bird < Adaptation::Message
|
68
|
-
# has_many :wings
|
69
|
-
#
|
70
153
|
# validates_value_of :side, "left", :in => :wings
|
71
154
|
# end
|
72
155
|
#
|
@@ -78,15 +161,30 @@ module ActiveRecord
|
|
78
161
|
|
79
162
|
if configuration[:in].nil?
|
80
163
|
validates_each(attr_names, configuration) do |record, attr_name, value|
|
81
|
-
|
164
|
+
string = record.send(attr_names[0].to_sym)
|
165
|
+
unless string.nil?
|
166
|
+
string = string.content unless string.is_a?(String)
|
167
|
+
end
|
168
|
+
if (attr_names[1].to_s != string)
|
82
169
|
record.errors.add(attr_name, configuration[:message])
|
83
170
|
end
|
84
171
|
end
|
85
172
|
else
|
86
173
|
validates_each(attr_names, configuration) do |record, attr_name, value|
|
87
174
|
found = false
|
88
|
-
|
89
|
-
|
175
|
+
configuration_in = configuration[:in].to_s
|
176
|
+
elements = configuration_in.to_s.split('.')
|
177
|
+
subelement = record
|
178
|
+
while elements.length > 1
|
179
|
+
subelement = record.send(elements[0].to_sym)
|
180
|
+
elements.slice!(0)
|
181
|
+
end
|
182
|
+
subelement.send(elements[0].to_sym).each do |s|
|
183
|
+
string = s.send(attr_names[0].to_sym)
|
184
|
+
unless string.nil?
|
185
|
+
string = string.content unless string.is_a?(String)
|
186
|
+
end
|
187
|
+
if (attr_names[1].to_s == string)
|
90
188
|
found = true
|
91
189
|
break
|
92
190
|
end
|
@@ -99,13 +197,15 @@ module ActiveRecord
|
|
99
197
|
# Validates whether the value of the specified xml attribute/element has a valid email format.
|
100
198
|
#
|
101
199
|
# Example:
|
102
|
-
# <contact email="mail@xample.com">...</contact>
|
103
200
|
#
|
104
201
|
# class Contact < Adaptation::Message
|
105
|
-
# has_one :attribute, :email
|
106
|
-
#
|
107
202
|
# validates_as_email :email
|
108
|
-
# end
|
203
|
+
# end
|
204
|
+
#
|
205
|
+
# c = Contact.new('<contact email="mail@xample.com">...</contact>')
|
206
|
+
# c.valid? # -> true
|
207
|
+
# c.email = "nomail"
|
208
|
+
# c.valid? # -> false
|
109
209
|
#
|
110
210
|
def validates_as_email(*attr_names)
|
111
211
|
configuration = {
|
data/lib/adaptation/version.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
|
2
2
|
|
3
|
-
class <%= class_name %>AdaptorTest <
|
4
|
-
|
5
|
-
#fixtures :your_table_name_here
|
3
|
+
class <%= class_name %>AdaptorTest < ActiveSupport::TestCase
|
6
4
|
|
7
5
|
def setup
|
8
6
|
end
|
9
7
|
|
10
8
|
# Replace this with your real tests.
|
11
|
-
|
9
|
+
test "should be true" do
|
12
10
|
assert true
|
13
11
|
end
|
12
|
+
|
14
13
|
end
|
@@ -1,24 +1,16 @@
|
|
1
1
|
require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
|
2
2
|
|
3
|
-
class <%= class_name %>Test <
|
3
|
+
class <%= class_name %>Test < ActiveSupport::TestCase
|
4
4
|
|
5
5
|
# Replace this with your real tests.
|
6
|
-
|
6
|
+
test "should be true" do
|
7
7
|
assert true
|
8
8
|
end
|
9
9
|
|
10
|
-
# assert the message is defined correctly comparing the initial xml
|
11
|
-
# from the fixture with the xml obtained from the Adaptation::Message
|
12
|
-
# object created with that fixture
|
13
|
-
#def test_not_parsed
|
14
|
-
# assert_parsed :<%= file_name %>
|
15
|
-
#end
|
16
|
-
|
17
10
|
# assert message passes our validations
|
18
11
|
#def test_validates
|
19
12
|
# assert_validates :<%= file_name %>
|
20
13
|
# assert_not_validates :<%= file_name %>_incorrect
|
21
14
|
#end
|
22
15
|
|
23
|
-
|
24
16
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adaptation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xavi Vila Morell
|
@@ -9,18 +9,18 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-07-24 00:00:00 +02:00
|
13
13
|
default_executable: adaptation
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: xml-simple
|
17
17
|
type: :runtime
|
18
18
|
version_requirement:
|
19
19
|
version_requirements: !ruby/object:Gem::Requirement
|
20
20
|
requirements:
|
21
|
-
- - "
|
21
|
+
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version:
|
23
|
+
version: 1.0.12
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activerecord
|
@@ -28,9 +28,9 @@ dependencies:
|
|
28
28
|
version_requirement:
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 2.3.3
|
34
34
|
version:
|
35
35
|
description: Adaptation is a framework for building "adaptors" for web-applications, so they can interact with other web-applications publishing messages and being subscribed to a message queue.
|
36
36
|
email: xavi@oaproject.net
|