symbiont-ruby 0.2.0 → 0.7.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/Rakefile CHANGED
@@ -2,8 +2,21 @@
2
2
 
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
+ require 'rubocop'
6
+ require 'rubocop/rake_task'
7
+ require 'rubocop-performance'
8
+ require 'rubocop-rspec'
9
+ require 'rubocop-rake'
5
10
  require 'yard'
6
11
 
12
+ RuboCop::RakeTask.new(:rubocop) do |t|
13
+ config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
14
+ t.options = ['--config', config_path]
15
+ t.requires << 'rubocop-rspec'
16
+ t.requires << 'rubocop-performance'
17
+ t.requires << 'rubocop-rake'
18
+ end
19
+
7
20
  RSpec::Core::RakeTask.new(:rspec)
8
21
 
9
22
  YARD::Rake::YardocTask.new(:doc) do |t|
@@ -13,6 +26,7 @@ end
13
26
 
14
27
  task default: :rspec
15
28
 
29
+ desc 'Code documentation coverage check'
16
30
  task yardoc: :doc do
17
31
  undocumented_code_objects = YARD::Registry.tap(&:load).select do |code_object|
18
32
  code_object.docstring.empty?
@@ -22,7 +36,7 @@ task yardoc: :doc do
22
36
  puts 'YARD COVERAGE [SUCCESS] => 100% documentation coverage!'
23
37
  else
24
38
  failing_code_objects = undocumented_code_objects.map do |code_object|
25
- "- #{code_object.class} => #{code_object.to_s}"
39
+ "- #{code_object.class} => #{code_object}"
26
40
  end.join("\n")
27
41
 
28
42
  abort("YARD COVERAGE [FAILURE] => No documentation found for: \n #{failing_code_objects}")
data/Steepfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ target :lib do
4
+ signature 'sig'
5
+ check 'lib'
6
+ end
data/bin/console CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
- require 'symbiont/ruby'
5
+ require 'symbiont'
5
6
 
6
7
  require 'pry'
7
8
  Pry.start
data/lib/symbiont.rb CHANGED
@@ -9,6 +9,7 @@ module Symbiont
9
9
  require_relative 'symbiont/trigger'
10
10
  require_relative 'symbiont/public_trigger'
11
11
  require_relative 'symbiont/private_trigger'
12
+ require_relative 'symbiont/isolator'
12
13
  require_relative 'symbiont/executor'
13
14
  require_relative 'symbiont/context'
14
15
 
@@ -32,7 +32,8 @@ module Symbiont
32
32
  # @api public
33
33
  # @since 0.1.0
34
34
  def evaluate(*required_contexts, context_direction: Trigger::IOK, &closure)
35
- public_trigger(*required_contexts, context_direction: context_direction, &closure).__evaluate__
35
+ Isolator.new(default_direction: context_direction, &closure)
36
+ .evaluate(*required_contexts)
36
37
  end
37
38
 
38
39
  # Starts execution of a proc object in the context of the passed object with the selected
@@ -59,63 +60,8 @@ module Symbiont
59
60
  # @api public
60
61
  # @since 0.1.0
61
62
  def evaluate_private(*required_contexts, context_direction: Trigger::IOK, &closure)
62
- private_trigger(*required_contexts, context_direction: context_direction, &closure).__evaluate__
63
- end
64
-
65
- # Factory method that instantiates a public trigger with the desired execution context,
66
- # the direction of method dispatching and the closure that needs to be performed.
67
- #
68
- # @param required_contexts [Array<Object>]
69
- # A set of objects that should be used as the main context series for method resolving
70
- # algorithm.
71
- # @param context_direction [Array<Symbol>]
72
- # An array of symbols that represents the direction of contexts. Possible values:
73
- #
74
- # - Symbiont::IOK
75
- # - Symbiont::OIK
76
- # - Symbiont::OKI
77
- # - Symbiont::IKO
78
- # - Symbiont::KOI
79
- # - Symbiont::KIO
80
- # @param closure [Proc]
81
- # Proc object that will be evaluated in many contexts: initial, outer and kernel.
82
- # @return [Symbiont::PublicTrigger]
83
- #
84
- # @see Symbiont::PublicTrigger
85
- # @see Symbiont::Trigger
86
- #
87
- # @api public
88
- # @since 0.1.0
89
- def public_trigger(*required_contexts, context_direction: Trigger::IOK, &closure)
90
- PublicTrigger.new(*required_contexts, context_direction: context_direction, &closure)
91
- end
92
-
93
- # Factory method that instantiates a private trigger with the desired execution context,
94
- # the direction of method dispatching and the closure that needs to be performed.
95
- #
96
- # @param required_contexts [Array<Object>]
97
- # A set of objects that should be used as the main context series for method resolving
98
- # algorithm.
99
- # @param context_direction [Array<Symbol>]
100
- # An array of symbols that represents the direction of contexts. Possible values:
101
- #
102
- # - Symbiont::IOK
103
- # - Symbiont::OIK
104
- # - Symbiont::OKI
105
- # - Symbiont::IKO
106
- # - Symbiont::KOI
107
- # - Symbiont::KIO
108
- # @param closure [Proc]
109
- # Proc object that will be evaluated in many contexts: initial, outer and kernel.
110
- # @return [Symbiont::PrivateTrigger]
111
- #
112
- # @see Symbiont::PrivateTrigger
113
- # @see Symbiont::Trigger
114
- #
115
- # @api public
116
- # @since 0.1.0
117
- def private_trigger(*required_contexts, context_direction: Trigger::IOK, &closure)
118
- PrivateTrigger.new(*required_contexts, context_direction: context_direction, &closure)
63
+ Isolator.new(default_direction: context_direction, &closure)
64
+ .evaluate_private(*required_contexts)
119
65
  end
