classx 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/ChangeLog +408 -2
  2. data/README +2 -2
  3. data/Rakefile +4 -3
  4. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-block_rb.html +1 -1
  5. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-callbacks_rb.html +1 -1
  6. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-change_rb.html +1 -1
  7. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-hunk_rb.html +1 -1
  8. data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs_rb.html +1 -1
  9. data/doc/output/coverage/-Library-Ruby-Gems-gems-rcov-0_8_1_2_0-lib-rcov_rb.html +1 -1
  10. data/doc/output/coverage/index.html +37 -172
  11. data/doc/output/coverage/lib-classx-attribute_rb.html +788 -0
  12. data/doc/output/coverage/{-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-drb-invokemethod_rb.html → lib-classx-attributes_rb.html} +96 -47
  13. data/doc/output/coverage/lib-classx-validate_rb.html +36 -36
  14. data/doc/output/coverage/lib-classx_rb.html +74 -151
  15. data/example/commandable.rb +28 -0
  16. data/lib/classx.rb +35 -112
  17. data/lib/classx/attribute.rb +178 -0
  18. data/lib/classx/attributes.rb +80 -8
  19. data/lib/classx/commandable.rb +38 -0
  20. data/lib/classx/validate.rb +1 -1
  21. data/spec/classx/default_option_spec.rb +140 -0
  22. data/spec/classx/handles_spec.rb +44 -0
  23. data/spec/classx/with_coerce.rb +79 -0
  24. data/spec/classx/with_extend.rb +25 -0
  25. data/spec/classx/with_include.rb +25 -0
  26. data/spec/classx/with_multiple_class_spec.rb +23 -0
  27. data/spec/classx/without_accessor_spec.rb +26 -0
  28. data/spec/classx/without_anyoption_spec.rb +23 -0
  29. data/spec/classx/writable_option_spec.rb +73 -0
  30. data/spec/classx_attributes_spec.rb +30 -0
  31. data/tasks/basic_config.rake +5 -1
  32. metadata +22 -15
  33. data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-drb-drb_rb.html +0 -2373
  34. data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-drb-eq_rb.html +0 -626
  35. data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-forwardable_rb.html +0 -828
  36. data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-pp_rb.html +0 -1257
  37. data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-prettyprint_rb.html +0 -1506
  38. data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-timeout_rb.html +0 -715
  39. data/lib/classx.rb.new +0 -102
  40. data/spec/classx_spec.rb +0 -261
@@ -0,0 +1,28 @@
1
+ $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib' )))
2
+ require 'classx'
3
+ require 'classx/commandable'
4
+
5
+ $ClassXCommandableMappingOf[Symbol] = String
6
+
7
+ class YourApp < ClassX
8
+ extend Commandable
9
+
10
+ has :arg1,
11
+ :kind_of => Symbol,
12
+ :desc => 'please specify arg1',
13
+ :coerce => { String => proc {|val| val.to_sym } }
14
+
15
+ has :arg2,
16
+ :kind_of => Integer,
17
+ :desc => "this is arg2",
18
+ :optional => true
19
+
20
+ def run
21
+ # do something!!
22
+ p attribute_of
23
+ end
24
+ end
25
+
26
+ if $0 == __FILE__
27
+ YourApp.from_argv.run
28
+ end
data/lib/classx.rb CHANGED
@@ -1,139 +1,62 @@
1
+ require 'classx/attribute'
2
+ require 'classx/attributes'
1
3
 
2
4
  class ClassX
3
- class AttrRequiredError < Exception; end
4
- class InvalidAttrArgument < Exception; end
5
+ class InstanceException < Exception; end
6
+ class AttrRequiredError < InstanceException; end
7
+ class InvalidAttrArgument < InstanceException; end
5
8
  class LazyOptionShouldHaveDefault < Exception; end
6
9
  class OptionalAttrShouldBeWritable < Exception; end
