moosex 0.0.17 → 0.0.18

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95164f069f5f27913dfeb6140414d1b0f15e9687
4
- data.tar.gz: 8c93aee2bfaea678c830ed0a1288e170a2bc0bf2
3
+ metadata.gz: ae6315aba6d50e3443b6e0b184a3d51a4ef676d2
4
+ data.tar.gz: e80dc006c7d9ba38c22130007416ca5f29650fec
5
5
  SHA512:
6
- metadata.gz: 23c4c3ff11a33e0d034621564c0c336ce42ab71e511dd04a35cb8a23e2292ac41f80097c9071f61f163461c9f0e98408ec98006342115fa23bb35d896935e7e4
7
- data.tar.gz: 9ee664b8973c9187a510ba14dec13fc89a4c40e3a596793f0a91233dcde4e2a6e711857941432d71ca61ad2a36dab0a03009b280112a198c3a65b1c860a1bcb5
6
+ metadata.gz: 660d4f1f3a542d7e21f66d7d8b335bfe6acb1cde810c65cf8ee37aa82227fe74185b9614a726b0e97f7d5db415182560a710cb072264cae6c7b7dce4b60b9d4c
7
+ data.tar.gz: 0f8071f6fcec75b2ef8d95e0dc2e02388abb45b7fd82aad2aec5b8eeb7be5b759ac02a2862d8f939fe7fe51c81afc326c0843772422bbc0ba577cf9d93fb68b6
data/Changelog CHANGED
@@ -1,7 +1,12 @@
1
+ 0.0.18 - 2013-02-12
2
+ - better meta #58
3
+ - reduce internal complexity #51, #70
4
+ - meta now has __moosex__ prefix #55
5
+
1
6
  0.0.17 - 2013-02-11
2
- - has now support an override option #56
3
- - has now support a doc option #57
4
- - has now should not require :is => default is :rw #54
7
+ - has now support an override option #56
8
+ - has now support a doc option #57
9
+ - has now should not require :is => default is :rw #54
5
10
  - add weak ref support #49
6
11
 
7
12
  0.0.16 - 2013-02-07
@@ -15,63 +20,63 @@
15
20
  - add init method to enable warnings and exceptions #43
16
21
 
17
22
  0.0.14 - 2013-02-05
18
- - roles with around/before/after basic support #41
23
+ - roles with around/before/after basic support #41
19
24
 
20
25
  0.0.13 - 2013-02-05
21
- - change around to receive a lambda #42
26
+ - change around to receive a lambda #42
22
27
 
23
28
  0.0.12 - 2013-02-05
24
- - basic support override attributes #19
25
- - basic support to roles #17
29
+ - basic support override attributes #19
30
+ - basic support to roles #17
26
31
 
27
32
  0.0.11 - 2013-02-04
28
- - basic support to after/before/around #12
29
- - improve exception #15
30
- - improve type system via MooseX::Types #16
31
-
33
+ - basic support to after/before/around #12
34
+ - improve exception #15
35
+ - improve type system via MooseX::Types #16
36
+
32
37
  0.0.10 - 2014-02-03
33
- - improve readme
38
+ - improve readme
34
39
  - BUILDARGS should accept different signatures #36
35
40
  - clearer create by default clear_#{attr_name}! public method
36
41
  - add attr :private #35
37
42
  - methods predicate, clearer and handles are no longer singleton methods #34
38
43
 
39
44
  0.0.9 - 2014-02-02
40
- - support to BUILD and BUILDARGS #5 and #6
41
- - support to trigger #7
42
- - support to coerce #8
45
+ - support to BUILD and BUILDARGS #5 and #6
46
+ - support to trigger #7
47
+ - support to coerce #8
43
48
 
44
49
  0.0.8 - 2014-02-01
45
50
  - should support init_arg option in attr #14
46
- - support lazy attributes / builder #4
47
- - support a custom name for getter / setter #9
48
-
51
+ - support lazy attributes / builder #4
52
+ - support a custom name for getter / setter #9
53
+
49
54
  0.0.7 - 2014-02-01
