ruby_ext 0.4.6
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/Rakefile +64 -0
- data/lib/ruby_ext/array.rb +13 -0
- data/lib/ruby_ext/basic_object.rb +22 -0
- data/lib/ruby_ext/class.rb +11 -0
- data/lib/ruby_ext/declarative_cache.rb +85 -0
- data/lib/ruby_ext/deep_clone.rb +62 -0
- data/lib/ruby_ext/extra_blank_slate.rb +16 -0
- data/lib/ruby_ext/file.rb +20 -0
- data/lib/ruby_ext/hash.rb +15 -0
- data/lib/ruby_ext/kernel.rb +69 -0
- data/lib/ruby_ext/micelaneous.rb +14 -0
- data/lib/ruby_ext/module.rb +119 -0
- data/lib/ruby_ext/multiple_inheritance.rb +76 -0
- data/lib/ruby_ext/must.rb +192 -0
- data/lib/ruby_ext/not_defined.rb +2 -0
- data/lib/ruby_ext/object.rb +8 -0
- data/lib/ruby_ext/observable2.rb +23 -0
- data/lib/ruby_ext/open_constructor.rb +51 -0
- data/lib/ruby_ext/open_object.rb +157 -0
- data/lib/ruby_ext/prepare_arguments.rb +105 -0
- data/lib/ruby_ext/prototype_inheritance.rb +110 -0
- data/lib/ruby_ext/should.rb +166 -0
- data/lib/ruby_ext/string.rb +44 -0
- data/lib/ruby_ext/symbol.rb +21 -0
- data/lib/ruby_ext/synchronize.rb +24 -0
- data/lib/ruby_ext/tuple.rb +7 -0
- data/lib/ruby_ext.rb +50 -0
- data/lib/spec_ext.rb +10 -0
- data/readme.md +66 -0
- data/spec/_prototype_inheritance_spec.rb +190 -0
- data/spec/array_spec.rb +8 -0
- data/spec/declarative_cache_spec.rb +115 -0
- data/spec/deep_clone_spec.rb +37 -0
- data/spec/helper.rb +20 -0
- data/spec/kernel_spec/TheNamespace/ClassA.rb +7 -0
- data/spec/kernel_spec/another_class.rb +5 -0
- data/spec/kernel_spec/the_namespace/class_b.rb +11 -0
- data/spec/kernel_spec.rb +53 -0
- data/spec/module_spec.rb +160 -0
- data/spec/multiple_inheritance_spec.rb +131 -0
- data/spec/must_spec.rb +29 -0
- data/spec/observable2_spec.rb +42 -0
- data/spec/open_constructor_spec.rb +36 -0
- data/spec/open_object_spec.rb +29 -0
- data/spec/prepare_arguments_spec.rb +46 -0
- data/spec/should_spec.rb +24 -0
- data/spec/spec.opts +2 -0
- data/spec/synchronize_spec.rb +80 -0
- metadata +127 -0
@@ -0,0 +1,166 @@
|
|
1
|
+
class AssertionError < StandardError; end
|
2
|
+
|
3
|
+
Object.class_eval do
|
4
|
+
def should_be! method
|
5
|
+
unless self.send("#{method}?") == true
|
6
|
+
raise AssertionError, "
|
7
|
+
ASSERTION FAILED (#{caller[0]}):
|
8
|
+
#{self.inspect} should be #{method}
|
9
|
+
", caller
|
10
|
+
end
|
11
|
+
|
12
|
+
return self
|
13
|
+
end
|
14
|
+
alias_method :should_have!, :should_be!
|
15
|
+
|
16
|
+
def should_not_be! method
|
17
|
+
unless self.send("#{method}?") == false
|
18
|
+
raise AssertionError, "
|
19
|
+
ASSERTION FAILED (#{caller[0]}):
|
20
|
+
#{self.inspect} should not be #{method}
|
21
|
+
", caller
|
22
|
+
end
|
23
|
+
|
24
|
+
return self
|
25
|
+
end
|
26
|
+
alias_method :should_not_have!, :should_not_be!
|
27
|
+
|
28
|
+
def should! cmd, arg = NotDefined
|
29
|
+
result = case cmd
|
30
|
+
when :be_never_called then
|
31
|
+
false
|
32
|
+
|
33
|
+
when :be_nil then
|
34
|
+
self.equal? nil
|
35
|
+
|
36
|
+
when :be_a
|
37
|
+
if arg.class == Array
|
38
|
+
arg.any?{|klass| self.is_a? klass}
|
39
|
+
else
|
40
|
+
self.is_a? arg
|
41
|
+
end
|
42
|
+
|
43
|
+
when :be_an
|
44
|
+
if arg.class == Array
|
45
|
+
arg.any?{|klass| self.is_a? klass}
|
46
|
+
else
|
47
|
+
self.is_a? arg
|
48
|
+
end
|
49
|
+
|
50
|
+
when :be
|
51
|
+
if arg.class == Array
|
52
|
+
arg.any?{|klass| self.respond_to :is?, klass}
|
53
|
+
else
|
54
|
+
self.respond_to :is?, arg
|
55
|
+
end
|
56
|
+
|
57
|
+
when :include then
|
58
|
+
self.include? arg
|
59
|
+
|
60
|
+
when :be_in then
|
61
|
+
arg.include? self
|
62
|
+
|
63
|
+
when :be_true then
|
64
|
+
self
|
65
|
+
|
66
|
+
when :be_false then
|
67
|
+
!self
|
68
|
+
|
69
|
+
when :be_empty then
|
70
|
+
self.empty?
|
71
|
+
|
72
|
+
else
|
73
|
+
if arg.equal? NotDefined
|
74
|
+
self.send cmd
|
75
|
+
else
|
76
|
+
self.send cmd, arg
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
unless result
|
81
|
+
unless arg.equal? NotDefined
|
82
|
+
raise AssertionError, "
|
83
|
+
ASSERTION FAILED (#{caller[0]}):
|
84
|
+
#{self.inspect} should #{cmd} #{arg.inspect}
|
85
|
+
", caller
|
86
|
+
else
|
87
|
+
raise AssertionError, "
|
88
|
+
ASSERTION FAILED (#{caller[0]}):
|
89
|
+
#{self.inspect} should #{cmd}
|
90
|
+
", caller
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
return self
|
95
|
+
end
|
96
|
+
|
97
|
+
def should_not! cmd, arg = NotDefined
|
98
|
+
result =
|
99
|
+
case cmd
|
100
|
+
when :be_never_called then
|
101
|
+
false
|
102
|
+
|
103
|
+
when :be_nil then
|
104
|
+
self.equal? nil
|
105
|
+
|
106
|
+
when :be_a
|
107
|
+
if arg.class == Array
|
108
|
+
arg.any?{|klass| self.is_a? klass}
|
109
|
+
else
|
110
|
+
self.is_a? arg
|
111
|
+
end
|
112
|
+
|
113
|
+
when :be_an
|
114
|
+
if arg.class == Array
|
115
|
+
arg.any?{|klass| self.is_a? klass}
|
116
|
+
else
|
117
|
+
self.is_a? arg
|
118
|
+
end
|
119
|
+
|
120
|
+
when :be
|
121
|
+
if arg.class == Array
|
122
|
+
arg.any?{|klass| self.respond_to :is?, klass}
|
123
|
+
else
|
124
|
+
self.respond_to :is?, arg
|
125
|
+
end
|
126
|
+
|
127
|
+
when :include then
|
128
|
+
self.include? arg
|
129
|
+
|
130
|
+
when :be_in then
|
131
|
+
arg.include? self
|
132
|
+
|
133
|
+
when :be_true then
|
134
|
+
self
|
135
|
+
|
136
|
+
when :be_false then
|
137
|
+
!self
|
138
|
+
|
139
|
+
when :be_empty then
|
140
|
+
self.empty?
|
141
|
+
|
142
|
+
else
|
143
|
+
if arg.equal? NotDefined
|
144
|
+
self.send cmd
|
145
|
+
else
|
146
|
+
self.send cmd, arg
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
if result
|
151
|
+
unless arg.equal? NotDefined
|
152
|
+
raise AssertionError, "
|
153
|
+
ASSERTION FAILED (#{caller[0]}):
|
154
|
+
#{self.inspect} should not #{cmd} #{arg.inspect}
|
155
|
+
", caller
|
156
|
+
else
|
157
|
+
raise AssertionError, "
|
158
|
+
ASSERTION FAILED (#{caller[0]}):
|
159
|
+
#{self.inspect} should not #{cmd}
|
160
|
+
", caller
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
return self
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
String.class_eval do
|
2
|
+
def dirname
|
3
|
+
File.expand_path(File.dirname(self))
|
4
|
+
end
|
5
|
+
|
6
|
+
def parent_dirname
|
7
|
+
File.expand_path(File.dirname(self) + "/..")
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_reader
|
11
|
+
self.to_sym
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_writer
|
15
|
+
"#{self}=".to_sym
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_iv
|
19
|
+
"@#{self}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def interpolate binding
|
23
|
+
binding.must_be.a Binding
|
24
|
+
return gsub(/\#\{.+?\}/) do |term|
|
25
|
+
identifier = term.slice(2 .. term.size-2)
|
26
|
+
binding.eval identifier
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.secure_token
|
31
|
+
original = [Time.now, (1..10).map{ rand.to_s }]
|
32
|
+
Digest::SHA1.hexdigest(original.flatten.join('--'))
|
33
|
+
end
|
34
|
+
|
35
|
+
def underscore
|
36
|
+
word = self.dup
|
37
|
+
word.gsub!(/::/, '/')
|
38
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
39
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
40
|
+
word.tr!("-", "_")
|
41
|
+
word.downcase!
|
42
|
+
word
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Symbol.class_eval do
|
2
|
+
def <=> other
|
3
|
+
self.to_s <=> other.to_s
|
4
|
+
end
|
5
|
+
|
6
|
+
def to_reader
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_writer
|
11
|
+
"#{self}=".to_sym
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_iv
|
15
|
+
"@#{self}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def + other
|
19
|
+
(self.to_s + other.to_s).to_sym
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
3
|
+
class Module
|
4
|
+
def synchronize_method *methods
|
5
|
+
methods.each do |method|
|
6
|
+
als = "sync_#{escape_method(method)}"
|
7
|
+
|
8
|
+
raise "Can't synchronize the '#{method}' twice!" if instance_methods.include?(als)
|
9
|
+
|
10
|
+
alias_method als, method
|
11
|
+
script = "\
|
12
|
+
def #{method} *p, &b
|
13
|
+
@monitor ||= Monitor.new
|
14
|
+
@monitor.synchronize{#{als} *p, &b}
|
15
|
+
end"
|
16
|
+
class_eval script, __FILE__, __LINE__
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def synchronize_all_methods include_super = false
|
21
|
+
methods = self.instance_methods(include_super).collect{|m| m.to_sym}
|
22
|
+
synchronize_method *methods
|
23
|
+
end
|
24
|
+
end
|
data/lib/ruby_ext.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
core = [
|
2
|
+
'facets/array/indexable', # Array first!, last!
|
3
|
+
'facets/enumerable/every',
|
4
|
+
'facets/enumerable/group_by',
|
5
|
+
'facets/exception/detail', # pretty print
|
6
|
+
'facets/duplicable', # false.dup(), false.clone() and so on.
|
7
|
+
'facets/blank',
|
8
|
+
'facets/numeric/round.rb', # round_at, round_to
|
9
|
+
'facets/hash',
|
10
|
+
'facets/string/interpolate',
|
11
|
+
# 'facets/ostruct',
|
12
|
+
# 'facets/openobject' it has broken implementation and is completelly rewritend in ruby-ext
|
13
|
+
]
|
14
|
+
|
15
|
+
more = [
|
16
|
+
# 'facets/basicobject', causes problem with rspec
|
17
|
+
# 'facets/opencascade', causes problem with redefined OpenObject
|
18
|
+
]
|
19
|
+
|
20
|
+
(core + more).each{|f| require f}
|
21
|
+
|
22
|
+
{
|
23
|
+
:BasicObject => 'basic_object',
|
24
|
+
:OpenObject => 'open_object',
|
25
|
+
:OpenConstructor => 'open_constructor',
|
26
|
+
:Observable2 => 'observable2',
|
27
|
+
:ExtraBlankSlate => 'extra_blank_slate', # do I need it?
|
28
|
+
:Tuple => 'tuple',
|
29
|
+
}.each{|klass, file| Kernel.autoload klass, "ruby_ext/#{file}"}
|
30
|
+
|
31
|
+
%w{
|
32
|
+
file
|
33
|
+
array
|
34
|
+
hash
|
35
|
+
kernel
|
36
|
+
module
|
37
|
+
not_defined
|
38
|
+
object
|
39
|
+
class
|
40
|
+
string
|
41
|
+
symbol
|
42
|
+
|
43
|
+
deep_clone
|
44
|
+
declarative_cache
|
45
|
+
must
|
46
|
+
prepare_arguments
|
47
|
+
synchronize
|
48
|
+
micelaneous
|
49
|
+
multiple_inheritance
|
50
|
+
}.each{|f| require "ruby_ext/#{f}"}
|
data/lib/spec_ext.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec'
|
2
|
+
|
3
|
+
Spec::Example::ExampleGroup.class_eval do
|
4
|
+
def remove_constants *args
|
5
|
+
args = args.first if args.size == 1 and args.first.is_a?(Array)
|
6
|
+
# args.each{|c| raise "Invalid constant name '#{c}'!" unless c =~ /^[a-z_][a-z_0-9]*$/i}
|
7
|
+
# args = args.first if args.first.is_a?(Array)
|
8
|
+
args.each{|c| Object.send :remove_const, c if Object.const_defined? c}
|
9
|
+
end
|
10
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Ruby extensions
|
2
|
+
**ruby-ext** is a collection of various utility classes and standard library extensions for the Ruby language.
|
3
|
+
|
4
|
+
## must - assertion tool, kind of RSpec assertions in runtime code
|
5
|
+
|
6
|
+
1.must_be.in 1..2
|
7
|
+
"a".must_be.in 'a', 'b', 'c'
|
8
|
+
key.must_be.a String
|
9
|
+
value.must_not_be.nil
|
10
|
+
must_be.never_called
|
11
|
+
a.must_be == b
|
12
|
+
|
13
|
+
## inherit - combines include & extend in one
|
14
|
+
Do you remember this *def self.included(base) ... end* hack? You don't need it anymore.
|
15
|
+
|
16
|
+
module Feature
|
17
|
+
def cool_method; end
|
18
|
+
class_methods do
|
19
|
+
def cool_class_method; end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class TheClass
|
24
|
+
inherit Feature
|
25
|
+
end
|
26
|
+
|
27
|
+
TheClass.new.cool_method
|
28
|
+
TheClass.cool_class_method
|
29
|
+
|
30
|
+
## cache_method & synchronize_method
|
31
|
+
|
32
|
+
def complex_calculation
|
33
|
+
2 * 2
|
34
|
+
end
|
35
|
+
cache_method :complex_calculation
|
36
|
+
|
37
|
+
def money_transfer amount
|
38
|
+
@from -= amount
|
39
|
+
@to += amount
|
40
|
+
end
|
41
|
+
synchronize_method :money_transfer
|
42
|
+
|
43
|
+
## OpenConstructor - adds mass assignment to any class
|
44
|
+
|
45
|
+
class TheClass
|
46
|
+
include OpenConstructor
|
47
|
+
attr_accessor :a, :b
|
48
|
+
end
|
49
|
+
|
50
|
+
o = TheClass.new.set :a => 'a', :b => 'b'
|
51
|
+
o.a => 'a'
|
52
|
+
o.to_hash => {:a => 'a', :b => 'b'}
|
53
|
+
|
54
|
+
## More
|
55
|
+
|
56
|
+
These are just a small part of all handy methods and extensions, for more details please go to specs.
|
57
|
+
|
58
|
+
# Usage
|
59
|
+
|
60
|
+
$ sudo gem install ruby-ext
|
61
|
+
|
62
|
+
require 'ruby_ext'
|
63
|
+
|
64
|
+
Copyright (c) 2009 Alexey Petrushin [http://bos-tec.com](http://bos-tec.com), released under the MIT license.
|
65
|
+
|
66
|
+
[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require "#{File.dirname __FILE__}/helper"
|
2
|
+
require "ruby_ext/prototype_inheritance"
|
3
|
+
|
4
|
+
describe "Prototype Inheritance" do
|
5
|
+
after :each do
|
6
|
+
remove_constants %w(A B C)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should define and override methods" do
|
10
|
+
class A
|
11
|
+
instance_methods do
|
12
|
+
def instance_method
|
13
|
+
'first version'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class_methods do
|
17
|
+
def class_method
|
18
|
+
'first version'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
A.new.instance_method.should == "first version"
|
24
|
+
A.class_method.should == "first version"
|
25
|
+
|
26
|
+
|
27
|
+
A.instance_methods do
|
28
|
+
def instance_method
|
29
|
+
'second version'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
A.class_methods do
|
34
|
+
def class_method
|
35
|
+
'second version'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
A.new.instance_method.should == "second version"
|
40
|
+
A.class_method.should == "second version"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "showcase" do
|
44
|
+
class A
|
45
|
+
instance_methods do
|
46
|
+
def a; end
|
47
|
+
|
48
|
+
def overrided_method
|
49
|
+
'a version'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class_methods do
|
54
|
+
def class_a; end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.inherited target
|
58
|
+
target.prototype.send :attr_accessor, :some_accessor
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class B
|
63
|
+
instance_methods do
|
64
|
+
def b; end
|
65
|
+
|
66
|
+
def overrided_method
|
67
|
+
'b version'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class_methods do
|
72
|
+
def class_b; end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class C
|
77
|
+
inherit A, B
|
78
|
+
end
|
79
|
+
|
80
|
+
c = C.new
|
81
|
+
c.should respond_to(:a)
|
82
|
+
c.should respond_to(:b)
|
83
|
+
c.should respond_to(:some_accessor)
|
84
|
+
|
85
|
+
C.should respond_to(:class_a)
|
86
|
+
C.should respond_to(:class_b)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should inherit all ancestors class methods (and take order into account by overriding)" do
|
90
|
+
class A
|
91
|
+
instance_methods do
|
92
|
+
def a; end
|
93
|
+
|
94
|
+
def overrided
|
95
|
+
'a'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class_methods do
|
100
|
+
def class_a; end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class B
|
105
|
+
inherit A
|
106
|
+
|
107
|
+
instance_methods do
|
108
|
+
def b; end
|
109
|
+
|
110
|
+
def overrided
|
111
|
+
'b'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class_methods do
|
116
|
+
def class_b; end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class C
|
121
|
+
inherit B
|
122
|
+
end
|
123
|
+
|
124
|
+
c = C.new
|
125
|
+
c.should respond_to(:a)
|
126
|
+
c.should respond_to(:b)
|
127
|
+
c.overrided.should == 'b'
|
128
|
+
|
129
|
+
C.should respond_to(:class_a)
|
130
|
+
C.should respond_to(:class_b)
|
131
|
+
|
132
|
+
C.instance_methods do
|
133
|
+
def overrided
|
134
|
+
'c'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
c = C.new
|
138
|
+
c.overrided.should == 'c'
|
139
|
+
end
|
140
|
+
|
141
|
+
it "shouldn't redefine ancestors class methods (from error)" do
|
142
|
+
class A
|
143
|
+
class_methods do
|
144
|
+
def class_method; end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class B
|
149
|
+
inherit A
|
150
|
+
|
151
|
+
class_methods do
|
152
|
+
def class_method2; end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
A.should_not respond_to(:class_method2)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "methods defined on base class after inheritance must be propagated to all descendants" do
|
160
|
+
class A; end
|
161
|
+
|
162
|
+
class B
|
163
|
+
inherit A
|
164
|
+
end
|
165
|
+
|
166
|
+
B.instance_methods.should_not include('method_added_after_inheritance')
|
167
|
+
A.prototype.send(:define_method, :method_added_after_inheritance){}
|
168
|
+
A.instance_methods.should include('method_added_after_inheritance')
|
169
|
+
B.instance_methods.should include('method_added_after_inheritance')
|
170
|
+
end
|
171
|
+
|
172
|
+
it "classes included in base class after inheritance must be propagated to all descendants" do
|
173
|
+
class A; end
|
174
|
+
|
175
|
+
class B
|
176
|
+
inherit A
|
177
|
+
end
|
178
|
+
|
179
|
+
class C
|
180
|
+
instance_methods do
|
181
|
+
def module_added_after_inheritance; end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
A.instance_methods.should_not include('module_added_after_inheritance')
|
186
|
+
A.inherit C
|
187
|
+
A.instance_methods.should include('module_added_after_inheritance')
|
188
|
+
B.instance_methods.should include('module_added_after_inheritance')
|
189
|
+
end
|
190
|
+
end
|
data/spec/array_spec.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require "#{File.dirname __FILE__}/helper"
|
2
|
+
require "ruby_ext/declarative_cache"
|
3
|
+
|
4
|
+
describe 'DeclarativeCache' do
|
5
|
+
class CachedClass
|
6
|
+
attr_accessor :value
|
7
|
+
def value_get; @value end
|
8
|
+
cache_method :value_get
|
9
|
+
|
10
|
+
attr_accessor :value2
|
11
|
+
def value2_get; @value2 end
|
12
|
+
|
13
|
+
attr_accessor :params
|
14
|
+
def params_get param; @params[param] end
|
15
|
+
|
16
|
+
attr_accessor :multiplier
|
17
|
+
def *(arg)
|
18
|
+
@multiplier * arg
|
19
|
+
end
|
20
|
+
cache_method_with_params '*'
|
21
|
+
end
|
22
|
+
|
23
|
+
DeclarativeCache.cache_method CachedClass, :value2_get
|
24
|
+
DeclarativeCache.cache_method_with_params CachedClass, :params_get
|
25
|
+
|
26
|
+
it "Simple Cache" do
|
27
|
+
o = CachedClass.new
|
28
|
+
o.value = 0
|
29
|
+
o.value2 = 0
|
30
|
+
o.value_get.should == 0
|
31
|
+
o.value2_get.should == 0
|
32
|
+
|
33
|
+
o.value = 1
|
34
|
+
o.value2 = 1
|
35
|
+
o.value_get.should == 0
|
36
|
+
o.value2_get.should == 0
|
37
|
+
end
|
38
|
+
|
39
|
+
it "clear_cache_method" do
|
40
|
+
o = CachedClass.new
|
41
|
+
o.value = 0
|
42
|
+
o.value_get.should == 0
|
43
|
+
|
44
|
+
o.value = 1
|
45
|
+
o.value_get.should == 0
|
46
|
+
|
47
|
+
o.clear_cache_method
|
48
|
+
o.value_get.should == 1
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should check for parameters" do
|
52
|
+
o = CachedClass.new
|
53
|
+
lambda{o.value_get(1)}.should raise_error(/cache_method_with_params/)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "Cache With Params" do
|
57
|
+
o = CachedClass.new
|
58
|
+
o.params = {:a => :b}
|
59
|
+
o.params_get(:a).should == :b
|
60
|
+
o.params = {:a => :c}
|
61
|
+
o.params_get(:a).should == :b
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should works with operators" do
|
65
|
+
o = CachedClass.new
|
66
|
+
o.multiplier = 2
|
67
|
+
(o * 2).should == 4
|
68
|
+
o.multiplier = 3
|
69
|
+
(o * 2).should == 4
|
70
|
+
end
|
71
|
+
|
72
|
+
class CachedClass2
|
73
|
+
class << self
|
74
|
+
attr_accessor :value
|
75
|
+
def value_get; @value end
|
76
|
+
cache_method :value_get
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "Simple Cache" do
|
81
|
+
CachedClass2.value = 0
|
82
|
+
CachedClass2.value_get.should == 0
|
83
|
+
CachedClass2.value = 1
|
84
|
+
CachedClass2.value_get.should == 0
|
85
|
+
end
|
86
|
+
|
87
|
+
module CachedModule
|
88
|
+
attr_accessor :value
|
89
|
+
def value_get; @value end
|
90
|
+
cache_method :value_get
|
91
|
+
end
|
92
|
+
|
93
|
+
class CachedClass3
|
94
|
+
include CachedModule
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should also works with modules (from error)" do
|
98
|
+
o = CachedClass.new
|
99
|
+
o.value = 0
|
100
|
+
o.value_get.should == 0
|
101
|
+
|
102
|
+
o.value = 1
|
103
|
+
o.value_get.should == 0
|
104
|
+
end
|
105
|
+
|
106
|
+
class CachedClass4
|
107
|
+
attr_accessor :value
|
108
|
+
def value_get; @value end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should not allow to cache twice" do
|
112
|
+
CachedClass4.cache_method :value_get
|
113
|
+
lambda{CachedClass4.cache_method :value_get}.should raise_error(/twice/)
|
114
|
+
end
|
115
|
+
end
|