decorations 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31bf145c0d39101e6c4aaf1c1ef9bc4d44286e72fbbac2c2cf15bac1e94764d6
4
- data.tar.gz: 29c49a2c78b92a09d15b8aee25e2730d54ff2d79e9f688819d546d00b097c269
3
+ metadata.gz: e4ee3f37027bf274381c6141e50c22890fffb443c765339da9810715528403a1
4
+ data.tar.gz: 0453c34181729f003cbe2434597a4554e97345b7e747ca5eb69fb17dda3a7bbe
5
5
  SHA512:
6
- metadata.gz: 2c242c574f807b2d6a2d27448e38c86895892b5e785c2da95238865b717482274f7d3aa285690bed21cff93398ffb87d852183fdd460e62b2b805ff2e699d18c
7
- data.tar.gz: c22dbe2455e391069b6ad9c765b6159e061ad046e0be6fd4173626aaec986bdc1c352d6eb0df474c1520b0a80c9114e61414f14d5218290170364f759b0ade14
6
+ metadata.gz: 3ed165419148484137d8651336a6d2811509a61418ba33b2673246dda6aa244fc18ff5c4b40142a430e12e2f21ef8c678651bb0740f10d1de8bc6ab8a086abb6
7
+ data.tar.gz: 45b0edd2d3f819c28d80df2edad449396eac6ebbc878d071a574d3161fac889a5aafdc84639c0a338315101ad63c5bd979dce7711ffc350c2a4fe4ee61206222
data/Gemfile.lock CHANGED
@@ -1,35 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- decorations (0.1.4)
4
+ decorations (1.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.0)
10
10
  coderay (1.1.2)
11
- coveralls (0.7.1)
12
- multi_json (~> 1.3)
13
- rest-client
14
- simplecov (>= 0.7)
15
- term-ansicolor
16
- thor
17
11
  diff-lcs (1.3)
18
- docile (1.3.2)
19
- domain_name (0.5.20190701)
20
- unf (>= 0.0.5, < 1.0.0)
21
12
  gem-release (2.1.1)
22
- http-accept (1.7.0)
23
- http-cookie (1.0.3)
24
- domain_name (~> 0.5)
25
13
  jaro_winkler (1.5.4)
26
- json (2.2.0)
27
14
  method_source (0.9.2)
28
- mime-types (3.3)
29
- mime-types-data (~> 3.2015)
30
- mime-types-data (3.2019.1009)
31
- multi_json (1.14.1)
32
- netrc (0.11.0)
33
15
  parallel (1.18.0)
34
16
  parser (2.6.5.0)
35
17
  ast (~> 2.4.0)
@@ -41,11 +23,6 @@ GEM
41
23
  yard (~> 0.9.11)
42
24
  rainbow (3.0.0)
43
25
  rake (10.5.0)
44
- rest-client (2.1.0)
45
- http-accept (>= 1.7.0, < 2.0)
46
- http-cookie (>= 1.0.2, < 2.0)
47
- mime-types (>= 1.16, < 4.0)
48
- netrc (~> 0.8)
49
26
  rspec (3.9.0)
50
27
  rspec-core (~> 3.9.0)
51
28
  rspec-expectations (~> 3.9.0)
@@ -67,18 +44,6 @@ GEM
67
44
  ruby-progressbar (~> 1.7)
68
45
  unicode-display_width (>= 1.4.0, < 1.7)
69
46
  ruby-progressbar (1.10.1)
70
- simplecov (0.17.1)
71
- docile (~> 1.1)
72
- json (>= 1.8, < 3)
73
- simplecov-html (~> 0.10.0)
74
- simplecov-html (0.10.2)
75
- term-ansicolor (1.7.1)
76
- tins (~> 1.0)
77
- thor (0.20.3)
78
- tins (1.22.0)
79
- unf (0.1.4)
80
- unf_ext
81
- unf_ext (0.0.7.6)
82
47
  unicode-display_width (1.6.0)
83
48
  yard (0.9.20)
84
49
  yardstick (0.9.9)
@@ -89,16 +54,13 @@ PLATFORMS
89
54
 
