glue 0.20.0 → 0.21.0

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.
Files changed (58) hide show
  1. data/CHANGELOG +161 -110
  2. data/INSTALL +12 -12
  3. data/README +1 -1
  4. data/Rakefile +43 -45
  5. data/doc/AUTHORS +5 -5
  6. data/doc/LICENSE +3 -3
  7. data/doc/RELEASES +32 -24
  8. data/install.rb +7 -17
  9. data/lib/facet/object/alias_class.rb +12 -0
  10. data/lib/glue.rb +35 -35
  11. data/lib/glue/array.rb +46 -46
  12. data/lib/glue/aspects.rb +199 -209
  13. data/lib/glue/attribute.rb +15 -15
  14. data/lib/glue/autoreload.rb +1 -1
  15. data/lib/glue/builder.rb +48 -0
  16. data/lib/glue/builder/xml.rb +114 -0
  17. data/lib/glue/cache.rb +189 -0
  18. data/lib/glue/configuration.rb +108 -90
  19. data/lib/glue/flexob.rb +17 -17
  20. data/lib/glue/hash.rb +71 -71
  21. data/lib/glue/helper.rb +12 -12
  22. data/lib/glue/idgen.rb +9 -0
  23. data/lib/glue/idgen/md5.rb +24 -0
  24. data/lib/glue/idgen/sequential.rb +15 -0
  25. data/lib/glue/literal_method.rb +44 -0
  26. data/lib/glue/localization.rb +130 -0
  27. data/lib/glue/logger.rb +98 -98
  28. data/lib/glue/misc.rb +7 -7
  29. data/lib/glue/mixins.rb +19 -19
  30. data/lib/glue/number.rb +8 -8
  31. data/lib/glue/object.rb +2 -2
  32. data/lib/glue/pool.rb +43 -43
  33. data/lib/glue/property.rb +392 -392
  34. data/lib/glue/sanitize.rb +34 -34
  35. data/lib/glue/settings.rb +1 -1
  36. data/lib/glue/snapshot.rb +104 -0
  37. data/lib/glue/string.rb +129 -129
  38. data/lib/glue/time.rb +53 -53
  39. data/lib/glue/uri.rb +162 -162
  40. data/lib/glue/validation.rb +421 -421
  41. data/lib/vendor/blankslate.rb +53 -0
  42. data/test/glue/builder/tc_xml.rb +56 -0
  43. data/test/glue/tc_aspects.rb +90 -90
  44. data/test/glue/tc_attribute.rb +11 -11
  45. data/test/glue/tc_builder.rb +30 -0
  46. data/test/glue/tc_configuration.rb +97 -97
  47. data/test/glue/tc_flexob.rb +10 -10
  48. data/test/glue/tc_hash.rb +23 -23
  49. data/test/glue/tc_localization.rb +49 -0
  50. data/test/glue/tc_logger.rb +31 -31
  51. data/test/glue/tc_numbers.rb +9 -9
  52. data/test/glue/tc_property.rb +67 -67
  53. data/test/glue/tc_property_mixins.rb +17 -17
  54. data/test/glue/tc_property_type_checking.rb +13 -13
  55. data/test/glue/tc_strings.rb +94 -94
  56. data/test/glue/tc_uri.rb +65 -65
  57. data/test/glue/tc_validation.rb +196 -196
  58. metadata +26 -4
data/lib/glue/property.rb CHANGED
@@ -21,48 +21,48 @@ module Glue
21
21
 
22
22
  class Property
23
23
 
