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
@@ -1,12 +1,49 @@
1
1
  module ClassX
2
+ # you can define classx base class using DSL
3
+ #
4
+ # require 'classx'
5
+ # require 'classx/declare'
6
+ # include ClassX::Declare
7
+ #
8
+ # classx :Klass do
9
+ # has :x
10
+ # end
11
+ #
12
+ # Klass.new(:x => 10)
13
+ #
14
+ # or you can define nested.
15
+ #
16
+ # classx :Klass do
17
+ # classx :Klass2 do
18
+ # has :x
19
+ # end
20
+ # end
21
+ #
22
+ # #=> define Klass::Klass2
23
+ #
2
24
  module Declare
3
- def classx name, &block
25
+ def classx name, options=[] , ctx=_guess_parent_namespace(), &block
26
+ options.push(:Declare)
4
27
  klass = Class.new
5
28
  klass.class_eval do
29
+ options.each do |mod|
30
+ __send__ ::ClassX::MODULE_USAGE_MAP_OF[mod], ::ClassX.const_get(mod)
31
+ end
6
32
  include(ClassX)
7
33
  end
8
- klass.class_eval &block
9
- eval "::#{name.capitalize} = klass"
34
+ klass.class_eval(&block)
35
+ ctx.module_eval do
36
+ const_set(name.to_s.capitalize, klass)
37
+ end
10
38
  end
39
+
40
+ private
41
+ def _guess_parent_namespace klass=self
42
+ if self.respond_to? :module_eval
43
+ klass
44
+ else
45
+ klass.class
46
+ end
47
+ end
11
48
  end
12
49
  end
@@ -5,10 +5,11 @@ module ClassX
5
5
  # SYNOPSIS
6
6
  #
7
7
  # require 'classx/role/logger'
8
- # class YourApp < ClassX
8
+ # class YourApp
9
+ # include ClassX
9
10
  # extends ClassX::Commandable
10
11
  # include ClassX::Role::Logger
11
- #
12
+ #
12
13
  # def run
13
14
  # logger.debug("debug!!")
14
15
  # # do something
@@ -21,10 +22,15 @@ module ClassX
21
22
  #
22
23
  # SEE ALSO: +ClassX::Commandable+
23
24
  #
24
- module Logger
25
+ module Logger #:doc:
25
26
  extend ClassX::Attributes
26
27
 
27
- module ToLogLevel
28
+ # added log_level's attribute class to utility method
29
+ #
30
+ # your_class.attribute_of['log_level'].to_log_level #=> 0
31
+ # your_class.attribute_of['log_level'].to_i # alias for to_log_level
32
+ #
33
+ module ToLogLevel #:nodoc:
28
34
  def to_log_level str=self.get
29
35
  ::Logger::Severity.const_get(str.upcase)
30
36
  end
@@ -32,10 +38,13 @@ module ClassX
32
38
  alias to_i to_log_level
33
39
  end
34
40
 
35
- has :logger,
36
- :lazy => true,
41
+ # dummy method for rdoc.
42
+ def logger; end
43
+
44
+ has :logger,
37
45
  :optional => true,
38
46
  :no_cmd_option => true,
47
+ :lazy => true,
39
48
  :default => proc {|mine|
40
49
  logger = ::Logger.new(mine.logfile)
41
50
  logger.level = mine.attribute_of['log_level'].to_i
@@ -44,19 +53,14 @@ module ClassX
44
53
  logger
45
54
  }
46
55
 
47
- has :log_level,
56
+ has :log_level,
48
57
  :kind_of => String,
49
58
  :desc => 'log_level (debug|info|warn|error|fatal) (default info)',
50
59
  :optional => true,
51
60
  :default => 'info',
52
61
  :include => ToLogLevel,
53
62
  :validate => proc {|val|
54
- begin
55
- ::Logger::Severity.const_get(val.upcase)
56
- rescue NameError => e
57
- return false
58
- end
59
- true
63
+ val && ::Logger::Severity.const_defined?(val.to_s.upcase)
60
64
  }
61
65
 
62
66
  has :logfile,
@@ -1,38 +1,40 @@
1
+ #
2
+ # for validatation Hash parameter declaretively.
3
+ #
4
+ # require 'classx/validate'
5
+ #
6
+ # class YourClass
7
+ #
8
+ # def run params
9
+ # validated_prams = Class::Validate.validate params do
10
+ # has :x
11
+ # has :y, :default => "hoge", :kind_of => Hash
12
+ # end
13
+ #
14
+ # # do something with params
15
+ #
16
+ # end
17
+ # end
18
+ #
19
+ # YourClass.new.run(:x => 10) # raise ClassX::AttrRequiredError
20
+ #
1
21
  module ClassX::Validate
