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.
- data/ChangeLog +408 -2
- data/README +2 -2
- data/Rakefile +4 -3
- data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-block_rb.html +1 -1
- data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-callbacks_rb.html +1 -1
- data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-change_rb.html +1 -1
- data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs-hunk_rb.html +1 -1
- data/doc/output/coverage/-Library-Ruby-Gems-gems-diff-lcs-1_1_2-lib-diff-lcs_rb.html +1 -1
- data/doc/output/coverage/-Library-Ruby-Gems-gems-rcov-0_8_1_2_0-lib-rcov_rb.html +1 -1
- data/doc/output/coverage/index.html +37 -172
- data/doc/output/coverage/lib-classx-attribute_rb.html +788 -0
- 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
- data/doc/output/coverage/lib-classx-validate_rb.html +36 -36
- data/doc/output/coverage/lib-classx_rb.html +74 -151
- data/example/commandable.rb +28 -0
- data/lib/classx.rb +35 -112
- data/lib/classx/attribute.rb +178 -0
- data/lib/classx/attributes.rb +80 -8
- data/lib/classx/commandable.rb +38 -0
- data/lib/classx/validate.rb +1 -1
- data/spec/classx/default_option_spec.rb +140 -0
- data/spec/classx/handles_spec.rb +44 -0
- data/spec/classx/with_coerce.rb +79 -0
- data/spec/classx/with_extend.rb +25 -0
- data/spec/classx/with_include.rb +25 -0
- data/spec/classx/with_multiple_class_spec.rb +23 -0
- data/spec/classx/without_accessor_spec.rb +26 -0
- data/spec/classx/without_anyoption_spec.rb +23 -0
- data/spec/classx/writable_option_spec.rb +73 -0
- data/spec/classx_attributes_spec.rb +30 -0
- data/tasks/basic_config.rake +5 -1
- metadata +22 -15
- data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-drb-drb_rb.html +0 -2373
- data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-drb-eq_rb.html +0 -626
- data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-forwardable_rb.html +0 -828
- data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-pp_rb.html +0 -1257
- data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-prettyprint_rb.html +0 -1506
- data/doc/output/coverage/-System-Library-Frameworks-Ruby_framework-Versions-1_8-usr-lib-ruby-1_8-timeout_rb.html +0 -715
- data/lib/classx.rb.new +0 -102
- 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
|
4
|
-
class
|
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
|
-
|
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
|
-
|
60
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
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
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
-
|
128
|
-
|
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
|
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
|
data/lib/classx/attributes.rb
CHANGED
@@ -1,13 +1,85 @@
|
|
1
1
|
class ClassX
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|