strategic 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/strategic.svg)](http://badge.fury.io/rb/strategic)
|
4
4
|
[![rspec](https://github.com/AndyObtiva/strategic/actions/workflows/ruby.yml/badge.svg)](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)
|