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 CHANGED
@@ -6,3 +6,5 @@
6
6
  - migrated to ActiveRrecord validations
7
7
  * 0.0.6
8
8
  - forced to use ROXML version 1.2
9
+ * 0.0.7
10
+ - Documentation update + Message class clean up
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__ and __Models__.
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
@@ -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 _<hello>_, adaptation will search for a class extending Adaptation::Adaptor named _HelloAdaptor_.
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
@@ -15,76 +15,83 @@ module Adaptation
15
15
  #
16
16
  #* Automated mapping between classes and xml attributes and elements.
17
17
  #
18
- # class Contact < Adaptation::Message
19
- # has_one :text, :name
20
- # end
18
+ # class Contact < Adaptation::Message
19
+ # has_one :text, :name
20
+ # end
21
21
  #
22
- # ...is automatically mapped to a xml structure with root element named "contact", such as:
22
+ # ...is automatically mapped to a xml structure with root element named "contact", such as:
23
23
  #
24
- # <contact>
25
- # <name>Name</name>
26
- # </contact>
24
+ # <contact>
25
+ # <name>Name</name>
26
+ # </contact>
27
27
  #
28
- # ...which gives Contact#name
28
+ # ...which gives Contact#name
29
29
  #
30
30
  #
31
31
  #* Associations between objects controlled by simple meta-programming macros.
32
32
  #
33
- # class Agenda < Adaptation::Message
34
- # has_one :attribute, :type
35
- # has_one :text, :owner
36
- # has_many :contacts
37
- # end
33
+ # class Agenda < Adaptation::Message
34
+ # has_one :attribute, :type
35
+ # has_one :text, :owner
36
+ # has_many :contacts
37
+ # end
38
38
  #
39
- # class Contact < Adaptation::Message
40
- # has_one :text, :name
41
- # end
39
+ # class Contact < Adaptation::Message
40
+ # has_one :text, :name
41
+ # end
42
42
  #
43
- # Agenda class would be mapping the following xml structure:
43
+ # Agenda class would be mapping the following xml structure:
44
44
  #
45
- # <agenda type="...">
46
- # <owner>...</owner>
47
- # <contact>...</contact>
48
- # <contact>...</contact>
49
- # ...
50
- # </agenda>
45
+ # <agenda type="...">
46
+ # <owner>...</owner>
47
+ # <contact>...</contact>
48
+ # <contact>...</contact>
49
+ # ...
50
+ # </agenda>
51
51
  #
52
- # while the _Contact_ class would map:
52
+ # while the _Contact_ class would map:
53
53
  #
54
- # <contact>
55
- # <name>...</name>
56
- # </contact>
54
+ # <contact>
55
+ # <name>...</name>
56
+ # </contact>
57
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
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
- # We could have wrote Agenda like this, to change the contacts container name:
61
+ # We could have wrote Agenda like this, to change the contacts container name:
62
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
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
- # and Contact like:
69
+ # and Contact like:
70
70
  #
71
- # class Contact < Adaptation::Message
72
- # belongs_to :contact_list
73
- # has_one :text, :name
74
- # end
71
+ # class Contact < Adaptation::Message
72
+ # has_one :text, :name
73
+ # end
75
74
  #
76
- # Then the mapping in Agenda would be:
75
+ # Then the mapping in Agenda would be:
77
76
  #
78
- # <agenda type="...">
79
- # <owner>...</owner>
80
- # <contact_list>
81
- # <contact>...</contact>
82
- # </contact_list>
83
- # </agenda>
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
- def self.has_brothers?
244
- brothers_containers = []
245
- @@classes_with_brothers.each do |cwb|
246
- if cwb =~ /^#{self.to_s}:/
247
- brothers_containers << cwb
248
- end
249
- end
250
- if brothers_containers.empty?
251
- return nil
252
- else
253
- return brothers_containers
254
- end
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.6
7
- date: 2008-07-24 00:00:00 +02:00
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: false
18
+ has_rdoc: true
19
19
  required_ruby_version: !ruby/object:Gem::Version::Requirement
20
20
  requirements:
21
21
  - - ">"