industrialist 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d4306467a233c5874542880e1f7e2f30300be18d28dad188e8c02c6fb9212e5
4
- data.tar.gz: 7c88ab7b91c2363c35474711b6017b4b77be3266b31a53dae9be9dca6ee3a429
3
+ metadata.gz: 858f0f4e068299c8eab65bf53cc4b78b5d582ad1a36a81bd85c41654c21e9855
4
+ data.tar.gz: ed03501fc2ab8f74f5ac29d1e47675ac77977e5c859a5a9ddd9701b28afdbc70
5
5
  SHA512:
6
- metadata.gz: a18c367c3960e114cdc7b202ceecdb9ce8c3897f836e87cfadc08b8e0a432277a4b8d6b0f7ea39163a231addbd7cbea76dfa9f6c9a8a38d780dd9fff4e7c5795
7
- data.tar.gz: 9ea2a2c21b12b3bb8a8d15b411f629c320de13e546304aa3244bd0a45250890cca27470dfc09a64de0109ab012f0df0590bfa2e7e2a458e969077b6df3715faf
6
+ metadata.gz: 751a1bbef0a2f80b1936d0b23608880fd5a3cec7a4dcdeea0d8f705c96a4c86d37c5576364cf484159054be6845deadb3bb038fb298daa959d96fe7add723877
7
+ data.tar.gz: 8ec6e11e6851d7f17a0f7e92e3ebb6e246daab3b747534cf365ea623a1d4ff3390a202cdb92d7e815320b3062439fe82a0981a06837e19c0f93d98822f35e170
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- industrialist (0.3.0)
4
+ industrialist (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -36,7 +36,7 @@ end
36
36
  AutomobileFactory.build(:sedan)
37
37
  ```
38
38
 
39
- The Ruby way to do this is with a Hash:
39
+ Another way to do this is with a hash:
40
40
 
41
41
  ```ruby
42
42
  class Sedan; end
@@ -60,9 +60,23 @@ AutomobileFactory.build(:coupe)
60
60
 
61
61
  But, 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.
62
62
 
63
+ The Ruby way to do this is with conventions and metaprogramming:
64
+
65
+ ```ruby
66
+ class AutomobileFactory
67
+ def self.build(automobile_type, *args)
68
+ Object.get_const("#{automobile_type.capitalize}").new(*args)
69
+ end
70
+ end
71
+ ```
72
+
73
+ But, factories of this type also have issues. 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`.
74
+
75
+ You can find a deeper dive into the motivations behind Industrialst [here](https://engineering.entelo.com/extension-without-modification-cb0f9cfb64a3).
76
+
63
77
  ## Usage
64
78
 
65
- Industrialist creates factories for you. Just include the Manufacturable module in a base class and give the factory a name. Industrialist also allows children of the base class to register themselves with the factory by specifying their corresponding key. Like this:
79
+ Industrialist creates factories for you. Just include the Manufacturable module in a base class and call `create_factory` with a name. Industrialist also allows children of the base class to register themselves with the factory by specifying their corresponding key.
66
80
 
67
81
  ```ruby
68
82
  class Automobile
@@ -78,11 +92,71 @@ class Coupe < Automobile
78
92
  corresponds_to :coupe
79
93
  end
80
94
 
95
+ AutomobileFactory.build(:sedan) # => #<Sedan:0x00007ff64d88ce58>
96
+ ```
97
+
98
+ Manufacturable classes may also correspond to multiple keys:
99
+
100
+ ```ruby
81
101
  class Cabriolet < Automobile
102
+ corresponds_to :cabriolet
82
103
  corresponds_to :convertible
83
104
  end
105
+ ```
106
+
107
+ By 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`.
108
+
109
+ ```ruby
110
+ class Airplane
111
+ include Industrialist::Manufacturable
112
+ create_factory :AirplaneFactory
113
+ end
114
+
115
+ class Biplane < Airplane
116
+ manufacturable_default
117
+ corresponds_to :biplane
118
+ end
119
+
120
+ class FighterJet < Airplane
121
+ corresponds_to :fighter
122
+ end
84
123
 
85
- AutomobileFactory.build(:convertible)
124
+ AirplaneFactory.build(:plane) # => #<Biplane:0x00007ffcd4165610>
125
+ ```
126
+
127
+ Finally, Industrialist will 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:
128
+
129
+ ```ruby
130
+ class Train
131
+ include Industrialist::Manufacturable
132
+ create_factory :TrainFactory
133
+ end
134
+
135
+ class SteamEngine < Train
136
+ corresponds_to engine: :steam
137
+ end
138
+
139
+ class Diesel < Train
140
+ corresponds_to engine: :diesel
141
+ end
142
+
143
+ class Boxcar < Train
144
+ corresponds_to cargo: :boxcar
145
+ end
146
+
147
+ class Carriage < Train
148
+ corresponds_to passenger: :carriage
149
+ end
150
+
151
+ class Sleeper < Train
152
+ corresponds_to passenger: :sleeper
153
+ end
154
+
155
+ def train_car(role, type)
156
+ TrainFactory.build(role => type)
157
+ end
158
+
159
+ train_car(:engine, :diesel) # => #<Diesel:0x00007ff64f846640>
86
160
  ```
87
161
 
88
162
  ## Installation
@@ -101,15 +175,22 @@ Or install it yourself as:
101
175
 
102
176
  $ gem install industrialist
103
177
 
104
- ## Development
178
+ If you are using Industrialist with Rails, you'll need to preload your manufacturable objects in the development and test environments in an intializer, like this:
105
179
 
106
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
180
+ ```ruby
181
+ def require_factory(class_type)
182
+ Dir[Rails.root.join('app', "#{class_type}", '**', '*.rb').to_s].each { |file| require file }
183
+ end
107
184
 
108
- 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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
185
+ if %w(development test).include?(Rails.env)
186
+ require_factory('automobiles')
187
+ require_factory('books')
188
+ end
189
+ ```
109
190
 
110
191
  ## Contributing
111
192
 
112
- Bug reports and pull requests are welcome on GitHub at https://github.com/entelo/industrialist. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
193
+ Bug reports and pull requests are welcome on GitHub at https://github.com/entelo/industrialist.
113
194
 
114
195
  ## License
115
196
 
@@ -1,5 +1,7 @@
1
1
  module Industrialist
2
2
  class Factory
3
+ DEFAULT_KEY = :__manufacturable_default__
4
+
3
5
  attr_reader :registry
4
6
 
5
7
  def initialize
@@ -11,10 +13,12 @@ module Industrialist
11
13
  end
12
14
 
13
15
  def build(key, *args)
14
- klass = registry[factory_key(key)]
16
+ klass = registry[factory_key(key)] || registry[DEFAULT_KEY]
15
17
  klass&.new(*args)
16
18
  end
17
19
 
20
+ private
21
+
18
22
  def factory_key(key)
19
23
  (key.respond_to?(:to_sym) && key.to_sym) || key
20
24
  end
@@ -3,12 +3,11 @@ require 'industrialist/warning_helper'
3
3
 
4
4
  module Industrialist
5
5
  module Manufacturable
6
- extend WarningHelper
7
-
8
- ALREADY_INCLUDED_WARNING_MESSAGE = 'warning: a factory is already defined on this class hierarchy'.freeze
6
+ ALREADY_INCLUDED_WARNING_MESSAGE = 'warning: overriding previously defined factory on this class hierarchy'.freeze
7
+ MULTIPLE_DEFAULT_WARNING_MESSAGE = 'warning: overriding a previously registered default class'.freeze
9
8
 
10
9
  def self.included(base)
11
- warning(ALREADY_INCLUDED_WARNING_MESSAGE) if base.class_variable_defined?(:@@factory)
10
+ WarningHelper.warning(ALREADY_INCLUDED_WARNING_MESSAGE) if base.class_variable_defined?(:@@factory)
12
11
 
13
12
  base.extend ClassMethods
14
13
  base.class_variable_set(:@@factory, Industrialist::Factory.new)
@@ -23,6 +22,12 @@ module Industrialist
23
22
  factory.register(key, self)
24
23
  end
25
24
 
25
+ def manufacturable_default
26
+ WarningHelper.warning(MULTIPLE_DEFAULT_WARNING_MESSAGE) if factory.registry[Industrialist::Factory::DEFAULT_KEY]
27
+
28
+ factory.register(Industrialist::Factory::DEFAULT_KEY, self)
29
+ end
30
+
26
31
  def factory
27
32
  class_variable_get(:@@factory)
28
33
  end
@@ -1,3 +1,3 @@
1
1
  module Industrialist
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
@@ -1,6 +1,6 @@
1
1
  module Industrialist
2
- module WarningHelper
3
- def warning(message)
2
+ class WarningHelper
3
+ def self.warning(message)
4
4
  most_recent_caller = caller(2..2).first.split(':')
5
5
  file_name = most_recent_caller[0]
6
6
  line_number = most_recent_caller[1]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: industrialist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alan Ridlehoover
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2019-03-23 00:00:00.000000000 Z
12
+ date: 2019-03-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler