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.
- data/.gitignore +49 -0
- data/.rspec +2 -0
- data/CHANGELOG.textile +49 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +36 -0
- data/README.textile +6 -1
- data/Rakefile +42 -9
- data/VERSION +1 -1
- data/gorillib.gemspec +110 -73
- data/lib/gorillib/array/deep_compact.rb +3 -12
- data/lib/gorillib/datetime/#flat.rb# +30 -0
- data/lib/gorillib/datetime/flat.rb +2 -10
- data/lib/gorillib/datetime/parse.rb +3 -1
- data/lib/gorillib/enumerable/sum.rb +37 -35
- data/lib/gorillib/hash/deep_compact.rb +3 -13
- data/lib/gorillib/logger/log.rb +1 -1
- data/lib/gorillib/numeric/clamp.rb +9 -0
- data/lib/gorillib/object/try.rb +10 -0
- data/lib/gorillib/object/try_dup.rb +44 -0
- data/lib/gorillib/string/human.rb +1 -3
- data/lib/gorillib/string/truncate.rb +2 -2
- data/spec/array/compact_blank_spec.rb +37 -0
- data/spec/array/extract_options_spec.rb +47 -0
- data/spec/datetime/flat_spec.rb +38 -0
- data/spec/datetime/parse_spec.rb +48 -0
- data/spec/enumerable/sum_spec.rb +56 -0
- data/spec/hash/compact_spec.rb +70 -0
- data/spec/hash/deep_compact_spec.rb +37 -0
- data/spec/hash/deep_merge_spec.rb +117 -0
- data/spec/hash/keys_spec.rb +111 -0
- data/spec/hash/reverse_merge_spec.rb +25 -0
- data/spec/hash/slice_spec.rb +43 -0
- data/spec/hash/zip_spec.rb +31 -0
- data/spec/logger/log_spec.rb +31 -0
- data/spec/metaprogramming/aliasing_spec.rb +177 -0
- data/spec/metaprogramming/cattr_accessor_spec.rb +41 -0
- data/spec/metaprogramming/class_attribute_spec.rb +75 -0
- data/spec/metaprogramming/delegation_spec.rb +166 -0
- data/spec/metaprogramming/mattr_accessor_spec.rb +44 -0
- data/spec/metaprogramming/singleton_class_spec.rb +9 -0
- data/spec/{numeric_spec.rb → numeric/clamp_spec.rb} +2 -2
- data/spec/object/blank_spec.rb +93 -0
- data/spec/object/try_dup_spec.rb +47 -0
- data/spec/object/try_spec.rb +20 -0
- data/spec/spec_helper.rb +13 -8
- data/spec/string/constantize_spec.rb +56 -0
- data/spec/string/human_spec.rb +66 -0
- data/spec/string/inflections_spec.rb +74 -0
- data/{test → spec}/string/inflector_test_cases.rb +0 -0
- data/spec/string/truncate_spec.rb +42 -0
- data/spec/support/kcode_test_helper.rb +16 -0
- metadata +209 -96
- data/.document +0 -5
- data/fiddle/hubahuba.rb +0 -62
- data/spec/blank_spec.rb +0 -86
- data/spec/deep_compact_spec.rb +0 -36
- data/spec/gorillib_spec.rb +0 -7
- data/spec/rcov.opts +0 -6
- data/spec/spec.opts +0 -4
- data/spec/spec_tasks.rake +0 -15
- data/test/abstract_unit.rb +0 -25
- data/test/array/compact_blank_test.rb +0 -33
- data/test/array/extract_options_test.rb +0 -39
- data/test/datetime/flat_test.rb +0 -0
- data/test/datetime/parse_test.rb +0 -0
- data/test/enumerable/sum_test.rb +0 -50
- data/test/hash/compact_test.rb +0 -38
- data/test/hash/deep_merge_test.rb +0 -30
- data/test/hash/keys_test.rb +0 -110
- data/test/hash/reverse_merge_test.rb +0 -20
- data/test/hash/slice_test.rb +0 -47
- data/test/hash/zip_test.rb +0 -0
- data/test/logger/log_test.rb +0 -0
- data/test/metaprogramming/aliasing_test.rb +0 -188
- data/test/metaprogramming/cattr_accessor_test.rb +0 -38
- data/test/metaprogramming/class_attribute_test.rb +0 -73
- data/test/metaprogramming/delegation_test.rb +0 -166
- data/test/metaprogramming/mattr_accessor_test.rb +0 -40
- data/test/metaprogramming/singleton_class_test.rb +0 -9
- data/test/object/blank_test.rb +0 -22
- data/test/string/constantize_test.rb +0 -30
- data/test/string/human_test.rb +0 -65
- data/test/string/inflections_test.rb +0 -57
- 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
|