120
66
 
121
67
  # Gets the method object taken from the context that can respond to it.
@@ -142,7 +88,8 @@ module Symbiont
142
88
  # @api public
143
89
  # @since 0.1.0
144
90
  def public_method(method_name, *required_contexts, context_direction: Trigger::IOK, &closure)
145
- public_trigger(*required_contexts, context_direction: context_direction, &closure).method(method_name)
91
+ Isolator.new(default_direction: context_direction, &closure)
92
+ .public_method(method_name, *required_contexts)
146
93
  end
147
94
 
148
95
  # Gets the method object taken from the context that can respond to it.
@@ -169,7 +116,8 @@ module Symbiont
169
116
  # @api public
170
117
  # @since 0.1.0
171
118
  def private_method(method_name, *required_contexts, context_direction: Trigger::IOK, &closure)
172
- private_trigger(*required_contexts, context_direction: context_direction, &closure).method(method_name)
119
+ Isolator.new(default_direction: context_direction, &closure)
120
+ .private_method(method_name, *required_contexts)
173
121
  end
174
122
  end
175
123
  end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Symbiont
4
+ # Special object that wraps your proc object from any place and provides
5
+ # an ability to invoke this proc object lazily inside an any series of contexts.
6
+ #
7
+ # @api public
8
+ # @since 0.3.0
9
+ class Isolator
10
+ # Is raised when closure is not provided.
11
+ #
12
+ # @see #initialize
13
+ #
14
+ # @api public
15
+ # @since 0.3.0
16
+ UnprovidedClosureAttributeError = Class.new(ArgumentError)
17
+
18
+ # Proc object that will be evaluated in many contexts: initial, outer and kernel.
19
+ # Will be used as an outer-context for the method resolution.
20
+ #
21
+ # @return [Proc]
22
+ #
23
+ # @api public
24
+ # @since 0.3.0
25
+ attr_reader :closure
26
+
27
+ # An array of symbols that represents the direction of contexts. Used by default.
28
+ #
29
+ # @return [Array<Symbol>]
30
+ #
31
+ # @api public
32
+ # @since 0.3.0
33
+ attr_reader :default_direction
34
+
35
+ # Instantiates isolator object with corresponding default direction and closure.
36
+ #
37
+ # @option default_direction [Array<Symbol>]
38
+ # An array of symbols that represents the direction of contexts which is used as default
39
+ # context direction. Symbiont::Trigger::IOK is chosen by default.
40
+ # @param closure [Proc]
41
+ # Proc object that will be evaluated in many contexts: initial, outer and kernel.
42
+ # Will be used as an outer-context for the method resolution.
43
+ #
44
+ # @api public
45
+ # @since 0.3.0
46
+ def initialize(default_direction: Trigger::IOK, &closure)
47
+ raise UnprovidedClosureAttributeError, 'You should provide a closure' unless block_given?
48
+
49
+ @default_direction = default_direction
50
+ @closure = closure
51
+ end
52
+
53
+ # Starts execution of a proc object in the context of the passed object with the selected
54
+ # direction of method dispatching. Delegates execution to a public trigger.
55
+ #
56
+ # @param required_contexts [Array<Object>]
57
+ # A set of objects that should be used as the main context series for method resolving
58
+ # algorithm.
59
+ # @param direction [Array<Symbol>]
60
+ # An array of symbols that represents the direction of contexts.
61
+ # @return [void]
62
+ #
63
+ # @see Symbiont::Trigger#__evaluate__
64
+ # @see Symbiont::PublicTrigger
65
+ #
66
+ # @api public
67
+ # @since 0.3.0
68
+ def evaluate(*required_contexts, direction: default_direction)
69
+ public_trigger(*required_contexts, direction: direction).__evaluate__
70
+ end
71
+
72
+ # Starts execution of a proc object in the context of the passed object with the selected
73
+ # direction of method dispatching. Delegates execution to a private trigger.
74
+ #
75
+ # @param required_contexts [Array<Object>]
76
+ # A set of objects that should be used as the main context series for method resolving
77
+ # algorithm.
78
+ # @param direction [Array<Symbol>]
79
+ # An array of symbols that represents the direction of contexts.
80
+ # @return [void]
81
+ #
82
+ # @see Symbiont::Trigger#__evaluate__
83
+ # @see Symbiont::PrivateTrigger
84
+ #
85
+ # @api public
86
+ # @since 0.3.0
87
+ def evaluate_private(*required_contexts, direction: default_direction)
88
+ private_trigger(*required_contexts, direction: direction).__evaluate__
89
+ end
90
+
91
+ # Gets the method object taken from the context that can respond to it.
92
+ # Considers only public methods.
93
+ #
94
+ # @param method_name [Symbol,String] A name of required method.
95
+ # @param required_contexts [Array<Object>]
96
+ # A set of objects that should be used as the main context series for method resolving
97
+ # algorithm.
98
+ # @param direction [Array<Symbol>]
99
+ # An array of symbols that represents the direction of contexts.
100
+ # @return [Method]
101
+ #
102
+ # @see Symbiont::PublicTrigger
103
+ # @see Symbiont::Trigger#method
104
+ #
105
+ # @api public
106
+ # @since 0.3.0
107
+ def public_method(method_name, *required_contexts, direction: default_direction)
108
+ public_trigger(*required_contexts, direction: direction).method(method_name)
109
+ end
110
+
111
+ # Gets the method object taken from the context that can respond to it.
112
+ # Considers private methods and public methods.
113
+ #
114
+ # @param method_name [Symbol,String] A name of required method.
115
+ # @param required_contexts [Array<Object>]
116
+ # A set of objects that should be used as the main context series for method resolving
117
+ # algorithm.
118
+ # @param direction [Array<Symbol>]
119
+ # An array of symbols that represents the direction of contexts.
120
+ # @return [Method]
121
+ #
122
+ # @see Symbiont::PrivateTrigger
123
+ # @see Symbiont::Trigger#method
124
+ #
125
+ # @api public
126
+ # @since 0.3.0
127
+ def private_method(method_name, *required_contexts, direction: default_direction)
128
+ private_trigger(*required_contexts, direction: direction).method(method_name)
129
+ end
130
+
131
+ private
132
+
133
+ # Factory method that instantiates a public trigger with the desired execution context,
134
+ # the direction of method dispatching and the closure that needs to be performed.
135
+ #
136
+ # @param required_contexts [Array<Object>]
137
+ # A set of objects that should be used as the main context series for method resolving
138
+ # algorithm.
139
+ # @param direction [Array<Symbol>]
140
+ # An array of symbols that represents the direction of contexts. Possible values:
141
+ #
142
+ # - Symbiont::IOK
143
+ # - Symbiont::OIK
144
+ # - Symbiont::OKI
145
+ # - Symbiont::IKO
146
+ # - Symbiont::KOI
147
+ # - Symbiont::KIO
148
+ # @return [Symbiont::PublicTrigger]
149
+ #
150
+ # @see Symbiont::PublicTrigger
151
+ # @see Symbiont::Trigger
152
+ #
153
+ # @api private
154
+ # @since 0.3.0
155
+ def public_trigger(*required_contexts, direction: default_direction)
156
+ PublicTrigger.new(*required_contexts, context_direction: direction, &closure)
157
+ end
158
+
159
+ # Factory method that instantiates a private trigger with the desired execution context,
160
+ # the direction of method dispatching and the closure that needs to be performed.
161
+ #
162
+ # @param required_contexts [Array<Object>]
163
+ # A set of objects that should be used as the main context series for method resolving
164
+ # algorithm.
165
+ # @param direction [Array<Symbol>]
166
+ # An array of symbols that represents the direction of contexts. Possible values:
167
+ #
168
+ # - Symbiont::IOK
169
+ # - Symbiont::OIK
170
+ # - Symbiont::OKI
171
+ # - Symbiont::IKO
172
+ # - Symbiont::KOI
173
+ # - Symbiont::KIO
174
+ # @return [Symbiont::PrivateTrigger]
175
+ #
176
+ # @see Symbiont::PrivateTrigger
177
+ # @see Symbiont::Trigger
178
+ #
179
+ # @api private
180
+ # @since 0.3.0
181
+ def private_trigger(*required_contexts, direction: default_direction)
182
+ PrivateTrigger.new(*required_contexts, context_direction: direction, &closure)
183
+ end
184
+ end
185
+ end
@@ -17,7 +17,7 @@ module Symbiont
17
17
  #