50
55
  - add min version of ruby should be 2.0.x
51
56
 
52
57
  0.0.6 - 2014-02-01
53
- - fix bug when extends subclass, now it is safe #18
54
- - required attr with default value will no longer throw exception #30
55
- - supports handles for: single method, array, Class or Module #27
58
+ - fix bug when extends subclass, now it is safe #18
59
+ - required attr with default value will no longer throw exception #30
60
+ - supports handles for: single method, array, Class or Module #27
56
61
 
57
62
  0.0.5 - 2014-01-31
58
- - should support handles #13 (partial)
63
+ - should support handles #13 (partial)
59
64
 
60
65
  0.0.4 - 2014-01-31
61
- - fix an issue related to ruby > 1.9.2
66
+ - fix an issue related to ruby > 1.9.2
62
67
 
63
68
  0.0.3 - 2014-01-31
64
- - add support to clearer #26
65
- - add support to predicate #11
66
- - add support to handle more than one attribute #2
67
- - small improvements
69
+ - add support to clearer #26
70
+ - add support to predicate #11
71
+ - add support to handle more than one attribute #2
72
+ - small improvements
68
73
 
69
74
  0.0.2 - 2014-01-31
70
- - fix one important bug, not it is possible use in more than one class
71
- - add require option
72
- - supports :ro, :rw, :rwp ( read-only, read-write and read-write-private) options
73
- - supports default value as lambda or constant
74
- - supports isa as class/module name or lambda
75
+ - fix one important bug, not it is possible use in more than one class
76
+ - add require option
77
+ - supports :ro, :rw, :rwp ( read-only, read-write and read-write-private) options
78
+ - supports default value as lambda or constant
79
+ - supports isa as class/module name or lambda
75
80
 
76
81
  0.0.1 - 2014-01-31
77
- - first release
82
+ - first release
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- moosex (0.0.17)
4
+ moosex (0.0.18)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -474,7 +474,7 @@ Optional.
474
474
 
475
475
  ## doc => String
476
476
 
477
- You can add a string metadata about the attribute. It will be stored, and you can use this in a near future.
477
+ You can add a string metadata about the attribute. If you include MooseX with `meta: true` you can inspect the list of attributes and documentation.
478
478
 
479
479
  Optional.
480
480
 
@@ -557,8 +557,48 @@ The around hook is agressive: it will substitute the original method for a lambd
557
557
 
558
558
  it is useful to manipulate the return value or argument list, add a begin/rescue block, aditional validations, etc, if you need.
559
559
 
560
+ ## MooseX.init
561
+
562
+ The init method is useful to change some behavior of MooseX on the fly.
563
+
564
+ ### warnings => true|false
565
+
566
+ will disable all warnings from MooseX. It is Global. Default is true.
567
+
568
+ ```ruby
569
+ class X
570
+ include MooseX.init(warnings: false)
571
+ ```
572
+
573
+ ### fatal => true|false
574
+
575
+ all warnings will raise exceptions. It is Global. Default is false
576
+
577
+ ```ruby
578
+ class X
579
+ include MooseX.init(fatal: true)
580
+ ```
581
+
582
+ ### meta => Symbol|String|true|false
583
+
584
+ will expose an alias for the class metadata in the class. If you use true, we will generate a method 'meta', if you provide a Symbol or String we will create a method with same name.
585
+
586
+ ```ruby
587
+ class X
588
+ include MooseX.init(meta: true)
589
+
590
+ has :foo, { is: :rw, doc => "this is foo"}
591
+ end
592
+
593
+ X.meta.info # will return { :foo => "this is foo" }
594
+ ```
595
+
596
+ The metadata has two public methods: attrs and info. Be careful.
597
+
560
598
  ## MooseX::Types
561
599
 
600
+ **WARNING** This will be extract for a parallel project/ gem!
601
+
562
602
  MooseX has a built-in type system to be helpful in many circunstances. How many times you need check if some argument is_a? Something? Or it respond_to? :some_method ? Now it is over. If you include the **MooseX::Types** module in your MooseX class you can use:
