decoratable 0.0.1
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 +7 -0
- data/.travis.yml +8 -0
- data/Gemfile +3 -0
- data/Rakefile +9 -0
- data/decoratable.gemspec +20 -0
- data/lib/decoratable.rb +159 -0
- data/lib/decoratable/countable.rb +26 -0
- data/lib/decoratable/debuggable.rb +11 -0
- data/lib/decoratable/hintable.rb +22 -0
- data/lib/decoratable/memoizable.rb +15 -0
- data/lib/decoratable/pryable.rb +12 -0
- data/lib/decoratable/retryable.rb +16 -0
- data/test/decoratable/countable_test.rb +22 -0
- data/test/decoratable/hintable_test.rb +29 -0
- data/test/decoratable/memoizable_test.rb +28 -0
- data/test/decoratable/pryable_test.rb +47 -0
- data/test/decoratable/retryable_test.rb +33 -0
- data/test/decoratable_test.rb +150 -0
- data/test/test_helper.rb +4 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6a8eadd3a9f64dd170469d9bf46f9765ce9d411a
|
4
|
+
data.tar.gz: e0daa4b811d58ef5b10b867b89743219b7a3ac0e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b81d3a486e381d52d909002417d19c2578c63c3c784e5e2ee32357c7fe807eee8b902a5c4d640e7184d9fc4321de13f08f623a18c34c7decf7db01896b1f4208
|
7
|
+
data.tar.gz: c49567ab494c3e5ccd247adc8c0492c4b0186eb7086bbce37a6e579d288ab2b34f9abab76243ad65943d7eb5f2b630aa4c9007480505f0dabae6caf800ba1071
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
data/decoratable.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "decoratable"
|
6
|
+
spec.version = "0.0.1"
|
7
|
+
spec.authors = ["ecin"]
|
8
|
+
spec.email = ["ecin@copypastel.com"]
|
9
|
+
spec.description = "Decorate your methods."
|
10
|
+
spec.summary = "Easily define decorations for your methods. Put a bow on it."
|
11
|
+
spec.homepage = "https://github.com/ecin/decoratable"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files`.split($/)
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_development_dependency "pry"
|
20
|
+
end
|
data/lib/decoratable.rb
ADDED
@@ -0,0 +1,159 @@
|
|
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
|
+
# measurable
|
66
|
+
# memoizable
|
67
|
+
# def get
|
68
|
+
# …
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# # Rescue and retry any Timeout::Errors, up to 5 times
|
72
|
+
# retryable 5, on: [Timeout::Error]
|
73
|
+
# def post
|
74
|
+
# …
|
75
|
+
# end
|
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 |*decorator_args|
|
89
|
+
# Wrap method_added to decorate the next method definition.
|
90
|
+
self.singleton_class.instance_eval do
|
91
|
+
alias_method "method_added_without_#{decoration_name}", :method_added
|
92
|
+
end
|
93
|
+
|
94
|
+
unless method_defined?(:__decorated_method__)
|
95
|
+
define_method(:__decorated_method__) { @__decorated_method__ }
|
96
|
+
end
|
97
|
+
|
98
|
+
unless method_defined?(:__args__)
|
99
|
+
define_method(:__args__) { @__args__ }
|
100
|
+
end
|
101
|
+
|
102
|
+
unless method_defined?(:__block__)
|
103
|
+
define_method(:__block__) { @__block__ }
|
104
|
+
end
|
105
|
+
|
106
|
+
# This method_added will affect the next decorated method.
|
107
|
+
define_singleton_method(:method_added) do |method_name|
|
108
|
+
|
109
|
+
original_method = instance_method(method_name)
|
110
|
+
|
111
|
+
decoration = Module.new do
|
112
|
+
self.singleton_class.instance_eval do
|
113
|
+
define_method(:name) do
|
114
|
+
"Decoratable::#{decoration_name}(#{method_name})"
|
115
|
+
end
|
116
|
+
|
117
|
+
alias_method :inspect, :name
|
118
|
+
alias_method :to_s, :name
|
119
|
+
end
|
120
|
+
|
121
|
+
define_method(method_name) do |*args, &block|
|
122
|
+
begin
|
123
|
+
# The decoration should have access to the original
|
124
|
+
# method it's modifying, along with the method call's
|
125
|
+
# arguments.
|
126
|
+
@__decorated_method__ = original_method
|
127
|
+
@__args__ = args
|
128
|
+
@__block__ = block
|
129
|
+
|
130
|
+
decoration_method.bind(self).call(*decorator_args) do
|
131
|
+
super(*args, &block)
|
132
|
+
end
|
133
|
+
ensure
|
134
|
+
@__decorated_method__ = nil
|
135
|
+
@__args__ = nil
|
136
|
+
@__block__ = nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Call aspect before "real" method.
|
142
|
+
prepend decoration
|
143
|
+
|
144
|
+
# Call next method_added link in the chain.
|
145
|
+
__send__("method_added_without_#{decoration_name}", method_name)
|
146
|
+
|
147
|
+
# Remove ourselves from method_added chain.
|
148
|
+
self.singleton_class.instance_eval do
|
149
|
+
alias_method :method_added, "method_added_without_#{decoration_name}"
|
150
|
+
remove_method "method_added_without_#{decoration_name}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
ensure
|
155
|
+
@@lock.unlock if @@lock.locked?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "decoratable"
|
2
|
+
|
3
|
+
module Countable
|
4
|
+
extend Decoratable
|
5
|
+
|
6
|
+
module Helper
|
7
|
+
def define_reader(object, key)
|
8
|
+
unless object.respond_to?(key)
|
9
|
+
object.define_singleton_method(key) { instance_variable_get(:"@#{key}") }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module_function :define_reader
|
14
|
+
end
|
15
|
+
|
16
|
+
def countable
|
17
|
+
key = :"#{__decorated_method__.name}_call_count"
|
18
|
+
Helper.define_reader(self, key)
|
19
|
+
|
20
|
+
instance_variable = :"@#{key}"
|
21
|
+
count = instance_variable_get(instance_variable).to_i
|
22
|
+
instance_variable_set(instance_variable, count + 1)
|
23
|
+
|
24
|
+
yield
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "decoratable"
|
2
|
+
|
3
|
+
module Hintable
|
4
|
+
extend Decoratable
|
5
|
+
|
6
|
+
def hintable(*classes, require_block: false)
|
7
|
+
argument_names = __decorated_method__.parameters.map { |(_, param)| param }
|
8
|
+
checks = __args__.zip(classes, argument_names)
|
9
|
+
|
10
|
+
# check args for types
|
11
|
+
failed_check = checks.find { |arg, klass, _| !arg.is_a?(klass) }
|
12
|
+
if failed_check
|
13
|
+
raise ArgumentError, "#{failed_check[2]} expected argument of type #{failed_check[1]}, was #{failed_check[0].class} (#{failed_check[0].inspect})"
|
14
|
+
end
|
15
|
+
|
16
|
+
if require_block && __block__.nil?
|
17
|
+
raise ArgumentError, "#{__decorated_method__.name} requires a block"
|
18
|
+
end
|
19
|
+
|
20
|
+
yield
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "decoratable"
|
2
|
+
|
3
|
+
module Memoizable
|
4
|
+
extend Decoratable
|
5
|
+
|
6
|
+
def memoizable
|
7
|
+
key = :"@#{__decorated_method__.name}_cache"
|
8
|
+
|
9
|
+
if instance_variable_defined?(key)
|
10
|
+
instance_variable_get key
|
11
|
+
else
|
12
|
+
instance_variable_set key, yield
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "decoratable"
|
2
|
+
|
3
|
+
module Retryable
|
4
|
+
extend Decoratable
|
5
|
+
|
6
|
+
def retryable(tries = 1, options = { on: [RuntimeError] } )
|
7
|
+
attempts = 0
|
8
|
+
|
9
|
+
begin
|
10
|
+
yield
|
11
|
+
rescue *options[:on]
|
12
|
+
attempts += 1
|
13
|
+
attempts > tries ? raise : retry
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "decoratable/countable"
|
4
|
+
|
5
|
+
describe Countable do
|
6
|
+
|
7
|
+
before do
|
8
|
+
klass = Class.new do
|
9
|
+
extend Countable
|
10
|
+
|
11
|
+
countable
|
12
|
+
def call; end
|
13
|
+
end
|
14
|
+
|
15
|
+
@object = klass.new
|
16
|
+
end
|
17
|
+
|
18
|
+
it "keeps count of how many times a method is called" do
|
19
|
+
3.times { @object.call }
|
20
|
+
@object.call_call_count.must_equal 3
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "decoratable/hintable"
|
4
|
+
|
5
|
+
describe Hintable do
|
6
|
+
|
7
|
+
before do
|
8
|
+
klass = Class.new do
|
9
|
+
extend Hintable
|
10
|
+
|
11
|
+
hintable(Integer, require_block: true)
|
12
|
+
def call(a); end
|
13
|
+
end
|
14
|
+
|
15
|
+
@object = klass.new
|
16
|
+
end
|
17
|
+
|
18
|
+
it "checks argument types" do
|
19
|
+
proc { @object.call(:a) }.must_raise ArgumentError, /#{Regexp.escape("a expected argument of type Integer, was Symbol (:a)")}/
|
20
|
+
end
|
21
|
+
|
22
|
+
it "checks for a required block" do
|
23
|
+
proc { @object.call(1) }.must_raise ArgumentError, /call requires a block/
|
24
|
+
end
|
25
|
+
|
26
|
+
it "steps out of the way for the correct arguments" do
|
27
|
+
@object.call(1) { }
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "decoratable/memoizable"
|
4
|
+
|
5
|
+
describe Memoizable do
|
6
|
+
|
7
|
+
before do
|
8
|
+
klass = Class.new do
|
9
|
+
extend Memoizable
|
10
|
+
|
11
|
+
memoizable
|
12
|
+
def call
|
13
|
+
@count ||= 0
|
14
|
+
@count += 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
@object = klass.new
|
19
|
+
end
|
20
|
+
|
21
|
+
it "memoizes a function's return value" do
|
22
|
+
3.times { @object.call }
|
23
|
+
|
24
|
+
# If method was memoized, the counter shouldn't have incremented
|
25
|
+
@object.call.must_equal 1
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "decoratable/pryable"
|
4
|
+
|
5
|
+
describe Pryable do
|
6
|
+
|
7
|
+
# stub Binding#pry for test; I'm sorry
|
8
|
+
class Binding
|
9
|
+
@@pry_count = 0
|
10
|
+
|
11
|
+
def self.pry_count
|
12
|
+
@@pry_count
|
13
|
+
end
|
14
|
+
|
15
|
+
def pry
|
16
|
+
@@pry_count += 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
before do
|
21
|
+
klass = Class.new do
|
22
|
+
extend Pryable
|
23
|
+
|
24
|
+
pryable(on: [NoMethodError, ArgumentError])
|
25
|
+
def call
|
26
|
+
@count ||= 0
|
27
|
+
|
28
|
+
case @count
|
29
|
+
when 0 then raise NoMethodError
|
30
|
+
when 1 then raise ArgumentError
|
31
|
+
else raise RuntimeError
|
32
|
+
end
|
33
|
+
|
34
|
+
ensure
|
35
|
+
@count += 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
@object = klass.new
|
40
|
+
end
|
41
|
+
|
42
|
+
it "enters a pry session for the specified exceptions" do
|
43
|
+
proc { 3.times { @object.call } }.must_raise RuntimeError
|
44
|
+
Binding.pry_count.must_equal 2
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "decoratable/retryable"
|
4
|
+
|
5
|
+
describe Retryable do
|
6
|
+
|
7
|
+
before do
|
8
|
+
klass = Class.new do
|
9
|
+
extend Retryable
|
10
|
+
|
11
|
+
retryable(3, on: [RuntimeError, ArgumentError])
|
12
|
+
def call
|
13
|
+
@count ||= 0
|
14
|
+
|
15
|
+
case @count
|
16
|
+
when 0 then raise RuntimeError
|
17
|
+
when 1 then raise ArgumentError
|
18
|
+
when 2 then raise NoMethodError
|
19
|
+
else raise NameError
|
20
|
+
end
|
21
|
+
ensure
|
22
|
+
@count += 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
@object = klass.new
|
27
|
+
end
|
28
|
+
|
29
|
+
it "retries a specific number of times on specific errors" do
|
30
|
+
proc { @object.call }.must_raise NoMethodError
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "decoratable"
|
4
|
+
require "decoratable/memoizable"
|
5
|
+
require "decoratable/countable"
|
6
|
+
require "decoratable/hintable"
|
7
|
+
|
8
|
+
require "logger"
|
9
|
+
|
10
|
+
describe Decoratable do
|
11
|
+
|
12
|
+
# Test-only decorations
|
13
|
+
module Decorations
|
14
|
+
extend Decoratable
|
15
|
+
|
16
|
+
include Countable
|
17
|
+
include Hintable
|
18
|
+
include Memoizable
|
19
|
+
|
20
|
+
def measurable(logger = Logger.new(STDOUT))
|
21
|
+
current = Time.now
|
22
|
+
yield
|
23
|
+
ensure
|
24
|
+
original_method = __decorated_method__
|
25
|
+
method_location, line = original_method.source_location
|
26
|
+
marker = "#{original_method.owner}##{original_method.name}[#{method_location}:#{line}]"
|
27
|
+
duration = (Time.now - current).round(2)
|
28
|
+
|
29
|
+
logger.info "#{marker} took #{duration}s to run."
|
30
|
+
end
|
31
|
+
|
32
|
+
def auditable
|
33
|
+
name = __decorated_method__.name
|
34
|
+
|
35
|
+
key = :"@audit_log"
|
36
|
+
audit_log = instance_variable_get(key) || []
|
37
|
+
audit_log << name
|
38
|
+
instance_variable_set(key, audit_log)
|
39
|
+
|
40
|
+
yield
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "decorates a method" do
|
45
|
+
klass = Class.new do
|
46
|
+
extend Decorations
|
47
|
+
|
48
|
+
countable
|
49
|
+
def call; end
|
50
|
+
end
|
51
|
+
|
52
|
+
object = klass.new
|
53
|
+
3.times { object.call }
|
54
|
+
object.call_call_count.must_equal 3
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can pass configuration arguments to the decoration" do
|
58
|
+
logger = mock_logger
|
59
|
+
klass = Class.new do
|
60
|
+
extend Decorations
|
61
|
+
|
62
|
+
measurable(logger)
|
63
|
+
def initialize; end
|
64
|
+
end
|
65
|
+
|
66
|
+
klass.new
|
67
|
+
logger.verify
|
68
|
+
end
|
69
|
+
|
70
|
+
it "can have multiple decorations on a method" do
|
71
|
+
klass = Class.new do
|
72
|
+
extend Decorations
|
73
|
+
|
74
|
+
countable
|
75
|
+
memoizable
|
76
|
+
def call
|
77
|
+
@counter ||= 0
|
78
|
+
@counter += 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
object = klass.new
|
83
|
+
3.times { object.call }
|
84
|
+
|
85
|
+
# Check countable() works
|
86
|
+
object.call_call_count.must_equal 3
|
87
|
+
|
88
|
+
# Check memoizable() works
|
89
|
+
object.call.must_equal 1
|
90
|
+
end
|
91
|
+
|
92
|
+
it "only decorates the next defined method" do
|
93
|
+
klass = Class.new do
|
94
|
+
extend Decorations
|
95
|
+
|
96
|
+
attr_reader :call2_call_count
|
97
|
+
|
98
|
+
countable
|
99
|
+
def call; end
|
100
|
+
def call2; end
|
101
|
+
end
|
102
|
+
|
103
|
+
object = klass.new
|
104
|
+
3.times { object.call }
|
105
|
+
3.times { object.call2 }
|
106
|
+
|
107
|
+
object.call_call_count.must_equal 3
|
108
|
+
object.call2_call_count.must_equal nil
|
109
|
+
end
|
110
|
+
|
111
|
+
it "allows access to the original decorated method" do
|
112
|
+
klass = Class.new do
|
113
|
+
extend Decorations
|
114
|
+
|
115
|
+
attr_reader :audit_log
|
116
|
+
|
117
|
+
auditable
|
118
|
+
def initialize; end
|
119
|
+
|
120
|
+
auditable
|
121
|
+
def call; end
|
122
|
+
end
|
123
|
+
|
124
|
+
object = klass.new
|
125
|
+
object.call
|
126
|
+
object.audit_log.must_equal [:initialize, :call]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "gives access to the arguments and blocks of the original method call" do
|
130
|
+
klass = Class.new do
|
131
|
+
extend Decorations
|
132
|
+
|
133
|
+
hintable(Integer, String, require_block: true)
|
134
|
+
def call(a, b); end
|
135
|
+
end
|
136
|
+
|
137
|
+
object = klass.new
|
138
|
+
proc { object.call(:a, 1) }.must_raise ArgumentError, /#{Regexp.escape("a expected argument of type Integer, was Symbol (:a)")}/
|
139
|
+
proc { object.call(1, :b) }.must_raise ArgumentError, /#{Regexp.escape("b expected argument of type String, was Symbol (:b)")}/
|
140
|
+
proc { object.call(1, "") }.must_raise ArgumentError, /call requires a block/
|
141
|
+
end
|
142
|
+
|
143
|
+
def mock_logger
|
144
|
+
logger = Minitest::Mock.new
|
145
|
+
logger.expect(:info, nil) do |message|
|
146
|
+
message =~ /took \d+\.\d+s to run/
|
147
|
+
end
|
148
|
+
logger
|
149
|
+
end
|
150
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: decoratable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ecin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pry
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Decorate your methods.
|
28
|
+
email:
|
29
|
+
- ecin@copypastel.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".travis.yml"
|
35
|
+
- Gemfile
|
36
|
+
- Rakefile
|
37
|
+
- decoratable.gemspec
|
38
|
+
- lib/decoratable.rb
|
39
|
+
- lib/decoratable/countable.rb
|
40
|
+
- lib/decoratable/debuggable.rb
|
41
|
+
- lib/decoratable/hintable.rb
|
42
|
+
- lib/decoratable/memoizable.rb
|
43
|
+
- lib/decoratable/pryable.rb
|
44
|
+
- lib/decoratable/retryable.rb
|
45
|
+
- test/decoratable/countable_test.rb
|
46
|
+
- test/decoratable/hintable_test.rb
|
47
|
+
- test/decoratable/memoizable_test.rb
|
48
|
+
- test/decoratable/pryable_test.rb
|
49
|
+
- test/decoratable/retryable_test.rb
|
50
|
+
- test/decoratable_test.rb
|
51
|
+
- test/test_helper.rb
|
52
|
+
homepage: https://github.com/ecin/decoratable
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata: {}
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 2.4.3
|
73
|
+
signing_key:
|
74
|
+
specification_version: 4
|
75
|
+
summary: Easily define decorations for your methods. Put a bow on it.
|
76
|
+
test_files:
|
77
|
+
- test/decoratable/countable_test.rb
|
78
|
+
- test/decoratable/hintable_test.rb
|
79
|
+
- test/decoratable/memoizable_test.rb
|
80
|
+
- test/decoratable/pryable_test.rb
|
81
|
+
- test/decoratable/retryable_test.rb
|
82
|
+
- test/decoratable_test.rb
|
83
|
+
- test/test_helper.rb
|
84
|
+
has_rdoc:
|