7
10
  class RequiredAttrShouldNotHaveDefault < Exception; end
8
- class <<self
9
- def has name, attrs={}
10
- name = name.to_s
11
11
 
12
- setter_definition = ''
13
- if !attrs[:respond_to].nil?
14
- setter_definition += <<-END_OF_RESPOND_TO
15
- raise InvalidAttrArgument, "param :#{name}'s value \#{val.inspect} should respond_to #{attrs[:respond_to]}}" unless val.respond_to? #{attrs[:respond_to]}
16
- END_OF_RESPOND_TO
17
- end
18
- if !attrs[:kind_of].nil?
19
- setter_definition += <<-END_OF_KIND_OF
20
- raise InvalidAttrArgument, "param :#{name}'s value \#{val.inspect} should kind_of #{attrs[:kind_of]}" unless val.kind_of? #{attrs[:kind_of]}
21
- END_OF_KIND_OF
22
- end
23
-
24
- self.class_eval <<-END_OF_ACCESSOR
25
- attr_reader "#{name}"
26
-
27
- def #{name}= val
28
- #{setter_definition}
29
- @#{name} = val
30
- end
31
- END_OF_ACCESSOR
32
-
33
- if attrs[:default].nil?
34
- raise LazyOptionShouldHaveDefault, "in :#{name}: :lazy option need specifying :default" if attrs[:lazy]
35
- else
36
- # when you specify :optional to false explicitly, raise Error.
37
- if attrs[:optional].nil?
38
- attrs[:optional] = true
39
- end
40
- raise RequiredAttrShouldNotHaveDefault, "in :#{name}: required attribute should not have :default option" unless attrs[:optional]
41
- case attrs[:default]
42
- when Proc
43
- register_attr_default_value_proc name, &attrs[:default]
44
- else
45
- register_attr_default_value name, attrs[:default]
46
- end
47
- end
48
-
49
- if attrs[:optional]
50
- if attrs[:writable].nil?
51
- attrs[:writable] = true
52
- else
53
- raise OptionalAttrShouldBeWritable unless attrs[:writable]
54
- end
55
- else
56
- register_attr_required name
57
- end
12
+ extend Attributes
58
13
 
59
- unless attrs[:writable]
60
- __send__ :private,"#{name}="
61
- end
14
+ def initialize *args
15
+ hash = before_init(*args)
62
16
 
17
+ unless hash && hash.kind_of?(Hash)
18
+ raise ArgumentError, "#{hash.inspect} was wrong as arguments. please specify kind of Hash instance"
63
19
  end
64
20
 
65
- def register_attr_default_value name, value
66
- self.class_eval do
67
- define_method "set_attr_default_value_of[#{name}]" do
68
- self.__send__ "#{name}=", value
69
- end
70
-
71
- private "set_attr_default_value_of[#{name}]"
72
- end
21
+ # allow String or Symbol for key
22
+ tmp_hash = {}
23
+ hash.each do |key,val|
24
+ tmp_hash[key.to_s] = val
73
25
  end
26
+ hash = tmp_hash
74
27
 
75
- def register_attr_default_value_proc name, &block
76
- self.class_eval do
77
- define_method "set_attr_default_value_of[#{name}]" do
78
- self.__send__ "#{name}=", block.call(self)
79
- end
80
-
81
- private "set_attr_default_value_of[#{name}]"
28
+ cached_attribute_of = attribute_of
29
+ hash.each do |key, val|
30
+ if cached_attribute_of[key]
31
+ cached_attribute_of[key].set val
82
32
  end
83
33
  end
84
34
 
85
- def register_attr_required name
86
- define_method "attr_required[#{name}]" do
87
- end
88
-
89
- private "attr_required[#{name}]"
35
+ cached_attribute_of.each do |key, val|
36
+ next if val.class.lazy?
37
+ raise AttrRequiredError, "param: :#{key} is required to #{hash.inspect}" if !val.class.optional? && !val.get
90
38
  end
