strategic 1.0.1 → 1.1.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +11 -4
- data/lib/strategic.rb +32 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60db744a19fb4a7e6ac36c0fc5d36a6868a801d296c9331b4e865e087dd93c31
|
4
|
+
data.tar.gz: a88167c7f3a97fe47be46abef4ccd840597e237bc84812a1da586db501cc7868
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0dd52c3176aa17bab03d9de1affdfbd8b90156278277ad3b2ade3a5d4401982a83208b5d04b54c9df39faf66845bd374f0eff9cd71cc6977382382fc7f4138a
|
7
|
+
data.tar.gz: 966b2e8d07234cf47e0d6da3c622628d777970d99f7c5b6725760b53f7958e013b206aa6eb287d1da2c30a869373648a004db528d40647b89422cf812a4e7a90
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 1.1.0
|
4
|
+
|
5
|
+
- Generate `strategy_name` attribute on `Strategic` class if it does not already exist like in the case of a Rails migration column
|
6
|
+
- Automatically set `strategy_name` attribute when setting `strategy` attribute (either `strategy_name` attribute in Ruby or column in Rails)
|
7
|
+
- Load `strategy` attribute from `strategy_name` attribute on `after_initialize` in Rails
|
8
|
+
|
3
9
|
## 1.0.1
|
4
10
|
|
5
11
|
- Fix error "undefined method `new' for Strategic::Strategy:Module" that occurs when setting an empty string strategy (must return nil or default strategy)
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Strategic 1.0
|
1
|
+
# Strategic 1.1.0
|
2
2
|
## Painless Strategy Pattern in Ruby and Rails
|
3
3
|
[](http://badge.fury.io/rb/strategic)
|
4
4
|
[](https://github.com/AndyObtiva/strategic/actions/workflows/ruby.yml)
|
@@ -28,7 +28,7 @@ code (Open/Closed Principle).
|
|
28
28
|
externalizing all logic concerning algorithmic variations into separate strategy
|
29
29
|
classes that are easy to find, maintain and extend while honoring the Open/Closed Principle and avoiding conditionals.
|
30
30
|
|
31
|
-
In summary, if you make a class called `TaxCalculator` strategic by including the `Strategic` mixin module, now you are able to drop strategies under the `tax_calculator` directory sitting next to the class (e.g. `tax_calculator/us_strategy.rb`, `tax_calculator/canada_strategy.rb`) while gaining extra [API](#api) methods to grab strategy names to present in a user interface (`.strategy_names`), set a strategy (`#strategy=(strategy_name)`), and/or instantiate `TaxCalculator` directly with a strategy from the get-go (`.new_with_strategy(strategy_name, *initialize_args)`). Finally, you can simply invoke strategy methods on the main strategic model (e.g. `tax_calculator.tax_for(39.78)`).
|
31
|
+
In summary, if you make a class called `TaxCalculator` strategic by including the `Strategic` mixin module, now you are able to drop strategies under the `tax_calculator` directory sitting next to the class (e.g. `tax_calculator/us_strategy.rb`, `tax_calculator/canada_strategy.rb`) while gaining extra [API](#api) methods to grab strategy names to present in a user interface (`.strategy_names`), set a strategy (`#strategy=(strategy_name)` or `#strategy_name=(strategy_name)`), and/or instantiate `TaxCalculator` directly with a strategy from the get-go (`.new_with_strategy(strategy_name, *initialize_args)`). Finally, you can simply invoke strategy methods on the main strategic model (e.g. `tax_calculator.tax_for(39.78)`).
|
32
32
|
|
33
33
|
### Example
|
34
34
|
|
@@ -86,6 +86,12 @@ tax_calculator.strategy = 'us'
|
|
86
86
|
tax_calculator = TaxCalculator.new_with_strategy('us', args)
|
87
87
|
```
|
88
88
|
|
89
|
+
4b. Alternatively in Rails, instantiate or create an ActiveRecord model with `strategy_name` column attribute included in args (you may generate migration for `strategy_name` column via `rails g migration add_strategy_name_to_resources strategy_name:string`):
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
tax_calculator = TaxCalculator.create(args) # args include strategy_name
|
93
|
+
```
|
94
|
+
|
89
95
|
5. Invoke the strategy implemented method:
|
90
96
|
|
91
97
|
```ruby
|
@@ -116,7 +122,7 @@ If no strategy is selected and you try to invoke a method that belongs to strate
|
|
116
122
|
Add the following to bundler's `Gemfile`.
|
117
123
|
|
118
124
|
```ruby
|
119
|
-
gem 'strategic', '~> 1.0
|
125
|
+
gem 'strategic', '~> 1.1.0'
|
120
126
|
```
|
121
127
|
|
122
128
|
### Option 2: Manual
|
@@ -124,7 +130,7 @@ gem 'strategic', '~> 1.0.1'
|
|
124
130
|
Or manually install and require library.
|
125
131
|
|
126
132
|
```bash
|
127
|
-
gem install strategic -v1.0
|
133
|
+
gem install strategic -v1.1.0
|
128
134
|
```
|
129
135
|
|
130
136
|
```ruby
|
@@ -141,6 +147,7 @@ Steps:
|
|
141
147
|
- Includes the `Strategic::Strategy` module
|
142
148
|
- Has a class name that ends with `Strategy` suffix (e.g. `NewCustomerStrategy`)
|
143
149
|
4. Set strategy on strategic model using `strategy=` attribute writer method or instantiate with `new_with_strategy` class method, which takes a strategy name string (any case), strategy class, or mirror object (having a class matching strategy name minus the word `Strategy`) (note: you can call `::strategy_names` class method to obtain available strategy names or `::stratgies` to obtain available strategy classes)
|
150
|
+
5. Alternatively in Rails, create migration `rails g migration add_strategy_name_to_resources strategy_name:string` and set strategy via `strategy_name` column, storing in database. On load of the model, the right strategy is automatically loaded based on `strategy_name` column.
|
144
151
|
6. Invoke strategy method needed
|
145
152
|
|
146
153
|
## API
|
data/lib/strategic.rb
CHANGED
@@ -23,6 +23,31 @@ module Strategic
|
|
23
23
|
def self.included(klass)
|
24
24
|
klass.extend(ClassMethods)
|
25
25
|
klass.require_strategies
|
26
|
+
rails_mode = klass.respond_to?(:column_names) && klass.column_names.include?('strategy_name')
|
27
|
+
if rails_mode
|
28
|
+
klass.include(ExtraRailsMethods)
|
29
|
+
klass.after_initialize :reload_strategy
|
30
|
+
else
|
31
|
+
klass.include(ExtraRubyMethods)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module ExtraRailsMethods
|
36
|
+
def strategy_name=(string)
|
37
|
+
self['strategy_name'] = string
|
38
|
+
strategy_class = self.class.strategy_class_for(string)
|
39
|
+
@strategy = strategy_class&.new(self)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module ExtraRubyMethods
|
44
|
+
attr_reader :strategy_name
|
45
|
+
|
46
|
+
def strategy_name=(string)
|
47
|
+
@strategy_name = string
|
48
|
+
strategy_class = self.class.strategy_class_for(string)
|
49
|
+
@strategy = strategy_class&.new(self)
|
50
|
+
end
|
26
51
|
end
|
27
52
|
|
28
53
|
module ClassMethods
|
@@ -109,13 +134,18 @@ module Strategic
|
|
109
134
|
end
|
110
135
|
|
111
136
|
def strategy=(string_or_class_or_object)
|
112
|
-
|
137
|
+
strategy_class = self.class.strategy_class_for(string_or_class_or_object)
|
138
|
+
self.strategy_name = strategy_class&.strategy_name
|
113
139
|
end
|
114
140
|
|
115
141
|
def strategy
|
116
142
|
@strategy
|
117
143
|
end
|
118
|
-
|
144
|
+
|
145
|
+
def reload_strategy
|
146
|
+
self.strategy = strategy_name
|
147
|
+
end
|
148
|
+
|
119
149
|
def method_missing(method_name, *args, &block)
|
120
150
|
if strategy&.respond_to?(method_name, *args, &block)
|
121
151
|
strategy.send(method_name, *args, &block)
|