decoratable 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/decoratable.gemspec +1 -1
- data/lib/decoratable/classic.rb +146 -0
- data/test/decoratable/classic_test.rb +43 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4faaa57297c2f587f2d751980cee3d857b0442a7
|
4
|
+
data.tar.gz: d6c7d401b73f284dbd4a9ff3a22f152e95481dc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cce79e57059864cf7b5d8414f71b077ace17d48231706ca0485ec50901dc6037a2e701ac98c9d2d24a39759cceee546b7f90007efb4a81723d7b89731c560efa
|
7
|
+
data.tar.gz: 14816d8694e7e63a38a85dad25f5f86f4b96e88e17cb14f516a4b07fd8d5950b7c8cd4f124581bfe5f1a8fb5f571af23d7028a2af4dc1bb13807fe152787efc9
|
data/decoratable.gemspec
CHANGED
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = "decoratable"
|
6
|
-
spec.version = "0.0.
|
6
|
+
spec.version = "0.0.5"
|
7
7
|
spec.authors = ["ecin"]
|
8
8
|
spec.email = ["ecin@copypastel.com"]
|
9
9
|
spec.description = "Decorate your methods."
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require "thread"
|
2
|
+
|
3
|
+
# Public: provide an easy way to define decorations
|
4
|
+
# that add common behaviour to a method.
|
5
|
+
#
|
6
|
+
# More info on decorations as implemented in Python:
|
7
|
+
# http://en.wikipedia.org/wiki/Python_syntax_and_semantics#Decorators
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# module Decorations
|
12
|
+
# extend Decoratable
|
13
|
+
#
|
14
|
+
# def retryable(tries = 1, options = { on: [RuntimeError] })
|
15
|
+
# attempts = 0
|
16
|
+
#
|
17
|
+
# begin
|
18
|
+
# yield
|
19
|
+
# rescue *options[:on]
|
20
|
+
# attempts += 1
|
21
|
+
# attempts > tries ? raise : retry
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# def measurable(logger = STDOUT)
|
26
|
+
# start = Time.now
|
27
|
+
# yield
|
28
|
+
# ensure
|
29
|
+
# original_method = __decorated_method__
|
30
|
+
# method_location, line = original_method.source_location
|
31
|
+
# marker = "#{original_method.owner}##{original_method.name}[#{method_location}:#{line}]"
|
32
|
+
# duration = (Time.now - start).round(2)
|
33
|
+
#
|
34
|
+
# logger.puts "#{marker} took #{duration}s to run."
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# def debuggable
|
38
|
+
# begin
|
39
|
+
# yield
|
40
|
+
# rescue => e
|
41
|
+
# puts "Caught #{e}!!!"
|
42
|
+
# require "debug"
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# def memoizable
|
47
|
+
# key = :"@#{__decorated_method__.name}_cache"
|
48
|
+
#
|
49
|
+
# instance_variable_set(key, {}) unless defined?(key)
|
50
|
+
# cache = instance_variable_get(key)
|
51
|
+
#
|
52
|
+
# if cache.key?(__args__)
|
53
|
+
# cache[__args__]
|
54
|
+
# else
|
55
|
+
# cache[__args__] = yield
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# class Client
|
61
|
+
# extend Decorations
|
62
|
+
#
|
63
|
+
# # Let's keep track of how long #get takes to run,
|
64
|
+
# # and memoize the return value
|
65
|
+
# def get
|
66
|
+
# …
|
67
|
+
# end
|
68
|
+
# measurable :get
|
69
|
+
# memoizable :get
|
70
|
+
#
|
71
|
+
# # Rescue and retry any Timeout::Errors, up to 5 times
|
72
|
+
# def post
|
73
|
+
# …
|
74
|
+
# end
|
75
|
+
# retryable :post, 5, on: [Timeout::Error]
|
76
|
+
# end
|
77
|
+
module Decoratable
|
78
|
+
@@lock = Mutex.new
|
79
|
+
|
80
|
+
def self.extended(klass)
|
81
|
+
# This #method_added affects all methods defined in the module
|
82
|
+
# that extends Decoratable.
|
83
|
+
def klass.method_added(decoration_name)
|
84
|
+
return unless @@lock.try_lock
|
85
|
+
|
86
|
+
decoration_method = instance_method(decoration_name)
|
87
|
+
|
88
|
+
define_method(decoration_name) do |method_name, *decorator_args|
|
89
|
+
unless method_defined?(:__original_caller__)
|
90
|
+
define_method(:__original_caller__) { @__original_caller__ }
|
91
|
+
end
|
92
|
+
|
93
|
+
unless method_defined?(:__decorated_method__)
|
94
|
+
define_method(:__decorated_method__) { @__decorated_method__ }
|
95
|
+
end
|
96
|
+
|
97
|
+
unless method_defined?(:__args__)
|
98
|
+
define_method(:__args__) { @__args__ }
|
99
|
+
end
|
100
|
+
|
101
|
+
unless method_defined?(:__block__)
|
102
|
+
define_method(:__block__) { @__block__ }
|
103
|
+
end
|
104
|
+
|
105
|
+
original_method = instance_method(method_name)
|
106
|
+
|
107
|
+
decoration = Module.new do
|
108
|
+
self.singleton_class.instance_eval do
|
109
|
+
define_method(:name) do
|
110
|
+
"Decoratable::#{decoration_name}(#{method_name})"
|
111
|
+
end
|
112
|
+
|
113
|
+
alias_method :inspect, :name
|
114
|
+
alias_method :to_s, :name
|
115
|
+
end
|
116
|
+
|
117
|
+
define_method(method_name) do |*args, &block|
|
118
|
+
begin
|
119
|
+
# The decoration should have access to the original
|
120
|
+
# method it's modifying, along with the method call's
|
121
|
+
# arguments.
|
122
|
+
@__decorated_method__ = original_method
|
123
|
+
@__args__ = args
|
124
|
+
@__block__ = block
|
125
|
+
@__original_caller__ ||= caller
|
126
|
+
|
127
|
+
decoration_method.bind(self).call(*decorator_args) do
|
128
|
+
super(*args, &block)
|
129
|
+
end
|
130
|
+
ensure
|
131
|
+
@__decorated_method__ = nil
|
132
|
+
@__args__ = nil
|
133
|
+
@__block__ = nil
|
134
|
+
@__original_caller__ = nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Call aspect before "real" method.
|
140
|
+
prepend decoration
|
141
|
+
end
|
142
|
+
ensure
|
143
|
+
@@lock.unlock if @@lock.locked?
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "decoratable/classic"
|
4
|
+
|
5
|
+
require "logger"
|
6
|
+
|
7
|
+
describe "Decoratable: Classic Style" do
|
8
|
+
# Test-only decorations
|
9
|
+
module Decorations
|
10
|
+
extend Decoratable
|
11
|
+
|
12
|
+
def loggable(logger: Logger.new(STDOUT))
|
13
|
+
logger.info __decorated_method__.name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
it "decorates a method, classic style" do
|
17
|
+
logger = mock_logger
|
18
|
+
klass = Class.new do
|
19
|
+
extend Decorations
|
20
|
+
|
21
|
+
def call; end
|
22
|
+
loggable :call, logger: logger
|
23
|
+
end
|
24
|
+
|
25
|
+
object = klass.new
|
26
|
+
3.times { object.call }
|
27
|
+
end
|
28
|
+
|
29
|
+
def mock_logger
|
30
|
+
logger = Minitest::Mock.new
|
31
|
+
|
32
|
+
# We expect info to be called thrice
|
33
|
+
logger.expect(:info, nil, [:call])
|
34
|
+
logger.expect(:info, nil, [:call])
|
35
|
+
logger.expect(:info, nil, [:call])
|
36
|
+
|
37
|
+
logger
|
38
|
+
end
|
39
|
+
|
40
|
+
# Remove Decoratable constant so we reset back to original
|
41
|
+
Object.send(:remove_const, :Decoratable)
|
42
|
+
load "decoratable.rb"
|
43
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: decoratable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ecin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -65,6 +65,7 @@ files:
|
|
65
65
|
- Rakefile
|
66
66
|
- decoratable.gemspec
|
67
67
|
- lib/decoratable.rb
|
68
|
+
- lib/decoratable/classic.rb
|
68
69
|
- lib/decoratable/countable.rb
|
69
70
|
- lib/decoratable/debuggable.rb
|
70
71
|
- lib/decoratable/deprecatable.rb
|
@@ -73,6 +74,7 @@ files:
|
|
73
74
|
- lib/decoratable/pryable.rb
|
74
75
|
- lib/decoratable/retryable.rb
|
75
76
|
- lib/decoratable/synchronizable.rb
|
77
|
+
- test/decoratable/classic_test.rb
|
76
78
|
- test/decoratable/countable_test.rb
|
77
79
|
- test/decoratable/deprecatable_test.rb
|
78
80
|
- test/decoratable/hintable_test.rb
|
@@ -107,6 +109,7 @@ signing_key:
|
|
107
109
|
specification_version: 4
|
108
110
|
summary: Easily define decorations for your methods. Put a bow on it.
|
109
111
|
test_files:
|
112
|
+
- test/decoratable/classic_test.rb
|
110
113
|
- test/decoratable/countable_test.rb
|
111
114
|
- test/decoratable/deprecatable_test.rb
|
112
115
|
- test/decoratable/hintable_test.rb
|