decorations 0.1.4 → 1.0.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 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