24
- # If set to true, perform type checking on property set.
25
- # Useful when debugging.
26
-
27
- cattr_accessor :type_checking, false
28
-
29
- # The symbol of the property.
30
-
31
- attr_accessor :symbol
32
-
33
- # The class of the property.
34
-
35
- attr_accessor :klass
36
-
37
- # Additional metadata (like sql declaration, sql index, etc)
38
- # Here is a list of predefined metadata:
39
- #
40
- # [+:reader+]
41
- # create reader?
42
- #
43
- # [+:writer+]
44
- # create writer?
45
- #
46
- # [+:sql_index+]
47
- # create an sql index for the column this poperty maps to?
48
- #
49
- # You can use this mechanism to add your own, custom,
50
- # metadata.
51
-
52
- attr_accessor :meta
53
-
54
- def initialize(symbol, klass, meta = {})
55
- @symbol, @klass = symbol, klass
56
- @meta = meta
57
- end
58
-
59
- def ==(other)
60
- return @symbol == other.symbol
61
- end
62
-
63
- def to_s
64
- return @symbol.to_s
65
- end
24
+ # If set to true, perform type checking on property set.
25
+ # Useful when debugging.
26
+
27
+ cattr_accessor :type_checking, false
28
+
29
+ # The symbol of the property.
30
+
31
+ attr_accessor :symbol
32
+
33
+ # The class of the property.
34
+
35
+ attr_accessor :klass
36
+
37
+ # Additional metadata (like sql declaration, sql index, etc)
38
+ # Here is a list of predefined metadata:
39
+ #
40
+ # [+:reader+]
41
+ # create reader?
42
+ #
43
+ # [+:writer+]
44
+ # create writer?
45
+ #
46
+ # [+:sql_index+]
47
+ # create an sql index for the column this poperty maps to?
48
+ #
49
+ # You can use this mechanism to add your own, custom,
50
+ # metadata.
51
+
52
+ attr_accessor :meta
53
+
54
+ def initialize(symbol, klass, meta = {})
55
+ @symbol, @klass = symbol, klass
56
+ @meta = meta
57
+ end
58
+
59
+ def ==(other)
60
+ return @symbol == other.symbol
61
+ end
62
+
63
+ def to_s
64
+ return @symbol.to_s
65
+ end
66
66
 
67
67
  end
68
68
 
@@ -70,241 +70,241 @@ end
70
70
 
71
71
  module PropertyUtils
72
72
 
