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