method_decorators 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - jruby-18mode
7
+ - jruby-19mode
8
+ - rbx-18mode
9
+ - rbx-19mode
10
+ - ruby-head
11
+ - jruby-head
12
+ - ree
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in method_decorators.gemspec
4
+ gemspec
5
+
6
+ gem 'rake'
7
+ gem 'rspec'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Michael Fairley
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # MethodDecorators
2
+
3
+ Python's function decorators for Ruby.
4
+
5
+ ## Installation
6
+ `gem install method_decorators`
7
+
8
+ ## Usage
9
+
10
+ ### Using a decorator
11
+ Extend MethodDecorators in a class where you want to use them, and then stick `+DecoratorName` before your method declaration to use it.
12
+
13
+ ```ruby
14
+ class SlowMath
15
+ extend MethodDecorators
16
+
17
+ +Memoized
18
+ def fib(n)
19
+ if n <= 1
20
+ 1
21
+ else
22
+ fib(n - 1) * fib(n - 2)
23
+ end
24
+ end
25
+ end
26
+ ```
27
+
28
+ ### Defining a decorator
29
+
30
+ ```ruby
31
+ class Transactional < MethodDecorator
32
+ def call(wrapped, *args, &blk)
33
+ ActiveRecord::Base.transaction do
34
+ wrapped.call(*args, &blk)
35
+ end
36
+ end
37
+ end
38
+ ```
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ module MethodDecorators
2
+ VERSION = "0.9.0"
3
+ end
@@ -0,0 +1,69 @@
1
+ require "method_decorators/version"
2
+
3
+ module MethodDecorators
4
+ def method_added(name)
5
+ super
6
+ orig_method = instance_method(name)
7
+
8
+ if private_method_defined?(name); visibility = :private
9
+ elsif protected_method_defined?(name); visibility = :protected
10
+ else visibility = :public
11
+ end
12
+
13
+ decorators = MethodDecorator.current_decorators
14
+ return if decorators.empty?
15
+
16
+ define_method(name) do |*args, &blk|
17
+ decorators.reduce(orig_method.bind(self)) do |callable, decorator|
18
+ lambda{|*a, &b| decorator.call(callable, *a, &b) }
19
+ end.call(*args, &blk)
20
+ end
21
+
22
+ case visibility
23
+ when :protected; protected name
24
+ when :private; private name
25
+ end
26
+ end
27
+
28
+ def singleton_method_added(name)
29
+ super
30
+ orig_method = method(name)
31
+
32
+ decorators = MethodDecorator.current_decorators
33
+ return if decorators.empty?
34
+
35
+ MethodDecorators.define_others_singleton_method(self, name) do |*args, &blk|
36
+ decorators.reduce(orig_method) do |callable, decorator|
37
+ lambda{|*a, &b| decorator.call(callable, *a, &b) }
38
+ end.call(*args, &blk)
39
+ end
40
+ end
41
+
42
+ def self.define_others_singleton_method(klass, name, &blk)
43
+ if klass.respond_to?(:define_singleton_method)
44
+ klass.define_singleton_method(name, &blk)
45
+ else
46
+ class << klass
47
+ self
48
+ end.send(:define_method, name, &blk)
49
+ end
50
+ end
51
+ end
52
+
53
+ class MethodDecorator
54
+ @@current_decorators = []
55
+
56
+ def self.current_decorators
57
+ decs = @@current_decorators
58
+ @@current_decorators = []
59
+ decs
60
+ end
61
+
62
+ def self.+@
63
+ +new
64
+ end
65
+
66
+ def +@
67
+ @@current_decorators.unshift(self)
68
+ end
69
+ end
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/method_decorators/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Michael Fairley"]
6
+ gem.email = ["michaelfairley@gmail.com"]
7
+ gem.description = %q{Python's function decorators for Ruby}
8
+ gem.summary = %q{Python's function decorators for Ruby}
9
+ gem.homepage = "http://github.com/michaelfairley/method_decorators"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "method_decorators"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = MethodDecorators::VERSION
17
+ end
@@ -0,0 +1,248 @@
1
+ require 'spec_helper'
2
+
3
+ class Base
4
+ extend MethodDecorators
5
+ end
6
+
7
+ describe MethodDecorators do
8
+ subject { klass.new }
9
+
10
+ describe "decorating with a simple decorator" do
11
+ let(:klass) do
12
+ Class.new Base do
13
+ +Stringify
14
+ def three
15
+ 3
16
+ end
17
+ end
18
+ end
19
+
20
+ it "works" do
21
+ subject.three.should == '3'
22
+ end
23
+ end
24
+
25
+ describe "decorating with a decorator that takes arguments" do
26
+ let(:klass) do
27
+ Class.new Base do
28
+ +AddN.new(1)
29
+ def four
30
+ 3
31
+ end
32
+ end
33
+ end
34
+
35
+ it "works" do
36
+ subject.four.should == 4
37
+ end
38
+ end
39
+
40
+ describe "decorating an instance method" do
41
+ describe "that is public" do
42
+ let(:klass) do
43
+ Class.new Base do
44
+ +Stringify
45
+ def three
46
+ 3
47
+ end
48
+ end
49
+ end
50
+
51
+ it "works" do
52
+ subject.three.should == '3'
53
+ end
54
+ end
55
+
56
+ describe "that is protected" do
57
+ let(:klass) do
58
+ Class.new Base do
59
+ protected
60
+ +Stringify
61
+ def three
62
+ 3
63
+ end
64
+ end
65
+ end
66
+
67
+ it "works" do
68
+ subject.protected_methods.map(&:to_s).should include 'three'
69
+ subject.send(:three).should == '3'
70
+ end
71
+ end
72
+
73
+ describe "that is private" do
74
+ let(:klass) do
75
+ Class.new Base do
76
+ private
77
+ +Stringify
78
+ def three
79
+ 3
80
+ end
81
+ end
82
+ end
83
+
84
+ it "works" do
85
+ subject.private_methods.map(&:to_s).should include 'three'
86
+ subject.send(:three).should == '3'
87
+ end
88
+ end
89
+
90
+ describe "with multiple decorators" do
91
+ let(:klass) do
92
+ Class.new Base do
93
+ +Stringify
94
+ +AddN.new(3)
95
+ def six
96
+ 3
97
+ end
98
+ end
99
+ end
100
+
101
+ it "works" do
102
+ subject.six.should == '6'
103
+ end
104
+ end
105
+
106
+ describe "that takes args" do
107
+ let(:klass) do
108
+ Class.new Base do
109
+ +Stringify
110
+ def sum(a, b)
111
+ a + b
112
+ end
113
+ end
114
+ end
115
+
116
+ it "works" do
117
+ subject.sum(1, 2).should == "3"
118
+ end
119
+ end
120
+
121
+ describe "that takes a block" do
122
+ let(:klass) do
123
+ Class.new Base do
124
+ +Stringify
125
+ def double(&blk)
126
+ blk.call + blk.call
127
+ end
128
+ end
129
+ end
130
+
131
+ it "works" do
132
+ subject.double{ 2 }.should == '4'
133
+ end
134
+ end
135
+
136
+ describe "with a decorator that messes with the args" do
137
+ let(:klass) do
138
+ Class.new Base do
139
+ +Reverse
140
+ def echo(a, b)
141
+ [a, b]
142
+ end
143
+ end
144
+ end
145
+
146
+ it "works" do
147
+ subject.echo(1, 2).should == [2, 1]
148
+ end
149
+ end
150
+ end
151
+
152
+ describe "decorating a singleton method" do
153
+ subject { klass }
154
+
155
+ describe "that is public" do
156
+ let(:klass) do
157
+ Class.new Base do
158
+ +Stringify
159
+ def self.three
160
+ 3
161
+ end
162
+ end
163
+ end
164
+
165
+ it "works" do
166
+ subject.three.should == '3'
167
+ end
168
+ end
169
+
170
+ describe "that is private" do
171
+ let(:klass) do
172
+ Class.new Base do
173
+ +Stringify
174
+ def self.three
175
+ 3
176
+ end
177
+ private_class_method :three
178
+ end
179
+ end
180
+
181
+ it "works" do
182
+ subject.private_methods.map(&:to_s).should include 'three'
183
+ subject.send(:three).should == '3'
184
+ end
185
+ end
186
+
187
+ describe "with multiple decorators" do
188
+ let(:klass) do
189
+ Class.new Base do
190
+ +Stringify
191
+ +AddN.new(3)
192
+ def self.six
193
+ 3
194
+ end
195
+ end
196
+ end
197
+
198
+ it "works" do
199
+ subject.six.should == '6'
200
+ end
201
+ end
202
+
203
+ describe "that takes args" do
204
+ let(:klass) do
205
+ Class.new Base do
206
+ +Stringify
207
+ def self.sum(a, b)
208
+ a + b
209
+ end
210
+ end
211
+ end
212
+
213
+ it "works" do
214
+ subject.sum(1, 2).should == "3"
215
+ end
216
+ end
217
+
218
+ describe "that takes a block" do
219
+ let(:klass) do
220
+ Class.new Base do
221
+ +Stringify
222
+ def self.double(&blk)
223
+ blk.call + blk.call
224
+ end
225
+ end
226
+ end
227
+
228
+ it "works" do
229
+ subject.double{ 2 }.should == '4'
230
+ end
231
+ end
232
+
233
+ describe "with a decorator that messes with the args" do
234
+ let(:klass) do
235
+ Class.new Base do
236
+ +Reverse
237
+ def self.echo(a, b)
238
+ [a, b]
239
+ end
240
+ end
241
+ end
242
+
243
+ it "works" do
244
+ subject.echo(1, 2).should == [2, 1]
245
+ end
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,17 @@
1
+ require 'method_decorators'
2
+
3
+ require 'support/stringify'
4
+ require 'support/add_n'
5
+ require 'support/reverse'
6
+
7
+ # This file was generated by the `rspec --init` command. Conventionally, all
8
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
9
+ # Require this file using `require "spec_helper.rb"` to ensure that it is only
10
+ # loaded once.
11
+ #
12
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
13
+ RSpec.configure do |config|
14
+ config.treat_symbols_as_metadata_keys_with_true_values = true
15
+ config.run_all_when_everything_filtered = true
16
+ config.filter_run :focus
17
+ end
@@ -0,0 +1,9 @@
1
+ class AddN < MethodDecorator
2
+ def initialize(n)
3
+ @n = n
4
+ end
5
+
6
+ def call(orig, *args, &blk)
7
+ orig.call(*args, &blk) + @n
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class Reverse < MethodDecorator
2
+ def call(orig, *args, &blk)
3
+ orig.call(*args.reverse, &blk)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Stringify < MethodDecorator
2
+ def call(orig, *args, &blk)
3
+ orig.call(*args, &blk).to_s
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: method_decorators
3
+ version: !ruby/object:Gem::Version
4
+ hash: 59
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 9
9
+ - 0
10
+ version: 0.9.0
11
+ platform: ruby
12
+ authors:
13
+ - Michael Fairley
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-04-24 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: Python's function decorators for Ruby
22
+ email:
23
+ - michaelfairley@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - .rspec
33
+ - .travis.yml
34
+ - Gemfile
35
+ - LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - lib/method_decorators.rb
39
+ - lib/method_decorators/version.rb
40
+ - method_decorators.gemspec
41
+ - spec/method_decorators_spec.rb
42
+ - spec/spec_helper.rb
43
+ - spec/support/add_n.rb
44
+ - spec/support/reverse.rb
45
+ - spec/support/stringify.rb
46
+ homepage: http://github.com/michaelfairley/method_decorators
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options: []
51
+
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.8.17
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Python's function decorators for Ruby
79
+ test_files:
80
+ - spec/method_decorators_spec.rb
81
+ - spec/spec_helper.rb
82
+ - spec/support/add_n.rb
83
+ - spec/support/reverse.rb
84
+ - spec/support/stringify.rb