90
55
  DEPENDENCIES
91
56
  bundler (~> 1.16)
92
- coveralls
93
57
  decorations!
94
58
  gem-release
95
59
  pry
96
60
  pry-doc
97
61
  rake (~> 10.0)
98
- rest-client (>= 1.8.0)
99
62
  rspec (~> 3.0)
100
63
  rubocop
101
- simplecov
102
64
  yard
103
65
  yardstick
104
66
 
data/README.md CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/decorations.svg)](https://badge.fury.io/rb/decorations)
4
4
  [![Build Status](https://travis-ci.org/watmin/Ruby-decorations.svg?branch=master)](https://travis-ci.org/watmin/Ruby-decorations)
5
- [![Coverage Status](https://coveralls.io/repos/github/watmin/Ruby-decorations/badge.svg?branch=master)](https://coveralls.io/github/watmin/Ruby-decorations?branch=master)
6
5
 
7
6
  Python like decorators for Ruby. Inspired by Rack and previous attempts at decorations
8
7
 
@@ -24,22 +23,22 @@ Or install it yourself as:
24
23
 
25
24
  ## Usage
26
25
 
27
- Create a class that will have decorated methods and create decator classes to before actions.
28
-
29
- The decorator class must:
30
- * implement #call
31
- * must invoke call\_next(this, chain, \*args)
32
- * must return the result of call\_next.
26
+ Create a class that will have decorated methods and create decator classes to be executed around the decorated method.
33
27
 
34
28
  ```ruby
35
29
  require 'decorations'
36
30
 
37
31
  class LoggingDecorator < Decorator
38
- def call(this, chain, *args)
39
- puts "[#{Time.now}] #{decorated_class}.#{decorated_method.name} was called"
40
- result = call_next(this, chain, *args)
41
- puts "[#{Time.now}] #{decorated_class}.#{decorated_method.name} has finished"
42
- result
32
+ before
33
+ def print_started
34
+ @start_time = Time.now
35
+ puts "[#{@start_time}] #{decorated_class}.#{decorated_method.name} was called"
36
+ end
37
+
38
+ after
39
+ def print_finished
40
+ end_time = Time.now
41
+ puts "[#{end_time}] #{decorated_class}.#{decorated_method.name} has finished. Took #{end_time - @start_time} seconds"
43
42
  end
44
43
  end
45
44
 
@@ -47,16 +46,72 @@ class Application
47
46
  extend Decorations
48
47
 
49
48
  decorate LoggingDecorator
50
- def perform_task
51
- 2 + 2
49
+ def perform_task(a, b: 2)
50
+ a + b
51
+ end
52
+
53
+ decorate LoggingDecorator
54
+ def perform_task_with_a_block
55
+ yield
52
56
  end
53
57
  end
54
58
 
55
59
  app = Application.new
56
- app.perform_task
57
- # => [2019-10-31 02:00:31 -0700] Application.perform_task was called
58
- # => [2019-10-31 02:00:31 -0700] Application.perform_task has finished
60
+ app.perform_task(2, b: 2)
61
+ # [2019-11-01 19:50:59 -0700] Application.perform_task was called
62
+ # [2019-11-01 19:50:59 -0700] Application.perform_task has finished. Took 3.51e-05 seconds
59
63
  # => 4
64
+
65
+ app.perform_task_with_a_block { puts 'in a block' }
66
+ # [2019-11-01 19:55:37 -0700] Application.perform_task_with_a_block was called
67
+ # in a block
68
+ # [2019-11-01 19:55:37 -0700] Application.perform_task_with_a_block has finished. Took 5.32e-05 seconds
69
+ # => nil
70
+ ```
71
+
72
+ You can also pass in parameters to decorator methods:
73
+
74
+ ```
75
+ class AnotherDecorator < Decorator
76
+ def initialize(some, params)
77
+ @some = some
78
+ @params = params
79
+ end
80
+
81
+ before
82
+ def puts_some
83
+ puts @some
84
+ end
85
+
86
+ after
87
+ def puts_params
88
+ puts @params
89
+ end
90
+ end
91
+
92
+ class AnotherDemo
93
+ extends Decorations
94
+
95
+ decorate AnotherDecorator, 'value 1', 'value 2'
96
+ def another_method
97
+ puts 'running puts in yet another method'
98
+ end
99
+ end
100
+
101
+ demo = AnotherDemo.new
102
+ demo.another_method
103
+ # value 1
104
+ # running puts in yet another method
105
+ # value 2
106
+ # => nil
107
+
108
+ ```
109
+
110
+ When testing decorated methods, execute `Decorations.disable` before requiring your source files. In your spec\_helper.rb add the following lines before your library is loaded:
111
+
112
+ ```ruby
113
+ require 'decorations'
114
+ Decorations.disable
60
115
  ```
61
116
 
62
117
  ## Development
data/bin/console CHANGED
@@ -7,9 +7,19 @@ require 'decorations'
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
9
  class DecoratorDemo < Decorator
10
- def call(this, chain, *args)
10
+ before
11
+ def print_message
11
12
  puts "'#{decorated_class}' has '#{decorated_method.name}' decorated"
12
- call_next(this, chain, *args)
13
+ end
14
+
15
+ after
16
+ def do_math
17
+ puts 2 + 2
18
+ end
19
+
20
+ after
21
+ def something_else
22
+ puts 'something else'
13
23
  end
14
24
  end
15
25
 
@@ -20,6 +30,17 @@ class Demo
20
30
  def demo_method
21
31
  puts 'am I decorated?'
22
32
  end
33
+
34
+ decorate DecoratorDemo
35
+ def demo_block
36
+ yield
37
+ end
38
+
39
+ decorate DecoratorDemo
40
+ def demo_kwargs(first: 1, second: nil)
41
+ puts "first is #{first}"
42
+ puts "second is #{second}"
43
+ end
23
44
  end
24
45
 
25
46
  require 'pry'
data/decorations.gemspec CHANGED
@@ -30,15 +30,12 @@ Gem::Specification.new do |spec|
30
30
  spec.require_paths = ['lib']
31
31
 
32
32
  spec.add_development_dependency 'bundler', '~> 1.16'
33
- spec.add_development_dependency 'coveralls'
34
33
  spec.add_development_dependency 'gem-release'
35
34
  spec.add_development_dependency 'pry'
36
35
  spec.add_development_dependency 'pry-doc'
37
36
  spec.add_development_dependency 'rake', '~> 10.0'
38
- spec.add_development_dependency 'rest-client', '>= 1.8.0'
39
37
  spec.add_development_dependency 'rspec', '~> 3.0'
40
38
  spec.add_development_dependency 'rubocop'
41
- spec.add_development_dependency 'simplecov'
42
39
  spec.add_development_dependency 'yard'
43
40
  spec.add_development_dependency 'yardstick'
44
41
  end
data/lib/decorations.rb CHANGED
@@ -20,6 +20,19 @@ module Decorations
20
20
  end
21
21
  end
22
22
 
23
+ ##
24
+ # Disables injecting decorations. Necessary for testing decorated methods
25
+ #
26
+ # @return [Void]
27
+ #
28
+ # @example
29
+ # Decorations.disable
30
+ #
31
+ # @api public
32
+ def self.disable
33
+ @disabled = true
34
+ end
35
+
23
36
  ##
24
37
  # Decorates a method execute's the klass' #call method around the decorated method
25
38
  #
@@ -67,7 +80,10 @@ module Decorations
67
80
  # @api private
68
81
  def append_decorations(name, decorators, decorated_methods)
69
82
  decorators.each do |klass, args|
70
- decorated_methods[name] << klass.new(self, instance_method(name), *args)
83
+ decoration = klass.new(*args)
84
+ decoration.__send__(:decorated_class=, self)
85
+ decoration.__send__(:decorated_method=, instance_method(name))
86
+ decorated_methods[name] << decoration
71
87
  end
72
88
  end
73
89
 
@@ -80,6 +96,7 @@ module Decorations
80
96
  #
81
97
  # @api private
82
98
  def method_added(name)
99
+ return if @disabled
83
100
  return unless @decorators
84
101
 
85
102
  @decorated_methods ||= Hash.new { |h, k| h[k] = [] }
@@ -87,9 +104,9 @@ module Decorations
87
104
  @decorators = nil
88
105
 
89
106
  class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
90
- def #{name}(*args, &blk)
107
+ def #{name}(*args, &block)
91
108
  chain = self.class.decorated_methods[#{name.inspect}].dup
92
- Decorator.new(self, :method_added).call_next(self, chain, *args, &blk)
109
+ Decorator.new.__send__(:call, self, chain, *args, &block)
93
110
  end
94
111
  RUBY_EVAL
95
112
  end
@@ -3,5 +3,5 @@
3
3
  module Decorations
4
4
  ##
5
5
  # The version of the Ruby-decorations gem
6
- VERSION = '0.1.4'
6
+ VERSION = '1.0.0'
7
7
  end
data/lib/decorator.rb CHANGED
@@ -1,71 +1,56 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'decorator_dsl'
4
+
3
5
  ##
4
6
  # Base decorator class
5
7
  class Decorator
8
+ extend DecoratorDsl
9
+
10
+ private
11
+
6
12
  ##
7
- # @!attribute [r] decorated_class
13
+ # @!attribute [a] decorated_class
8
14
  # The class being decorated
9
15
  #
10
16
  # @return [Class]
11
17
  #
12
- # @example
13
- # decorator.decoated_class #=> Class
14
- #
15
- # @api public
16
- attr_reader :decorated_class
18
+ # @api private
19
+ attr_accessor :decorated_class
17
20
 
18
21
  ##
19
- # @!attribute [r] decorated_class
22
+ # @!attribute [a] decorated_class
20
23
  # The method being decorated
21
24
  #
22
25
  # @return [Symbol]
23
26
  #
24
- # @example
25
- # decorator.decorated_method #=> Symbol
26
- #
27
- # @api public
28
- attr_reader :decorated_method
29
-
30
- ##
31
- # Decorator constructor interface
32
- #
33
- # @param decorated_class [Class] The class that is being decorated
34
- # @param decorated_method [Symbol] The method that is being decorated
35
- #
36
- # @return [Decorator]
37
- #
38
27
  # @api private
39
- def initialize(decorated_class, decorated_method)
40
- @decorated_class = decorated_class
41
- @decorated_method = decorated_method
42
- end
28
+ attr_accessor :decorated_method
43
29
 
44
30
  ##
45
31
  # The hook to call chained decorations
46
32
  #
47
33
  # @param this [Instance] the instance of the object with the wrapper method
48
34
  # @param chain [Array<Decorator>] the remaining decorators to be called
49
- # @param *args [Array<Object>] the arguments to pass to the wrapper method
35
+ # @param args [Array<Object>] the arguments to pass to the wrapper method
36
+ # @param block [Proc] the block to pass to the wrapped method
50
37
  #
51
38
  # @return [Object] the return value of the next_caller
52
39
  #
53
- # @example
54
- # class DecoratorDemo < Decorator
55
- # def call(this, chain, *args)
56
- # puts "'#{decorated_class}' has '#{decorated_method.name}' decorated"
57
- # call_next(this, chain, *args)
58
- # end
59
- # end
60
- #
61
- # @api public
62
- def call_next(this, chain, *args)
40
+ # @api private
41
+ def call(this, chain, *args, &block)
63
42
  next_caller = chain.shift
64
43
 
65
- if next_caller.nil?
66
- decorated_method.bind(this).call(*args)
67
- else
68
- next_caller.call(this, chain, *args)
69
- end
44
+ self.class.__send__(:before_method)&.each { |method_name| __send__(method_name) }
45
+
46
+ ret = if next_caller.nil?
47
+ decorated_method.bind(this).call(*args, &block)
48
+ else
49
+ next_caller.__send__(:call, this, chain, *args, &block)
50
+ end
51
+
52
+ self.class.__send__(:after_method)&.each { |method_name| __send__(method_name) }
53
+
54
+ ret
70
55
  end
71
56
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ ##
6
+ # DSL for Decorator to define before and after hooks for a wrapped method
7
+ module DecoratorDsl
8
+ ##
9
+ # Injects the DSL attributes in the class received
10
+ #
11
+ # @param receiver [Class] the class extending DecoratorDsl
12
+ #
13
+ # @return [Void]
14
+ #
15
+ # @api private
16
+ def self.extended(receiver)
17
+ class << receiver
18
+ private
19
+
20
+ attr_accessor :before_method, :before_set, :after_method, :after_set
21
+ end
22
+ end
23
+
24
+ ##
25
+ # Adds the next method to be hook into executing before decorated method
26
+ #
27
+ # @return [Void]
28
+ #
29
+ # @example
30
+ # class DecoratorDemo < Decorator
31
+ # before :print_message
32
+ # def print_message(this, chain, *args)
33
+ # puts "'#{decorated_class}' has '#{decorated_method.name}' decorated"
34
+ # end
35
+ # end
36
+ #
37
+ # class Demo
38
+ # extend Decorations
39
+ #
40
+ # decorate DecoratorDemo
41
+ # def demo_method
42
+ # puts 'am I decorated?'
43
+ # end
44
+ # end
45
+ #
46
+ # demo = Demo.new
47
+ # demo.demo_method
48
+ # # => 'Demo' has 'demo_method' decorated
49
+ # # => am I decorated?
50
+ #
51
+ # @api public
52
+ def before
53
+ @before_method ||= Set.new
54
+ @before_set = true
55
+ end
56
+
57
+ ##
58
+ # Adds the next method to be hook into executing after decorated method
59
+ #
60
+ # @return [Void]
61
+ #
62
+ # @example
63
+ # class DecoratorDemo < Decorator
64
+ # after
65
+ # def print_message(this, chain, *args)
66
+ # puts "'#{decorated_class}' has '#{decorated_method.name}' decorated"
67
+ # end
68
+ # end
69
+ #
70
+ # class Demo
71
+ # extend Decorations
72
+ #
73
+ # decorate DecoratorDemo
74
+ # def demo_method
75
+ # puts 'am I decorated?'
76
+ # end
77
+ # end
78
+ #
79
+ # demo = Demo.new
80
+ # demo.demo_method
81
+ # # => am I decorated?
82
+ # # => 'Demo' has 'demo_method' decorated
83
+ #
84
+ # @api public
85
+ def after
86
+ @after_method ||= Set.new
87
+ @after_set = true
88
+ end
89
+
90
+ private
91
+
92
+ ##
93
+ # Hooks the methods defined for a class
94
+ #
95
+ # @param name [Symbol] the name of the method being defined
96
+ #
97
+ # @return [Void]
98
+ #
99
+ # @api private
100
+ def method_added(name)
101
+ if before_set
102
+ @before_set = false
103
+ @before_method << name
104
+ end
105
+
106
+ return unless after_set
107
+
108
+ @after_set = false
109
+ @after_method << name
110
+ end
111
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decorations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Shields
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-31 00:00:00.000000000 Z
11
+ date: 2019-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.16'
27
- - !ruby/object:Gem::Dependency
28
- name: coveralls
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
27
  - !ruby/object:Gem::Dependency
42
28
  name: gem-release
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +80,6 @@ dependencies:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
82
  version: '10.0'
97
- - !ruby/object:Gem::Dependency
98
- name: rest-client
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 1.8.0
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: 1.8.0
111
83
  - !ruby/object:Gem::Dependency
112
84
  name: rspec
113
85
  requirement: !ruby/object:Gem::Requirement
@@ -136,20 +108,6 @@ dependencies:
136
108
  - - ">="
137
109
  - !ruby/object:Gem::Version
138
110
  version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: simplecov
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
111
  - !ruby/object:Gem::Dependency
154
112
  name: yard
155
113
  requirement: !ruby/object:Gem::Requirement
@@ -202,6 +160,7 @@ files:
202
160
  - lib/decorations.rb
203
161
  - lib/decorations/version.rb
204
162
  - lib/decorator.rb
163
+ - lib/decorator_dsl.rb
205
164
  homepage: https://github.com/watmin/Ruby-decorations
206
165
  licenses:
207
166
  - MIT