91
39
 
92
- ATTR_REGEX = /^([^=]*?)=$/
93
- def attributes
94
- ( public_instance_methods + private_instance_methods ).select {|meth|
95
- meth.to_s =~ ATTR_REGEX
96
- }.map {|item|
97
- item.to_s.sub(ATTR_REGEX) { $1 }
98
- }
99
- end
100
-
101
- ATTR_REQUIRED_REGEX = /^attr_required\[(.*?)\]/
102
- def required_attributes
103
- private_instance_methods.select {|meth|
104
- meth.to_s =~ ATTR_REQUIRED_REGEX
105
- }.map {|item|
106
- item.sub(ATTR_REQUIRED_REGEX) { $1 }
107
- }
108
- end
40
+ after_init
109
41
  end
110
42
 
111
- def initialize hash={}
112
- before_init hash
113
-
114
- unless hash && hash.kind_of?(Hash)
115
- raise ArgumentError, "#{hash.inspect} was wrong as arguments. please specify kind of Hash instance"
116
- end
117
-
118
- hash = hash.inject({}) {|h,item| h[item.first.to_s] = item.last; h } # allow String or Symbol for key
119
- self.class.required_attributes.each do |name|
120
- raise AttrRequiredError, "param :#{name} is required to #{hash.inspect}" unless hash.keys.include?(name)
121
- end
122
- hash.each do |key,val|
123
- if respond_to? "#{key}=", true
124
- __send__ "#{key}=", val
43
+ def attribute_of
44
+ hash = {}
45
+ if self.class.attribute_of
46
+ self.class.attribute_of.keys.each do |key|
47
+ hash[key] = __send__ "attribute_of:#{key}"
125
48
  end
126
49
  end
127
- private_methods.select do |meth|
128
- meth.to_s =~ /^set_attr_default_value_of\[(.*?)\]$/
129
- end.each do |meth|
130
- __send__ meth
131
- end
132
- after_init
50
+
51
+ hash
133
52
  end
134
53
 
135
54
  # just extend point
136
- def before_init hash
55
+ def before_init *args
56
+ raise ArgumentError if args.size > 1
57
+
58
+ hash = args.first
59
+ hash.nil? ? {} : hash
137
60
  end
138
61
 
139
62
  def after_init
@@ -0,0 +1,178 @@
1
+ class 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
13
+
14
+ define_method :value_class do
15
+ args[:isa] || args[:kind_of]
16
+ end
17
+
18
+ # description for attribute
19
+ define_method :desc do
20
+ args[:desc]
21
+ end
22
+
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
49
+
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
70
+ end
71
+
72
+ break if result
73
+ end
74
+
75
+ return result
76
+ end
77
+ else
78
+ return val
79
+ end
80
+ end
81
+
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
103
+ end
104
+
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
+ args[:default]
113
+ end
114
+ end
115
+
116
+ # when this option specify true, not raise error in #initialize without value.
117
+ define_method :optional? do
118
+ return args[:optional]
119
+ end
120
+
121
+ # when it lazy option specified, it will not be initialized when #initialize.
122
+ define_method :lazy? do
123
+ return args[:lazy]
124
+ end
125
+
126
+ end
127
+ __send__ :extend, tmp_mod
128
+
129
+ raise ClassX::RequiredAttrShouldNotHaveDefault if args[:optional] == false && !args[:default].nil?
130
+ raise ClassX::OptionalAttrShouldBeWritable if args[:optional] && args[:writable] == false
131
+
132
+ define_method :initialize do |val|
133
+ @parent = val
134
+ @data = nil
135
+ end
136
+
137
+ define_method :get do
138
+ @data ||= self.class.default(@parent)
139
+ end
140
+
141
+ define_method :set do |val|
142
+ val = self.class.coerce(val)
143
+ raise ClassX::InvalidAttrArgument unless self.class.validate? val
144
+ @data = val
145
+ end
146
+
147
+ # for extending attribute point.
148
+ if args[:include]
149
+ case args[:include]
150
+ when Array
151
+ args[:include].each do |mod|
152
+ self.__send__ :include, mod
153
+ end
154
+ else
155
+ self.__send__ :include, args[:include]
156
+ end
157
+ end
158
+
159
+ if args[:extend]
160
+ case args[:extend]
161
+ when Array
162
+ args[:extend].each do |mod|
163
+ self.__send__ :extend, mod
164
+ end
165
+ else
166
+ self.__send__ :extend, args[:extend]
167
+ end
168
+ end
169
+
170
+ define_method :inspect do
171
+ "<#ClassX::Attribute #{self.class.config.inspect}:#{object_id} #{ @data.nil? ? '' : '@data=' + @data.inspect } >"
172
+ end
173
+ end
174
+
175
+ klass
176
+ end
177
+ end
178
+ end
@@ -1,13 +1,85 @@
1
1
  class ClassX
