gorillib 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/.gitignore +49 -0
  2. data/.rspec +2 -0
  3. data/CHANGELOG.textile +49 -0
  4. data/Gemfile +15 -0
  5. data/Gemfile.lock +36 -0
  6. data/README.textile +6 -1
  7. data/Rakefile +42 -9
  8. data/VERSION +1 -1
  9. data/gorillib.gemspec +110 -73
  10. data/lib/gorillib/array/deep_compact.rb +3 -12
  11. data/lib/gorillib/datetime/#flat.rb# +30 -0
  12. data/lib/gorillib/datetime/flat.rb +2 -10
  13. data/lib/gorillib/datetime/parse.rb +3 -1
  14. data/lib/gorillib/enumerable/sum.rb +37 -35
  15. data/lib/gorillib/hash/deep_compact.rb +3 -13
  16. data/lib/gorillib/logger/log.rb +1 -1
  17. data/lib/gorillib/numeric/clamp.rb +9 -0
  18. data/lib/gorillib/object/try.rb +10 -0
  19. data/lib/gorillib/object/try_dup.rb +44 -0
  20. data/lib/gorillib/string/human.rb +1 -3
  21. data/lib/gorillib/string/truncate.rb +2 -2
  22. data/spec/array/compact_blank_spec.rb +37 -0
  23. data/spec/array/extract_options_spec.rb +47 -0
  24. data/spec/datetime/flat_spec.rb +38 -0
  25. data/spec/datetime/parse_spec.rb +48 -0
  26. data/spec/enumerable/sum_spec.rb +56 -0
  27. data/spec/hash/compact_spec.rb +70 -0
  28. data/spec/hash/deep_compact_spec.rb +37 -0
  29. data/spec/hash/deep_merge_spec.rb +117 -0
  30. data/spec/hash/keys_spec.rb +111 -0
  31. data/spec/hash/reverse_merge_spec.rb +25 -0
  32. data/spec/hash/slice_spec.rb +43 -0
  33. data/spec/hash/zip_spec.rb +31 -0
  34. data/spec/logger/log_spec.rb +31 -0
  35. data/spec/metaprogramming/aliasing_spec.rb +177 -0
  36. data/spec/metaprogramming/cattr_accessor_spec.rb +41 -0
  37. data/spec/metaprogramming/class_attribute_spec.rb +75 -0
  38. data/spec/metaprogramming/delegation_spec.rb +166 -0
  39. data/spec/metaprogramming/mattr_accessor_spec.rb +44 -0
  40. data/spec/metaprogramming/singleton_class_spec.rb +9 -0
  41. data/spec/{numeric_spec.rb → numeric/clamp_spec.rb} +2 -2
  42. data/spec/object/blank_spec.rb +93 -0
  43. data/spec/object/try_dup_spec.rb +47 -0
  44. data/spec/object/try_spec.rb +20 -0
  45. data/spec/spec_helper.rb +13 -8
  46. data/spec/string/constantize_spec.rb +56 -0
  47. data/spec/string/human_spec.rb +66 -0
  48. data/spec/string/inflections_spec.rb +74 -0
  49. data/{test → spec}/string/inflector_test_cases.rb +0 -0
  50. data/spec/string/truncate_spec.rb +42 -0
  51. data/spec/support/kcode_test_helper.rb +16 -0
  52. metadata +209 -96
  53. data/.document +0 -5
  54. data/fiddle/hubahuba.rb +0 -62
  55. data/spec/blank_spec.rb +0 -86
  56. data/spec/deep_compact_spec.rb +0 -36
  57. data/spec/gorillib_spec.rb +0 -7
  58. data/spec/rcov.opts +0 -6
  59. data/spec/spec.opts +0 -4
  60. data/spec/spec_tasks.rake +0 -15
  61. data/test/abstract_unit.rb +0 -25
  62. data/test/array/compact_blank_test.rb +0 -33
  63. data/test/array/extract_options_test.rb +0 -39
  64. data/test/datetime/flat_test.rb +0 -0
  65. data/test/datetime/parse_test.rb +0 -0
  66. data/test/enumerable/sum_test.rb +0 -50
  67. data/test/hash/compact_test.rb +0 -38
  68. data/test/hash/deep_merge_test.rb +0 -30
  69. data/test/hash/keys_test.rb +0 -110
  70. data/test/hash/reverse_merge_test.rb +0 -20
  71. data/test/hash/slice_test.rb +0 -47
  72. data/test/hash/zip_test.rb +0 -0
  73. data/test/logger/log_test.rb +0 -0
  74. data/test/metaprogramming/aliasing_test.rb +0 -188
  75. data/test/metaprogramming/cattr_accessor_test.rb +0 -38
  76. data/test/metaprogramming/class_attribute_test.rb +0 -73
  77. data/test/metaprogramming/delegation_test.rb +0 -166
  78. data/test/metaprogramming/mattr_accessor_test.rb +0 -40
  79. data/test/metaprogramming/singleton_class_test.rb +0 -9
  80. data/test/object/blank_test.rb +0 -22
  81. data/test/string/constantize_test.rb +0 -30
  82. data/test/string/human_test.rb +0 -65
  83. data/test/string/inflections_test.rb +0 -57
  84. data/test/string/truncate_test.rb +0 -37
