{"id":15723698,"url":"https://github.com/entelo/industrialist","last_synced_at":"2025-04-01T06:32:17.265Z","repository":{"id":56877574,"uuid":"174460947","full_name":"entelo/industrialist","owner":"entelo","description":"Industrialist manufactures factories that build self-registered classes.","archived":false,"fork":false,"pushed_at":"2020-07-28T04:27:27.000Z","size":46,"stargazers_count":11,"open_issues_count":2,"forks_count":2,"subscribers_count":24,"default_branch":"master","last_synced_at":"2024-10-25T10:39:32.708Z","etag":null,"topics":["factory-method-pattern","factory-pattern","gang-of-four","ruby","ruby-gem"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/entelo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null}},"created_at":"2019-03-08T03:14:48.000Z","updated_at":"2024-02-28T00:57:47.000Z","dependencies_parsed_at":"2022-08-20T23:10:11.089Z","dependency_job_id":null,"html_url":"https://github.com/entelo/industrialist","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entelo%2Findustrialist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entelo%2Findustrialist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entelo%2Findustrialist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entelo%2Findustrialist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/entelo","download_url":"https://codeload.github.com/entelo/industrialist/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222703811,"owners_count":17025840,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["factory-method-pattern","factory-pattern","gang-of-four","ruby","ruby-gem"],"created_at":"2024-10-03T22:12:53.390Z","updated_at":"2024-11-02T11:04:32.578Z","avatar_url":"https://github.com/entelo.png","language":"Ruby","readme":"[![Gem Version](https://badge.fury.io/rb/industrialist.svg)](https://badge.fury.io/rb/industrialist)\n[![Maintainability](https://api.codeclimate.com/v1/badges/96f6341cfb748a19f90c/maintainability)](https://codeclimate.com/github/entelo/industrialist/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/96f6341cfb748a19f90c/test_coverage)](https://codeclimate.com/github/entelo/industrialist/test_coverage)\n[![CircleCI](https://circleci.com/gh/entelo/industrialist.svg?style=svg)](https://circleci.com/gh/entelo/industrialist)\n\n# Industrialist\n\nIndustrialist makes your factory code easy to extend and resilient to change.\n\nIt was inspired by the Gang-of-Four [factory method](https://en.wikipedia.org/wiki/Factory_method_pattern) and [abstract factory](https://en.wikipedia.org/wiki/Abstract_factory_pattern) patterns.\n\nFactory code often involves a case statement. If you are switching on a key in order to choose which class to build, you have a factory:\n\n```ruby\ndef automobile(automobile_type)\n  case automobile_type\n  when :sedan\n    Sedan.new\n  when :coupe\n    Coupe.new\n  when :convertible\n    Cabriolet.new\n  end\nend\n```\n\nThis code often lives inside a class with other responsibilities. By applying the [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), you can extract it into a factory class:\n\n```ruby\nclass AutomobileFactory\n  def self.build(automobile_type)\n    automobile_klass(automobile_type)\u0026.new\n  end\n\n  def self.automobile_klass(automobile_type)\n    case automobile_type\n    when :sedan\n      Sedan\n    when :coupe\n      Coupe\n    when :convertible\n      Cabriolet\n    end\n  end\nend\n\nAutomobileFactory.build(:sedan)  # =\u003e #\u003cSedan:0x00007ff64d88ce58\u003e\n```\n\nAnother way to do this is with a hash:\n\n```ruby\nclass AutomobileFactory\n  AUTOMOBILE_KLASSES = {\n    sedan: Sedan,\n    coupe: Coupe,\n    convertible: Cabriolet\n  }.freeze\n\n  def self.build(automobile_type)\n    AUTOMOBILE_KLASSES[automobile_type]\u0026.new\n  end\nend\n\nAutomobileFactory.build(:coupe)  # =\u003e #\u003cCoupe:0x00007ff64b6a372\u003e\n```\n\nBut, both of these approaches require you to maintain your factory by hand. In order to extend these factories, you must modify them, which violates the [Open/Closed Principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle).\n\nThe Ruby way to do this is with conventions and metaprogramming:\n\n```ruby\nclass AutomobileFactory\n  def self.build(automobile_type, *args)\n    Object.get_const(\"#{automobile_type.capitalize}\").new(*args)\n  end\nend\n```\n\nBut, factories of this type also have issues. If your convention changes, you'll have to edit the factory, which violates teh Open/Closed principle. Or, if your keys are not easily mapped to a convention, you won't be able to use this type of factory. For example, the `Cabriolet` class above corresponds to the key `:convertible`. \n\nYou can find a deeper dive into the motivations behind Industrialst [here](https://engineering.entelo.com/extension-without-modification-cb0f9cfb64a3).\n\n## Usage\n\nIndustrialist manages a factory of factories, so you don't have to. Setting it up is easy. When you create a factory class, extend `Industrialist::Factory`, and tell Industrialist the base class of the classes your factory will manufacture:\n\n```ruby\nclass AutomobileFactory\n  extend Industrialist::Factory\n  manufactures Automobile\nend\n```\n\nNext, tell Industrialist that the base class is manufacturable by extending `Industrialist::Manufacturable`:\n\n```ruby\nclass Automobile\n  extend Industrialist::Manufacturable\nend\n```\n\nAnd, finally, tell each of your subclasses what key to register themselves under:\n\n```ruby\nclass Sedan \u003c Automobile\n  corresponds_to :sedan\nend\n\nclass Coupe \u003c Automobile\n  corresponds_to :coupe\nend\n```\n\nAs the subclasses are loaded by Ruby, they register themselves with the appropriate factory so that you can do this:\n\n```ruby\nAutomobileFactory.build(:sedan)  # =\u003e #\u003cSedan:0x00007ff64d88ce58\u003e\n```\n\nManufacturable classes may also correspond to multiple keys:\n\n```ruby\nclass Cabriolet \u003c Automobile\n  corresponds_to :cabriolet\n  corresponds_to :convertible\nend\n```\n\nBy default, Industrialist factories will return `nil` when built with an unregistered key. If you would instead prefer a default object, you can designate a `manufacturable_default`.\n\n```ruby\nclass PlaneFactory\n  extend Industrialist::Factory\n  manufactures Plane\nend\n\nclass Plane\n  extend Industrialist::Manufacturable\nend\n\nclass Biplane \u003c Plane\n  manufacturable_default\n  corresponds_to :biplane\nend\n\nclass FighterJet \u003c Plane\n  corresponds_to :fighter\nend\n\nPlaneFactory.build(:bomber)  # =\u003e #\u003cBiplane:0x00007ffcd4165610\u003e\n```\n\nIndustrialist can accept any Ruby object as a key, which is handy when you need to define more complex keys. For example, you could use a hash:\n\n```ruby\nclass TrainFactory\n  extend Industrialist::Factory\n  manufactures Train\nend\n\nclass Train\n  extend Industrialist::Manufacturable\nend\n\nclass SteamEngine \u003c Train\n  corresponds_to engine: :steam\nend\n\nclass Diesel \u003c Train\n  corresponds_to engine: :diesel\nend\n\nclass Boxcar \u003c Train\n  corresponds_to cargo: :boxcar\nend\n\nclass Carriage \u003c Train\n  corresponds_to passenger: :carriage\nend\n\nclass Sleeper \u003c Train\n  corresponds_to passenger: :sleeper\nend\n\nTrainFactory.build(engine: :diesel)  # =\u003e #\u003cDiesel:0x00007ff64f846640\u003e\n```\n\nFor convenience, you can choose not to define your own factories. Instead, just use Industrialist directly:\n\n```ruby\nIndustrialist.build(:plane, :bomber)          # =\u003e #\u003cBiplane:0x00007ffcd4165610\u003e\nIndustrialist.build(:train, engine: :diesel)  # =\u003e #\u003cDiesel:0x00007ff64f846640\u003e\nIndustrialist.build(:autombile, :sedan)       # =\u003e #\u003cSedan:0x00007ff64d88ce58\u003e\n```\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'industrialist'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install industrialist\n\nIf you are using Industrialist with Rails, you'll need to\n\n```ruby\nIndustrialist.config do |config|\n  config.manufacturable_paths \u003c\u003c Rails.root.join('app', 'planes')\n  config.manufacturable_paths \u003c\u003c Rails.root.join('app', 'trains')\n  config.manufacturable_paths \u003c\u003c Rails.root.join('app', 'automobiles')\nend\n```\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/entelo/industrialist.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the Industrialist project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/entelo/industrialist/blob/master/CODE_OF_CONDUCT.md).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fentelo%2Findustrialist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fentelo%2Findustrialist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fentelo%2Findustrialist/lists"}