decors 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +5 -0
- data/README.md +18 -0
- data/decors.gemspec +22 -0
- data/lib/decors/decorator_base.rb +25 -0
- data/lib/decors/decorator_definition.rb +17 -0
- data/lib/decors/method_added_listener.rb +35 -0
- data/lib/decors.rb +7 -0
- data/spec/decors_spec.rb +369 -0
- data/spec/spec_helper.rb +19 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c33d4924184f251e5ee9c3a372251355e09efe7f
|
4
|
+
data.tar.gz: 9ddc59be81ccc266b78d36b3b9dc656b37c97bc0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3b965a9750314f1f8e921510c9e6275eae49ec18c3f8a2285b796700acfb813e9db6aa4f95e9c68d179d1cc2665bf8891c093a9617a94971f44cf4098f1f801e
|
7
|
+
data.tar.gz: 6f6e62a25f06fe9e2d474aa1ec45cc43c85f4e598d070e2b0da5ee9b42d854b8b0a44ab96f5e2d4b4567921dd9ac5a4ee75d8a4b766c46a0820b8b6b008132e4
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Decors
|
2
|
+
|
3
|
+
#### Yet another implementation of Python Decorators/Java annotation in ruby
|
4
|
+
|
5
|
+
Here are other implementations:
|
6
|
+
- https://github.com/wycats/ruby_decorators
|
7
|
+
- https://github.com/michaelfairley/method_decorators
|
8
|
+
- https://github.com/fredwu/ruby_decorators
|
9
|
+
- https://gist.github.com/reu/2762650
|
10
|
+
|
11
|
+
## Install
|
12
|
+
|
13
|
+
Add `gem 'decors'` to your Gemfile and then `bundle`
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
## License
|
18
|
+
|
data/decors.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require 'decors'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "decors"
|
8
|
+
gem.version = ::Decors::VERSION
|
9
|
+
gem.authors = ['Vivien Meyet']
|
10
|
+
gem.email = ['vivien@getbannerman.com']
|
11
|
+
gem.description = "Ruby implementation of Python method decorators / Java annotations"
|
12
|
+
gem.summary = gem.description
|
13
|
+
gem.homepage = 'https://github.com/getbannerman/decors'
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_development_dependency 'pry-byebug', '~> 0'
|
21
|
+
gem.add_development_dependency 'rspec', '~> 0'
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Decors
|
2
|
+
class DecoratorBase
|
3
|
+
attr_reader :decorated_class, :decorated_method, :decorator_args, :decorator_kwargs, :decorator_block
|
4
|
+
|
5
|
+
def initialize(decorated_class, decorated_method, *args, **kwargs, &block)
|
6
|
+
@decorated_class = decorated_class
|
7
|
+
@decorated_method = decorated_method
|
8
|
+
@decorator_args = args
|
9
|
+
@decorator_kwargs = kwargs
|
10
|
+
@decorator_block = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(instance, *args, &block)
|
14
|
+
undecorated_call(instance, *args, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def undecorated_call(instance, *args, &block)
|
18
|
+
decorated_method.bind(instance).call(*args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def decorated_method_name
|
22
|
+
decorated_method.name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Decors
|
2
|
+
module DecoratorDefinition
|
3
|
+
def define_mixin_decorator(decorator_name, decorator_class)
|
4
|
+
define_decorator(decorator_name, decorator_class, mixin: true)
|
5
|
+
end
|
6
|
+
|
7
|
+
def define_decorator(decorator_name, decorator_class, mixin: false)
|
8
|
+
method_definer = mixin ? :define_method : :define_singleton_method
|
9
|
+
|
10
|
+
send(method_definer, decorator_name) do |*params, &blk|
|
11
|
+
ctx = self.singleton_class? ? ObjectSpace.each_object(self).first : self
|
12
|
+
ctx.send(:extend, MethodAddedListener)
|
13
|
+
ctx.declared_decorators << [decorator_class, params, blk]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Decors
|
2
|
+
# Mixin that add method_added hooks
|
3
|
+
module MethodAddedListener
|
4
|
+
def method_added(meth)
|
5
|
+
super
|
6
|
+
handle_method_addition(self, meth)
|
7
|
+
end
|
8
|
+
|
9
|
+
def singleton_method_added(meth)
|
10
|
+
super
|
11
|
+
handle_method_addition(singleton_class, meth)
|
12
|
+
end
|
13
|
+
|
14
|
+
def declared_decorators
|
15
|
+
@declared_decorators ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# method addition handling is the same for singleton and instance method
|
21
|
+
def handle_method_addition(clazz, method_name)
|
22
|
+
# @_ignore_additions allows to temporarily disable the hook
|
23
|
+
return if @_ignore_additions || declared_decorators.empty?
|
24
|
+
decorator_class, params, blk = declared_decorators.pop
|
25
|
+
|
26
|
+
decorated_method = clazz.instance_method(method_name)
|
27
|
+
|
28
|
+
@_ignore_additions = true
|
29
|
+
decorator = decorator_class.new(clazz, decorated_method, *params, &blk)
|
30
|
+
@_ignore_additions = false
|
31
|
+
|
32
|
+
clazz.send(:define_method, method_name) { |*args, &block| decorator.call(self, *args, &block) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/decors.rb
ADDED
data/spec/decors_spec.rb
ADDED
@@ -0,0 +1,369 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Decors do
|
4
|
+
before { stub_class(:TestClass) { extend Decors::DecoratorDefinition } }
|
5
|
+
before {
|
6
|
+
stub_class(:Spy) {
|
7
|
+
def self.passed_args(*args, **kwargs, &block)
|
8
|
+
arguments(args: args, kwargs: kwargs, evald_block: block&.call)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.arguments(*); end
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
context 'when simple case decorator' do
|
16
|
+
before {
|
17
|
+
stub_class(:SimpleDecorator, inherits: [::Decors::DecoratorBase]) {
|
18
|
+
def initialize(decorated_class, decorated_method, *deco_args, **deco_kwargs, &deco_block)
|
19
|
+
super
|
20
|
+
Spy.passed_args(*deco_args, **deco_kwargs, &deco_block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(instance, *args, &block)
|
24
|
+
super
|
25
|
+
Spy.passed_args(*args, &block)
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
TestClass.class_eval { define_decorator :SimpleDecorator, SimpleDecorator }
|
30
|
+
}
|
31
|
+
|
32
|
+
context 'It receive all the parameters at initialization' do
|
33
|
+
it { expect(SimpleDecorator).to receive(:new).with(TestClass, anything, 1, 2, a: 3).and_call_original }
|
34
|
+
it { expect(Spy).to receive(:arguments).with(args: [1, 2], kwargs: { a: 3 }, evald_block: 'ok') }
|
35
|
+
|
36
|
+
after {
|
37
|
+
TestClass.class_eval {
|
38
|
+
SimpleDecorator(1, 2, a: 3) { 'ok' }
|
39
|
+
def test_method(*); end
|
40
|
+
|
41
|
+
def test_method_not_decorated(*); end
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'It receive the instance and the arguments passed to the method when called' do
|
47
|
+
let(:instance) { TestClass.new }
|
48
|
+
before {
|
49
|
+
TestClass.class_eval {
|
50
|
+
SimpleDecorator()
|
51
|
+
def test_method(*args, &block)
|
52
|
+
Spy.passed_args(*args, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_method_not_decorated; end
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
it { expect_any_instance_of(SimpleDecorator).to receive(:call).with(instance, 1, a: 2, b: 3, &proc { 'yes' }) }
|
60
|
+
it { expect(Spy).to receive(:arguments).with(args: [1], kwargs: { a: 2, b: 3 }, evald_block: 'yes').twice }
|
61
|
+
|
62
|
+
after {
|
63
|
+
instance.test_method(1, a: 2, b: 3) { 'yes' }
|
64
|
+
instance.test_method_not_decorated
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when decorator is defining a method during initialization' do
|
70
|
+
before {
|
71
|
+
stub_class(:StrangeDecorator, inherits: [::Decors::DecoratorBase]) {
|
72
|
+
def initialize(decorated_class, decorated_method, *deco_args, **deco_kwargs, &deco_block)
|
73
|
+
super
|
74
|
+
decorated_class.send(:define_method, :foo) { 42 }
|
75
|
+
end
|
76
|
+
|
77
|
+
def call(*)
|
78
|
+
super * 2
|
79
|
+
end
|
80
|
+
}
|
81
|
+
|
82
|
+
TestClass.class_eval { define_decorator :StrangeDecorator, StrangeDecorator }
|
83
|
+
}
|
84
|
+
|
85
|
+
before {
|
86
|
+
TestClass.class_eval {
|
87
|
+
StrangeDecorator()
|
88
|
+
StrangeDecorator()
|
89
|
+
def test_method
|
90
|
+
5
|
91
|
+
end
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
it { expect(TestClass.new.test_method).to eq 5 * 2 * 2 }
|
96
|
+
it { expect(TestClass.new.foo).to eq 42 }
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when mutiple decorators' do
|
100
|
+
before {
|
101
|
+
Spy.class_eval {
|
102
|
+
@ordered_calls = []
|
103
|
+
|
104
|
+
class << self
|
105
|
+
attr_reader :ordered_calls
|
106
|
+
|
107
|
+
def calling(name)
|
108
|
+
self.ordered_calls << name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
}
|
112
|
+
|
113
|
+
stub_class(:Deco1, inherits: [::Decors::DecoratorBase]) {
|
114
|
+
def call(*)
|
115
|
+
Spy.calling(:deco1_before)
|
116
|
+
super
|
117
|
+
Spy.calling(:deco1_after)
|
118
|
+
end
|
119
|
+
}
|
120
|
+
|
121
|
+
stub_class(:Deco2, inherits: [::Decors::DecoratorBase]) {
|
122
|
+
def call(*)
|
123
|
+
Spy.calling(:deco2_before)
|
124
|
+
super
|
125
|
+
Spy.calling(:deco2_after)
|
126
|
+
end
|
127
|
+
}
|
128
|
+
|
129
|
+
TestClass.class_eval {
|
130
|
+
define_decorator :Deco1, Deco1
|
131
|
+
define_decorator :Deco2, Deco2
|
132
|
+
|
133
|
+
Deco2()
|
134
|
+
Deco1()
|
135
|
+
def test_method(*)
|
136
|
+
Spy.calling(:inside)
|
137
|
+
end
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
before { TestClass.new.test_method }
|
142
|
+
it { expect(Spy.ordered_calls).to eq [:deco2_before, :deco1_before, :inside, :deco1_after, :deco2_after] }
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'when method has return value' do
|
146
|
+
before {
|
147
|
+
stub_class(:ModifierDeco, inherits: [::Decors::DecoratorBase])
|
148
|
+
|
149
|
+
TestClass.class_eval {
|
150
|
+
define_decorator :ModifierDeco, ModifierDeco
|
151
|
+
|
152
|
+
ModifierDeco()
|
153
|
+
def test_method
|
154
|
+
:ok
|
155
|
+
end
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
it { expect(TestClass.new.test_method).to eq :ok }
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'when method has arguments' do
|
163
|
+
before {
|
164
|
+
stub_class(:ModifierDeco, inherits: [::Decors::DecoratorBase])
|
165
|
+
|
166
|
+
TestClass.class_eval {
|
167
|
+
define_decorator :ModifierDeco, ModifierDeco
|
168
|
+
|
169
|
+
ModifierDeco()
|
170
|
+
def test_method(*args, &block)
|
171
|
+
Spy.passed_args(*args, &block)
|
172
|
+
end
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
it { expect(Spy).to receive(:arguments).with(args: [1, 2, 3], kwargs: { a: :a }, evald_block: 'yay') }
|
177
|
+
after { TestClass.new.test_method(1, 2, 3, a: :a) { 'yay' } }
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when changing arguments given to the method' do
|
181
|
+
before {
|
182
|
+
stub_class(:ModifierDeco, inherits: [::Decors::DecoratorBase]) {
|
183
|
+
def call(instance, *)
|
184
|
+
undecorated_call(instance, 1, 2, 3, a: :a, &proc { 'yay' })
|
185
|
+
end
|
186
|
+
}
|
187
|
+
|
188
|
+
TestClass.class_eval {
|
189
|
+
define_decorator :ModifierDeco, ModifierDeco
|
190
|
+
|
191
|
+
ModifierDeco()
|
192
|
+
def test_method(*args, &block)
|
193
|
+
Spy.passed_args(*args, &block)
|
194
|
+
end
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
it { expect(Spy).to receive(:arguments).with(args: [1, 2, 3], kwargs: { a: :a }, evald_block: 'yay') }
|
199
|
+
after { TestClass.new.test_method }
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'when method is recursive' do
|
203
|
+
before {
|
204
|
+
stub_class(:AddOneToArg, inherits: [::Decors::DecoratorBase]) {
|
205
|
+
def call(instance, *args)
|
206
|
+
undecorated_call(instance, args.first + 1)
|
207
|
+
end
|
208
|
+
}
|
209
|
+
|
210
|
+
TestClass.class_eval {
|
211
|
+
define_decorator :AddOneToArg, AddOneToArg
|
212
|
+
|
213
|
+
AddOneToArg()
|
214
|
+
def test_method(n)
|
215
|
+
return 0 if n.zero?
|
216
|
+
n + test_method(n - 2)
|
217
|
+
end
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
it { expect(TestClass.new.test_method(4)).to eq 5 + 4 + 3 + 2 + 1 }
|
222
|
+
end
|
223
|
+
|
224
|
+
context 'when already has a method_added' do
|
225
|
+
before {
|
226
|
+
stub_module(:TestMixin) {
|
227
|
+
def method_added(*)
|
228
|
+
Spy.called
|
229
|
+
end
|
230
|
+
}
|
231
|
+
stub_class(:Deco, inherits: [::Decors::DecoratorBase])
|
232
|
+
}
|
233
|
+
it { expect(Spy).to receive(:called) }
|
234
|
+
|
235
|
+
after {
|
236
|
+
TestClass.class_eval {
|
237
|
+
extend TestMixin
|
238
|
+
|
239
|
+
define_decorator :Deco, Deco
|
240
|
+
|
241
|
+
def test_method; end
|
242
|
+
}
|
243
|
+
}
|
244
|
+
end
|
245
|
+
|
246
|
+
context 'when inherited' do
|
247
|
+
before {
|
248
|
+
stub_class(:Deco, inherits: [::Decors::DecoratorBase])
|
249
|
+
|
250
|
+
TestClass.class_eval {
|
251
|
+
define_decorator :Deco, Deco
|
252
|
+
|
253
|
+
Deco()
|
254
|
+
def test_method
|
255
|
+
:ok
|
256
|
+
end
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
it {
|
261
|
+
stub_class(:TestClass2, inherits: [TestClass])
|
262
|
+
TestClass2.class_eval {
|
263
|
+
Deco()
|
264
|
+
def test_method
|
265
|
+
:ko
|
266
|
+
end
|
267
|
+
}
|
268
|
+
|
269
|
+
expect(TestClass.new.test_method).to eq :ok
|
270
|
+
expect(TestClass2.new.test_method).to eq :ko
|
271
|
+
}
|
272
|
+
|
273
|
+
it {
|
274
|
+
stub_class(:TestClass3, inherits: [TestClass])
|
275
|
+
|
276
|
+
TestClass3.class_eval {
|
277
|
+
Deco()
|
278
|
+
def test_method
|
279
|
+
"this is #{super}"
|
280
|
+
end
|
281
|
+
}
|
282
|
+
|
283
|
+
expect(TestClass3.new.test_method).to eq 'this is ok'
|
284
|
+
}
|
285
|
+
end
|
286
|
+
|
287
|
+
context 'when decorating a class method' do
|
288
|
+
before {
|
289
|
+
stub_class(:Deco, inherits: [::Decors::DecoratorBase]) {
|
290
|
+
def call(*)
|
291
|
+
super
|
292
|
+
Spy.called
|
293
|
+
end
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
297
|
+
context 'when mixin extended on the class (singleton method in class)' do
|
298
|
+
before {
|
299
|
+
TestClass.class_eval {
|
300
|
+
define_decorator :Deco, Deco
|
301
|
+
|
302
|
+
Deco()
|
303
|
+
def self.test_method
|
304
|
+
:ok
|
305
|
+
end
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
it { expect(Spy).to receive(:called) }
|
310
|
+
after { TestClass.test_method }
|
311
|
+
end
|
312
|
+
|
313
|
+
context 'when mixin extended on the class (method in singleton class)' do
|
314
|
+
before {
|
315
|
+
TestClass.class_eval {
|
316
|
+
class << self
|
317
|
+
extend Decors::DecoratorDefinition
|
318
|
+
|
319
|
+
define_decorator :Deco, Deco
|
320
|
+
|
321
|
+
Deco()
|
322
|
+
def test_method
|
323
|
+
:ok
|
324
|
+
end
|
325
|
+
end
|
326
|
+
}
|
327
|
+
}
|
328
|
+
|
329
|
+
it { expect(Spy).to receive(:called) }
|
330
|
+
after { TestClass.test_method }
|
331
|
+
end
|
332
|
+
|
333
|
+
context 'when mixin extended on the class (both method in singleton class and singleton method in class)' do
|
334
|
+
before {
|
335
|
+
TestClass.class_eval {
|
336
|
+
define_decorator :Deco, Deco
|
337
|
+
|
338
|
+
Deco()
|
339
|
+
def self.test_method__in_class
|
340
|
+
:ok
|
341
|
+
end
|
342
|
+
|
343
|
+
def self.untest_method__in_class
|
344
|
+
end
|
345
|
+
|
346
|
+
class << self
|
347
|
+
extend Decors::DecoratorDefinition
|
348
|
+
|
349
|
+
define_decorator :Deco, Deco
|
350
|
+
|
351
|
+
Deco()
|
352
|
+
def test_method__in_singleton
|
353
|
+
:ok
|
354
|
+
end
|
355
|
+
|
356
|
+
def untest_method__in_singleton
|
357
|
+
end
|
358
|
+
end
|
359
|
+
}
|
360
|
+
}
|
361
|
+
|
362
|
+
it { expect(Spy).to receive(:called) and TestClass.test_method__in_class }
|
363
|
+
it { expect(Spy).to receive(:called) and TestClass.test_method__in_singleton }
|
364
|
+
it { expect(Spy).to_not receive(:called) and TestClass.untest_method__in_class }
|
365
|
+
it { expect(Spy).to_not receive(:called) and TestClass.untest_method__in_singleton }
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path('../../lib/decors', __FILE__)
|
2
|
+
|
3
|
+
module SpecHelpers
|
4
|
+
def stub_class(class_name, inherits: [], &class_eval)
|
5
|
+
klass = stub_const(class_name.to_s, Class.new(*inherits))
|
6
|
+
klass.class_eval(&class_eval) if class_eval
|
7
|
+
klass
|
8
|
+
end
|
9
|
+
|
10
|
+
def stub_module(module_name, &module_eval)
|
11
|
+
mod = stub_const(module_name.to_s, Module.new)
|
12
|
+
mod.module_eval(&module_eval) if module_eval
|
13
|
+
mod
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.include SpecHelpers
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: decors
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vivien Meyet
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pry-byebug
|
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
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Ruby implementation of Python method decorators / Java annotations
|
42
|
+
email:
|
43
|
+
- vivien@getbannerman.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- CHANGELOG.md
|
50
|
+
- README.md
|
51
|
+
- decors.gemspec
|
52
|
+
- lib/decors.rb
|
53
|
+
- lib/decors/decorator_base.rb
|
54
|
+
- lib/decors/decorator_definition.rb
|
55
|
+
- lib/decors/method_added_listener.rb
|
56
|
+
- spec/decors_spec.rb
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
homepage: https://github.com/getbannerman/decors
|
59
|
+
licenses: []
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 2.6.8
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: Ruby implementation of Python method decorators / Java annotations
|
81
|
+
test_files:
|
82
|
+
- spec/decors_spec.rb
|
83
|
+
- spec/spec_helper.rb
|