73
- # Add accessors to the properties to the given target
74
- # (Module or Class). For simplicity also create the
75
- # meta accessors.
76
- #
77
- # [+target+]
78
- # The target class or module
79
- #--
80
- # gmosx: Perhaps we 'll optimize this in the future.
81
- #++
82
-
83
- def self.enchant(target, force = false)
84
- unless target.instance_variables.include?('@__props')
85
- # FIXME: should be thread safe here!
86
- target.instance_variable_set('@__meta', Flexob.new)
87
- target.instance_variable_set('@__props', SafeArray.new)
88
-
89
- # gmosx: Ruby surprises and amazes me! We are in the Metaclass
90
- # when defining methods and attributes so @__props is really
91
- # a class scoped variable that unlike @@__props is not shared
92
- # through the hierarchy.
93
-
94
- target.module_eval %{
95
- def self.__props
96
- @__props
97
- end
98
-
99
- def self.properties
100
- @__props
101
- end
102
-
103
- def self.__props=(props)
104
- @__props = props
105
- end
106
-
107
- def self.__meta
108
- @__meta
109
- end
110
-
111
- def self.__meta=(meta)
112
- @__meta = meta
113
- end
114
-
115
- def self.metadata
116
- @__meta
117
- end
118
- }
119
-
120
- if target.is_a?(Class)
121
-
122
- # Add some extra code to append features to
123
- # subclasses.
124
-
125
- target.module_eval %{
126
- def self.inherited(child)
127
- Glue::PropertyUtils.enchant(child)
128
- Glue::PropertyUtils.copy_props(self, child)
129
- # gmosx: We have to define @@__props first to avoid
130
- # reusing the hash from the module. super must stay
131
- # at the end.
132
- super
133
- end
134
- }
135
-
136
- else
137
-
138
- # Add some extra code for modules to append
139
- # their features to classes that include it.
140
-
141
- target.module_eval %{
142
- def self.append_features(base)
143
- # gmosx: We have to define @@__props first to avoid
144
- # reusing the hash from the module. super must stay
145
- # at the end.
146
- Glue::PropertyUtils.copy_features(self, base)
147
- super
148
- end
149
- }
150
-
151
- end
152
- end
153
- end
154
-
155
- # Copy properties from src (Module or Class) to dest.
156
-
157
- def self.copy_props(src, dest)
158
- src.__props.each do |p|
159
- add_prop(dest, p)
160
- end
161
-
162
- # copy the metadata.
163
- src.__meta.each do |k, val|
164
- if val.is_a?(TrueClass)
165
- dest.__meta[k] = val
166
- else
167
- dest.__meta[k] = val.dup
168
- end
169
- # val.each { |v| dest.meta(k, v) } if val
170
- end
171
- end
172
-
173
- # Add the property to the target (Class or Module)
174
-
175
- def self.add_prop(target, prop)
176
- if idx = target.__props.index(prop)
177
- # override in case of duplicates. Keep the order of the props.
178
- target.__props[idx] = prop
179
- else
180
- target.__props << prop
181
- end
182
-
183
- # Store the property in the :props_and_relations
184
- # metadata array.
185
-
186
- target.meta :props_and_relations, prop
187
-
188
- # Precompile the property read/write methods
189
-
190
- s, klass = prop.symbol, prop.klass
191
-
192
- if prop.meta[:reader]
193
- target.module_eval %{
194
- def #{s}
195
- return @#{s}
196
- end
197
- }
198
- end
199
-
200
- # gmosx: __force_xxx reuses xxx= to allow for easier
201
- # overrides.
202
-
203
- if prop.meta[:writer]
204
- target.module_eval %{
205
- #{prop_setter(prop)}
206
-
207
- def __force_#{s}(val)
208
- self.#{s}=(} + case klass.name
209
- when Fixnum.name
210
- "val.to_i()"
211
- when String.name
212
- "val.to_s()"
213
- when Float.name
214
- "val.to_f()"
215
- when Time.name
216
- "Time.parse(val.to_s())"
217
- when TrueClass.name, FalseClass.name
218
- "val.to_i() > 0"
219
- else
220
- "val"
221
- end + %{)
222
- end
223
- }
224
- end
225
- end
226
-
227
- # Generates the property setter code. Can be overriden
228
- # to support extra functionality (example: markup)
229
-
230
- def self.prop_setter(prop)
231
- s = prop.symbol
232
-
233
- code = %{
234
- def #{s}=(val)
235
- }
236
-
237
- if Glue::Property.type_checking
238
- code << %{
239
- unless #{prop.klass} == val.class
240
- raise "Invalid type, expected '#{prop.klass}', is '\#\{val.class\}'."
241
- end
242
- }
243
- end
244
-
245
- code << %{
246
- @#{s} = val
247
- end
248
- }
249
-
250
- return code
251
- end
252
-
253
- # Get the property metadata for the given symbol.
254
-
255
- def self.get_prop(klass, sym)
256
- return klass.__props.find { |p| p.symbol == sym }
257
- end
258
-
259
- # Include meta-language mixins
260
-
261
- def self.include_meta_mixins(target)
262
- target.module_eval %{ include Glue::Validation } if defined?(Glue::Validation)
263
- # gmosx: TODO, make Og::MetaLanguage equivalent to Validation.
264
- # target.module_eval %{ extend Og::MetaLanguage } if defined?(Og::MetaLanguage)
265
- target.module_eval %{ include Glue::Aspects } if defined?(Glue::Aspects)
266
- target.send(:include, Og::EntityMixin) if defined?(Og::EntityMixin)
267
- end
268
-
269
- def self.copy_features(this, other)
270
- Glue::PropertyUtils.enchant(other)
271
- Glue::PropertyUtils.copy_props(this, other)
272
- Glue::PropertyUtils.include_meta_mixins(other)
273
- end
274
-
275
- # Resolves the parameters passed to the propxxx macros
276
- # to generate the meta, klass and symbols variables. This
277
- # way the common functionality is factored out.
278
- #
279
- # [+params+]
280
- # The params to resolve.
281
- # [+one_symbol+]
282
- # If true, only resolves one symbol (used in prop).
283
-
284
- def self.resolve_prop_params(*params)
285
- meta = {}
286
- klass = Object
287
- symbols = []
288
-
289
- for param in params.flatten
290
- if param.is_a?(Class)
291
- klass = param
292
- elsif param.is_a?(Symbol)
293
- symbols << param
294
- elsif param.is_a?(TrueClass) or param.is_a?(TrueClass)
295
- writer = param
296
- elsif param.is_a?(Hash)
297
- # the meta hash.
298
- meta.update(param) { |k, a, b| [a,b].join(' ') }
299
- else
300
- raise 'Error when defining property!'
301
- end
302
- end
303
-
304
- raise 'No symbols provided!' if symbols.empty?
305
-
306
- return meta, klass, symbols
307
- end
73
+ # Add accessors to the properties to the given target
74
+ # (Module or Class). For simplicity also create the
75
+ # meta accessors.
76
+ #
77
+ # [+target+]
78
+ # The target class or module
79
+ #--
80
+ # gmosx: Perhaps we 'll optimize this in the future.
81
+ #++
82
+
83
+ def self.enchant(target, force = false)
84
+ unless target.instance_variables.include?('@__props')
85
+ # FIXME: should be thread safe here!
86
+ target.instance_variable_set('@__meta', Flexob.new)
87
+ target.instance_variable_set('@__props', SafeArray.new)
88
+
89
+ # gmosx: Ruby surprises and amazes me! We are in the Metaclass
90
+ # when defining methods and attributes so @__props is really
91
+ # a class scoped variable that unlike @@__props is not shared
92
+ # through the hierarchy.
93
+
94
+ target.module_eval %{
95
+ def self.__props
96
+ @__props
97
+ end
98
+
99
+ def self.properties
100
+ @__props
101
+ end
102
+
103
+ def self.__props=(props)
104
+ @__props = props
105
+ end
106
+
107
+ def self.__meta
108
+ @__meta
109
+ end
110
+
111
+ def self.__meta=(meta)
112
+ @__meta = meta
113
+ end
114
+
115
+ def self.metadata
116
+ @__meta
117
+ end
118
+ }
119
+
120
+ if target.is_a?(Class)
121
+
122
+ # Add some extra code to append features to
123
+ # subclasses.
124
+
125
+ target.module_eval %{
126
+ def self.inherited(child)
127
+ Glue::PropertyUtils.enchant(child)
128
+ Glue::PropertyUtils.copy_props(self, child)
129
+ # gmosx: We have to define @@__props first to avoid
130
+ # reusing the hash from the module. super must stay
131
+ # at the end.
132
+ super
133
+ end
134
+ }
135
+
136
+ else
137
+
138
+ # Add some extra code for modules to append
139
+ # their features to classes that include it.
140
+
141
+ target.module_eval %{
142
+ def self.append_features(base)
143
+ # gmosx: We have to define @@__props first to avoid
144
+ # reusing the hash from the module. super must stay
145
+ # at the end.
146
+ Glue::PropertyUtils.copy_features(self, base)
147
+ super
148
+ end
149
+ }
150
+
151
+ end
152
+ end
153
+ end
154
+
155
+ # Copy properties from src (Module or Class) to dest.
156
+
157
+ def self.copy_props(src, dest)
158
+ src.__props.each do |p|
159
+ add_prop(dest, p)
160
+ end
161
+
162
+ # copy the metadata.
163
+ src.__meta.each do |k, val|
164
+ if val.is_a?(TrueClass)
165
+ dest.__meta[k] = val
166
+ else
167
+ dest.__meta[k] = val.dup
168
+ end
169
+ # val.each { |v| dest.meta(k, v) } if val
170
+ end
171
+ end
172
+
173
+ # Add the property to the target (Class or Module)
174
+
175
+ def self.add_prop(target, prop)
176
+ if idx = target.__props.index(prop)
177
+ # override in case of duplicates. Keep the order of the props.
178
+ target.__props[idx] = prop
179
+ else
180
+ target.__props << prop
181
+ end
182
+
183
+ # Store the property in the :props_and_relations
184
+ # metadata array.
185
+
186
+ target.meta :props_and_relations, prop
187
+
188
+ # Precompile the property read/write methods
189
+
190
+ s, klass = prop.symbol, prop.klass
191
+
192
+ if prop.meta[:reader]
193
+ target.module_eval %{
194
+ def #{s}
195
+ return @#{s}
196
+ end
197
+ }
198
+ end
199
+
200
+ # gmosx: __force_xxx reuses xxx= to allow for easier
201
+ # overrides.
202
+
203
+ if prop.meta[:writer]
204
+ target.module_eval %{
205
+ #{prop_setter(prop)}
206
+
207
+ def __force_#{s}(val)
208
+ self.#{s}=(} + case klass.name
209
+ when Fixnum.name
210
+ "val.to_i()"
211
+ when String.name
212
+ "val.to_s()"
213
+ when Float.name
214
+ "val.to_f()"
215
+ when Time.name
216
+ "Time.parse(val.to_s())"
217
+ when TrueClass.name, FalseClass.name
218
+ "val.to_i() > 0"
219
+ else
220
+ "val"
221
+ end + %{)
222
+ end
223
+ }
224
+ end
225
+ end
226
+
227
+ # Generates the property setter code. Can be overriden
228
+ # to support extra functionality (example: markup)
229
+
230
+ def self.prop_setter(prop)
231
+ s = prop.symbol
232
+
233
+ code = %{
234
+ def #{s}=(val)
235
+ }
236
+
237
+ if Glue::Property.type_checking
238
+ code << %{
239
+ unless #{prop.klass} == val.class
240
+ raise "Invalid type, expected '#{prop.klass}', is '\#\{val.class\}'."
241
+ end
242
+ }
243
+ end
244
+
245
+ code << %{
246
+ @#{s} = val
247
+ end
248
+ }
249
+
250
+ return code
251
+ end
252
+
253
+ # Get the property metadata for the given symbol.
254
+
255
+ def self.get_prop(klass, sym)
256
+ return klass.__props.find { |p| p.symbol == sym }
257
+ end
258
+
259
+ # Include meta-language mixins
260
+
261
+ def self.include_meta_mixins(target)
262
+ target.module_eval %{ include Glue::Validation } if defined?(Glue::Validation)
263
+ # gmosx: TODO, make Og::MetaLanguage equivalent to Validation.
264
+ # target.module_eval %{ extend Og::MetaLanguage } if defined?(Og::MetaLanguage)
265
+ target.module_eval %{ include Glue::Aspects } if defined?(Glue::Aspects)
266
+ target.send(:include, Og::EntityMixin) if defined?(Og::EntityMixin)
267
+ end
268
+
269
+ def self.copy_features(this, other)
270
+ Glue::PropertyUtils.enchant(other)
271
+ Glue::PropertyUtils.copy_props(this, other)
272
+ Glue::PropertyUtils.include_meta_mixins(other)
273
+ end
274
+
275
+ # Resolves the parameters passed to the propxxx macros
276
+ # to generate the meta, klass and symbols variables. This
277
+ # way the common functionality is factored out.
278
+ #
279
+ # [+params+]
280
+ # The params to resolve.
281
+ # [+one_symbol+]
282
+ # If true, only resolves one symbol (used in prop).
283
+
284
+ def self.resolve_prop_params(*params)
285
+ meta = {}
286
+ klass = Object
287
+ symbols = []
288
+
289
+ for param in params.flatten
290
+ if param.is_a?(Class)
291
+ klass = param
292
+ elsif param.is_a?(Symbol)
293
+ symbols << param
294
+ elsif param.is_a?(TrueClass) or param.is_a?(TrueClass)
295
+ writer = param
296
+ elsif param.is_a?(Hash)
297
+ # the meta hash.
298
+ meta.update(param) { |k, a, b| [a,b].join(' ') }
299
+ else
300
+ raise 'Error when defining property!'
301
+ end
302
+ end
303
+
304
+ raise 'No symbols provided!' if symbols.empty?
305
+
306
+ return meta, klass, symbols
307
+ end
308
308
 