563
603
 
564
604
  ### isAny
@@ -860,6 +900,8 @@ ex3 = BuildArgsExample2.new() # x == 4, y == 8
860
900
 
861
901
  ## EVENTS
862
902
 
903
+ **WARNING** This will be extract for a parallel project/ gem!
904
+
863
905
  MooseX has a built-in event system, and it should be useful if you want to avoid after/before hooks ( depends of what is your problem ).
864
906
 
865
907
  ```ruby
@@ -4,21 +4,26 @@
4
4
  # Author:: Tiago Peczenyj (mailto:tiago.peczenyj@gmail.com)
5
5
  # Copyright:: Copyright (c) 2014 Tiago Peczenyj
6
6
  # License:: MIT
7
- #
7
+
8
8
  require "moosex/version"
9
9
  require "moosex/types"
10
+ require "moosex/exceptions"
11
+ require "moosex/meta"
12
+ require "moosex/core"
13
+ require "moosex/attribute"
10
14
  require "weakref"
11
15
 
12
16
  module MooseX
17
+ @@ALIAS = nil
13
18
  @@MOOSEX_WARNINGS = true
14
19
  @@MOOSEX_FATAL = false
15
-
16
- class FatalError < StandardError
17
- end
18
-
20
+
19
21
  def self.warn(x, *c)
20
- raise FatalError, "[MooseX] exception: #{x}",*c if @@MOOSEX_FATAL
21
- Kernel.warn("[MooseX] warning: #{x}") if @@MOOSEX_WARNINGS
22
+ if @@MOOSEX_FATAL
23
+ raise FatalError, "[MooseX] exception: #{x}",*c
24
+ elsif @@MOOSEX_WARNINGS
25
+ Kernel.warn("[MooseX] warning: #{x}")
26
+ end
22
27
  end
23
28
 
24
29
  def self.init(args={})
@@ -29,648 +34,76 @@ module MooseX
29
34
  if args.has_key? :fatal
30
35
  @@MOOSEX_FATAL = !! args[:fatal]
31
36
  end
32
-
33
- self
34
- end
35
-
36
- class RequiredMethodNotFoundError < NameError
37
- end
38
37
 
39
- def MooseX.included(c)
40
-
41
- c.extend(MooseX::Core)
42
-
43
- def c.init(*args)
44
- __meta.roles.each{|role| role.call(*args)}
45
-
46
- self
38
+ if args.has_key?(:meta) && !! args[:meta]
39
+ @@ALIAS = (args[:meta].is_a?(TrueClass))? :meta : args[:meta]
47
40
  end
48
41
 
49
- def c.included(x)
50
-
51
- MooseX.included(x)
52
- x.__meta.load_from(self.__meta)
53
-
54
- return unless x.is_a? Class
55
-
56
- x.__meta.load_hooks(self.__meta)
57
- self.__meta.init_klass(x)
58
-
59
- x.__meta.requires.each do |method|
60
- unless x.public_instance_methods.include? method
61
- MooseX.warn "you must implement method '#{method}' in #{x} #{x.class}: required"# if $MOOSEX_DEBUG
62
- end
63
- end
64
- end
65
-
66
- meta = MooseX::Meta.new
67
-
68
- unless c.respond_to? :__meta
69
- c.class_exec do
70
- define_singleton_method(:__meta) { meta }
71
- define_singleton_method(:__meta_define_method) do |method_name, &proc|
72
- define_method(method_name, proc)
73
- end
74
- end
75
- end
76
-
77
- def initialize(*args)
78
- if self.respond_to? :BUILDARGS
79
- args = self.BUILDARGS(*args)
80
- else
81
- args = args[0]
82
- end
83
-
84
- self.class.__meta().init(self, args || {})
85
-
86
- self.BUILD() if self.respond_to? :BUILD
87
- end
88
-
89
- def c.inherited(subclass)
90
- subclass.class_exec do
91
- old_meta = subclass.__meta
92
-
93
- meta = MooseX::Meta.new(old_meta)
94
-
95
- define_singleton_method(:__meta) { meta }
96
- end
97
- end
98
-
42
+ self
99
43
  end
100
-
101
- class Meta
102
- attr_reader :attrs, :requires, :before, :after, :around, :roles
103
44
 
104
- def initialize(old_meta=nil)
105
- @initialized = false
106
- @attrs = {}
107
- @requires = []
108
- @roles = []
109
- @before = Hash.new { |hash, key| hash[key] = [] }
110
- @after = Hash.new { |hash, key| hash[key] = [] }
111
- @around = Hash.new { |hash, key| hash[key] = [] }
45
+ def initialize(*args)
46
+ if self.respond_to? :BUILDARGS
47
+ args = self.BUILDARGS(*args)
48
+ else
49
+ args = args[0]
50
+ end
112
51
 
113
- if old_meta
114
- old_meta.attrs.each_pair do |key, value|
115
- @attrs[key] = value.clone
116
- end
117
- @requires = old_meta.requires.clone
118
- end
119
- end
52
+ self.class.__moosex__meta.init(self, args || {})
120
53
 
121
- def load_from(other_meta)
122
- other_meta.attrs.each_pair do |key, value|
123
- @attrs[key] = value.clone
124
- end
125
- @requires += other_meta.requires
126
- end
127
-
128
- def load_hooks(other_meta)
129
- other_meta.before.each_pair do |m, b|
130
- @before[m] += b.clone
131
- end
132
- other_meta.after.each_pair do |m, b|
133
- @after[m] += b.clone
134
- end
135
- other_meta.around.each_pair do |m, b|
136
- @around[m] += b.clone
137
- end
138
- end
54
+ self.BUILD() if self.respond_to? :BUILD
55
+ end
139
56
 
140
- def add(attr)
141
- if @attrs.has_key?(attr.attr_symbol) && ! attr.override
142
- raise FatalError, "#{attr.attr_symbol} already exists, you should specify override: true"
143
- end
144
- @attrs[attr.attr_symbol] = attr
145
- end
57
+ def MooseX.included(class_or_module)
146
58
 
147
- def add_requires(method)
148
- @requires << method
149
- end
59
+ class_or_module.extend(MooseX::Core)
150
60
 
151
- def add_before(method_name, block)
152
- @before[method_name] << block.clone
153
- end
61
+ unless class_or_module.respond_to? :__moosex__meta
62
+ meta = MooseX::Meta.new
154
63
 
155
- def add_after(method_name, block)
156
- @after[method_name] << block.clone
157
- end
64
+ class_or_module.define_singleton_method(:__moosex__meta) { meta }
158
65
 
159
- def add_around(method_name, block)
160
- @around[method_name] << block.clone
161
- end
162
-
163
- def add_role(block)
164
- @roles << block
165
- end
166
-
167
- def init_klass(klass)
168
- #return if @initialized
169
-
170
- [@before.keys + @after.keys + @around.keys].flatten.uniq.each do |method_name|
171
- begin
172
- method = klass.instance_method method_name
173
- rescue => e
174
- MooseX.warn "Unable to apply hooks (after/before/around) in #{klass}::#{method_name} : #{e}" # if $MOOSEX_DEBUG
175
- next
66
+ if @@ALIAS
67
+ class_or_module.class_eval do
68
+ class_or_module.define_singleton_method(@@ALIAS) { meta }
176
69
  end
177
-
178
- before = @before[method_name]
179
- after = @after[method_name]
180
- around = @around[method_name]
181
-
182
- klass.__meta_define_method(method_name) do |*args, &proc|
183
- before.each{|b| b.call(self,*args, &proc)}
184
-
185
- original = lambda do |object, *args, &proc|
186
- method.bind(object).call(*args, &proc)
187
- end
188
-
189
- result = around.inject(original) do |lambda1, lambda2|
190
- lambda2.curry[lambda1]
191
- end.call(self, *args, &proc)
192
-
193
- after.each{|b| b.call(self,*args, &proc)}
194
-
195
- result
196
- end
197
- end
198
- end
199
-
200
- def init(object, args)
201
- @attrs.each_pair{ |symbol, attr| attr.init(object, args) }
202
-
203
- MooseX.warn "unused attributes #{args} for #{object.class}", caller unless args.empty?
204
-
205
- @requires.each do |method|
206
- unless object.respond_to? method
207
- raise RequiredMethodNotFoundError,
208
- "you must implement method '#{method}' in #{object.class}: required"
209
- end
210
- end
211
- end
212
- end
213
-
214
- module Core
215
- def on_init(&block)
216
- __meta.add_role(block)
70
+ @@ALIAS = false
71
+ end
217
72
  end
218
73
 
219
- def after(*methods_name, &block)
220
- methods_name.each do |method_name|
221
- begin
222
- method = instance_method method_name
223
-
224
- define_method method_name do |*args, &proc|
225
- result = method.bind(self).call(*args, &proc)
226
- block.call(self,*args,&proc)
227
- result
228
- end
229
- rescue => e
230
- MooseX.warn "unable to apply hook after in #{method_name} @ #{self}: #{e}", caller() if self.is_a?(Class)
231
- __meta.add_after(method_name, block)
232
- end
233
- end
234
- end
235
-
236
- def before(*methods_name, &block)
237
- methods_name.each do |method_name|
238
- begin
239
- method = instance_method method_name
240
-
241
- define_method method_name do |*args, &proc|
242
- block.call(self,*args, &proc)
243
- method.bind(self).call(*args, &proc)
244
- end
245
- rescue => e
246
- MooseX.warn "unable to apply hook before in #{method_name} @ #{self}: #{e}", caller() if self.is_a?(Class)
247
- __meta.add_before(method_name, block)
248
- end
249
- end
250
- end
251
-
252
- def around(*methods_name, &block)
253
- methods_name.each do |method_name|
254
- begin
255
-
256
- method = instance_method method_name
257
-
258
- code = Proc.new do | o, *a, &proc|
259
- method.bind(o).call(*a,&proc)
260
- end
261
-
262
- define_method method_name do |*args, &proc|
263
- block.call(code, self,*args, &proc)
264
- end
265
-
266
- rescue => e
267
- MooseX.warn "unable to apply hook around in #{method_name} @ #{self}: #{e}", caller() if self.is_a?(Class)
268
- __meta.add_around(method_name, block)
269
- end
270
- end
271
- end
272
-
273
- def requires(*methods)
274
-
275
- methods.each do |method_name|
276
- __meta.add_requires(method_name)
277
- end
278
- end
279
-
280
- def has(attr_name, attr_options = {})
281
- if attr_name.is_a? Array
282
- attr_name.each do |attr|
283
- has(attr, attr_options)
284
- end
285
- elsif attr_name.is_a? Hash
286
- attr_name.each_pair do |attr, options |
287
- has(attr, options)
288
- end
289
- else
290
- attr = MooseX::Attribute.new(attr_name, attr_options, self)
291
-
292
- __meta.add(attr)
293
-
294
- attr.methods.each_pair do |method, proc|
295
- define_method method, &proc
296
- end
297
-
298
- if attr.is.eql?(:rwp)
299
- private attr.writter
300
- elsif attr.is.eql?(:private)
301
- private attr.writter
302
- private attr.reader
303
- end
304
- end
74
+ def class_or_module.init(*args)
75
+ __moosex__meta.init_roles(*args)
76
+
77
+ self
305
78
  end
306
- end
307
-
308
- class InvalidAttributeError < TypeError
309
-
310
- end
311
79
 
312
- class Attribute
313
- include MooseX::Types
80
+ def class_or_module.inherited(subclass)
81
+ old_meta = subclass.__moosex__meta
314
82
 
315
- attr_reader :attr_symbol, :is, :reader, :writter, :lazy, :builder, :methods, :override
316
- DEFAULTS= {
317
- is: :rw,
318
- weak: false,
319
- lazy: false,
320
- clearer: false,
321
- required: false,
322
- predicate: false,
323
- isa: isAny,
324
- handles: {},
325
- trigger: lambda {|object,value|}, # TODO: implement
326
- coerce: lambda {|object| object}, # TODO: implement
327
- doc: nil,
328
- override: false,
329
- }
83
+ meta = MooseX::Meta.new(old_meta)
330
84
 
331
- REQUIRED = []
332
-
333
- VALIDATE = {
334
- is: lambda do |is, field_name|
335
- unless [:rw, :rwp, :ro, :lazy, :private].include?(is)
336
- raise InvalidAttributeError, "invalid value for field '#{field_name}' is '#{is}', must be one of :private, :rw, :rwp, :ro or :lazy"
337
- end
338
- end,
339
- };
340
-
341
- COERCE = {
342
- is: lambda do |is, field_name|
343
- is.to_sym
344
- end,
345
- isa: lambda do |isa, field_name|
346
- isType(isa)
347
- end,
348
- default: lambda do |default, field_name|
349
- return default if default.is_a? Proc
350
-
351
- return lambda { default }
352
- end,
353
- required: lambda do |required, field_name|
354
- !!required
355
- end,
356
- lazy: lambda do |lazy, field_name|
357
- !!lazy
358
- end,
359
- predicate: lambda do |predicate, field_name|
360
- if ! predicate
361
- return false
362
- elsif predicate.is_a? TrueClass
363
- return "has_#{field_name}?".to_sym
364
- end
365
-
366
- begin
367
- predicate.to_sym
368
- rescue => e
369
- # create a nested exception here
370
- raise InvalidAttributeError, "cannot coerce field predicate to a symbol for #{field_name}: #{e}"
371
- end
372
- end,
373
- clearer: lambda do|clearer, field_name|
374
- if ! clearer
375
- return false
376
- elsif clearer.is_a? TrueClass
377
- return "clear_#{field_name}!".to_sym
378
- end
85
+ subclass.define_singleton_method(:__moosex__meta) { meta }
86
+ end
379
87
 
380
- begin
381
- clearer.to_sym
382
- rescue => e
383
- # create a nested exception here
384
- raise InvalidAttributeError, "cannot coerce field clearer to a symbol for #{field_name}: #{e}"
385
- end
386
- end,
387
- handles: lambda do |handles, field_name|
388
-
389
- unless handles.is_a? Hash
390
-
391
- array_of_handles = handles
392
-
393
- unless array_of_handles.is_a? Array
394
- array_of_handles = [ array_of_handles ]
395
- end
396
-
397
- handles = array_of_handles.map do |handle|
398
-
399
- if handle == BasicObject
400
-
401
- raise InvalidAttributeError, "ops, should not use BasicObject for handles in #{field_name}"
402
-
403
- elsif handle.is_a? Class
404
-
405
- handle = handle.public_instance_methods - handle.superclass.public_instance_methods
406
-
407
- elsif handle.is_a? Module
408
-
409
- handle = handle.public_instance_methods
410
-
411
- end
412
-
413
- handle
414
-
415
- end.flatten.reduce({}) do |hash, method_name|
416
- hash.merge({ method_name => method_name })
417
- end
418
- end
419
-
420
- handles.map do |key,value|
421
- if value.is_a? Hash
422
- raise "ops! Handle should accept only one map / currying" unless value.count == 1
423
-
424
- original, currying = value.shift
425
-
426
- { key.to_sym => [original.to_sym, currying] }
427
- else
428
- { key.to_sym => value.to_sym }
429
- end
430
- end.reduce({}) do |hash,e|
431
- hash.merge(e)
432
- end
433
- end,
434
- reader: lambda do |reader, field_name|
435
- reader.to_sym
436
- end,
437
- writter: lambda do |writter, field_name|
438
- writter.to_sym
439
- end,
440
- builder: lambda do |builder, field_name|
441
- unless builder.is_a? Proc
442
- builder_method_name = builder.to_sym
443
- builder = lambda do |object|
444
- object.send(builder_method_name)
445
- end
446
- end
447
-
448
- builder
449
- end,
450
- init_arg: lambda do |init_arg, field_name|
451
- init_arg.to_sym
452
- end,
453
- trigger: lambda do |trigger, field_name|
454
- unless trigger.is_a? Proc
455
- trigger_method_name = trigger.to_sym
456
- trigger = lambda do |object, value|
457
- object.send(trigger_method_name,value)
458
- end
459
- end
460
-
461
- trigger
462
- end,
463
- coerce: lambda do |coerce, field_name|
464
- unless coerce.is_a? Proc
465
- coerce_method_name = coerce.to_sym
466
- coerce = lambda do |object|
467
- object.send(coerce_method_name)
468
- end
469
- end
470
-
471
- coerce
472
- end,
473
- weak: lambda do |weak, field_name|
474
- !! weak
475
- end,
476
- doc: lambda do |doc, field_name|
477
- doc.to_s
478
- end,
479
- override: lambda do |override, field_name|
480
- !! override
481
- end,
482
- };
483
-
484
- def initialize(a, o ,x)
485
- #o ||= {}
486
- # todo extract this to a framework, see issue #21 on facebook
487
- o = DEFAULTS.merge({
488
- reader: a,
489
- writter: a.to_s.concat("=").to_sym,
490
- builder: "build_#{a}".to_sym,
491
- init_arg: a,
492
- }).merge(o)
493
-
494
- REQUIRED.each { |field|
495
- unless o.has_key?(field)
496
- raise InvalidAttributeError, "field #{field} is required for Attribute #{a}"
497
- end
498
- }
499
- COERCE.each_pair do |field, coerce|
500
- if o.has_key? field
501
- o[field] = coerce.call(o[field], a)
502
- end
503
- end
504
- VALIDATE.each_pair do |field, validate|
505
- return if ! o.has_key? field
506
-
507
- validate.call(o[field], a)
508
- end
509
-
510
- if o[:is].eql? :ro
511
- o[:writter] = nil
512
- elsif o[:is].eql? :lazy
513
- o[:lazy] = true
514
- o[:writter] = nil
515
- end
516
-
517
- unless o[:lazy]
518
- o[:builder] = nil
519
- end
520
-
521
- if o[:weak]
522
- old_coerce = o[:coerce]
523
- o[:coerce] = lambda do |value|
524
- WeakRef.new old_coerce.call(value)
525
- end
526
- end
527
-
528
- @attr_symbol = a
529
- @is = o.delete(:is)
530
- @isa = o.delete(:isa)
531
- @default = o.delete(:default)
532
- @required = o.delete(:required)
533
- @predicate = o.delete(:predicate)
534
- @clearer = o.delete(:clearer)
535
- @handles = o.delete(:handles)
536
- @lazy = o.delete(:lazy)
537
- @reader = o.delete(:reader)
538
- @writter = o.delete(:writter)
539
- @builder = o.delete(:builder)
540
- @init_arg = o.delete(:init_arg)
541
- @trigger = o.delete(:trigger)
542
- @coerce = o.delete(:coerce)
543
- @weak = o.delete(:weak)
544
- @documentation = o.delete(:doc)
545
- @override = o.delete(:override)
546
- @methods = {}
547
-
548
- MooseX.warn "Unused attributes #{o} for attribute #{a} @ #{x} #{x.class}",caller() if ! o.empty?
549
-
550
- if @reader
551
- @methods[@reader] = generate_reader
552
- end
553
-
554
- if @writter
555
- @methods[@writter] = generate_writter
556
- end
557
- inst_variable_name = "@#{@attr_symbol}".to_sym
558
- if @predicate
559
- @methods[@predicate] = Proc.new do
560
- instance_variable_defined? inst_variable_name
561
- end
562
- end
563
-
564
- if @clearer
565
- @methods[@clearer] = Proc.new do
566
- if instance_variable_defined? inst_variable_name
567
- remove_instance_variable inst_variable_name
568
- end
569
- end
570
- end
571
-
572
- attr_symbol = @attr_symbol
573
- @handles.each_pair do | method, target_method |
574
- if target_method.is_a? Array
575
- original, currying = target_method
576
-
577
- @methods[method] = Proc.new do |*args, &proc|
578
-
579
- a1 = [ currying ]
580
-
581
- if currying.is_a?Proc
582
- a1 = currying.call()
583
- elsif currying.is_a? Array
584
- a1 = currying.map{|c| (c.is_a?(Proc)) ? c.call : c }
585
- end
586
-
587
- self.send(attr_symbol).send(original, *a1, *args, &proc)
588
- end
589
- else
590
- @methods[method] = Proc.new do |*args, &proc|
591
- self.send(attr_symbol).send(target_method, *args, &proc)
592
- end
593
- end
594
- end
595
- end
596
-
597
- def init(object, args)
598
- value = nil
599
- value_from_default = false
88
+ def class_or_module.included(other_class_or_module)
600
89
 
601
- if args.has_key? @init_arg
602
- value = args.delete(@init_arg)
603
- elsif @default
604
- value = @default.call
605
- value_from_default = true
606
- elsif @required
607
- raise InvalidAttributeError, "attr \"#{@attr_symbol}\" is required"
608
- else
609
- return
610
- end
90
+ MooseX.included(other_class_or_module)
611
91
 
612
- value = @coerce.call(value)
613
- begin
614
- @isa.call( value )
615
- rescue MooseX::Types::TypeCheckError => e
616
- raise MooseX::Types::TypeCheckError, "isa check for field #{attr_symbol}: #{e}"
617
- end
618
- unless value_from_default
619
- @trigger.call(object, value)
620
- end
621
- inst_variable_name = "@#{@attr_symbol}".to_sym
622
- object.instance_variable_set inst_variable_name, value
623
- end
92
+ other_class_or_module.__moosex__meta.load_from(self)
624
93
 
625
- private
626
- def generate_reader
627
- inst_variable_name = "@#{@attr_symbol}".to_sym
628
-
629
- builder = @builder
630
- before_get = lambda {|object| }
94
+ if other_class_or_module.is_a? Class
631
95
 
632
- if @lazy
633
- type_check = @isa
634
- coerce = @coerce
635
- trigger = @trigger
636
- before_get = lambda do |object|
637
- return if object.instance_variable_defined? inst_variable_name
96
+ other_class_or_module.__moosex__meta.load_from_klass(self)
638
97
 
639
- value = builder.call(object)
640
- value = coerce.call(value)
641
- begin
642
- type_check.call( value )
643
- rescue MooseX::Types::TypeCheckError => e
644
- raise MooseX::Types::TypeCheckError, "isa check for #{inst_variable_name} from builder: #{e}"
645
- end
98
+ self.__moosex__meta.init_klass(other_class_or_module).each_pair do |method_name, proc|
99
+ other_class_or_module.class_eval do
100
+ define_method(method_name,&proc)
101
+ end
102
+ end
646
103
 
647
- trigger.call(object, value)
648
- object.instance_variable_set(inst_variable_name, value)
649
- end
650
- end
104
+ other_class_or_module.__moosex__meta.verify_requires_for(other_class_or_module)
651
105
 
652
- Proc.new do
653
- before_get.call(self)
654
- instance_variable_get inst_variable_name
655
- end
106
+ end
656
107
  end
657
-
658
- def generate_writter
659
- writter_name = @writter
660
- inst_variable_name = "@#{@attr_symbol}".to_sym
661
- coerce = @coerce
662
- type_check = @isa
663
- trigger = @trigger
664
- Proc.new do |value|
665
- value = coerce.call(value)
666
- begin
667
- type_check.call( value )
668
- rescue MooseX::Types::TypeCheckError => e
669
- raise MooseX::Types::TypeCheckError, "isa check for #{writter_name}: #{e}"
670
- end
671
- trigger.call(self,value)
672
- instance_variable_set inst_variable_name, value
673
- end
674
- end
675
108
  end
676
109
  end