classx 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/ChangeLog +354 -0
  2. data/README +5 -0
  3. data/Rakefile +2 -2
  4. data/bench/attribute_get.rb +73 -0
  5. data/bench/attribute_set.rb +53 -19
  6. data/bench/define_attribute.rb +226 -0
  7. data/bench/initialize.rb +25 -7
  8. data/doc/output/coverage/index.html +74 -128
  9. data/doc/output/coverage/lib-classx-attribute_rb.html +291 -190
  10. data/doc/output/coverage/lib-classx-attributes_rb.html +167 -101
  11. data/doc/output/coverage/lib-classx-bracketable_rb.html +671 -0
  12. data/doc/output/coverage/lib-classx-class_attributes_rb.html +775 -0
  13. data/doc/output/coverage/lib-classx-commandable_rb.html +727 -0
  14. data/doc/output/coverage/{-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-block_rb.html → lib-classx-declare_rb.html} +60 -62
  15. data/doc/output/coverage/lib-classx-validate_rb.html +43 -41
  16. data/doc/output/coverage/lib-classx_rb.html +208 -78
  17. data/example/commandable.rb +1 -0
  18. data/lib/classx.rb +146 -16
  19. data/lib/classx/attribute.rb +244 -143
  20. data/lib/classx/attributes.rb +93 -27
  21. data/lib/classx/bracketable.rb +61 -0
  22. data/lib/classx/class_attributes.rb +165 -0
  23. data/lib/classx/commandable.rb +55 -4
  24. data/lib/classx/declare.rb +40 -3
  25. data/lib/classx/role/logger.rb +17 -13
  26. data/lib/classx/validate.rb +26 -24
  27. data/spec/classx/handles_spec.rb +21 -6
  28. data/spec/classx/serialize_spec.rb +57 -0
  29. data/spec/classx/{with_coerce.rb → with_coerce_spec.rb} +0 -0
  30. data/spec/classx/with_extend_spec.rb +58 -0
  31. data/spec/classx/with_include_spec.rb +58 -0
  32. data/spec/classx/with_validate_spec.rb +363 -0
  33. data/spec/classx/without_anyoption_spec.rb +1 -1
  34. data/spec/classx/writable_option_spec.rb +29 -4
  35. data/spec/classx_bracketable_spec.rb +160 -0
  36. data/spec/classx_class_attributes/default_option_spec.rb +121 -0
  37. data/spec/classx_class_attributes/dsl_accessor_spec.rb +88 -0
  38. data/spec/classx_class_attributes/handles_spec.rb +77 -0
  39. data/spec/classx_class_attributes/with_coerce_spec.rb +119 -0
  40. data/spec/classx_class_attributes/with_extend_spec.rb +64 -0
  41. data/spec/classx_class_attributes/with_include_spec.rb +64 -0
  42. data/spec/classx_class_attributes/with_multiple_class_spec.rb +60 -0
  43. data/spec/classx_class_attributes/with_validate_spec.rb +248 -0
  44. data/spec/classx_class_attributes/without_accessor_spec.rb +19 -0
  45. data/spec/classx_class_attributes/without_anyoption_spec.rb +21 -0
  46. data/spec/classx_class_attributes/writable_option_spec.rb +100 -0
  47. data/spec/classx_declare_spec.rb +117 -0
  48. data/spec/classx_validate_spec.rb +1 -3
  49. data/tasks/basic_tasks.rake +1 -1
  50. metadata +36 -26
  51. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-callbacks_rb.html +0 -932
  52. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-change_rb.html +0 -779
  53. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-hunk_rb.html +0 -867
  54. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs_rb.html +0 -1715
  55. data/doc/output/coverage/-Library-Ruby-Gems-gems-rcov-0_8_1_2_0-lib-rcov_rb.html +0 -1598
  56. data/spec/classx/with_extend.rb +0 -27
  57. data/spec/classx/with_include.rb +0 -27
@@ -24,6 +24,7 @@ class YourApp
24
24
  def run
25
25
  # do something!!
26
26
  logger.info('starting your_app')
27
+ attribute_of
27
28
  logger.debug(attribute_of.pretty_inspect)
28
29
  logger.info('end your app')
29
30
  end
@@ -1,15 +1,43 @@
1
1
  require 'classx/attribute'
2
2
  require 'classx/attributes'
3
3
 