2
22
  private
3
- #
4
- # for validatation Hash parameter declaretively.
5
- #
6
- # require 'classx/validate'
7
- #
8
- # class YourClass
9
- # include ClassX::Validate
10
- #
11
- # def run params
12
- # validate params do
13
- # has :x
14
- # has :y, :default => "hoge", :kind_of => Hash
15
- # end
16
- #
17
- # # do something with params
18
- #
19
- # end
20
- # end
21
- #
22
- # YourClass.new.run(:x => 10) # raise ClassX::AttrRequiredError
23
- #
24
- def validate hash, &block
23
+ def validate hash, &block #:doc:
25
24
  # FIXME: it's experimental feature for caching validate class.
26
25
  # it can use class variable because it use caller[0] as key.
27
- @@__validate_cached ||= {}
26
+ @@__validate_cached ||= {}
28
27
  uniq_key = caller[0]
29
28
  unless @@__validate_cached[uniq_key]
30
29
  @@__validate_cached[uniq_key] = Class.new
31
30
  @@__validate_cached[uniq_key].class_eval do
32
31
  include ::ClassX
32
+ include ::ClassX::Bracketable
33
33
  end
34
34
  @@__validate_cached[uniq_key].class_eval(&block)
35
35
  end
36
- @@__validate_cached[uniq_key].new hash
36
+ @@__validate_cached[uniq_key].new hash
37
37
  end
38
+
39
+ module_function :validate
38
40
  end
@@ -8,19 +8,28 @@ describe ClassX do
8
8
  @class1 = Class.new
9
9
  @class1.class_eval do
10
10
  include ClassX
11
- has :x, :handles => { :x_inspect => :inspect }
11
+ has :x, :handles => {
12
+ :x_inspect => :inspect,
13
+ :x_slice => :slice
14
+ }
12
15
  end
13
16
  end
14
17
 
15
18
  it 'should respond_to x_inspect method' do
16
- obj = Object.new
17
- @class1.new(:x => obj).should be_respond_to(:x_inspect)
19
+ obj = []
20
+ @class1.new(:x => obj).respond_to?(:x_inspect).should be_true
18
21
  end
19
22
 
20
23
  it 'should delegate method to value' do
21
- obj = Object.new
24
+ obj = []
22
25
  @class1.new(:x => obj).x_inspect.should == obj.inspect
23
26
  end
27
+
28
+ it 'should delegate method with args to value' do
29
+ obj = []
30
+ obj.push 1
31
+ @class1.new(:x => obj).x_slice(0).should == obj.slice(0)
32
+ end
24
33
  end
25
34
 
26
35
  describe 'with handles option as Array' do
@@ -29,19 +38,25 @@ describe ClassX do
29
38
  @class1.class_eval do
30
39
  include ClassX
31
40
 
32
- has :x, :handles => [ :length ]
41
+ has :x, :handles => [ :length, :slice ]
33
42
  end
34
43
  end
35
44
 
36
45
  it 'should respond_to item name method' do
37
46
  obj = [1, 2, 3]
38
- @class1.new(:x => obj).should be_respond_to(:length)
47
+ @class1.new(:x => obj).respond_to?(:length).should be_true
39
48
  end
40
49
 
41
50
  it 'should delegate method to the same item name' do
42
51
  obj = [1, 2, 3]
43
52
  @class1.new(:x => obj).length.should == obj.length
44
53
  end
54
+
55
+ it 'should delegate method with args to value' do
56
+ obj = [1, 2, 3]
57
+ obj.push 1
58
+ @class1.new(:x => obj).slice(0).should == obj.slice(0)
59
+ end
45
60
  end
46
61
  end
47
62
  end
