glue 0.20.0 → 0.21.0

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