18
18
  # @param method_name [String,Symbol] Method that a context should respond to.
19
19
  # @raise NoMethodError
20
- # Is raised when no one of the contexts are able to respond to the required method.
20
+ # Is raised when no one of the contexts are able to respond to the required method.
21
21
  # @return [Objcet]
22
22
  #
23
23
  # @see Symbiont::Trigger#__actual_context__
@@ -26,8 +26,47 @@ module Symbiont
26
26
  # @since 0.1.0
27
27
  def __actual_context__(method_name)
28
28
  __directed_contexts__.find do |context|
29
- context.respond_to?(method_name, true)
29
+ begin
30
+ context.respond_to?(method_name, true)
31
+ rescue ::NoMethodError
32
+ # NOTE:
33
+ # this situation is caused when the context object does not respodond to
34
+ # #resond_to? method (BasicObject instances for example)
35
+
36
+ context_singleton = __extract_singleton_class__(context)
37
+
38
+ context_singleton.private_instance_methods(true).include?(method_name) ||
39
+ context_singleton.instance_methods(true).include?(method_name)
40
+ end
30
41
  end || super
31
42
  end
43
+
44
+ # Returns a corresponding public/private method object of the actual context.
45
+ #
46
+ # @param method_name [String,Symbol] Method name
47
+ # @return [Method]
48
+ #
49
+ # @see [Symbiont::Trigger#method]
50
+ #
51
+ # @api private
52
+ # @since 0.5.0
53
+ def method(method_name)
54
+ __context__ = __actual_context__(method_name)
55
+
56
+ # NOTE:
57
+ # block is used cuz #__actual_context__can raise
58
+ # ::NoMethodError (ContextNoMethodError) too (and we should raise it).
59
+ begin
60
+ __context__.method(method_name)
61
+ rescue ::NoMethodError
62
+ # NOTE:
63
+ # this situation is caused when the context object does not respond
64
+ # to #method method (BasicObject instances for example). We can extract
65
+ # method objects via it's singleton class.
66
+
67
+ __context_singleton__ = __extract_singleton_class__(__context__)
68
+ __context_singleton__.instance_method(method_name).bind(__context__)
69
+ end
70
+ end
32
71
  end