@@ -0,0 +1,111 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/hash/keys'
3
+
4
+ describe Hash do
5
+ class SubclassingArray < Array
6
+ end
7
+
8
+ class SubclassingHash < Hash
9
+ end
10
+
11
+ before do
12
+ @strings = { 'a' => 1, 'b' => 2 }
13
+ @symbols = { :a => 1, :b => 2 }
14
+ @mixed = { :a => 1, 'b' => 2 }
15
+ @fixnums = { 0 => 1, 1 => 2 }
16
+ if RUBY_VERSION < '1.9.0'
17
+ @illegal_symbols = { "\0" => 1, "" => 2, [] => 3 }
18
+ else
19
+ @illegal_symbols = { [] => 3 }
20
+ end
21
+ end
22
+
23
+ it 'responds to #symbolize_keys, #symbolize_keys!, #stringify_keys, #stringify_keys!' do
24
+ {}.should respond_to(:symbolize_keys )
25
+ {}.should respond_to(:symbolize_keys!)
26
+ {}.should respond_to(:stringify_keys )
27
+ {}.should respond_to(:stringify_keys!)
28
+ end
29
+
30
+ describe '#symbolize_keys' do
31
+ it 'converts keys that are all symbols' do
32
+ @symbols.symbolize_keys.should == @symbols
33
+ end
34
+
35
+ it 'converts keys that are all strings' do
36
+ @strings.symbolize_keys.should == @symbols
37
+ @strings['a'].should == 1
38
+ end
39
+
40
+ it 'converts keys that are mixed' do
41
+ @mixed.symbolize_keys.should == @symbols
42
+ @mixed['b'].should == 2
43
+ end
44
+ end
45
+
46
+ describe '#symbolize_keys!' do
47
+ it 'converts keys that are all symbols' do
48
+ @symbols.symbolize_keys!.should == @symbols
49
+ end
50
+
51
+ it 'converts keys that are all strings' do
52
+ @strings.symbolize_keys!.should == @symbols
53
+ @strings[:a].should == 1
54
+ end
55
+
56
+ it 'converts keys that are mixed' do
57
+ @mixed.symbolize_keys!.should == @symbols
58
+ @mixed[:b].should == 2
59
+ end
60
+
61
+ it 'preserves keys that can not be symbolized' do
62
+ @illegal_symbols.symbolize_keys.should == @illegal_symbols
63
+ @illegal_symbols.dup.symbolize_keys!.should == @illegal_symbols
64
+ end
65
+
66
+ it 'preserves fixnum keys' do
67
+ @fixnums.symbolize_keys.should == @fixnums
68
+ @fixnums.dup.symbolize_keys!.should == @fixnums
69
+ end
70
+ end
71
+
72
+ describe '#stringify_keys' do
73
+ it 'converts keys that are all symbols' do
74
+ @symbols.stringify_keys.should == @strings
75
+ end
76
+
77
+ it 'converts keys that are all strings' do
78
+ @strings.stringify_keys.should == @strings
79
+ end
80
+
81
+ it 'converts keys that are mixed' do
82
+ @mixed.stringify_keys.should == @strings
83
+ end
84
+ end
85
+
86
+ describe '#stringify_keys!' do
87
+ it 'converts keys that are all symbols' do
88
+ @symbols.dup.stringify_keys!.should == @strings
89
+ end
90
+
91
+ it 'converts keys that are all strings' do
92
+ @strings.dup.stringify_keys!.should == @strings
93
+ end
94
+
95
+ it 'converts keys that are all mixed' do
96
+ @mixed.dup.stringify_keys!.should == @strings
97
+ end
98
+ end
99
+
100
+ describe '#assert_valid_keys' do
101
+ it 'succeeds when valid' do
102
+ { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]).should be_nil
103
+ { :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny).should be_nil
104
+ end
105
+ it 'raises when there are invalid keys' do
106
+ lambda{ { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) }.should raise_error(ArgumentError, "Unknown key(s): failore")
107
+ lambda{ { :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny) }.should raise_error(ArgumentError, "Unknown key(s): failore")
108
+ end
109
+ end
110
+
111
+ end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/hash/reverse_merge'
3
+
4
+ describe Hash do
5
+ describe 'reverse_merge' do
6
+
7
+ before do
8
+ @defaults = { :a => "x", :b => "y", :c => 10 }.freeze
9
+ @options = { :a => 1, :b => 2 }
10
+ @expected = { :a => 1, :b => 2, :c => 10 }
11
+ end
12
+
13
+ it 'Should merge defaults into options, creating a new hash' do
14
+ @options.reverse_merge(@defaults).should == @expected
15
+ @options.should_not == @expected
16
+ end
17
+
18
+
19
+ it 'Should merge! defaults into options, replacing options.' do
20
+ @merged = @options.dup
21
+ @merged.reverse_merge!(@defaults).should == @expected
22
+ @merged.should == @expected
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/hash/slice'
3
+
4
+ describe Hash do
5
+ describe '#slice' do
6
+ it 'should return a new hash with only the given keys' do
7
+ original = { :a => 'x', :b => 'y', :c => 10 }
8
+ expected = { :a => 'x', :b => 'y' }
9
+
10
+ original.slice(:a, :b).should == expected
11
+ original.should_not == expected
12
+ end
13
+
14
+ it 'Should replace the hash with only the given keys' do
15
+ original = { :a => 'x', :b => 'y', :c => 10 }
16
+ expected = { :c => 10 }
17
+
18
+ original.slice!(:a, :b).should == expected
19
+ end
20
+
21
+ it 'should return a new hash with only the given keys when given an array key' do
22
+ original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" }
23
+ expected = { [:a, :b] => "an array key", :c => 10 }
24
+
25
+ original.slice([:a, :b], :c).should == expected
26
+ original.should_not == expected
27
+ end
28
+
29
+ it 'should replace the hash with only the given keys when given an array key' do
30
+ original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" }
31
+ expected = { :a => 'x', :b => 'y' }
32
+
33
+ original.slice!([:a, :b], :c).should == expected
34
+ end
35
+
36
+ it 'Should grab each of the splatted keys' do
37
+ original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" }
38
+ expected = { :a => 'x', :b => "y" }
39
+
40
+ original.slice(*[:a, :b]).should == expected
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/hash/zip'
3
+
4
+ describe Hash do
5
+ describe '#zip' do
6
+ it 'builds a hash from keys and values' do
7
+ Hash.zip([:a, :b, :c], [1, 2, 3]).should == { :a => 1, :b => 2, :c => 3 }
8
+ end
9
+
10
+ it 'ignores extra values' do
11
+ Hash.zip([:a, :b, :c], [1, 2, 3, 4, 5]).should == { :a => 1, :b => 2, :c => 3 }
12
+ end
13
+
14
+ it 'supplies nil values for extra keys' do
15
+ Hash.zip([:a, :b, :c, :d], [1, 2, 3]).should == { :a => 1, :b => 2, :c => 3, :d => nil }
16
+ end
17
+
18
+ it 'uses the default block if given' do
19
+ hsh = Hash.zip([:a, :b, :c], [1, 2, 3]){|h,k| h[k] = :foo }
20
+ hsh.should == { :a => 1, :b => 2, :c => 3 }
21
+ hsh[:d].should == :foo
22
+ end
23
+
24
+ it 'uses the default value if given' do
25
+ hsh = Hash.zip([:a, :b, :c], [1, 2, 3], :bar)
26
+ hsh.should == { :a => 1, :b => 2, :c => 3 }
27
+ hsh[:d].should == :bar
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ CODE_FILE = File.dirname(__FILE__)+'/../../lib/gorillib/logger/log.rb'
3
+ require CODE_FILE
4
+
5
+ describe 'Logger' do
6
+ describe '#dump' do
7
+ it 'inspects each arg and sends tab-separated to Log.debug' do
8
+ Log.should_receive(:debug).with(%Q{{:hi=>"there"}\t3\t"bye"})
9
+ Log.dump({ :hi => "there" }, 3, "bye")
10
+ end
11
+ end
12
+
13
+ it 'does not create a log if one exists' do
14
+ dummy = 'dummy'
15
+ Object.instance_eval{ remove_const(:Log) rescue nil ; ::Log = dummy }
16
+ load(CODE_FILE)
17
+ ::Log.should equal(dummy)
18
+ Object.instance_eval{ remove_const(:Log) rescue nil }
19
+ end
20
+
21
+ it 'creates a new log to STDERR' do
22
+ @old_stderr = $stderr
23
+ $stderr = StringIO.new
24
+ Object.instance_eval{ remove_const(:Log) rescue nil }
25
+ load(CODE_FILE)
26
+ Log.info 'hi mom'
27
+ $stderr.string.should =~ /hi mom/
28
+ $stderr = @old_stderr
29
+ end
30
+
31
+ end
@@ -0,0 +1,177 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/metaprogramming/aliasing'
3
+
4
+ module BarMethodAliaser
5
+ def self.included(foo_class)
6
+ foo_class.class_eval do
7
+ include BarMethods
8
+ alias_method_chain :bar, :baz
9
+ end
10
+ end
11
+ end
12
+
13
+ module BarMethods
14
+ def bar_with_baz
15
+ bar_without_baz << '_with_baz'
16
+ end
17
+
18
+ def quux_with_baz!
19
+ quux_without_baz! << '_with_baz'
20
+ end
21
+
22
+ def quux_with_baz?
23
+ false
24
+ end
25
+
26
+ def quux_with_baz=(v)
27
+ send(:quux_without_baz=, v) << '_with_baz'
28
+ end
29
+
30
+ def duck_with_orange
31
+ duck_without_orange << '_with_orange'
32
+ end
33
+ end
34
+
35
+ describe 'metaprogramming' do
36
+ before do
37
+ Object.const_set :FooClassWithBarMethod, Class.new{ def bar() 'bar' end }
38
+ @instance = FooClassWithBarMethod.new
39
+ end
40
+
41
+ after do
42
+ Object.instance_eval { remove_const :FooClassWithBarMethod }
43
+ end
44
+
45
+ describe 'alias_method_chain' do
46
+ it 'creates a with_ and without_ method that chain' do
47
+ @instance.should respond_to(:bar)
48
+ feature_aliases = [:bar_with_baz, :bar_without_baz]
49
+
50
+ feature_aliases.each do |method|
51
+ @instance.should_not respond_to(method)
52
+ end
53
+ @instance.bar.should == 'bar'
54
+
55
+ FooClassWithBarMethod.class_eval{ include BarMethodAliaser }
56
+ feature_aliases.each do |method|
57
+ @instance.should respond_to(method)
58
+ end
59
+ @instance.bar.should == 'bar_with_baz'
60
+ @instance.bar_without_baz.should == 'bar'
61
+ end
62
+
63
+ it 'with bang' do
64
+ FooClassWithBarMethod.class_eval do
65
+ def quux!; 'quux' end
66
+ end
67
+
68
+ @instance.should_not respond_to(:quux_with_baz!)
69
+ FooClassWithBarMethod.class_eval do
70
+ include BarMethodAliaser
71
+ alias_method_chain :quux!, :baz
72
+ end
73
+ @instance.should respond_to(:quux_with_baz!)
74
+
75
+ @instance.quux!.should == 'quux_with_baz'
76
+ @instance.quux_without_baz!.should == 'quux'
77
+ end
78
+
79
+ it 'with same names between predicates and bang methods' do
80
+ FooClassWithBarMethod.class_eval do
81
+ def quux!; 'quux!' end
82
+ def quux?; true end
83
+ def quux=(v); 'quux=' end
84
+ end
85
+
86
+ @instance.should_not respond_to(:quux_with_baz!)
87
+ @instance.should_not respond_to(:quux_with_baz?)
88
+ @instance.should_not respond_to(:quux_with_baz=)
89
+
90
+ FooClassWithBarMethod.class_eval { include BarMethodAliaser }
91
+ @instance.should respond_to(:quux_with_baz!)
92
+ @instance.should respond_to(:quux_with_baz?)
93
+ @instance.should respond_to(:quux_with_baz=)
94
+
95
+ FooClassWithBarMethod.alias_method_chain :quux!, :baz
96
+ @instance.quux!.should == 'quux!_with_baz'
97
+ @instance.quux_without_baz!.should == 'quux!'
98
+
99
+ FooClassWithBarMethod.alias_method_chain :quux?, :baz
100
+ @instance.quux?.should == false
101
+ @instance.quux_without_baz?.should == true
102
+
103
+ FooClassWithBarMethod.alias_method_chain :quux=, :baz
104
+ @instance.send(:quux=, 1234).should == 'quux=_with_baz'
105
+ @instance.send(:quux_without_baz=, 1234).should == 'quux='
106
+ end
107
+
108
+ it 'with_feature_punctuation' do
109
+ FooClassWithBarMethod.class_eval do
110
+ def quux; 'quux' end
111
+ def quux?; 'quux?' end
112
+ include BarMethodAliaser
113
+ alias_method_chain :quux, :baz!
114
+ end
115
+
116
+ @instance.quux_with_baz!.should == 'quux_with_baz'
117
+
118
+ lambda{ FooClassWithBarMethod.alias_method_chain :quux?, :baz! }.should raise_error(NameError)
119
+ end
120
+
121
+ it 'yields target and punctuation' do
122
+ args = nil
123
+ FooClassWithBarMethod.class_eval do
124
+ def quux?; end
125
+ include BarMethods
126
+
127
+ FooClassWithBarMethod.alias_method_chain :quux?, :baz do |target, punctuation|
128
+ args = [target, punctuation]
129
+ end
130
+ end
131
+
132
+ args.should_not be_nil
133
+ args[0].should == 'quux'
134
+ args[1].should == '?'
135
+ end
136
+
137
+ it 'preserves private method status' do
138
+ FooClassWithBarMethod.class_eval do
139
+ def duck; 'duck' end
140
+ include BarMethodAliaser
141
+ private :duck
142
+ alias_method_chain :duck, :orange
143
+ end
144
+
145
+ lambda{ @instance.duck }.should raise_error(NoMethodError)
146
+
147
+ @instance.instance_eval{ duck }.should == 'duck_with_orange'
148
+ FooClassWithBarMethod.should be_private_method_defined(:duck)
149
+ end
150
+
151
+ it 'preserves protected method status' do
152
+ FooClassWithBarMethod.class_eval do
153
+ def duck; 'duck' end
154
+ include BarMethodAliaser
155
+ protected :duck
156
+ alias_method_chain :duck, :orange
157
+ end
158
+
159
+ lambda{ @instance.duck }.should raise_error(NoMethodError)
160
+
161
+ @instance.instance_eval{ duck }.should == 'duck_with_orange'
162
+ FooClassWithBarMethod.should be_protected_method_defined(:duck)
163
+ end
164
+
165
+ it 'preserves public method status' do
166
+ FooClassWithBarMethod.class_eval do
167
+ def duck; 'duck' end
168
+ include BarMethodAliaser
169
+ public :duck
170
+ alias_method_chain :duck, :orange
171
+ end
172
+
173
+ @instance.duck.should == 'duck_with_orange'
174
+ FooClassWithBarMethod.should be_public_method_defined(:duck)
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/metaprogramming/cattr_accessor'
3
+
4
+ describe 'metaprogramming' do
5
+ describe 'cattr_accessor' do
6
+ before do
7
+ @class = Class.new do
8
+ cattr_accessor :foo
9
+ cattr_accessor :bar, :instance_writer => false
10
+ cattr_reader :shaq, :instance_reader => false
11
+ end
12
+ @object = @class.new
13
+ end
14
+
15
+ it 'uses mattr default' do
16
+ @class.foo.should be_nil
17
+ @object.foo.should be_nil
18
+ end
19
+
20
+ it 'sets mattr value' do
21
+ @class.foo = :test
22
+ @object.foo.should == :test
23
+
24
+ @object.foo = :test2
25
+ @class.foo.should == :test2
26
+ end
27
+
28
+ it 'with instance_writer => false, does not create an instance writer' do
29
+ @class.should respond_to(:foo)
30
+ @class.should respond_to(:foo=)
31
+ @object.should respond_to(:bar)
32
+ @object.should_not respond_to(:bar=)
33
+ end
34
+
35
+ it 'with instance_reader => false, does not create an instance reader' do
36
+ @class.should respond_to(:shaq)
37
+ @object.should_not respond_to(:shaq)
38
+ @object.should_not respond_to(:shaq=)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,75 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/metaprogramming/class_attribute'
3
+
4
+ describe 'metaprogramming' do
5
+ describe 'class_attribute' do
6
+ before do
7
+ @klass = Class.new { class_attribute :setting }
8
+ @sub = Class.new(@klass)
9
+ end
10
+
11
+ it 'defaults to nil' do
12
+ @klass.setting.should be_nil
13
+ @sub.setting.should be_nil
14
+ end
15
+
16
+ it 'is inheritable' do
17
+ @klass.setting = 1
18
+ @sub.setting == 1
19
+ end
20
+
21
+ it 'is overridable' do
22
+ @sub.setting = 1
23
+ @klass.setting.should be_nil
24
+
25
+ @klass.setting = 2
26
+ @sub.setting.should == 1
27
+
28
+ Class.new(@sub).setting.should == 1
29
+ end
30
+
31
+ it 'creates a query? method' do
32
+ @klass.setting?.should == false
33
+ @klass.setting = 1
34
+ @klass.setting?.should == true
35
+ end
36
+
37
+ it 'instance reader delegates to class' do
38
+ @klass.new.setting.should be_nil
39
+
40
+ @klass.setting = 1
41
+ @klass.new.setting.should == 1
42
+ end
43
+
44
+ it 'instance override' do
45
+ object = @klass.new
46
+ object.setting = 1
47
+ @klass.setting.should be_nil
48
+ @klass.setting = 2
49
+ object.setting.should == 1
50
+ end
51
+
52
+ it 'instance query' do
53
+ object = @klass.new
54
+ object.setting?.should == false
55
+ object.setting = 1
56
+ object.setting?.should == true
57
+ end
58
+
59
+ it 'disabling instance writer' do
60
+ object = Class.new { class_attribute :setting, :instance_writer => false }.new
61
+ lambda{ object.setting = 'boom' }.should raise_error(NoMethodError)
62
+ end
63
+
64
+ it 'works well with singleton classes' do
65
+ object = @klass.new
66
+ object.singleton_class.setting = 'foo'
67
+ object.setting.should == 'foo'
68
+ end
69
+
70
+ it 'setter returns set value' do
71
+ val = @klass.send(:setting=, 1)
72
+ val.should == 1
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,166 @@
1
+ require File.dirname(__FILE__)+'/../spec_helper'
2
+ require 'gorillib/metaprogramming/delegation'
3
+
4
+ module One
5
+ Constant1 = "Hello World"
6
+ Constant2 = "What\'s up?"
7
+ end
8
+
9
+ class Ab
10
+ include One
11
+ Constant1 = "Hello World" # Will have different object id than One::Constant1
12
+ Constant3 = "Goodbye World"
13
+ end
14
+
15
+ module Xy
16
+ class Bc
17
+ include One
18
+ end
19
+ end
20
+
21
+ module Yz
22
+ module Zy
23
+ class Cd
24
+ include One
25
+ end
26
+ end
27
+ end
28
+
29
+ Somewhere = Struct.new(:street, :city)
30
+
31
+ Someone = Struct.new(:name, :place) do
32
+ delegate :street, :city, :to_f, :to => :place
33
+ delegate :upcase, :to => "place.city"
34
+ end
35
+
36
+ Invoice = Struct.new(:client) do
37
+ delegate :street, :city, :name, :to => :client, :prefix => true
38
+ delegate :street, :city, :name, :to => :client, :prefix => :customer
39
+ end
40
+
41
+ Project = Struct.new(:description, :person) do
42
+ delegate :name, :to => :person, :allow_nil => true
43
+ delegate :to_f, :to => :description, :allow_nil => true
44
+ end
45
+
46
+ Developer = Struct.new(:client) do
47
+ delegate :name, :to => :client, :prefix => nil
48
+ end
49
+
50
+ Tester = Struct.new(:client) do
51
+ delegate :name, :to => :client, :prefix => false
52
+ end
53
+
54
+ class Name
55
+ delegate :upcase, :to => :@full_name
56
+
57
+ def initialize(first, last)
58
+ @full_name = "#{first} #{last}"
59
+ end
60
+ end
61
+
62
+ # ===========================================================================
63
+ #
64
+ # Tests start
65
+
66
+ describe 'metaprogramming' do
67
+ describe 'delegation' do
68
+ before do
69
+ @david = Someone.new("David", Somewhere.new("Paulina", "Chicago"))
70
+ end
71
+
72
+ it 'delegates to methods' do
73
+ @david.street.should == "Paulina"
74
+ @david.city.should == "Chicago"
75
+ end
76
+
77
+ it 'delegates down hierarchy' do
78
+ @david.upcase.should == "CHICAGO"
79
+ end
80
+
81
+ it 'delegates to instance variables' do
82
+ david = Name.new("David", "Hansson")
83
+ david.upcase.should == "DAVID HANSSON"
84
+ end
85
+
86
+ it 'raises with a missing delegation target' do
87
+ lambda{ Name.send :delegate, :nowhere }.should raise_error(ArgumentError)
88
+ lambda{ Name.send :delegate, :noplace, :tos => :hollywood }.should raise_error(ArgumentError)
89
+ end
90
+
91
+ it 'uses a prefix' do
92
+ invoice = Invoice.new(@david)
93
+ invoice.client_name.should == "David"
94
+ invoice.client_street.should == "Paulina"
95
+ invoice.client_city.should == "Chicago"
96
+ end
97
+
98
+ it 'accepts a custom prefix' do
99
+ invoice = Invoice.new(@david)
100
+ invoice.customer_name.should == "David"
101
+ invoice.customer_street.should == "Paulina"
102
+ invoice.customer_city.should == "Chicago"
103
+ end
104
+
105
+ it 'delegation prefix with nil or false' do
106
+ Developer.new(@david).name.should == "David"
107
+ Tester.new(@david).name.should == "David"
108
+ end
109
+
110
+ it 'delegation prefix with instance variable' do
111
+ lambda{
112
+ Class.new do
113
+ def initialize(client)
114
+ @client = client
115
+ end
116
+ delegate :name, :address, :to => :@client, :prefix => true
117
+ end
118
+ }.should raise_error(ArgumentError)
119
+ end
120
+
121
+ it 'with allow_nil' do
122
+ rails = Project.new("Rails", Someone.new("David"))
123
+ rails.name.should == "David"
124
+ end
125
+
126
+ it 'with allow_nil, accepts a nil value' do
127
+ rails = Project.new("Rails")
128
+ rails.name.should be_nil
129
+ end
130
+
131
+ it 'with allow_nil, accepts a nil value and prefix' do
132
+ Project.class_eval do
133
+ delegate :name, :to => :person, :allow_nil => true, :prefix => true
134
+ end
135
+ rails = Project.new("Rails")
136
+ rails.person_name.should be_nil
137
+ end
138
+
139
+ it 'without allow_nil, raises an error on nil vlaue' do
140
+ david = Someone.new("David")
141
+ lambda{ david.street }.should raise_error(RuntimeError)
142
+ end
143
+
144
+ it 'delegates to method that exists on nil' do
145
+ nil_person = Someone.new(nil)
146
+ nil_person.to_f.should == 0.0
147
+ end
148
+
149
+ it 'delegates to method that exists on nil when allowing nil' do
150
+ nil_project = Project.new(nil)
151
+ nil_project.to_f.should == 0.0
152
+ end
153
+
154
+ it 'does not raise error when removing singleton instance methods' do
155
+ parent = Class.new do
156
+ def self.parent_method; end
157
+ end
158
+
159
+ Class.new(parent) do
160
+ class << self
161
+ delegate :parent_method, :to => :superclass
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end