2
- class Attributes
3
- attr_reader :name, :reader, :setter, :writable, :required
4
- def initialize name, options={ :is => :ro }
5
- @name = name.to_s
6
-
7
- if options[:writable]
8
- setter = proc.call {
9
- }
2
+ module Attributes
3
+ ATTRIBUTE_REGEX = /\Aattribute_of:(\w+)\z/
4
+
5
+ def attribute_of
6
+ unless @__attribute_of
7
+ @__attribute_of = {}
8
+ private_instance_methods.select {|meth| meth.to_s =~ ATTRIBUTE_REGEX }.each do |meth|
9
+ key = meth.to_s.sub(ATTRIBUTE_REGEX) { $1 }
10
+ @__attribute_of[key] = __send__ "attribute_of:#{key}"
11
+ end
10
12
  end
13
+
14
+ @__attribute_of
11
15
  end
16
+
17
+ private
18
+ def define_attribute name, attribute
19
+ klass_attribute = ClassX::AttributeFactory.create(attribute)
20
+ mod = Module.new
21
+ mod.module_eval do
22
+ define_method "attribute_of:#{name}" do
23
+ klass_attribute
24
+ end
25
+
26
+ private "attribute_of:#{name}"
27
+ end
28
+ self.extend(mod)
29
+ @__attribute_of ||= {}
30
+ @__attribute_of[name] = klass_attribute
31
+
32
+ define_method "attribute_of:#{name}" do
33
+ @__attribute_of ||= {}
34
+ @__attribute_of[name] ||= klass_attribute.new(self)
35
+ end
36
+
37
+ private "attribute_of:#{name}"
38
+ end
39
+
40
+ def add_attribute name, attrs={}
41
+ name = name.to_s
42
+
43
+ define_attribute(name, attrs)
44
+
45
+ define_method name do
46
+ attribute_of[name].get
47
+ end
48
+
49
+ define_method "#{name}=" do |val|
50
+ attribute_of[name].set val
51
+ end
52
+
53
+ cached_attribute_of = attribute_of
54
+ if cached_attribute_of[name]
55
+ unless cached_attribute_of[name].config[:writable]
56
+ private "#{name}="
57
+ end
58
+
59
+ if cached_attribute_of[name].config[:handles]
60
+ case cached_attribute_of[name].config[:handles]
61
+ when Hash
62
+ cached_attribute_of[name].config[:handles].each do |before, after|
63
+ define_method before do
64
+ attribute_of[name].get.__send__ after
65
+ end
66
+ end
67
+ when Array
68
+ cached_attribute_of[name].config[:handles].each do |meth|
69
+ define_method meth do
70
+ attribute_of[name].get.__send__ meth
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ alias has add_attribute
79
+
80
+ def included klass
81
+ klass.extend self
82
+ end
83
+
12
84
  end
13
85
  end