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.
- checksums.yaml +5 -5
- data/.gitignore +1 -1
- data/.rspec +1 -1
- data/.rubocop.yml +17 -112
- data/CHANGELOG.md +32 -0
- data/Gemfile +4 -2
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +1 -1
- data/README.md +70 -30
- data/Rakefile +15 -1
- data/Steepfile +6 -0
- data/bin/console +2 -1
- data/lib/symbiont.rb +1 -0
- data/lib/symbiont/executor.rb +8 -60
- data/lib/symbiont/isolator.rb +185 -0
- data/lib/symbiont/private_trigger.rb +41 -2
- data/lib/symbiont/public_trigger.rb +40 -1
- data/lib/symbiont/teleport.rb +9 -0
- data/lib/symbiont/trigger.rb +20 -5
- data/lib/symbiont/version.rb +1 -1
- data/sig/.keep +0 -0
- data/symbiont-ruby.gemspec +12 -10
- metadata +29 -27
- data/.hound.yml +0 -2
- data/.travis.yml +0 -14
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
|
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
data/bin/console
CHANGED
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
|
|
data/lib/symbiont/executor.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
63
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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
|