gorillib 0.0.7 → 0.0.8

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