decorate 0.3.0
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/History.txt +3 -0
- data/Manifest.txt +15 -0
- data/README.txt +37 -0
- data/Rakefile +13 -0
- data/docsrc/repo +8 -0
- data/lib/decorate.rb +104 -0
- data/lib/decorate/around_decorator.rb +107 -0
- data/lib/decorate/before_decorator.rb +66 -0
- data/lib/decorate/create_alias.rb +28 -0
- data/lib/decorate/memoize.rb +39 -0
- data/lib/decorate/module_method.rb +52 -0
- data/lib/decorate/private_method.rb +50 -0
- data/lib/decorate/protected_method.rb +19 -0
- data/lib/decorate/public_method.rb +18 -0
- data/test.rb +120 -0
- metadata +110 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
README.txt
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
Rakefile
|
5
|
+
test.rb
|
6
|
+
docsrc/repo
|
7
|
+
lib/decorate.rb
|
8
|
+
lib/decorate/create_alias.rb
|
9
|
+
lib/decorate/private_method.rb
|
10
|
+
lib/decorate/protected_method.rb
|
11
|
+
lib/decorate/public_method.rb
|
12
|
+
lib/decorate/module_method.rb
|
13
|
+
lib/decorate/memoize.rb
|
14
|
+
lib/decorate/before_decorator.rb
|
15
|
+
lib/decorate/around_decorator.rb
|
data/README.txt
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
= decorate
|
2
|
+
|
3
|
+
Homepage:: http://github.com/lang/decorate
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
Python style decorators for Ruby, some common decorators like
|
8
|
+
private_method are provided out of the box.
|
9
|
+
|
10
|
+
Decorators that come with the decorate library:
|
11
|
+
|
12
|
+
* Decorate::PrivateMethod
|
13
|
+
* Decorate::ProtectedMethod
|
14
|
+
* Decorate::PublicMethod
|
15
|
+
* Decorate::ModuleMethod
|
16
|
+
* Decorate::Memoize
|
17
|
+
|
18
|
+
Helpers to create your own decorators:
|
19
|
+
|
20
|
+
* Decorate::AroundDecorator
|
21
|
+
* Decorate::BeforeDecorator
|
22
|
+
|
23
|
+
== Hygiene issues
|
24
|
+
|
25
|
+
Decorate hooks into (aka redefines) Module#method_added and
|
26
|
+
Object#singleton_method_added via the classic alias/delegate pattern.
|
27
|
+
If you override these methods in one of your classes that use
|
28
|
+
decorators, make sure to call +super+, otherwise decorate breaks.
|
29
|
+
|
30
|
+
Also, private_method, protected_method, public_method and
|
31
|
+
module_method are defined as private methods of Module, but only if
|
32
|
+
the respective files are required.
|
33
|
+
|
34
|
+
== License
|
35
|
+
|
36
|
+
Decorate is licensed under the same terms as the main Ruby
|
37
|
+
implementation. See http://www.ruby-lang.org/en/LICENSE.txt.
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "hoe"
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift("lib")
|
4
|
+
require "decorate"
|
5
|
+
|
6
|
+
Hoe.new "decorate", Decorate::VERSION do |p|
|
7
|
+
p.author = "Stefan Lang"
|
8
|
+
p.email = "langstefan@gmx.at"
|
9
|
+
p.url = "http://github.com/lang/decorate"
|
10
|
+
p.remote_rdoc_dir = ""
|
11
|
+
p.need_tar = true
|
12
|
+
p.need_zip = true
|
13
|
+
end
|
data/docsrc/repo
ADDED
data/lib/decorate.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Decorate
|
2
|
+
|
3
|
+
VERSION = "0.3.0"
|
4
|
+
|
5
|
+
# A BlockDecorator instance wraps an object (+block+) and delegates
|
6
|
+
# calls to +decorate+ to the wrapped objects +call+ method.
|
7
|
+
class BlockDecorator
|
8
|
+
|
9
|
+
def initialize(block)
|
10
|
+
@block = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def decorate(klass, method_name)
|
14
|
+
@block.call(klass, method_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
# Push a decorator on the current threads decorator stack.
|
20
|
+
# A decorator is an object that responds to +decorate+ taking a
|
21
|
+
# class and a method name (symbol) as arguments.
|
22
|
+
def self.push_decorator(decorator)
|
23
|
+
raise TypeError, "#{decorator} not a decorator" unless decorator
|
24
|
+
(Thread.current[:_decorator_stack_] ||= []).push(decorator)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Clear the current threads decorator stack. Returns the old stack
|
28
|
+
# as an Enumerable.
|
29
|
+
def self.clear_decorators
|
30
|
+
stack = (Thread.current[:_decorator_stack_] ||= []).dup
|
31
|
+
Thread.current[:_decorator_stack_].clear
|
32
|
+
stack
|
33
|
+
end
|
34
|
+
|
35
|
+
# Add a decorator that will be applied to the next method
|
36
|
+
# definition. Either pass an object that responds to
|
37
|
+
# decorate(klass, method_name) or a block. The block will be wrapped
|
38
|
+
# in a BlockDecorator.
|
39
|
+
#
|
40
|
+
# Example:
|
41
|
+
#
|
42
|
+
# def trace_def
|
43
|
+
# Decorate.decorate { |klass, method_name|
|
44
|
+
# puts "Method #{method_name.inspect} defined in #{klass.inspect}"
|
45
|
+
# }
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# class Foo
|
49
|
+
# trace_def
|
50
|
+
# def bar
|
51
|
+
# # ...
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
# # prints: Method :bar defined in Foo
|
55
|
+
def self.decorate(decorator = nil, &block)
|
56
|
+
if decorator.nil?
|
57
|
+
raise "decorator argument or block required" if block.nil?
|
58
|
+
decorator = BlockDecorator.new(block)
|
59
|
+
elsif block
|
60
|
+
raise "won't accept block if decorator argument is given"
|
61
|
+
end
|
62
|
+
push_decorator(decorator)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Apply the current threads decorator stack to the specified method.
|
66
|
+
#
|
67
|
+
# Decorate hooks into Module#method_added and
|
68
|
+
# Object#singleton_method_added to call this method.
|
69
|
+
def self.process_decorators(klass, method_name)
|
70
|
+
Decorate.clear_decorators.reverse!.each { |decorator|
|
71
|
+
decorator.decorate(klass, method_name)
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
class Module
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
alias _method_added_without_decorate method_added
|
82
|
+
|
83
|
+
def method_added(method_name)
|
84
|
+
#puts "method_added: #{self.inspect}[#{object_id}] #{method_name}"
|
85
|
+
_method_added_without_decorate(method_name)
|
86
|
+
Decorate.process_decorators(self, method_name)
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
class Object
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
alias _singleton_method_added_without_decorate singleton_method_added
|
96
|
+
|
97
|
+
def singleton_method_added(method_name)
|
98
|
+
_singleton_method_added_without_decorate(method_name)
|
99
|
+
klass = class << self; self; end
|
100
|
+
#puts "singleton_method_added: #{klass.inspect}[#{klass.object_id}] #{method_name}"
|
101
|
+
Decorate.process_decorators(klass, method_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require "decorate"
|
2
|
+
require "decorate/create_alias"
|
3
|
+
|
4
|
+
module Decorate::AroundDecorator
|
5
|
+
|
6
|
+
# An AroundCall holds the auxiliary information that is passed as
|
7
|
+
# argument to an around method.
|
8
|
+
class AroundCall
|
9
|
+
|
10
|
+
# Receiving object.
|
11
|
+
attr_reader :receiver
|
12
|
+
|
13
|
+
# The message that was sent resulting in this around call.
|
14
|
+
attr_reader :message
|
15
|
+
|
16
|
+
# The name of the method that constitutes the "core" behaviour
|
17
|
+
# (behaviour without the around logic).
|
18
|
+
attr_reader :wrapped_message
|
19
|
+
|
20
|
+
# Original argument list.
|
21
|
+
attr_reader :args
|
22
|
+
|
23
|
+
# Original block.
|
24
|
+
attr_reader :block
|
25
|
+
|
26
|
+
# Holds the result of a transfer to the wrapped method.
|
27
|
+
attr_reader :result
|
28
|
+
|
29
|
+
def initialize(receiver, message, wrapped_message, args, block)
|
30
|
+
@receiver = receiver
|
31
|
+
@message = message
|
32
|
+
@wrapped_message = wrapped_message
|
33
|
+
@args = args
|
34
|
+
@block = block
|
35
|
+
@result = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# Call the wrapped method. +args+ and +block+ default to original
|
39
|
+
# ones passed by client code. The return value of the wrapped
|
40
|
+
# method is stored in the +result+ attribute and also returned
|
41
|
+
# from transfer.
|
42
|
+
def transfer(args = @args, &block)
|
43
|
+
block ||= @block
|
44
|
+
@result = @receiver.__send__(@wrapped_message, *args, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
# Example:
|
50
|
+
#
|
51
|
+
# require "decorate/around_decorator"
|
52
|
+
#
|
53
|
+
# class Ad
|
54
|
+
# extend Decorate::AroundDecorator
|
55
|
+
#
|
56
|
+
# around_decorator :wrap, :call => :wrap
|
57
|
+
#
|
58
|
+
# def wrap(call)
|
59
|
+
# puts "Before #{call.inspect}"
|
60
|
+
# call.transfer
|
61
|
+
# puts "After #{call.inspect}"
|
62
|
+
# call.result + 1
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# wrap
|
66
|
+
# def foo(*args, &block)
|
67
|
+
# puts "foo: #{args.inspect}, block: #{block.inspect}"
|
68
|
+
# rand 10
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# >> o = Ad.new
|
74
|
+
# => <Ad:0xb7bd1e80>
|
75
|
+
# >> o.foo
|
76
|
+
# Before #<Decorate::AroundDecorator::AroundCall:0xb7bd0828 @message=:foo, @result=nil, @receiver=#<Ad:0xb7bd1e80>, @args=[], @block=nil, @wrapped_message=:foo_without_wrap>
|
77
|
+
# foo: [], block: nil
|
78
|
+
# After #<Decorate::AroundDecorator::AroundCall:0xb7bd0828 @message=:foo, @result=5, @receiver=#<Ad:0xb7bd1e80>, @args=[], @block=nil, @wrapped_message=:foo_without_wrap>
|
79
|
+
# => 6
|
80
|
+
def around_decorator(decorator_name, opts) #:doc:
|
81
|
+
around_method_name = opts[:call]
|
82
|
+
unless around_method_name.kind_of?(Symbol)
|
83
|
+
raise "Option :call with Symbol argument required"
|
84
|
+
end
|
85
|
+
unkown_opt = opts.keys.find { |opt| ![:call].include?(opt) }
|
86
|
+
if unkown_opt
|
87
|
+
raise "Unknown option #{unknown_opt.inspect}"
|
88
|
+
end
|
89
|
+
|
90
|
+
self.class.send(:define_method, decorator_name) {
|
91
|
+
Decorate.decorate { |klass, method_name|
|
92
|
+
wrapped_method_name =
|
93
|
+
Decorate.create_alias(klass, method_name, decorator_name)
|
94
|
+
klass.class_eval <<-EOF, __FILE__, __LINE__
|
95
|
+
def #{method_name}(*args, &block)
|
96
|
+
call = Decorate::AroundDecorator::AroundCall.new(
|
97
|
+
self, :#{method_name}, :#{wrapped_method_name},
|
98
|
+
args, block)
|
99
|
+
__send__(:#{around_method_name}, call)
|
100
|
+
end
|
101
|
+
EOF
|
102
|
+
}
|
103
|
+
}
|
104
|
+
end
|
105
|
+
private :around_decorator
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "decorate"
|
2
|
+
require "decorate/create_alias"
|
3
|
+
|
4
|
+
# This module is highly experimental and might change significantly or
|
5
|
+
# be removed completely since its usefulness is highly questionable in
|
6
|
+
# its current form.
|
7
|
+
module Decorate::BeforeDecorator
|
8
|
+
|
9
|
+
# Example:
|
10
|
+
#
|
11
|
+
# require "decorate/before_decorator"
|
12
|
+
#
|
13
|
+
# class Bf
|
14
|
+
# extend Decorate::BeforeDecorator
|
15
|
+
#
|
16
|
+
# before_decorator :trace_call, :call => :trace_call
|
17
|
+
#
|
18
|
+
# def trace_call(method_name, *args, &block)
|
19
|
+
# puts "Before #{self}.#{method_name}, args: #{args.inspect}, block: #{block.inspect}"
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# def foo
|
23
|
+
# puts "foo"
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# trace_call
|
27
|
+
# def bar
|
28
|
+
# puts "bar"
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# >> o = Bf.new
|
34
|
+
# >> o.foo
|
35
|
+
# foo
|
36
|
+
# >> o.bar
|
37
|
+
# Before #<Bf:0xb7b32dbc>.bar, args: [], block: nil
|
38
|
+
# bar
|
39
|
+
def before_decorator(decorator_name, opts) #:doc:
|
40
|
+
before_method_name = opts[:call]
|
41
|
+
unless before_method_name.kind_of?(Symbol)
|
42
|
+
raise "Option :call with Symbol argument required"
|
43
|
+
end
|
44
|
+
unkown_opt = opts.keys.find { |opt| ![:call].include?(opt) }
|
45
|
+
if unkown_opt
|
46
|
+
raise "Unknown option #{unknown_opt.inspect}"
|
47
|
+
end
|
48
|
+
|
49
|
+
self.class.send(:define_method, decorator_name) {
|
50
|
+
Decorate.decorate { |klass, method_name|
|
51
|
+
wrapped_method_name =
|
52
|
+
Decorate.create_alias(klass, method_name, decorator_name)
|
53
|
+
klass.class_eval <<-EOF, __FILE__, __LINE__
|
54
|
+
def #{method_name}(*args, &block)
|
55
|
+
self.__send__(:#{before_method_name},
|
56
|
+
:#{method_name}, *args, &block)
|
57
|
+
self.__send__(:#{wrapped_method_name},
|
58
|
+
*args, &block)
|
59
|
+
end
|
60
|
+
EOF
|
61
|
+
}
|
62
|
+
}
|
63
|
+
end
|
64
|
+
private :before_decorator
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Decorate
|
2
|
+
|
3
|
+
# Create a private alias for the instance method named +method_name+
|
4
|
+
# of class +klass+. The string representation of +id+ will be part
|
5
|
+
# of the alias to ease debugging. This method makes sure that the
|
6
|
+
# alias doesn't redefine an existing method.
|
7
|
+
#
|
8
|
+
# Returns the name of the new alias.
|
9
|
+
#
|
10
|
+
# In the simplest case, the alias will be
|
11
|
+
# <tt>"#{method_name}_without_#{id}"</tt>.
|
12
|
+
def self.create_alias(klass, method_name, id)
|
13
|
+
basename = "#{method_name}_without_#{id}"
|
14
|
+
|
15
|
+
i = 0
|
16
|
+
new_name = basename
|
17
|
+
loop {
|
18
|
+
break unless klass.method_defined?(new_name)
|
19
|
+
i += 1
|
20
|
+
new_name = "#{basename}_#{i}"
|
21
|
+
}
|
22
|
+
|
23
|
+
klass.send(:alias_method, new_name, method_name)
|
24
|
+
klass.send(:private, new_name)
|
25
|
+
new_name
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "decorate"
|
2
|
+
require "decorate/create_alias"
|
3
|
+
|
4
|
+
module Decorate::Memoize
|
5
|
+
|
6
|
+
# A naive memoization decorator, using a plain Hash as cache.
|
7
|
+
#
|
8
|
+
# Example usage:
|
9
|
+
#
|
10
|
+
# require "decorate/memoize"
|
11
|
+
#
|
12
|
+
# Decorate::Memoize.memoize
|
13
|
+
# def factorial(n)
|
14
|
+
# n == 0 ? 1 : n * factorial(n - 1)
|
15
|
+
# end
|
16
|
+
# factorial(7) # => 5040
|
17
|
+
#
|
18
|
+
# Memoization takes the arguments as well as the instance itself
|
19
|
+
# into account. You can also extend a module/class with
|
20
|
+
# Decorate::Memoize to leave off the module prefix. Note that this
|
21
|
+
# decorator doesn't work for methods that take a block.
|
22
|
+
def memoize
|
23
|
+
Decorate.decorate { |klass, method_name|
|
24
|
+
wrapped_method_name = Decorate.create_alias(klass, method_name, :memoize)
|
25
|
+
# TODO: should use weak hash tables
|
26
|
+
cache = Hash.new { |hash, key| hash[key] = {} }
|
27
|
+
klass.send(:define_method, method_name) { |*args|
|
28
|
+
icache = cache[self]
|
29
|
+
if icache.has_key?(args)
|
30
|
+
icache[args]
|
31
|
+
else
|
32
|
+
icache[args] = send(wrapped_method_name, *args)
|
33
|
+
end
|
34
|
+
}
|
35
|
+
}
|
36
|
+
end
|
37
|
+
module_function :memoize
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "decorate"
|
2
|
+
|
3
|
+
#--
|
4
|
+
# I'm not sure if module_method is the right name...
|
5
|
+
#++
|
6
|
+
|
7
|
+
module Decorate::ModuleMethod
|
8
|
+
|
9
|
+
# module_method decorator - makes the next defined method a module
|
10
|
+
# function. This decorator is available at the class and module
|
11
|
+
# level. The effect is the same as calling Module#module_function
|
12
|
+
# with the method name after the method definition.
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
#
|
16
|
+
# require "decorate/module_method"
|
17
|
+
#
|
18
|
+
# module Shell
|
19
|
+
#
|
20
|
+
# module_method
|
21
|
+
# def sh(command)
|
22
|
+
# system(command)
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# is equivalent to:
|
28
|
+
#
|
29
|
+
# module Shell
|
30
|
+
#
|
31
|
+
# def sh(command)
|
32
|
+
# system(command)
|
33
|
+
# end
|
34
|
+
# module_function :sh
|
35
|
+
#
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# In this example, +sh+ is now a method of the +Shell+ object as
|
39
|
+
# well as an instance method of the +Shell+ module. Read <tt>ri
|
40
|
+
# Module#module_function</tt> for more details.
|
41
|
+
def module_method #:doc:
|
42
|
+
Decorate.decorate { |klass, method_name|
|
43
|
+
klass.send :module_function, method_name
|
44
|
+
}
|
45
|
+
end
|
46
|
+
private :module_method
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
class Module
|
51
|
+
include Decorate::ModuleMethod
|
52
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "decorate"
|
2
|
+
|
3
|
+
module Decorate::PrivateMethod
|
4
|
+
|
5
|
+
# private_method decorator - makes the next defined method private.
|
6
|
+
# Can be used at the module-, class- and toplevel.
|
7
|
+
#
|
8
|
+
# Examples:
|
9
|
+
#
|
10
|
+
# require "decorate/private_method"
|
11
|
+
#
|
12
|
+
# class Foo
|
13
|
+
# private_method
|
14
|
+
# def bar
|
15
|
+
# puts "Foo#bar called"
|
16
|
+
# end
|
17
|
+
# def foo
|
18
|
+
# bar
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# f = Foo.new
|
22
|
+
# f.foo # Foo#bar called
|
23
|
+
# f.bar # NoMethodError: private method `bar' called for #<Foo:0xb7be2f64>
|
24
|
+
#
|
25
|
+
# my_object = Object.new
|
26
|
+
# private_method
|
27
|
+
# def my_object.foo
|
28
|
+
# puts "foo"
|
29
|
+
# end
|
30
|
+
# my_object.foo # => NoMethodError: private method `foo' called for #<Object:0xb7bdce20>
|
31
|
+
#
|
32
|
+
# private_method
|
33
|
+
# Foo.send(:define_method, :baz) { puts "baz" }
|
34
|
+
# f.baz # => NoMethodError: private method `baz' called for #<Foo:0xb7ba7d38>
|
35
|
+
def private_method #:doc:
|
36
|
+
Decorate.decorate { |klass, method_name|
|
37
|
+
klass.send :private, method_name
|
38
|
+
}
|
39
|
+
end
|
40
|
+
private :private_method
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# Make private_method available at the class/module level.
|
45
|
+
class Module
|
46
|
+
include Decorate::PrivateMethod
|
47
|
+
end
|
48
|
+
|
49
|
+
# Make private_method available at the toplevel.
|
50
|
+
extend Decorate::PrivateMethod
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "decorate"
|
2
|
+
|
3
|
+
module Decorate::ProtectedMethod
|
4
|
+
# protected_method decorator - makes the next defined method
|
5
|
+
# protected. Otherwise works like
|
6
|
+
# Decorate::PrivateMethod#private_method.
|
7
|
+
def protected_method #:doc:
|
8
|
+
Decorate.decorate { |klass, method_name|
|
9
|
+
klass.send :protected, method_name
|
10
|
+
}
|
11
|
+
end
|
12
|
+
private :protected_method
|
13
|
+
end
|
14
|
+
|
15
|
+
class Module
|
16
|
+
include Decorate::ProtectedMethod
|
17
|
+
end
|
18
|
+
|
19
|
+
extend Decorate::ProtectedMethod
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "decorate"
|
2
|
+
|
3
|
+
module Decorate::PublicMethod
|
4
|
+
# public_method decorator - makes the next defined method public.
|
5
|
+
# Otherwise works like Decorate::PrivateMethod#private_method.
|
6
|
+
def public_method #:doc:
|
7
|
+
Decorate.decorate { |klass, method_name|
|
8
|
+
klass.send :public, method_name
|
9
|
+
}
|
10
|
+
end
|
11
|
+
private :public_method
|
12
|
+
end
|
13
|
+
|
14
|
+
class Module
|
15
|
+
include Decorate::PublicMethod
|
16
|
+
end
|
17
|
+
|
18
|
+
extend Decorate::PublicMethod
|
data/test.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
$:.unshift "lib"
|
2
|
+
|
3
|
+
require "decorate/private_method"
|
4
|
+
require "decorate/memoize"
|
5
|
+
|
6
|
+
class Foo
|
7
|
+
|
8
|
+
def foo
|
9
|
+
puts "foo"
|
10
|
+
bar
|
11
|
+
end
|
12
|
+
|
13
|
+
private_method
|
14
|
+
def bar
|
15
|
+
puts "bar"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class M1
|
21
|
+
extend Decorate::Memoize
|
22
|
+
|
23
|
+
memoize
|
24
|
+
def m1(a, b)
|
25
|
+
puts "#{self}.m1(#{a}, #{b})"
|
26
|
+
case [a,b]
|
27
|
+
when [1,2]; 1
|
28
|
+
when [2,3]; 2
|
29
|
+
when [4,5]; 3
|
30
|
+
else -1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
puts "defining class method m1"
|
35
|
+
|
36
|
+
# doesn't work (yet)
|
37
|
+
# Must hook into Object#singleton_method_added to make it work!
|
38
|
+
memoize
|
39
|
+
def self.m1(a, b)
|
40
|
+
puts "#{self}.m1(#{a}, #{b})"
|
41
|
+
case [a,b]
|
42
|
+
when [1,2]; 1
|
43
|
+
when [2,3]; 2
|
44
|
+
when [4,5]; 3
|
45
|
+
else -1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
extend Decorate::Memoize
|
52
|
+
|
53
|
+
memoize
|
54
|
+
def mx(a, b)
|
55
|
+
puts "#{self}.m1(#{a}, #{b})"
|
56
|
+
case [a,b]
|
57
|
+
when [1,2]; 1
|
58
|
+
when [2,3]; 2
|
59
|
+
when [4,5]; 3
|
60
|
+
else -1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
Decorate::Memoize.memoize
|
65
|
+
def my(a, b)
|
66
|
+
puts "#{self}.m1(#{a}, #{b})"
|
67
|
+
case [a,b]
|
68
|
+
when [1,2]; 1
|
69
|
+
when [2,3]; 2
|
70
|
+
when [4,5]; 3
|
71
|
+
else -1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private_method
|
76
|
+
def private_toplevel_method
|
77
|
+
puts "private_toplevel_method called"
|
78
|
+
end
|
79
|
+
|
80
|
+
require "decorate/before_decorator"
|
81
|
+
class Bf
|
82
|
+
extend Decorate::BeforeDecorator
|
83
|
+
|
84
|
+
before_decorator :trace_call, :call => :trace_call
|
85
|
+
|
86
|
+
def trace_call(method_name, *args, &block)
|
87
|
+
puts "Before #{self}.#{method_name}, args: #{args.inspect}, block: #{block.inspect}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def foo
|
91
|
+
puts "foo"
|
92
|
+
end
|
93
|
+
|
94
|
+
trace_call
|
95
|
+
def bar
|
96
|
+
puts "bar"
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
require "decorate/around_decorator"
|
102
|
+
class Ad
|
103
|
+
extend Decorate::AroundDecorator
|
104
|
+
|
105
|
+
around_decorator :wrap, :call => :wrap
|
106
|
+
|
107
|
+
def wrap(call)
|
108
|
+
puts "Before #{call.inspect}"
|
109
|
+
call.transfer
|
110
|
+
puts "After #{call.inspect}"
|
111
|
+
call.result + 1
|
112
|
+
end
|
113
|
+
|
114
|
+
wrap
|
115
|
+
def foo(*args, &block)
|
116
|
+
puts "foo: #{args.inspect}, block: #{block.inspect}"
|
117
|
+
rand 10
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: decorate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Stefan Lang
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-31 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: hoe
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 2
|
30
|
+
- 8
|
31
|
+
- 0
|
32
|
+
version: 2.8.0
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
description: |-
|
36
|
+
Python style decorators for Ruby, some common decorators like
|
37
|
+
private_method are provided out of the box.
|
38
|
+
|
39
|
+
Decorators that come with the decorate library:
|
40
|
+
|
41
|
+
* Decorate::PrivateMethod
|
42
|
+
* Decorate::ProtectedMethod
|
43
|
+
* Decorate::PublicMethod
|
44
|
+
* Decorate::ModuleMethod
|
45
|
+
* Decorate::Memoize
|
46
|
+
|
47
|
+
Helpers to create your own decorators:
|
48
|
+
|
49
|
+
* Decorate::AroundDecorator
|
50
|
+
* Decorate::BeforeDecorator
|
51
|
+
email: langstefan@gmx.at
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files:
|
57
|
+
- README.txt
|
58
|
+
- History.txt
|
59
|
+
- Manifest.txt
|
60
|
+
files:
|
61
|
+
- README.txt
|
62
|
+
- History.txt
|
63
|
+
- Manifest.txt
|
64
|
+
- Rakefile
|
65
|
+
- test.rb
|
66
|
+
- docsrc/repo
|
67
|
+
- lib/decorate.rb
|
68
|
+
- lib/decorate/create_alias.rb
|
69
|
+
- lib/decorate/private_method.rb
|
70
|
+
- lib/decorate/protected_method.rb
|
71
|
+
- lib/decorate/public_method.rb
|
72
|
+
- lib/decorate/module_method.rb
|
73
|
+
- lib/decorate/memoize.rb
|
74
|
+
- lib/decorate/before_decorator.rb
|
75
|
+
- lib/decorate/around_decorator.rb
|
76
|
+
has_rdoc: true
|
77
|
+
homepage: http://github.com/lang/decorate
|
78
|
+
licenses: []
|
79
|
+
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options:
|
82
|
+
- --main
|
83
|
+
- README.txt
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
requirements: []
|
103
|
+
|
104
|
+
rubyforge_project: decorate
|
105
|
+
rubygems_version: 1.3.7
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: Python style decorators for Ruby, some common decorators like private_method are provided out of the box
|
109
|
+
test_files: []
|
110
|
+
|