Skip to content

Commit

Permalink
Merge pull request #12 from 0exp/release/v0.3.0
Browse files Browse the repository at this point in the history
[release] 0.2.0 => 0.3.0
  • Loading branch information
0exp committed Jun 15, 2018
2 parents 3e9874a + f4116ca commit 82f3c69
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 84 deletions.
2 changes: 0 additions & 2 deletions .hound.yml

This file was deleted.

8 changes: 4 additions & 4 deletions .travis.yml
@@ -1,9 +1,9 @@
language: ruby
rvm:
- 2.2.9
- 2.3.6
- 2.4.3
- 2.5.0
- 2.2.10
- 2.3.7
- 2.4.4
- 2.5.1
- ruby-head

sudo: false
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -1,6 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.

## [0.3.0] 2018-06-15
### Added
- `Symbiont::Isolator` - proc object isolation layer for delayed invocations;

## [0.2.0] 2018-04-22
### Added
- Logo ^_^ (special thanks to **Viktoria Karaulova**)
Expand Down
29 changes: 29 additions & 0 deletions README.md
Expand Up @@ -55,6 +55,7 @@ require 'symbiont'
- [Mixing a module with default delegation direction](#mixing-a-module-with-default-delegation-direction)
- [Mixing a module with certain delegation direction](#mixing-a-module-with-certain-delegation-direction)
- [Multiple inner contexts](#multiple-inner-contexts)
- [Isolator - proc object isolation layer for delayed invocations](#isolator---proc-object-isolation-layer-for-delayed-invocations)

# Problems and motivaiton

Expand Down Expand Up @@ -390,6 +391,34 @@ Symbiont::Executor.public_method(:data, object_a, object_b, &closure).call # =>
Symbiont::Executor.public_method(:info, object_a, object_b, &closure).call # => "object_info"
```

## Isolator - proc object isolation layer for delayed invocations

`Symbiont::Isolator` is a special object that wraps your proc object from any place and provides
an ability to invoke this proc object lazily inside an any series of contexts.
All `Symbiont::Executor` features are supported (by the way, `Symbiont::Executor`
uses `Symbiont::Isolator` under the hood).

```ruby
# Usage:

# with default direction (Symbiont::IOK)
isolator = Symbiont::Isolator.new { call_any_method }

# with custom direction
isolator = Symbiont::Isolator.new(default_direction: Symbiont::KIO) { call_any_method }

# invocation
isolator.evaluate(object_a, object_b) # use default direction defined on instantiation
isolator.evaluate(object_a, object_b, direction: Symbiont::KOI) # use custom direction
# same for #.evaluate_private

# getting a method object
isolator.public_method(:call_any_method, object_a, object_b) # use default direction defined on instantiation
isolator.public_method(:call_any_method, object_a, object_b, direction: Symbiont::KIO) # use custom direction
isolator.private_method(...)
# same for #.private_method
```

# Contributing

- Fork it ( https://github.com/0exp/symbiont-ruby/fork )
Expand Down
2 changes: 1 addition & 1 deletion bin/console
@@ -1,7 +1,7 @@
#!/usr/bin/env ruby

require 'bundler/setup'
require 'symbiont/ruby'
require 'symbiont'

require 'pry'
Pry.start
1 change: 1 addition & 0 deletions lib/symbiont.rb
Expand Up @@ -9,6 +9,7 @@ module Symbiont
require_relative 'symbiont/trigger'
require_relative 'symbiont/public_trigger'
require_relative 'symbiont/private_trigger'
require_relative 'symbiont/isolator'
require_relative 'symbiont/executor'
require_relative 'symbiont/context'

Expand Down
68 changes: 8 additions & 60 deletions lib/symbiont/executor.rb
Expand Up @@ -32,7 +32,8 @@ class << self
# @api public
# @since 0.1.0
def evaluate(*required_contexts, context_direction: Trigger::IOK, &closure)
public_trigger(*required_contexts, context_direction: context_direction, &closure).__evaluate__
Isolator.new(default_direction: context_direction, &closure)
.evaluate(*required_contexts)
end

# Starts execution of a proc object in the context of the passed object with the selected
Expand All @@ -59,63 +60,8 @@ def evaluate(*required_contexts, context_direction: Trigger::IOK, &closure)
# @api public
# @since 0.1.0
def evaluate_private(*required_contexts, context_direction: Trigger::IOK, &closure)
private_trigger(*required_contexts, context_direction: context_direction, &closure).__evaluate__
end

# Factory method that instantiates a public trigger with the desired execution context,
# the direction of method dispatching and the closure that needs to be performed.
#
# @param required_contexts [Array<Object>]
# A set of objects that should be used as the main context series for method resolving
# algorithm.
# @param context_direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts. Possible values:
#
# - Symbiont::IOK
# - Symbiont::OIK
# - Symbiont::OKI
# - Symbiont::IKO
# - Symbiont::KOI
# - Symbiont::KIO
# @param closure [Proc]
# Proc object that will be evaluated in many contexts: initial, outer and kernel.
# @return [Symbiont::PublicTrigger]
#
# @see Symbiont::PublicTrigger
# @see Symbiont::Trigger
#
# @api public
# @since 0.1.0
def public_trigger(*required_contexts, context_direction: Trigger::IOK, &closure)
PublicTrigger.new(*required_contexts, context_direction: context_direction, &closure)
end

# Factory method that instantiates a private trigger with the desired execution context,
# the direction of method dispatching and the closure that needs to be performed.
#
# @param required_contexts [Array<Object>]
# A set of objects that should be used as the main context series for method resolving
# algorithm.
# @param context_direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts. Possible values:
#
# - Symbiont::IOK
# - Symbiont::OIK
# - Symbiont::OKI
# - Symbiont::IKO
# - Symbiont::KOI
# - Symbiont::KIO
# @param closure [Proc]
# Proc object that will be evaluated in many contexts: initial, outer and kernel.
# @return [Symbiont::PrivateTrigger]
#
# @see Symbiont::PrivateTrigger
# @see Symbiont::Trigger
#
# @api public
# @since 0.1.0
def private_trigger(*required_contexts, context_direction: Trigger::IOK, &closure)
PrivateTrigger.new(*required_contexts, context_direction: context_direction, &closure)
Isolator.new(default_direction: context_direction, &closure)
.evaluate_private(*required_contexts)
end

# Gets the method object taken from the context that can respond to it.
Expand All @@ -142,7 +88,8 @@ def private_trigger(*required_contexts, context_direction: Trigger::IOK, &closur
# @api public
# @since 0.1.0
def public_method(method_name, *required_contexts, context_direction: Trigger::IOK, &closure)
public_trigger(*required_contexts, context_direction: context_direction, &closure).method(method_name)
Isolator.new(default_direction: context_direction, &closure)
.public_method(method_name, *required_contexts)
end

# Gets the method object taken from the context that can respond to it.
Expand All @@ -169,7 +116,8 @@ def public_method(method_name, *required_contexts, context_direction: Trigger::I
# @api public
# @since 0.1.0
def private_method(method_name, *required_contexts, context_direction: Trigger::IOK, &closure)
private_trigger(*required_contexts, context_direction: context_direction, &closure).method(method_name)
Isolator.new(default_direction: context_direction, &closure)
.private_method(method_name, *required_contexts)
end
end
end
Expand Down
185 changes: 185 additions & 0 deletions lib/symbiont/isolator.rb
@@ -0,0 +1,185 @@
# frozen_string_literal: true

module Symbiont
# Special object that wraps your proc object from any place and provides
# an ability to invoke this proc object lazily inside an any series of contexts.
#
# @api public
# @since 0.3.0
class Isolator
# Is raised when closure is not provided.
#
# @see #initialize
#
# @api public
# @since 0.3.0
UnprovidedClosureAttributeError = Class.new(ArgumentError)

# Proc object that will be evaluated in many contexts: initial, outer and kernel.
# Will be used as an outer-context for the method resolution.
#
# @return [Proc]
#
# @api public
# @since 0.3.0
attr_reader :closure

# An array of symbols that represents the direction of contexts. Used by default.
#
# @return [Array<Symbol>]
#
# @api public
# @since 0.3.0
attr_reader :default_direction

# Instantiates isolator object with corresponding default direction and closure.
#
# @option default_direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts which is used as default
# context direction. Symbiont::Trigger::IOK is chosen by default.
# @param closure [Proc]
# Proc object that will be evaluated in many contexts: initial, outer and kernel.
# Will be used as an outer-context for the method resolution.
#
# @api public
# @since 0.3.0
def initialize(default_direction: Trigger::IOK, &closure)
raise UnprovidedClosureAttributeError, 'You should provide a closure' unless block_given?

@default_direction = default_direction
@closure = closure
end

# Starts execution of a proc object in the context of the passed object with the selected
# direction of method dispatching. Delegates execution to a public trigger.
#
# @param required_contexts [Array<Object>]
# A set of objects that should be used as the main context series for method resolving
# algorithm.
# @param direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts.
# @return [void]
#
# @see Symbiont::Trigger#__evaluate__
# @see Symbiont::PublicTrigger
#
# @api public
# @since 0.3.0
def evaluate(*required_contexts, direction: default_direction)
public_trigger(*required_contexts, direction: direction).__evaluate__
end

# Starts execution of a proc object in the context of the passed object with the selected
# direction of method dispatching. Delegates execution to a private trigger.
#
# @param required_contexts [Array<Object>]
# A set of objects that should be used as the main context series for method resolving
# algorithm.
# @param direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts.
# @return [void]
#
# @see Symbiont::Trigger#__evaluate__
# @see Symbiont::PrivateTrigger
#
# @api public
# @since 0.3.0
def evaluate_private(*required_contexts, direction: default_direction)
private_trigger(*required_contexts, direction: direction).__evaluate__
end

# Gets the method object taken from the context that can respond to it.
# Considers only public methods.
#
# @param method_name [Symbol,String] A name of required method.
# @param required_contexts [Array<Object>]
# A set of objects that should be used as the main context series for method resolving
# algorithm.
# @param direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts.
# @return [Method]
#
# @see Symbiont::PublicTrigger
# @see Symbiont::Trigger#method
#
# @api public
# @since 0.3.0
def public_method(method_name, *required_contexts, direction: default_direction)
public_trigger(*required_contexts, direction: direction).method(method_name)
end

# Gets the method object taken from the context that can respond to it.
# Considers private methods and public methods.
#
# @param method_name [Symbol,String] A name of required method.
# @param required_contexts [Array<Object>]
# A set of objects that should be used as the main context series for method resolving
# algorithm.
# @param direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts.
# @return [Method]
#
# @see Symbiont::PrivateTrigger
# @see Symbiont::Trigger#method
#
# @api public
# @since 0.3.0
def private_method(method_name, *required_contexts, direction: default_direction)
private_trigger(*required_contexts, direction: direction).method(method_name)
end

private

# Factory method that instantiates a public trigger with the desired execution context,
# the direction of method dispatching and the closure that needs to be performed.
#
# @param required_contexts [Array<Object>]
# A set of objects that should be used as the main context series for method resolving
# algorithm.
# @param direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts. Possible values:
#
# - Symbiont::IOK
# - Symbiont::OIK
# - Symbiont::OKI
# - Symbiont::IKO
# - Symbiont::KOI
# - Symbiont::KIO
# @return [Symbiont::PublicTrigger]
#
# @see Symbiont::PublicTrigger
# @see Symbiont::Trigger
#
# @api private
# @since 0.3.0
def public_trigger(*required_contexts, direction: default_direction)
PublicTrigger.new(*required_contexts, context_direction: direction, &closure)
end

# Factory method that instantiates a private trigger with the desired execution context,
# the direction of method dispatching and the closure that needs to be performed.
#
# @param required_contexts [Array<Object>]
# A set of objects that should be used as the main context series for method resolving
# algorithm.
# @param direction [Array<Symbol>]
# An array of symbols that represents the direction of contexts. Possible values:
#
# - Symbiont::IOK
# - Symbiont::OIK
# - Symbiont::OKI
# - Symbiont::IKO
# - Symbiont::KOI
# - Symbiont::KIO
# @return [Symbiont::PrivateTrigger]
#
# @see Symbiont::PrivateTrigger
# @see Symbiont::Trigger
#
# @api private
# @since 0.3.0
def private_trigger(*required_contexts, direction: default_direction)
PrivateTrigger.new(*required_contexts, context_direction: direction, &closure)
end
end
end
4 changes: 3 additions & 1 deletion lib/symbiont/trigger.rb
Expand Up @@ -153,9 +153,11 @@ class Symbiont::Trigger < BasicObject
# @api private
# @since 0.1.0
def initialize(*initial_contexts, context_direction: IOK, &closure)
# :nocov:
unless ::Kernel.block_given?
::Kernel.raise(UnprovidedClosureAttributeError, 'block attribute should be provided')
end
# :nocov:

# rubocop:disable Layout/SpaceAroundKeyword
unless(context_direction == IOK || context_direction == OIK || context_direction == OKI ||
Expand Down Expand Up @@ -230,7 +232,7 @@ def __actual_context__(method_name)
#
# @api private
# @since 0.1.0
def method_missing(method_name, *arguments, &block) # rubocop:disable Style/MethodMissing
def method_missing(method_name, *arguments, &block) # rubocop:disable Style/MethodMissingSuper
__actual_context__(method_name).send(method_name, *arguments, &block)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/symbiont/version.rb
Expand Up @@ -5,5 +5,5 @@ module Symbiont
#
# @api public
# @since 0.1.0
VERSION = '0.2.0'
VERSION = '0.3.0'
end

0 comments on commit 82f3c69

Please sign in to comment.