4
+ # usage
5
+ #
6
+ # require 'classx'
7
+ # class Point
8
+ # include ClassX
9
+ #
10
+ # has :x, :kind_of => Fixnum
11
+ # has :y, :kind_of => Fixnum
12
+ # end
13
+ #
14
+ # class Point3D < Point
15
+ # has :z, :writable => true, :kind_of => Fixnum, :optional => true
16
+ # end
17
+ #
18
+ # Point.new(:x => 30, :y => 40) #=> <# Point @x=30, @y=40 >
19
+ # point3d = Point3D.new(:x => 30, :y => 40, :z => 50) #=> <# Point3D @x=30, @y=40, @z=50 >
20
+ # point3d.z = 60.0 # raise ClassX::InvalidAttrArgument
4
21
  module ClassX
22
+ autoload :ClassAttributes, 'classx/class_attributes'
23
+ autoload :CAttrs, 'classx/class_attributes'
5
24
  autoload :Validate, 'classx/validate'
6
25
  autoload :Commandable, 'classx/commandable'
7
26
  autoload :Declare, 'classx/declare'
8
- autoload :Util, 'classx/util'
27
+ autoload :Bracketable, 'classx/bracketable'
9
28
  module Role
10
29
  autoload :Logger, 'classx/role/logger'
11
30
  end
12
31
 
32
+ MODULE_USAGE_MAP_OF = {
33
+ :ClassAttributes => :extend,
34
+ :CAttrs => :extend,
35
+ :Commandable => :extend,
36
+ :Declare => :extend,
37
+ :Bracketable => :include,
38
+ :Validate => :include,
39
+ }
40
+
13
41
  class InstanceException < Exception; end
14
42
  class AttrRequiredError < InstanceException; end
15
43
  class InvalidAttrArgument < InstanceException; end
@@ -17,10 +45,10 @@ module ClassX
17
45
  class OptionalAttrShouldBeWritable < Exception; end
18
46
  class RequiredAttrShouldNotHaveDefault < Exception; end
19
47
 
20
- def self.included klass
21
- klass.extend(Attributes)
22
- end
23
-
48
+ # *args is Hash in default.
49
+ # Hash should have attribute's key and valid value for attribute.
50
+ # This method checking required value is setted and taking value is valid to attribute.
51
+ #
24
52
  def initialize *args
25
53
  hash = before_init(*args)
26
54
 
@@ -28,21 +56,20 @@ module ClassX
28
56
  raise ArgumentError, "#{hash.inspect} was wrong as arguments. please specify kind of Hash instance"
29
57
  end
30
58
 
31
- # allow String or Symbol for key
59
+ # allow String or Symbol for key
32
60
  tmp_hash = {}
33
61
  hash.each do |key,val|
34
62
  tmp_hash[key.to_s] = val
35
63
  end
36
64
  hash = tmp_hash
37
65
 
38
- cached_attribute_of = attribute_of
39
66
  hash.each do |key, val|
40
- if cached_attribute_of[key]
41
- cached_attribute_of[key].set val
67
+ if attribute_of[key]
68
+ attribute_of[key].set val
42
69
  end
43
70
  end
44
71
 
45
- cached_attribute_of.each do |key, val|
72
+ attribute_of.each do |key, val|
46
73
  next if val.class.lazy?
47
74
  raise AttrRequiredError, "param: :#{key} is required to #{hash.inspect}" if !val.class.optional? && !val.get
48
75
  end
@@ -50,18 +77,32 @@ module ClassX
50
77
  after_init
51
78
  end
52
79
 
80
+ # return Hash of attribute's name as a key and attribute's meta class instance as a value.
81
+ # for example,
82
+ #
83
+ # class YourClass
84
+ # include ClassX
85
+ # has :x
86
+ # end
87
+ #
88
+ # obj = YourClass.new(:x => 10)
89
+ # obj.attribute_of #=> { "x" => <#<ClassX::Attribute> parent=<# YourClass> ... > }
90
+ #
53
91
  def attribute_of
54
- hash = {}
55
- if self.class.attribute_of
56
- self.class.attribute_of.keys.each do |key|
57
- hash[key] = __send__ "attribute_of:#{key}"
92
+ unless instance_variable_defined?('@__attribute_of') && @__attribute_of
93
+ @__attribute_of = {}
94
+ if self.class.attribute_of
95
+ self.class.attribute_of.keys.each do |key|
96
+ @__attribute_of[key] = __send__ "attribute_of:#{key}"
97
+ end
58
98
  end
