Project

coactive

0.0
The project is in a healthy, maintained state
Make classes coactive
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

Coactive

Make classes coactive.

Dependencies

  • ruby 2.3+
  • activesupport 5.0+

Installation

Add this line to your application's Gemfile:

gem 'coactive'

Then execute:

$ bundle

Usage

Coactors

Include Coactive::Base to your base class:

class Base
  include Coactive::Base
end

Define coactive classes that inherit your base class:

class A < Base
end

class B < Base
end

class C < Base
  coact A
  coact B
end

You can lookup coactors as follows:

C.new.coactors
# => [A, B]

Named coactors

You can also define coactive classes by using specific name:

class A < Base
  coaction :coactive_name
end

class B < Base
  coaction :coactive_name
end

class C < Base
  coact :coactive_name
end

C.new.coactors
# => [A, B]

Coactors are looked up from descendants of your base class. Note that the coactors are unordered.

In development mode of rails, it is necessary to load source files for looking up classes having specific coaction. You can configure source file locations by load_paths as the following example:

class Base
  include Coactive::Base

  configure_coactive do |config|
    config.load_paths = ['app/coactors']
  end
end

Object-based coactors

You can also define coactive classes by using object:

class ItemA
end

class ItemB
end

class Base::ItemA < Base
end

class Base::ItemB < Base
end

class Base::C < Base
  coact ItemA
  coact ItemB
end

Base::C.new.coactors
#=> [Base::ItemA, Base::ItemB]

Coactors are looked up from the namespace corresponding with caller classes.

You can also looked up coactors corresponding with superclass of object. You can configure this feature by lookup_superclass_for_object and lookup_superclass_until:

class Base
  include Coactive::Base

  configure_coactive do |config|
    config.lookup_superclass_for_object = true
    config.lookup_superclass_until = ['ActiveRecord::Base', 'ActiveModel::Base']
  end
end

Dynamic coactors

You can also dynamically lookup coactors by using block or instance method:

class A < Base
end

class B < Base
end

class C < Base
  # use block
  coact do
    if @condition == 'A'
      A
    else
      B
    end
  end

  def initialize(condition)
    @condition = condition
  end
end

C.new('A').coactors
#=> [A]
C.new('B').coactors
#=> [B]

class D < Base
  # use method
  coact :coactivate_with_condition

  def initialize(condition)
    @condition = condition
  end

  def coactivate_with_condition
    if @condition == 'A'
      A
    else
      B
    end
  end
end

D.new('A').coactors
#=> [A]
D.new('B').coactors
#=> [B]

Nested coactors

You can define nested coactors. For example:

class NestedA < Base
end

class NestedB < Base
end

class A < Base
  coact NestedA
end

class B < Base
  coact NestedB
end

class C < Base
  coact A
  coact B
end

C.new.coactors.map { |klass| [klass] + klass.new.coactors }.flatten
#=> [A, NestedA, B, NestedB]

Context

You can define variables used in a coactor as a context by including Coactive::Initializer. The variables are stored in context as follows:

class Base
  include Coactive::Base
  include Coactive::Initializer
end

class A < Base
  context :input
end

coactor = A.new(input: 'something')
coactor.context.input
#=> something

Required context

You can also define required context as follows:

class A < Base
  context :input, required: true
end

A.new
#=> Coactive::MissingContextError (missing required context: input)

Default value

You can also define default value as follows:

class A < Base
  context :input, default: 'something'
end

coactor = A.new
coactor.context.input
#=> something

Contextualizer

You can copy context variables to a coactor by calling contextualize:

class Base
  include Coactive::Base
  include Coactive::Initializer
  include Coactive::Contextualizer
end

class A < Base
  context :input
end

coactor = A.new(input: 'something')
coactor.contextualize
coactor.input
#=> something
coactor.instance_variable_get(:@input)
#=> something

Output

You can also set context when finished contextualize block:

class A < Base
  context :result, output: true

  def call
    @result = 'something'
  end
end

coactor = A.new
coactor.contextualize { coactor.call }
coactor.context.result
#=> something

Output return value

You can also set context from return value of contextualize block:

class A < Base
  context :result, output: :return
end

coactor = A.new
coactor.contextualize { 'return value' }
coactor.context.result
#=> return value

Configuration

You can set configurations in your base class as follows:

class Base
  include Coactive::Base

  configure_coactive do |config|
    # path to source files for coactors
    config.load_paths = ['app/coactors']
    # suffix of class that inherits base class
    config.class_suffix = 'Coactor'
    # cache coactors in memory
    config.use_cache = true
    # lookup coactors corresponding with superclass of object
    config.lookup_superclass_for_object = true
    # lookup coactors until superclass is not in the list
    config.lookup_superclass_until = ['ActiveRecord::Base', 'ActiveModel::Base']
  end
end

Contributing

Bug reports and pull requests are welcome at https://github.com/kanety/coactive.

License

The gem is available as open source under the terms of the MIT License.