glue 0.23.0 → 0.24.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.
- data/ProjectInfo +57 -0
- data/README +1 -1
- data/Rakefile +2 -2
- data/doc/RELEASES +16 -0
- data/lib/glue.rb +9 -1
- data/lib/glue/aspects.rb +30 -28
- data/lib/glue/bit.rb +53 -0
- data/lib/glue/configuration.rb +1 -1
- data/lib/glue/fixture.rb +1 -1
- data/lib/glue/flexob.rb +14 -2
- data/lib/glue/helper.rb +1 -0
- data/lib/glue/logger.rb +11 -11
- data/lib/glue/mailer/incoming.rb +1 -3
- data/lib/glue/mailer/outgoing.rb +2 -4
- data/lib/glue/on_included.rb +48 -0
- data/lib/glue/property.rb +193 -400
- data/lib/glue/template.rb +3 -3
- data/lib/glue/uri.rb +1 -1
- data/lib/glue/validation.rb +28 -23
- data/test/glue/tc_aspects.rb +2 -2
- data/test/glue/tc_logger.rb +2 -0
- data/test/glue/tc_property.rb +26 -10
- data/test/glue/tc_property_mixins.rb +15 -15
- data/test/glue/tc_property_type_checking.rb +11 -5
- data/test/glue/tc_validation.rb +1 -1
- metadata +65 -73
- data/lib/glue/metadata.rb +0 -60
- data/lib/glue/property.rb.old +0 -438
- data/test/glue/tc_metadata.rb +0 -33
data/lib/glue/mailer/outgoing.rb
CHANGED
@@ -7,10 +7,8 @@ module OutgoingMailer
|
|
7
7
|
|
8
8
|
attr_accessor :template_root
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
10
|
+
on_included %{ base.extend ClassMethods }
|
11
|
+
|
14
12
|
def initialize(from = nil, to = nil, subject = nil, body = FileTemplate.new)
|
15
13
|
super
|
16
14
|
@charset = Mailer.default_charset.dup
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# George Moschovitis <gm@navel.gr>
|
2
|
+
|
3
|
+
class Module
|
4
|
+
|
5
|
+
# A useful macro for dynamic modules.
|
6
|
+
#--
|
7
|
+
# FIXME: quick and easy implementation, should
|
8
|
+
# come up with something better. The name
|
9
|
+
# sucks too.
|
10
|
+
#++
|
11
|
+
def on_included(code)
|
12
|
+
tag = caller[0].split(' ').first.split(/\/|\\/).last.gsub(/:|\.|\(|\)/, '_')
|
13
|
+
old = "__included_#{tag}"
|
14
|
+
module_eval %{
|
15
|
+
class << self
|
16
|
+
alias_method :#{old}, :included
|
17
|
+
def included(base)
|
18
|
+
#{old}(base)
|
19
|
+
#{code}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
=begin Testing
|
27
|
+
|
28
|
+
module M
|
29
|
+
on_included %{
|
30
|
+
puts 'hello'
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
module Q
|
35
|
+
on_included %{
|
36
|
+
puts 'world'
|
37
|
+
}
|
38
|
+
on_included %{
|
39
|
+
puts 'it works'
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
class C
|
44
|
+
include M
|
45
|
+
include Q
|
46
|
+
end
|
47
|
+
|
48
|
+
=end
|
data/lib/glue/property.rb
CHANGED
@@ -1,457 +1,250 @@
|
|
1
|
-
require 'mega/
|
2
|
-
require 'mega/
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require '
|
7
|
-
require 'glue/
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# relational mapping, or web form population.
|
14
|
-
#
|
15
|
-
# Only Fixnums, Strings, Floats, Times, Booleans are
|
16
|
-
# converted.
|
17
|
-
#
|
18
|
-
# The default = methods do not force the types. A special
|
19
|
-
# __force_set method should be used instead.
|
1
|
+
require 'mega/annotation'
|
2
|
+
require 'mega/inheritor'
|
3
|
+
require 'mega/ohash'
|
4
|
+
|
5
|
+
require 'glue/on_included'
|
6
|
+
require 'og/entity'
|
7
|
+
require 'glue/validation'
|
8
|
+
require 'og/relation/all'
|
9
|
+
require 'glue/aspects'
|
10
|
+
|
11
|
+
# A convienience structure that holds property
|
12
|
+
# metadata.
|
20
13
|
#--
|
21
|
-
# TODO:
|
22
|
-
# Perhaps a sync is needed in evals (!!!!)
|
14
|
+
# TODO: reimplement type checking.
|
23
15
|
#++
|
24
16
|
|
25
17
|
class Property
|
26
|
-
|
27
|
-
# If set to true, perform type checking on property set.
|
28
|
-
# Useful when debugging.
|
29
|
-
|
30
|
-
cattr_accessor :type_checking, false
|
31
|
-
|
32
|
-
# The symbol of the property.
|
33
|
-
|
34
|
-
attr_accessor :symbol
|
18
|
+
attr_accessor :hash
|
35
19
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# Additional metadata (like sql declaration, sql index, etc)
|
41
|
-
# Here is a list of predefined metadata:
|
42
|
-
#
|
43
|
-
# [+:reader+]
|
44
|
-
# create reader?
|
45
|
-
#
|
46
|
-
# [+:writer+]
|
47
|
-
# create writer?
|
48
|
-
#
|
49
|
-
# [+:sql_index+]
|
50
|
-
# create an sql index for the column this poperty maps to?
|
51
|
-
#
|
52
|
-
# You can use this mechanism to add your own, custom,
|
53
|
-
# metadata.
|
54
|
-
|
55
|
-
attr_accessor :metadata
|
56
|
-
|
57
|
-
# Support legacy code, will be deprecated.
|
20
|
+
def initialize(hash)
|
21
|
+
@hash = hash
|
22
|
+
@hash = @hash.to_h unless @hash.is_a?(Hash)
|
23
|
+
end
|
58
24
|
|
59
|
-
|
60
|
-
|
25
|
+
def [](key)
|
26
|
+
@hash[key]
|
27
|
+
end
|
28
|
+
alias_method :method_missing, :[]
|
61
29
|
|
62
|
-
def
|
63
|
-
@
|
64
|
-
@metadata = metadata
|
30
|
+
def []=(key, val)
|
31
|
+
@hash[key] = val
|
65
32
|
end
|
66
33
|
|
67
|
-
def
|
68
|
-
|
34
|
+
def <=>(other)
|
35
|
+
@hash[:symbol] <=> other.hash[:symbol]
|
69
36
|
end
|
70
37
|
|
71
38
|
def to_s
|
72
|
-
|
73
|
-
end
|
39
|
+
@hash[:symbol].to_s
|
40
|
+
end
|
74
41
|
end
|
75
42
|
|
76
|
-
#
|
77
|
-
|
78
|
-
module PropertyUtils
|
43
|
+
# Property related utils and helpers.
|
79
44
|
|
80
|
-
|
81
|
-
|
82
|
-
|
45
|
+
class Property
|
46
|
+
class << self
|
47
|
+
|
48
|
+
# Populate an object from a hash of values.
|
49
|
+
# This is a truly dangerous method.
|
83
50
|
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
# when defining methods and attributes so @__props is really
|
98
|
-
# a class scoped variable that unlike @@__props is not shared
|
99
|
-
# through the hierarchy.
|
51
|
+
# === Options:
|
52
|
+
# * name
|
53
|
+
# * force_boolean
|
54
|
+
|
55
|
+
def populate_object(obj, values, options = {})
|
56
|
+
# If a class is passed create an instance.
|
57
|
+
obj = obj.new if obj.is_a?(Class)
|
58
|
+
|
59
|
+
for prop in obj.class.properties.values
|
60
|
+
unless options[:all]
|
61
|
+
next if :oid == prop.symbol or prop.editor == :none # TODO check for real key.
|
62
|
+
end
|
63
|
+
prop_name = prop.symbol.to_s
|
100
64
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
def self.properties
|
107
|
-
@__props
|
108
|
-
end
|
109
|
-
|
110
|
-
def self.__props=(props)
|
111
|
-
@__props = props
|
112
|
-
end
|
65
|
+
# See if there is an incoming request param for this prop.
|
66
|
+
|
67
|
+
if values.has_key?(prop_name)
|
113
68
|
|
114
|
-
|
115
|
-
@__meta
|
116
|
-
end
|
117
|
-
|
118
|
-
def self.__meta=(meta)
|
119
|
-
@__meta = meta
|
120
|
-
end
|
69
|
+
# if incoming file then read contents into a string.
|
121
70
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
#
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
# at the end.
|
139
|
-
super
|
140
|
-
end
|
141
|
-
}
|
142
|
-
|
71
|
+
prop_value = values[prop_name]
|
72
|
+
prop_value.read if prop_value.respond_to?(:read)
|
73
|
+
prop_value = prop_value.to_s unless prop_value.is_a?(Hash) or prop_value.is_a?(Array)
|
74
|
+
|
75
|
+
# If property is a Blob dont overwrite current property's data if "".
|
76
|
+
|
77
|
+
break if prop.klass == Og::Blob and prop_value.empty?
|
78
|
+
|
79
|
+
# Pass to property force.
|
80
|
+
|
81
|
+
obj.send("__force_#{prop_name}", prop_value)
|
82
|
+
elsif options[:force_boolean] and (prop.klass == TrueClass or prop.klass == FalseClass)
|
83
|
+
# Set a boolean property to false if it is not in the request.
|
84
|
+
# Only enabled if force_boolean == true.
|
85
|
+
|
86
|
+
obj.send("__force_#{prop_name}", 0)
|
143
87
|
else
|
144
|
-
|
145
|
-
# Add some extra code for modules to append
|
146
|
-
# their features to classes that include it.
|
88
|
+
# check if there is a hashed version of the property (in the form values[symbol.part])
|
147
89
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
Glue::PropertyUtils.copy_features(self, base)
|
154
|
-
super
|
90
|
+
property_parts = Hash.new
|
91
|
+
values.each do |k,v|
|
92
|
+
if k =~ /^#{prop_name}\./
|
93
|
+
part_key = k.sub("#{prop_name}.", "")
|
94
|
+
property_parts[part_key.to_sym] = values[k].to_s
|
155
95
|
end
|
156
|
-
|
157
|
-
|
96
|
+
end
|
97
|
+
|
98
|
+
# pass the hashed version to __force_hash_ for processing.
|
99
|
+
|
100
|
+
obj.send("__force_hash_#{prop_name}", property_parts) unless property_parts.empty?
|
158
101
|
end
|
159
102
|
end
|
160
|
-
end
|
161
103
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
add_prop(dest, p)
|
167
|
-
end
|
168
|
-
|
169
|
-
# copy the metadata.
|
170
|
-
src.__meta.each do |k, val|
|
171
|
-
if val.is_a?(TrueClass)
|
172
|
-
dest.__meta[k] = val
|
173
|
-
else
|
174
|
-
dest.__meta[k] = val.dup
|
175
|
-
end
|
176
|
-
# val.each { |v| dest.meta(k, v) } if val
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Add the property to the target (Class or Module)
|
181
|
-
|
182
|
-
def self.add_prop(target, prop)
|
183
|
-
if idx = target.__props.index(prop)
|
184
|
-
# override in case of duplicates. Keep the order of the props.
|
185
|
-
target.__props[idx] = prop
|
186
|
-
else
|
187
|
-
target.__props << prop
|
188
|
-
end
|
189
|
-
|
190
|
-
# Store the property in the :props_and_relations
|
191
|
-
# metadata array.
|
192
|
-
|
193
|
-
target.meta :props_and_relations, prop
|
194
|
-
|
195
|
-
# Precompile the property read/write methods
|
196
|
-
|
197
|
-
s, klass = prop.symbol, prop.klass
|
198
|
-
|
199
|
-
if prop.meta[:reader]
|
200
|
-
target.module_eval %{
|
201
|
-
def #{s}
|
202
|
-
return @#{s}
|
104
|
+
if options[:assign_relations]
|
105
|
+
for rel in obj.class.relations
|
106
|
+
unless options[:all]
|
107
|
+
next if rel.options[:editor] == :none
|
203
108
|
end
|
204
|
-
}
|
205
|
-
end
|
206
|
-
|
207
|
-
# gmosx: __force_xxx reuses xxx= to allow for easier
|
208
|
-
# overrides.
|
209
|
-
|
210
|
-
if prop.meta[:writer]
|
211
|
-
code = %{
|
212
|
-
#{prop_setter(prop)}
|
213
109
|
|
214
|
-
|
215
|
-
self.#{s}=(} + case klass.name
|
216
|
-
when Fixnum.name
|
217
|
-
"val.to_i()"
|
218
|
-
when String.name
|
219
|
-
"val.to_s()"
|
220
|
-
when Float.name
|
221
|
-
"val.to_f()"
|
222
|
-
when Time.name
|
223
|
-
"Time.parse(val.to_s())"
|
224
|
-
when TrueClass.name, FalseClass.name
|
225
|
-
"val.to_i() > 0"
|
226
|
-
else
|
227
|
-
"val"
|
228
|
-
end + %{)
|
229
|
-
end
|
110
|
+
rel_name = rel.name.to_s
|
230
111
|
|
231
|
-
|
232
|
-
|
112
|
+
# Renew the relations from values
|
113
|
+
# TODO, farms: custom callbacks for processing relations?
|
233
114
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
115
|
+
if rel.kind_of? Og::RefersTo
|
116
|
+
if foreign_oid = values[rel_name]
|
117
|
+
foreign_oid = nil if foreign_oid == 'nil' or foreign_oid == 'none'
|
118
|
+
end
|
119
|
+
obj.send("__force_#{rel.foreign_key}", foreign_oid)
|
120
|
+
elsif rel.kind_of? Og::JoinsMany or rel.kind_of? Og::HasMany
|
121
|
+
# Empty current relationships.
|
122
|
+
|
123
|
+
collection = obj.send(rel_name)
|
124
|
+
collection.remove_all
|
125
|
+
|
126
|
+
# Set new.
|
127
|
+
|
128
|
+
if values.has_key?(rel_name)
|
129
|
+
values[rel_name].each do |v|
|
130
|
+
child = rel.target_class[v.to_s.to_i]
|
131
|
+
collection << child
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
241
135
|
end
|
242
|
-
|
243
|
-
code << %{
|
244
|
-
end
|
245
|
-
}
|
246
|
-
|
247
|
-
target.module_eval(code)
|
248
136
|
end
|
249
|
-
end
|
250
137
|
|
251
|
-
|
252
|
-
|
138
|
+
return obj
|
139
|
+
end
|
140
|
+
|
141
|
+
def eval_helpers(writer, m, sym, klass)
|
142
|
+
return unless writer
|
253
143
|
|
254
|
-
def self.prop_setter(prop)
|
255
|
-
s = prop.symbol
|
256
|
-
|
257
144
|
code = %{
|
258
|
-
def #{
|
145
|
+
def __force_#{sym}(val)
|
146
|
+
self.#{sym}=(} + case klass.name
|
147
|
+
when 'Fixnum': 'val.nil? ? nil : val.to_i'
|
148
|
+
when 'String': 'val.to_s'
|
149
|
+
when 'Float': 'val.nil? ? nil : val.to_f'
|
150
|
+
when 'Time': 'Time.parse(val.to_s)'
|
151
|
+
when 'TrueClass', 'FalseClass': '(val == "on" or val == "true") ? true : (val.to_i > 0)'
|
152
|
+
when 'Og::Blob': 'val'
|
153
|
+
else
|
154
|
+
'val'
|
155
|
+
end + %{)
|
156
|
+
end
|
157
|
+
|
158
|
+
def __force_hash_#{sym}(hash)
|
259
159
|
}
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
}
|
160
|
+
|
161
|
+
case klass.name
|
162
|
+
when Time.name
|
163
|
+
code << %{
|
164
|
+
self.#{sym} = Time.local(hash[:year],hash[:month],hash[:day],hash[:hour],hash[:min])
|
165
|
+
}
|
267
166
|
end
|
268
167
|
|
269
168
|
code << %{
|
270
|
-
|
271
|
-
end
|
169
|
+
end
|
272
170
|
}
|
273
171
|
|
274
|
-
|
275
|
-
end
|
276
|
-
|
277
|
-
# Get the property metadata for the given symbol.
|
278
|
-
|
279
|
-
def self.get_prop(klass, sym)
|
280
|
-
return klass.__props.find { |p| p.symbol == sym }
|
281
|
-
end
|
172
|
+
m.module_eval(code)
|
173
|
+
end
|
282
174
|
|
283
|
-
# Include meta-language mixins
|
284
|
-
|
285
|
-
def self.include_meta_mixins(target)
|
286
|
-
target.module_eval %{ include Glue::Validation } if defined?(Glue::Validation)
|
287
|
-
# gmosx: TODO, make Og::MetaLanguage equivalent to Validation.
|
288
|
-
# target.module_eval %{ extend Og::MetaLanguage } if defined?(Og::MetaLanguage)
|
289
|
-
target.module_eval %{ include Glue::Aspects } if defined?(Glue::Aspects)
|
290
|
-
target.send(:include, Og::EntityMixin) if defined?(Og::EntityMixin)
|
291
175
|
end
|
292
|
-
|
293
|
-
def self.copy_features(this, other)
|
294
|
-
Glue::PropertyUtils.enchant(other)
|
295
|
-
Glue::PropertyUtils.copy_props(this, other)
|
296
|
-
Glue::PropertyUtils.include_meta_mixins(other)
|
297
|
-
end
|
298
|
-
|
299
|
-
# Resolves the parameters passed to the propxxx macros
|
300
|
-
# to generate the meta, klass and symbols variables. This
|
301
|
-
# way the common functionality is factored out.
|
302
|
-
#
|
303
|
-
# [+params+]
|
304
|
-
# The params to resolve.
|
305
|
-
# [+one_symbol+]
|
306
|
-
# If true, only resolves one symbol (used in prop).
|
307
|
-
|
308
|
-
def self.resolve_prop_params(*params)
|
309
|
-
meta = {}
|
310
|
-
klass = Object
|
311
|
-
symbols = []
|
312
|
-
|
313
|
-
for param in params.flatten
|
314
|
-
if param.is_a?(Class)
|
315
|
-
klass = param
|
316
|
-
elsif param.is_a?(Symbol)
|
317
|
-
symbols << param
|
318
|
-
elsif param.is_a?(TrueClass) or param.is_a?(TrueClass)
|
319
|
-
writer = param
|
320
|
-
elsif param.is_a?(Hash)
|
321
|
-
# the meta hash.
|
322
|
-
meta.update(param) { |k, a, b| [a,b].join(' ') }
|
323
|
-
else
|
324
|
-
raise 'Error when defining property!'
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
raise 'No symbols provided!' if symbols.empty?
|
329
|
-
|
330
|
-
return meta, klass, symbols
|
331
|
-
end
|
332
|
-
|
333
176
|
end
|
334
177
|
|
335
|
-
|
178
|
+
#--
|
179
|
+
# Extend the default Module.
|
180
|
+
#
|
181
|
+
# The properties hash, keeps the property metadata as a hash to avoid
|
182
|
+
# the null issue.
|
183
|
+
#++
|
336
184
|
|
337
185
|
class Module
|
186
|
+
[ nil, :_reader, :_writer, :_accessor].each do |m|
|
187
|
+
writer = (m != :reader)
|
188
|
+
code = %{
|
189
|
+
def prop#{m} (*args)
|
190
|
+
inheritor(:properties, {}, :merge) unless @properties
|
338
191
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
# for multiple properties.
|
345
|
-
#
|
346
|
-
# === Examples
|
347
|
-
#
|
348
|
-
# prop String, :name, :sql => "char(32), :sql_index => "name(32)"
|
349
|
-
# --> creates only writer.
|
350
|
-
# prop Fixnum, :oid, writer = true, :sql => "integer PRIMARY KEY"
|
351
|
-
# --> creates reader and writer.
|
352
|
-
|
353
|
-
def prop(*params)
|
354
|
-
meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
|
355
|
-
symbol = symbols.first
|
356
|
-
|
357
|
-
Glue::PropertyUtils.enchant(self)
|
358
|
-
|
359
|
-
property = Glue::Property.new(symbol, klass, meta)
|
360
|
-
|
361
|
-
reader = meta[:reader] || true
|
362
|
-
writer = writer || meta[:writer] || false
|
363
|
-
|
364
|
-
meta[:reader] = true if meta[:reader].nil?
|
365
|
-
if defined?(writer)
|
366
|
-
meta[:writer] = writer
|
367
|
-
else
|
368
|
-
meta[:writer] = true if meta[:writer].nil?
|
369
|
-
end
|
370
|
-
|
371
|
-
Glue::PropertyUtils.add_prop(self, property)
|
372
|
-
|
373
|
-
# gmosx: should be placed AFTER enchant!
|
374
|
-
|
375
|
-
Glue::PropertyUtils.include_meta_mixins(self)
|
376
|
-
end
|
377
|
-
|
378
|
-
# Helper method. Accepts a collection of symbols and generates
|
379
|
-
# properties. Only generates reader.
|
380
|
-
#
|
381
|
-
# Example:
|
382
|
-
# prop_reader String, :name, :title, :body, :sql => "char(32)"
|
383
|
-
|
384
|
-
def prop_reader(*params)
|
385
|
-
meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
|
386
|
-
|
387
|
-
meta[:reader] = true
|
388
|
-
meta[:writer] = false
|
389
|
-
|
390
|
-
for symbol in symbols
|
391
|
-
prop(klass, symbol, meta)
|
392
|
-
end
|
393
|
-
end
|
192
|
+
args = args.flatten
|
193
|
+
harg = {}
|
194
|
+
while args.last.is_a?(Hash)
|
195
|
+
harg.update(args.pop)
|
196
|
+
end
|
394
197
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
# prop_writer String, :name, :title, :body, :sql => "char(32)"
|
400
|
-
|
401
|
-
def prop_writer(*params)
|
402
|
-
meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
|
198
|
+
harg[:klass] = args.pop if args.last.is_a?(Class)
|
199
|
+
harg[:klass] ||= String
|
200
|
+
|
201
|
+
raise if args.empty? and harg.empty?
|
403
202
|
|
404
|
-
|
405
|
-
|
203
|
+
if !args.empty?
|
204
|
+
undef_keys = args.select{ |a| !method_defined?(a) }
|
205
|
+
unless undef_keys.empty?
|
206
|
+
attr#{m} *undef_keys
|
207
|
+
end
|
208
|
+
args.each { |a|
|
209
|
+
a = a.to_sym
|
210
|
+
an = define_annotation(a, harg)
|
211
|
+
ah = an.to_h.merge(:symbol => a)
|
212
|
+
# gmosx: allow for duplicate declarations.
|
213
|
+
properties![a] = Property.new(ah)
|
214
|
+
Property.eval_helpers(#{writer}, self, a, harg[:klass])
|
215
|
+
}
|
216
|
+
else
|
217
|
+
undef_keys = harg.keys.select{ |a| !method_defined?(a) }
|
218
|
+
attribute#{m} *undef_keys
|
219
|
+
harg.each { |a,h|
|
220
|
+
a = a.to_sym
|
221
|
+
an = define_annotation(a, h)
|
222
|
+
ah = an.to_h.merge(:symbol => a)
|
223
|
+
# gmosx: allow for property redefinitions.
|
224
|
+
properties![a] = Property.new(ah)
|
225
|
+
Property.eval_helpers(#{writer}, self, a, harg[:klass])
|
226
|
+
}
|
227
|
+
end
|
228
|
+
|
229
|
+
Module.__add_prop_hook__(self)
|
230
|
+
end
|
231
|
+
}
|
406
232
|
|
407
|
-
|
408
|
-
prop(klass, symbol, meta)
|
409
|
-
end
|
233
|
+
module_eval(code)
|
410
234
|
end
|
235
|
+
alias :property :prop_accessor
|
236
|
+
|
237
|
+
# NITRO specific!! leave blank in nano/mega.
|
238
|
+
# TODO: factor in eval_helpers into the hook!
|
411
239
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
# prop_accessor String, :name, :title, :body, :sql => "char(32)"
|
417
|
-
|
418
|
-
def prop_accessor(*params)
|
419
|
-
meta, klass, symbols = Glue::PropertyUtils.resolve_prop_params(params)
|
420
|
-
|
421
|
-
meta[:reader] = true
|
422
|
-
meta[:writer] = true
|
423
|
-
|
424
|
-
for symbol in symbols
|
425
|
-
prop(klass, symbol, meta)
|
426
|
-
end
|
240
|
+
def self.__add_prop_hook__(m)
|
241
|
+
m.send(:include, Og::EntityMixin) unless m.ancestors.include?(Og::EntityMixin)
|
242
|
+
m.send(:include, Glue::Validation) unless m.ancestors.include?(Glue::Validation)
|
243
|
+
m.send(:include, Glue::Aspects) unless m.ancestors.include?(Glue::Aspects)
|
427
244
|
end
|
428
|
-
alias_method :property, :prop_accessor
|
429
245
|
|
430
|
-
# Attach metadata.
|
431
|
-
# Guard against duplicates, no need to keep order.
|
432
|
-
# This method uses closures :)
|
433
|
-
#--
|
434
|
-
# gmosx: crappy implementation, recode.
|
435
|
-
#++
|
436
|
-
|
437
|
-
def meta(key, *val)
|
438
|
-
Glue::PropertyUtils.enchant(self)
|
439
|
-
|
440
|
-
if val.empty?
|
441
|
-
self.module_eval %{
|
442
|
-
@__meta[key] = true
|
443
|
-
}
|
444
|
-
else
|
445
|
-
val = val.first if val.size == 1
|
446
|
-
|
447
|
-
self.module_eval %{
|
448
|
-
@__meta[key] ||= []
|
449
|
-
@__meta[key].delete_if { |v| val == v }
|
450
|
-
@__meta[key] << val
|
451
|
-
}
|
452
|
-
end
|
453
|
-
end
|
454
|
-
|
455
246
|
end
|
456
247
|
|
457
248
|
# * George Moschovitis <gm@navel.gr>
|
249
|
+
# * Tom Sawyer <transfire@gmail.com>
|
250
|
+
# * Chris Farmiloe <chris.farmiloe@farmiloe.com>
|