59
99
  end
60
100
 
61
- hash
101
+ @__attribute_of
62
102
  end
63
103
 
64
- # just extend point
104
+ # processing initialize argument to hash
105
+ # you can override this method for not taking initializer your classx based class.
65
106
  def before_init *args
66
107
  raise ArgumentError if args.size > 1
67
108
 
@@ -69,7 +110,96 @@ module ClassX
69
110
  hash.nil? ? {} : hash
70
111
  end
71
112
 
113
+ alias process_init_args before_init
114
+
115
+ # automatically called this method on last of #initialize.
116
+ # you can override this method.
72
117
  def after_init
73
118
  end
74
119
 
120
+ # shared implementation for comparing classx based object.
121
+ def == other
122
+ return false unless other.kind_of? self.class
123
+ attribute_of.all? do |key, val|
124
+ val.get == other.__send__(key)
125
+ end
126
+ end
127
+
128
+ UNSERIALIZE_INSTANCE_VARIABLES = ["@__attribute_of", "@__attribute_data_of"]
129
+
130
+ # convert attribute key and value to Hash.
131
+ def to_hash
132
+ result = {}
133
+
134
+ attribute_of.each do |key, val|
135
+ result[key] = val.get
136
+ end
137
+
138
+ result
139
+ end
140
+
141
+ # dupping classx based class.
142
+ def dup
143
+ self.class.new(to_hash)
144
+ end
145
+
146
+ # for Marshal.dump
147
+ def marshal_dump
148
+ dump_of = {}
149
+ dump_of[:attribute_of] = to_hash
150
+ dump_of[:instance_variable_of] = {}
151
+ ( instance_variables.map {|ival| ival.to_s } - UNSERIALIZE_INSTANCE_VARIABLES ).each do |ival|
152
+ dump_of[:instance_variable_of][ival] = instance_variable_get(ival)
153
+ end
154
+
155
+ dump_of
156
+ end
157
+
158
+ # for Marshal.load
159
+ def marshal_load val
160
+ self.attribute_of.each do |k, v|
161
+ v.set(val[:attribute_of][k])
162
+ end
163
+ val[:instance_variable_of].each do |key, val|
164
+ instance_variable_set(key, val)
165
+ end
166
+ end
167
+
168
+ # for YAML.dump
169
+ def to_yaml opts={}
170
+ require 'yaml'
171
+ YAML.quick_emit(self, opts) do |out|
172
+ out.map( taguri, to_yaml_style ) do |map|
173
+ attribute_of = {}
174
+ to_hash.each do |key, val|
175
+ attribute_of[key] = val
176
+ end
177
+ map.add(:attribute_of, attribute_of)
178
+
179
+ instance_variable_of = {}
180
+ ( instance_variables.map {|ival| ival.to_s } - UNSERIALIZE_INSTANCE_VARIABLES ).each do |ival|
181
+ instance_variable_of[ival] = instance_variable_get(ival)
182
+ end
183
+ map.add(:instance_variable_of, instance_variable_of)
184
+ end
185
+ end
186
+ end
187
+
188
+ # for YAML.load
189
+ def yaml_initialize tag, val
190
+ self.attribute_of.each do |k, v|
191
+ v.set(val[:attribute_of][k])
192
+ end
193
+
194
+ val[:instance_variable_of].each do |k, v|
195
+ instance_variable_set(k, v)
196
+ end
197
+ end
198
+
199
+ private
200
+
201
+ def self.included klass
202
+ klass.extend(Attributes)
203
+ end
204
+
75
205
  end
@@ -1,183 +1,284 @@
1
1
  module ClassX
2
- class AttributeFactory
3
- def self.create args
4
- klass = Class.new
5
- klass.class_eval do
6
-
7
- # XXX: Hack for defining class method for klass
8
- tmp_mod = Module.new
9
- tmp_mod.module_eval do
10
- define_method :config do
11
- args
12
- end
2
+ module AttributeMethods #:nodoc:
3
+ module ClassMethods #:nodoc:
4
+ def value_class
5
+ config[:isa] || config[:kind_of]
6
+ end
13
7
 
14
- define_method :value_class do
15
- args[:isa] || args[:kind_of]
16
- end
8
+ # description for attribute
9
+ def desc
10
+ config[:desc]
11
+ end
12
+
13
+ # when this option specify true, not raise error in #initialize without value.
14
+ def optional?
15
+ return config[:optional]
16
+ end
17
+
18
+ # when it lazy option specified, it will not be initialized when #initialize.
19
+ def lazy?
20
+ return config[:lazy]
21
+ end
17
22
 
18
- # description for attribute
19
- define_method :desc do
20
- args[:desc]
23
+ def inspect
24
+ "ClassX::Attribute[#{self.config.inspect}]"
25
+ end
26
+
27
+ module CoerceWithHash #:nodoc:
28
+ def coerce val
29
+ result = val
30
+ config[:coerce].each do |cond, rule|
31
+ case cond
32
+ when Proc
33
+ if cond.call(val)
34
+ result = rule.call(val)
35
+ break
36
+ end
37
+ when Symbol
38
+ if val.respond_to? cond
39
+ result = rule.call(val)
40
+ break
41
+ end
42
+ when Module
43
+ if val.kind_of? cond
44
+ result = rule.call(val)
45
+ break
46
+ end
47
+ end
21
48
  end
22
49
 
23
- # you specify type changing rule with :coerce option.
24
- #
25
- define_method :coerce do |val|
26
- if args[:coerce]
27
- case args[:coerce]
28
- when Hash
29
- result = val
30
- args[:coerce].each do |cond, rule|
31
- case cond
32
- when Proc
33
- if cond.call(val)
34
- result = rule.call(val)
35
- break
36
- end
37
- when Symbol
38
- if val.respond_to? cond
39
- result = rule.call(val)
40
- break
41
- end
42
- when Module
43
- if val.kind_of? cond
44
- result = rule.call(val)
45
- break
46
- end
47
- end
48
- end
50
+ return result
51
+ end
52
+ end
53
+ module CoerceWithArray #:nodoc:
54
+ def coerce val
55
+ result = val
56
+ config[:coerce].each do |item|
57
+ raise unless item.kind_of? Hash
49
58
 
50
- return result
51
- when Array
52
- result = val
53
- args[:coerce].each do |item|
54
- raise unless item.kind_of? Hash
55
-
56
- case item
57
- when Hash
58
- item.each do |cond, rule|
59
-
60
- case cond
61
- when Proc
62
- if cond.call(val)
63
- result = rule.call(val)
64
- break
65
- end
66
- end
67
-
68
- break if result
69
- end
59
+ case item
60
+ when Hash
61
+ item.each do |cond, rule|
62
+ case cond
63
+ when Proc
64
+ if cond.call(val)
65
+ result = rule.call(val)
66
+ break
70
67
  end
71
-
72
- break if result
73
68
  end
74
69
 
75
- return result
70
+ break if result
76
71
  end
77
- else
78
- return val
79
72
  end
73
+
74
+ break if result
80
75
  end
81
76
 
82
- # you can specify :validate option for checking when value is setted.
83
- # you can use :respond_to as shotcut for specifying { :validate => proc {|val| respond_to?(val, true) } }
84
- # you can use :isa or :kind_of as shotcut for specifying { :validate => proc {|val| kind_of?(val) } }
85
- define_method :validate? do |val|
86
- if args[:validate]
87
- case args[:validate]
88
- when Proc
89
- return args[:validate].call(val)
90
- when Regexp
91
- return args[:validate] =~ val
92
- else
93
- return args[:validate] == val
94
- end
95
- elsif mod = ( args[:isa] || args[:kind_of] )
96
- return val.kind_of?(mod)
97
- elsif args[:respond_to]
98
- return val.respond_to?(args[:respond_to], true)
99
- else
100
- # nothing checked.
101
- true
102
- end
77
+ return result
78
+ end
79
+ end
80
+
81
+ module CoerceNothing #:nodoc:
82
+ def coerce val
83
+ val
84
+ end
85
+ end
86
+
87
+ module DefaultWithProc #:nodoc:
88
+ def default parent
89
+ config[:default].call(parent)
90
+ end
91
+ end
92
+ module DefaultWithNoProc #:nodoc:
93
+ def default parent
94
+ begin
95
+ config[:default].dup
96
+ rescue Exception
97
+ config[:default]
103
98
  end
99
+ end
100
+ end
104
101
 
105
- # default paramater for attribute.
106
- # if default is Proc, run Proc every time in instanciate.
107
- define_method :default do |parent|
108
- case args[:default]
109
- when Proc
110
- args[:default].call(parent)
111
- else
112
- begin
113
- args[:default].dup
114
- rescue Exception
115
- args[:default]
102
+ module ValidateWithProc #:nodoc:
103
+ def validate? val
104
+ return config[:validate].call(val)
105
+ end
106
+ end
107
+
108
+ module ValidateWithNotProc #:nodoc:
109
+ def validate? val
110
+ return config[:validate] === val
111
+ end
112
+ end
113
+
114
+ module ValidateEach #:nodoc:
115
+ def validate? val
116
+ return false unless val.respond_to? :all?
117
+
118
+ if self.value_class
119
+ return false unless val.kind_of?(self.value_class)
120
+
121
+ case val
122
+ when Hash
123
+ if config[:validate_each].arity == 2
124
+ val.all? {|item| config[:validate_each].call(*item) }
125
+ else
126
+ ClassX::Validate.validate(val, &config[:validate_each])
116
127
  end
128
+ else
129
+ val.all? {|item| config[:validate_each].call(*item) }
117
130
  end
131
+ else
132
+ val.all? {|item| config[:validate_each].call(*item) }
118
133
  end
134
+ end
135
+ end
119
136
 
120
- # when this option specify true, not raise error in #initialize without value.
121
- define_method :optional? do
122
- return args[:optional]
123
- end
137
+ module ValidateKindOf #:nodoc:
138
+ def validate? val
139
+ return val.kind_of?(self.value_class)
140
+ end
141
+ end
124
142
 
125
- # when it lazy option specified, it will not be initialized when #initialize.
126
- define_method :lazy? do
127
- return args[:lazy]
128
- end
143
+ module ValidateRespondTo #:nodoc:
144
+ def validate? val
145
+ return val.respond_to?(config[:respond_to])
146
+ end
147
+ end
129
148
 
130
- define_method :inspect do
131
- "ClassX::Attribute[#{self.config.inspect}]"
132
- end
149
+ module ValidateNothing #:nodoc:
150
+ def validate? val
151
+ # nothing checked.
152
+ true
133
153
  end
134
- __send__ :extend, tmp_mod
154
+ end
155
+ end
135
156
 
136
- raise ClassX::RequiredAttrShouldNotHaveDefault if args[:optional] == false && !args[:default].nil?
137
- raise ClassX::OptionalAttrShouldBeWritable if args[:optional] && args[:writable] == false
157
+ module InstanceMethods #:nodoc:
158
+ def initialize val
159
+ @parent = val
160
+ @data = nil
161
+ end
138
162
 
139
- define_method :initialize do |val|
140
- @parent = val
141
- @data = nil
142
- end
163
+ def get
164
+ @data ||= self.class.default(@parent)
165
+ end
166
+
167
+ # XXX:
168
+ # you should not call this method except for @parent instance's setter method.
169
+ # It's because caching as instance_variable in @parent instance for performance.
170
+ def set val
171
+ val = self.class.coerce(val)
172
+ raise ClassX::InvalidAttrArgument unless self.class.validate? val
173
+ @data = val
174
+ end
175
+
176
+ def inspect
177
+ "<#ClassX::Attribute:#{object_id} #{ @data.nil? ? '@data=nil' : '@data=' + @data.inspect } @parent=#{@parent} config=#{self.class.config.inspect}>"
178
+ end
179
+ end
180
+ end
181
+
182
+ #
183
+ # generating anonymous class for meta attribute class.
184
+ #
185
+ class AttributeFactory
186
+ #
187
+ # creating anonymous class for meta attribute class.
188
+ def self.create args
189
+ # TODO: hmm, ClassX::Commandable do nothing when freezed.
190
+ #
191
+ # if you would like to change attribute's infomation, it's better to redefine attribute.
192
+ # So, config should freezed.
193
+ # args.each do |key, val|
194
+ # key.freeze
195
+ # val.freeze
196
+ # end
197
+ # args.freeze
143
198
 
144
- define_method :get do
145
- @data ||= self.class.default(@parent)
199
+ raise ClassX::RequiredAttrShouldNotHaveDefault if args[:optional] == false && !args[:default].nil?
200
+ raise ClassX::OptionalAttrShouldBeWritable if args[:optional] && args[:writable] == false
201
+
202
+ klass = Class.new
203
+
204
+ klass.extend(ClassX::AttributeMethods::ClassMethods)
205
+
206
+ # you specify type changing rule with :coerce option.
207
+ if args[:coerce]
208
+ case args[:coerce]
209
+ when Hash
210
+ klass.extend(ClassX::AttributeMethods::ClassMethods::CoerceWithHash)
211
+ when Array
212
+ klass.extend(ClassX::AttributeMethods::ClassMethods::CoerceWithArray)
146
213
  end
214
+ else
215
+ klass.extend(ClassX::AttributeMethods::ClassMethods::CoerceNothing)
216
+ end
147
217
 
148
- define_method :set do |val|
149
- val = self.class.coerce(val)
150
- raise ClassX::InvalidAttrArgument unless self.class.validate? val
151
- @data = val
218
+ # default paramater for attribute.
219
+ # if default is Proc, run Proc every time in instanciate.
220
+ case args[:default]
221
+ when Proc
222
+ klass.extend(ClassX::AttributeMethods::ClassMethods::DefaultWithProc)
223
+ else
224
+ klass.extend(ClassX::AttributeMethods::ClassMethods::DefaultWithNoProc)
225
+ end
226
+
227
+ # you can specify :validate option for checking when value is setted.
228
+ # you can use :respond_to as shotcut for specifying { :validate => proc {|val| respond_to?(val, true) } }
229
+ # you can use :isa or :kind_of as shotcut for specifying { :validate => proc {|val| kind_of?(val) } }
230
+ if args[:validate]
231
+ case args[:validate]
232
+ when Proc
233
+ klass.extend(ClassX::AttributeMethods::ClassMethods::ValidateWithProc)
234
+ else
235
+ klass.extend(ClassX::AttributeMethods::ClassMethods::ValidateWithNotProc)
152
236
  end
237
+ elsif args[:validate_each]
238
+ klass.extend(ClassX::AttributeMethods::ClassMethods::ValidateEach)
239
+ elsif mod = ( args[:isa] || args[:kind_of] )
240
+ klass.extend(ClassX::AttributeMethods::ClassMethods::ValidateKindOf)
241
+ elsif args[:respond_to]
242
+ klass.extend(ClassX::AttributeMethods::ClassMethods::ValidateRespondTo)
243
+ else
244
+ klass.extend(ClassX::AttributeMethods::ClassMethods::ValidateNothing)
245
+ end
153
246
 
154
- # for extending attribute point.
155
- if args[:include]
156
- case args[:include]
157
- when Array
158
- args[:include].each do |mod|
159
- self.__send__ :include, mod
160
- end
161
- else
162
- self.__send__ :include, args[:include]
247
+ # for extending attribute point.
248
+ if args[:include]
249
+ case args[:include]
250
+ when Array
251
+ args[:include].each do |mod|
252
+ klass.__send__ :include, mod
163
253
  end
254
+ else
255
+ klass.__send__ :include, args[:include]
164
256
  end
257
+ end
165
258
 
166
- if args[:extend]
167
- case args[:extend]
168
- when Array
169
- args[:extend].each do |mod|
170
- self.__send__ :extend, mod
171
- end
172
- else
173
- self.__send__ :extend, args[:extend]
259
+ if args[:extend]
260
+ case args[:extend]
261
+ when Array
262
+ args[:extend].each do |mod|
263
+ klass.__send__ :extend, mod
174
264
  end
265
+ else
266
+ klass.__send__ :extend, args[:extend]
175
267
  end
268
+ end
176
269
 
177
- define_method :inspect do
178
- "<#ClassX::Attribute:#{object_id} #{ @data.nil? ? '@data=nil' : '@data=' + @data.inspect } config=#{self.class.config.inspect}>"
270
+ # XXX: Hack for defining class method for klass
271
+ tmp_mod = Module.new
272
+ tmp_mod.module_eval do
273
+ define_method :config do
274
+ args
179
275
  end
180
276
  end
277
+ klass.extend(tmp_mod)
278
+
279
+ klass.class_eval do
280
+ include ClassX::AttributeMethods::InstanceMethods
281
+ end
181
282
 
182
283
  klass
183
284
  end