classx 0.0.1 → 0.0.2

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 (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