309
309
  end
310
310
 
@@ -312,121 +312,121 @@ end
312
312
 
313
313
  class Module
314
314
 
315
- # Define a property (== typed attribute)
316
- # This works like Ruby's standard attr method, ie creates
317
- # only one property.
318
- #
319
- # Use the prop_reader, prop_writer, prop_accessor methods
320
- # for multiple properties.
321
- #
322
- # === Examples
323
- #
324
- # prop String, :name, :sql => "char(32), :sql_index => "name(32)"
325
- # --> creates only writer.
326
- # prop Fixnum, :oid, writer = true, :sql => "integer PRIMARY KEY"
327
- # --> creates reader and writer.
328
-
329
- def prop(*params)
330
- meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
331
- symbol = symbols.first
332
-
333
- Glue::PropertyUtils.enchant(self)
334
-
335
- property = Glue::Property.new(symbol, klass, meta)
336
-
337
- reader = meta[:reader] || true
338
- writer = writer || meta[:writer] || false
339
-
340
- meta[:reader] = true if meta[:reader].nil?
341
- if defined?(writer)
342
- meta[:writer] = writer
343
- else
344
- meta[:writer] = true if meta[:writer].nil?
345
- end
346
-
347
- Glue::PropertyUtils.add_prop(self, property)
348
-
349
- # gmosx: should be placed AFTER enchant!
350
-
351
- Glue::PropertyUtils.include_meta_mixins(self)
352
- end
353
-
354
- # Helper method. Accepts a collection of symbols and generates
355
- # properties. Only generates reader.
356
- #
357
- # Example:
358
- # prop_reader String, :name, :title, :body, :sql => "char(32)"
359
-
360
- def prop_reader(*params)
361
- meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
362
-
363
- meta[:reader] = true
364
- meta[:writer] = false
365
-
366
- for symbol in symbols
367
- prop(klass, symbol, meta)
368
- end
369
- end
370
-
371
- # Helper method. Accepts a collection of symbols and generates
372
- # properties. Only generates writer.
373
- #
374
- # Example:
375
- # prop_writer String, :name, :title, :body, :sql => "char(32)"
376
-
377
- def prop_writer(*params)
378
- meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
379
-
380
- meta[:reader] = false
381
- meta[:writer] = true
382
-
383
- for symbol in symbols
384
- prop(klass, symbol, meta)
385
- end
386
- end
387
-
388
- # Helper method. Accepts a collection of symbols and generates
389
- # properties. Generates reader and writer.
390
- #
391
- # Example:
392
- # prop_accessor String, :name, :title, :body, :sql => "char(32)"
393
-
394
- def prop_accessor(*params)
395
- meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
396
-
397
- meta[:reader] = true
398
- meta[:writer] = true
399
-
400
- for symbol in symbols
401
- prop(klass, symbol, meta)
402
- end
403
- end
404
- alias_method :property, :prop_accessor
405
-
406
- # Attach metadata.
407
- # Guard against duplicates, no need to keep order.
408
- # This method uses closures :)
409
- #--
410
- # gmosx: crappy implementation, recode.
411
- #++
412
-
413
- def meta(key, *val)
414
- Glue::PropertyUtils.enchant(self)
415
-
416
- if val.empty?
417
- self.module_eval %{
418
- @__meta[key] = true
419
- }
420
- else
421
- val = val.first if val.size == 1
422
-
423
- self.module_eval %{
424
- @__meta[key] ||= []
425
- @__meta[key].delete_if { |v| val == v }
426
- @__meta[key] << val
427
- }
428
- end
429
- end
315
+ # Define a property (== typed attribute)
316
+ # This works like Ruby's standard attr method, ie creates
317
+ # only one property.
318
+ #
319
+ # Use the prop_reader, prop_writer, prop_accessor methods
320
+ # for multiple properties.
321
+ #
322
+ # === Examples
323
+ #
324
+ # prop String, :name, :sql => "char(32), :sql_index => "name(32)"
325
+ # --> creates only writer.
326
+ # prop Fixnum, :oid, writer = true, :sql => "integer PRIMARY KEY"
327
+ # --> creates reader and writer.
328
+
329
+ def prop(*params)
330
+ meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
331
+ symbol = symbols.first
332
+
333
+ Glue::PropertyUtils.enchant(self)
334
+
335
+ property = Glue::Property.new(symbol, klass, meta)
336
+
337
+ reader = meta[:reader] || true
338
+ writer = writer || meta[:writer] || false
339
+
340
+ meta[:reader] = true if meta[:reader].nil?
341
+ if defined?(writer)
342
+ meta[:writer] = writer
343
+ else
344
+ meta[:writer] = true if meta[:writer].nil?
345
+ end
346
+
347
+ Glue::PropertyUtils.add_prop(self, property)
348
+
349
+ # gmosx: should be placed AFTER enchant!
350
+
351
+ Glue::PropertyUtils.include_meta_mixins(self)
352
+ end
353
+
354
+ # Helper method. Accepts a collection of symbols and generates
355
+ # properties. Only generates reader.
356
+ #
357
+ # Example:
358
+ # prop_reader String, :name, :title, :body, :sql => "char(32)"
359
+
360
+ def prop_reader(*params)
361
+ meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
362
+
363
+ meta[:reader] = true
364
+ meta[:writer] = false
365
+
366
+ for symbol in symbols
367
+ prop(klass, symbol, meta)
368
+ end
369
+ end
370
+
371
+ # Helper method. Accepts a collection of symbols and generates
372
+ # properties. Only generates writer.
373
+ #
374
+ # Example:
375
+ # prop_writer String, :name, :title, :body, :sql => "char(32)"
376
+
377
+ def prop_writer(*params)
378
+ meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
379
+
380
+ meta[:reader] = false
381
+ meta[:writer] = true
382
+
383
+ for symbol in symbols
384
+ prop(klass, symbol, meta)
385
+ end
386
+ end
387
+
388
+ # Helper method. Accepts a collection of symbols and generates
389
+ # properties. Generates reader and writer.
390
+ #
391
+ # Example:
392
+ # prop_accessor String, :name, :title, :body, :sql => "char(32)"
393
+
394
+ def prop_accessor(*params)
395
+ meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
396
+
397
+ meta[:reader] = true
398
+ meta[:writer] = true
399
+
400
+ for symbol in symbols
401
+ prop(klass, symbol, meta)
402
+ end
403
+ end
404
+ alias_method :property, :prop_accessor
405
+
406
+ # Attach metadata.
407
+ # Guard against duplicates, no need to keep order.
408
+ # This method uses closures :)
409
+ #--
410
+ # gmosx: crappy implementation, recode.
411
+ #++
412
+
413
+ def meta(key, *val)
414
+ Glue::PropertyUtils.enchant(self)
415
+
416
+ if val.empty?
417
+ self.module_eval %{
418
+ @__meta[key] = true
419
+ }
420
+ else
421
+ val = val.first if val.size == 1
422
+
423
+ self.module_eval %{
424
+ @__meta[key] ||= []
425
+ @__meta[key].delete_if { |v| val == v }
426
+ @__meta[key] << val
427
+ }
428
+ end
429
+ end
430
430
 
431
431
  end
432
432