classx 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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