method_decorators 0.9.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/.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