Toritori

Maintainability Test Coverage

Simple tool to work with Abstract Factories. It provides the DSL for defining a set factories and produce objects.

Installation

Add this line to your application's Gemfile:

gem 'toritori'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install toritori

Usage

Basics

Add the module to the class

require 'toritori'

class MyAbstractFactory
  include Toritori
end

It will provide an ablility to declare and refer individual factories

# Declaration
MyAbstractFactory.factory(:chair)
MyAbstractFactory.factory(:table)
# Access all factories
MyAbstractFactory.factories # => { chair: #<Toritori::Factory @name: :chair>, table: #<Toritori::Factory @name: :table> }
# Access individual factory
MyAbstractFactory.chair_factory # => #<Toritori::Factory @name: :chair>
MyAbstractFactory.table_factory # => #<Toritori::Factory @name: :table>

Creating objects is also easy

MyAbstractFactory.table_factory.create(<attrs>) # => #<Class>

To provide a specific class for factory to create instances

Sofa = Struct.new(:width)

class MyAbstractFactory
  include Toritori

  factory :sofa, produces: Sofa
end

MyAbstractFactory.sofa_factory # =>
MyAbstractFactory.sofa_factory.create(2300) # => #<Sofa @width=2300>

The library defaults is to use new method for instantiation and bypass parameters from create method. But if you need to customize this behaviour

class MyAbstractFactory
  include Toritori

  factory :file, produces: File, creation_method: :open
end

MyAbstractFactory.file_factory.create('/dev/null') # => #<File @path='/dev/null'>

Subclassing

For example:

class ModernFactory < MyAbstractFactory
  factories # => { chair: #<Toritori::Factory @name: :chair>,
            #      table: #<Toritori::Factory @name: :table>,
            #      sofa: #<Toritori::Factory @name: :sofa, @base_class=Sofa> }
end

If we need to add a wifi option to sofa

class ModernFactory < MyAbstractFactory
  sofa_factory.subclass do
    def add_wifi
      @wifi = true
    end

    attr_reader :wifi
  end
end

modern_sofa = ModernFactory.sofa_factory.create(2500)
modern_sofa.wifi # => nil
modern_sofa.add_wifi
modern_sofa.wifi # => true

If we need to add wifi option to initializer

class ModernFactory < MyAbstractFactory
  # Update initialize method
  chair_factory.subclass do
    def initialize(width, wifi)
      super(width)
      @wifi = wifi
    end

    attr_reader :wifi
  end
end

modern_chair = ModernFactory.chair_factory.create(2500, wifi: false)
modern_chair.wifi # => false

The subclass (ModernFactory) will gen a copy of factories so you can customize sublasses without side effects on a base class (MyAbstractFactory).

Sometimes when subclass definition is big it is better to put it into a separate file. To make the library to use that sub-class:

class ModernTable < MyAbstractFactory.table_factory.base_class
  # ... omitted ...
  end

class ModernFactory < MyAbstractFactory
  # Update initialize method
  table_factory.subclass(produces: ModernTable, creation_method: :produce) do
    def self.produce(...)
      new(...)
    end
  end

  table_factory.create # => #<ModernTable>
end

The sub-class should be a child of a base class we specified in factory of the parent abstract factory, otherwise you'll get Toritori::SubclassError. We recommend to have base classes (produces: option) for parent abstract factory defined explicitly to have an ability to refer them in sub-class files.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/andriy-baran/toritori. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

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

Code of Conduct

Everyone interacting in the Toritori project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.