@@ -0,0 +1,57 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+ require 'classx'
3
+
4
+ describe ClassX do
5
+ describe 'Serialize' do
6
+ before(:all) do
7
+ klass = Class.new
8
+ klass.class_eval do
9
+ include ClassX
10
+ has :x, :default => proc { [ "abc" ] }
11
+ has :y, :default => proc { {"foo" => "bar" } }
12
+ end
13
+
14
+ Object.const_set(:DumpedObject, klass)
15
+ end
16
+
17
+ it 'should be duplicatable' do
18
+ obj = DumpedObject.new(:x => ["not abc"])
19
+ obj2 = obj.dup
20
+ obj2.should == obj
21
+ end
22
+
23
+ it 'should be serialized with Marshal' do
24
+ obj = DumpedObject.new(:x => ["not abc"])
25
+ dump = Marshal.dump(obj)
26
+ Marshal.load(dump).should == obj
27
+ end
28
+
29
+ it 'should be restored instance_variables with Marshal' do
30
+ obj = DumpedObject.new(:x => ["not abc"])
31
+ val = "hoge"
32
+ obj.instance_variable_set("@hoge", val)
33
+
34
+ dump = Marshal.dump(obj)
35
+ new_obj = Marshal.load(dump)
36
+ new_obj.instance_variable_get("@hoge").should == val
37
+ end
38
+
39
+ it 'should be serialized with YAML' do
40
+ require 'yaml'
41
+ obj = DumpedObject.new(:x => ["not abc"])
42
+ dump = obj.to_yaml
43
+ YAML.load(dump).should == obj
44
+ end
45
+
46
+ it 'should be restored instance_variables with YAML' do
47
+ require 'yaml'
48
+ obj = DumpedObject.new(:x => ["not abc"])
49
+ val = "hoge"
50
+ obj.instance_variable_set("@hoge", val)
51
+
52
+ dump = obj.to_yaml
53
+ new_obj = YAML.load(dump)
54
+ new_obj.instance_variable_get("@hoge").should == val
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+ require 'classx'
3
+
4
+ describe ClassX do
5
+ describe '#has' do
6
+ describe 'with extend' do
7
+ describe "take a module as value" do
8
+ before do
9
+ @class = Class.new
10
+ mod = Module.new
11
+ mod.module_eval do
12
+ define_method :test do
13
+ :test
14
+ end
15
+ end
16
+ @class.class_eval do
17
+ include ClassX
18
+
19
+ has :x, :extend => mod
20
+ end
21
+ end
22
+
23
+ it 'attrubute :x should have test class method' do
24
+ @class.new(:x => 10).attribute_of['x'].class.test.should == :test
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "take multi modules as value" do
30
+ before do
31
+ @class = Class.new
32
+ mod1 = Module.new
33
+ mod1.module_eval do
34
+ define_method :test1 do
35
+ :test1
36
+ end
37
+ end
38
+
39
+ mod2 = Module.new
40
+ mod2.module_eval do
41
+ define_method :test2 do
42
+ :test2
43
+ end
44
+ end
45
+ @class.class_eval do
46
+ include ClassX
47
+
48
+ has :x, :extend => [ mod1, mod2 ]
49
+ end
50
+ end
51
+
52
+ it 'attrubute :x should have #test method' do
53
+ @class.new(:x => 10).attribute_of['x'].class.test1.should == :test1
54
+ @class.new(:x => 10).attribute_of['x'].class.test2.should == :test2
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,58 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+ require 'classx'
3
+
4
+ describe ClassX do
5
+ describe '#has' do
6
+ describe 'with include' do
7
+ describe "take a module as value" do
8
+ before do
9
+ @class = Class.new
10
+ mod = Module.new
11
+ mod.module_eval do
12
+ define_method :test do
13
+ :test
14
+ end
15
+ end
16
+ @class.class_eval do
17
+ include ClassX
18
+
19
+ has :x, :include => mod
20
+ end
21
+ end
22
+
23
+ it 'attrubute :x should have #test method' do
24
+ @class.new(:x => 10).attribute_of['x'].test.should == :test
25
+ end
26
+ end
27
+
28
+ describe "take multi modules as value" do
29
+ before do
30
+ @class = Class.new
31
+ mod1 = Module.new
32
+ mod1.module_eval do
33
+ define_method :test1 do
34
+ :test1
35
+ end
36
+ end
37
+
38
+ mod2 = Module.new
39
+ mod2.module_eval do
40
+ define_method :test2 do
41
+ :test2
42
+ end
43
+ end
44
+ @class.class_eval do
45
+ include ClassX
46
+
47
+ has :x, :include => [ mod1, mod2 ]
48
+ end
49
+ end
50
+
51
+ it 'attrubute :x should have #test method' do
52
+ @class.new(:x => 10).attribute_of['x'].test1.should == :test1
53
+ @class.new(:x => 10).attribute_of['x'].test2.should == :test2
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,363 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+ require 'classx'
3
+
4
+ describe ClassX do
5
+ describe '#has' do
6
+ describe 'with :validate option' do
7
+ describe 'when value is Proc' do
8
+ before do
9
+ @class = Class.new
10
+ @class.class_eval do
11
+ include ClassX
12
+ has :x,
13
+ :writable => true,
14
+ :validate => proc {|val| val.kind_of? Fixnum }
15
+ end
16
+ end
17
+
18
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
19
+ lambda { @class.new(:x => "str") }.should raise_error(ClassX::InvalidAttrArgument)
20
+ end
21
+
22
+ it 'should not raise error when it take valid args on instanciate' do
23
+ lambda { @class.new(:x => 10) }.should_not raise_error(Exception)
24
+ end
25
+
26
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
27
+ instance = @class.new(:x => 10)
28
+ lambda { instance.x = "str" }.should raise_error(ClassX::InvalidAttrArgument)
29
+ end
30
+
31
+ it 'should not raise error when it take valid args on update value' do
32
+ instance = @class.new(:x => 10)
33
+ lambda { instance.x = 20 }.should_not raise_error(Exception)
34
+ end
35
+ end
36
+
37
+ describe "when value is Regexp" do
38
+ before do
39
+ @class = Class.new
40
+ @class.class_eval do
41
+ include ClassX
42
+ has :x,
43
+ :writable => true,
44
+ :validate => /^test_/
45
+
46
+ end
47
+ end
48
+
49
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on instanciate' do
50
+ lambda { @class.new(:x => "hoge") }.should raise_error(ClassX::InvalidAttrArgument)
51
+ end
52
+
53
+ it 'should raise ClassX::InvalidAttrArgument when it take none String argument on instanciate' do
54
+ lambda { @class.new(:x => :hoge ) }.should raise_error(ClassX::InvalidAttrArgument)
55
+ end
56
+
57
+ it 'should not raise error when it take valid args on instanciate' do
58
+ lambda { @class.new(:x => "test_hoge") }.should_not raise_error(Exception)
59
+ end
60
+
61
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
62
+ instance = @class.new(:x => 'test_hoge')
63
+ lambda { instance.x = "hoge" }.should raise_error(ClassX::InvalidAttrArgument)
64
+ end
65
+
66
+ it 'should raise ClassX::InvalidAttrArgument when it take none String argument on update value' do
67
+ instance = @class.new(:x => 'test_hoge')
68
+ lambda { instance.x = :fuga }.should raise_error(ClassX::InvalidAttrArgument)
69
+ end
70
+
71
+ it 'should not raise error when it take valid args on update value' do
72
+ instance = @class.new(:x => 'test_hoge')
73
+ lambda { instance.x = "test_fuga" }.should_not raise_error(Exception)
74
+ end
75
+ end
76
+
77
+ describe 'when value is not Regexp or Proc' do
78
+ before do
79
+ @class = Class.new
80
+ @class.class_eval do
81
+ include ClassX
82
+ has :x,
83
+ :writable => true,
84
+ :validate => "validate_value"
85
+
86
+ end
87
+ end
88
+
89
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
90
+ lambda { @class.new(:x => "hoge") }.should raise_error(ClassX::InvalidAttrArgument)
91
+ end
92
+
93
+ it 'should not raise error when it take valid args on instanciate' do
94
+ lambda { @class.new(:x => "validate_value") }.should_not raise_error(Exception)
95
+ end
96
+
97
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
98
+ instance = @class.new(:x => "validate_value")
99
+ lambda { instance.x = "hoge" }.should raise_error(ClassX::InvalidAttrArgument)
100
+ end
101
+
102
+ it 'should not raise error when it take valid args on update value' do
103
+ instance = @class.new(:x => "validate_value")
104
+ lambda { instance.x = "validate_value" }.should_not raise_error(Exception)
105
+ end
106
+ end
107
+ end
108
+
109
+ describe 'with :kind_of option' do
110
+ before do
111
+ @class = Class.new
112
+ @class.class_eval do
113
+ include ClassX
114
+ has :x,
115
+ :writable => true,
116
+ :kind_of => Fixnum
117
+ end
118
+ end
119
+
120
+ it 'should define value_class' do
121
+ @class.attribute_of['x'].value_class.should == Fixnum
122
+ end
123
+
124
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
125
+ lambda { @class.new(:x => "str") }.should raise_error(ClassX::InvalidAttrArgument)
126
+ end
127
+
128
+ it 'should not raise error when it take valid args on instanciate' do
129
+ lambda { @class.new(:x => 10) }.should_not raise_error(Exception)
130
+ end
131
+
132
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
133
+ instance = @class.new(:x => 10)
134
+ lambda { instance.x = "str" }.should raise_error(ClassX::InvalidAttrArgument)
135
+ end
136
+
137
+ it 'should not raise error when it take valid args on update value' do
138
+ instance = @class.new(:x => 10)
139
+ lambda { instance.x = 20 }.should_not raise_error(Exception)
140
+ end
141
+ end
142
+
143
+ describe 'with :isa option' do
144
+ before do
145
+ @class = Class.new
146
+ @class.class_eval do
147
+ include ClassX
148
+ has :x,
149
+ :writable => true,
150
+ :isa => Fixnum
151
+ end
152
+ end
153
+
154
+ it 'should define value_class' do
155
+ @class.attribute_of['x'].value_class.should == Fixnum
156
+ end
157
+
158
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
159
+ lambda { @class.new(:x => "str") }.should raise_error(ClassX::InvalidAttrArgument)
160
+ end
161
+
162
+ it 'should not raise error when it take valid args on instanciate' do
163
+ lambda { @class.new(:x => 10) }.should_not raise_error(Exception)
164
+ end
165
+
166
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
167
+ instance = @class.new(:x => 10)
168
+ lambda { instance.x = "str" }.should raise_error(ClassX::InvalidAttrArgument)
169
+ end
170
+
171
+ it 'should not raise error when it take valid args on update value' do
172
+ instance = @class.new(:x => 10)
173
+ lambda { instance.x = 20 }.should_not raise_error(Exception)
174
+ end
175
+ end
176
+
177
+ describe 'with :respond_to option' do
178
+ before do
179
+ @class = Class.new
180
+ @class.class_eval do
181
+ include ClassX
182
+ has :x,
183
+ :writable => true,
184
+ :respond_to => :to_int
185
+ end
186
+ end
187
+
188
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
189
+ lambda { @class.new(:x => "str") }.should raise_error(ClassX::InvalidAttrArgument)
190
+ end
191
+
192
+ it 'should not raise error when it take valid args on instanciate' do
193
+ lambda { @class.new(:x => 10) }.should_not raise_error(Exception)
194
+ end
195
+
196
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
197
+ instance = @class.new(:x => 10)
198
+ lambda { instance.x = "str" }.should raise_error(ClassX::InvalidAttrArgument)
199
+ end
200
+
201
+ it 'should not raise error when it take valid args on update value' do
202
+ instance = @class.new(:x => 10)
203
+ lambda { instance.x = 20 }.should_not raise_error(Exception)
204
+ end
205
+ end
206
+
207
+ describe 'with :validate_each option and take Array' do
208
+ before do
209
+ @class = Class.new
210
+ @class.class_eval do
211
+ include ClassX
212
+ has :x,
213
+ :writable => true,
214
+ :validate_each => proc {|item| item.kind_of? String }
215
+ end
216
+ end
217
+
218
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
219
+ lambda { @class.new(:x => [ "str", 10 ]) }.should raise_error(ClassX::InvalidAttrArgument)
220
+ end
221
+
222
+ it 'should not raise error when it take valid args on instanciate' do
223
+ lambda { @class.new(:x => ['abc', 'def'] ) }.should_not raise_error(Exception)
224
+ end
225
+
226
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
227
+ instance = @class.new(:x => ['abc', 'def' ])
228
+ lambda { instance.x = ["str", 10] }.should raise_error(ClassX::InvalidAttrArgument)
229
+ end
230
+
231
+ it 'should not raise error when it take valid args on update value' do
232
+ instance = @class.new(:x => ['abc', 'def'])
233
+ lambda { instance.x = ['ghi', 'jkl'] }.should_not raise_error(Exception)
234
+ end
235
+ end
236
+
237
+ describe 'with :validate_each option and take Array' do
238
+ before do
239
+ @class = Class.new
240
+ @class.class_eval do
241
+ include ClassX
242
+ has :x,
243
+ :writable => true,
244
+ :kind_of => Array,
245
+ :validate_each => proc {|item| item.kind_of? String }
246
+ end
247
+ end
248
+
249
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
250
+ lambda { @class.new(:x => [ "str", 10 ]) }.should raise_error(ClassX::InvalidAttrArgument)
251
+ end
252
+
253
+ it 'should not raise error when it take valid args on instanciate' do
254
+ lambda { @class.new(:x => ['abc', 'def'] ) }.should_not raise_error(Exception)
255
+ end
256
+
257
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
258
+ instance = @class.new(:x => ['abc', 'def' ])
259
+ lambda { instance.x = ["str", 10] }.should raise_error(ClassX::InvalidAttrArgument)
260
+ end
261
+
262
+ it 'should not raise error when it take valid args on update value' do
263
+ instance = @class.new(:x => ['abc', 'def'])
264
+ lambda { instance.x = ['ghi', 'jkl'] }.should_not raise_error(Exception)
265
+ end
266
+ end
267
+
268
+ describe 'with :validate_each option and take Hash' do
269
+ before do
270
+ @class = Class.new
271
+ @class.class_eval do
272
+ include ClassX
273
+ has :x,
274
+ :writable => true,
275
+ :validate_each => proc {|key,val| val.kind_of? String }
276
+ end
277
+ end
278
+
279
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
280
+ lambda { @class.new(:x => { 'abc' => 10 }) }.should raise_error(ClassX::InvalidAttrArgument)
281
+ end
282
+
283
+ it 'should not raise error when it take valid args on instanciate' do
284
+ lambda { @class.new(:x => { 'abc' => 'str' } ) }.should_not raise_error(Exception)
285
+ end
286
+
287
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
288
+ instance = @class.new(:x => {'abc' => 'str' })
289
+ lambda { instance.x = {'abc' => 10 } }.should raise_error(ClassX::InvalidAttrArgument)
290
+ end
291
+
292
+ it 'should not raise error when it take valid args on update value' do
293
+ instance = @class.new(:x => {'abc' => 'str' })
294
+ lambda { instance.x = { 'ghi' => 'jkl' } }.should_not raise_error(Exception)
295
+ end
296
+ end
297
+
298
+ describe 'with :validate_each option with arity two and :kind_of and take Hash' do
299
+ before do
300
+ @class = Class.new
301
+ @class.class_eval do
302
+ include ClassX
303
+ has :x,
304
+ :writable => true,
305
+ :kind_of => Hash,
306
+ :validate_each => proc {|key,val| val.kind_of? String }
307
+ end
308
+ end
309
+
310
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
311
+ lambda { @class.new(:x => { 'abc' => 10 }) }.should raise_error(ClassX::InvalidAttrArgument)
312
+ end
313
+
314
+ it 'should not raise error when it take valid args on instanciate' do
315
+ lambda { @class.new(:x => { 'abc' => 'str' } ) }.should_not raise_error(Exception)
316
+ end
317
+
318
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
319
+ instance = @class.new(:x => {'abc' => 'str' })
320
+ lambda { instance.x = {'abc' => 10 } }.should raise_error(ClassX::InvalidAttrArgument)
321
+ end
322
+
323
+ it 'should not raise error when it take valid args on update value' do
324
+ instance = @class.new(:x => {'abc' => 'str' })
325
+ lambda { instance.x = { 'ghi' => 'jkl' } }.should_not raise_error(Exception)
326
+ end
327
+ end
328
+
329
+ describe 'with :validate_each option with arity two and :kind_of and take Hash' do
330
+ before do
331
+ @class = Class.new
332
+ @class.class_eval do
333
+ include ClassX
334
+ has :x,
335
+ :writable => true,
336
+ :kind_of => Hash,
337
+ :validate_each => proc {|mod|
338
+ has :foo
339
+ has :bar
340
+ }
341
+ end
342
+ end
343
+
344
+ it 'should raise ClassX::InstanceException when it take invalid args on instanciate' do
345
+ lambda { @class.new(:x => { 'abc' => 10 }) }.should raise_error(ClassX::AttrRequiredError)
346
+ end
347
+
348
+ it 'should not raise error when it take valid args on instanciate' do
349
+ lambda { @class.new(:x => { 'foo' => :foo, "bar" => :bar } ) }.should_not raise_error(Exception)
350
+ end
351
+
352
+ it 'should raise ClassX::InvalidAttrArgument when it take invalid args on update value' do
353
+ instance = @class.new(:x => {'foo' => :foo, "bar" => :bar })
354
+ lambda { instance.x = {'abc' => 10 } }.should raise_error(ClassX::AttrRequiredError)
355
+ end
356
+
357
+ it 'should not raise error when it take valid args on update value' do
358
+ instance = @class.new(:x => {'foo' => :foo, "bar" => :bar })
359
+ lambda { instance.x = {'foo' => :foo, "bar" => :bar, "baz" => :baz } }.should_not raise_error(Exception)
360
+ end
361
+ end
362
+ end
363
+ end