33
72
  end
@@ -26,8 +26,47 @@ module Symbiont
26
26
  # @since 0.1.0
27
27
  def __actual_context__(method_name)
28
28
  __directed_contexts__.find do |context|
29
- context.respond_to?(method_name, false)
29
+ begin
30
+ context.respond_to?(method_name, false)
31
+ rescue ::NoMethodError
32
+ # NOTE:
33
+ # this situation is caused when the context object does not respodond to
34
+ # #resond_to? method (BasicObject instances for example)
35
+
36
+ context_singleton = __extract_singleton_class__(context)
37
+ context_singleton.public_instance_methods(true).include?(method_name)
38
+ end
30
39
  end || super
31
40
  end
41
+
42
+ # Returns a corresponding public method object of the actual context.
43
+ #
44
+ # @param method_name [String,Symbol] Method name
45
+ # @raise [::NameError]
46
+ # @raise [Symbiont::Trigger::ContextNoMethodError, ::NoMethodError]
47
+ # @return [Method]
48
+ #
49
+ # @see [Symbiont::Trigger#method]
50
+ #
51
+ # @api private
52
+ # @since 0.5.0
53
+ def method(method_name)
54
+ __context__ = __actual_context__(method_name)
55
+
56
+ # NOTE:
57
+ # block is used cuz #__actual_context__can raise
58
+ # ::NoMethodError (ContextNoMethodError) too (and we should raise it)
59
+ begin
60
+ __context__.method(method_name)
61
+ rescue ::NoMethodError
62
+ # NOTE:
63
+ # this situation is caused when the context object does not respond
64
+ # to #method method (BasicObject instances for example). We can extract
65
+ # method objects via it's singleton class.
66
+
67
+ __context_singleton__ = __extract_singleton_class__(__context__)
68
+ __context_singleton__.public_instance_method(method_name).bind(__context__)
69
+ end
70
+ end
32
71
  end
33
72
  end