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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +11 -4
  4. data/lib/strategic.rb +32 -2
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d1b5e48f559fa9befbe74660a5894d73aa99e9acb9ab31daf6d592e50d5200e
4
- data.tar.gz: b0064808d6119cd5e860762c82483d457c30c4a5d22b703060fbef323a781086
3
+ metadata.gz: 60db744a19fb4a7e6ac36c0fc5d36a6868a801d296c9331b4e865e087dd93c31
4
+ data.tar.gz: a88167c7f3a97fe47be46abef4ccd840597e237bc84812a1da586db501cc7868
5
5
  SHA512:
6
- metadata.gz: 351e5f342baf23c732723b97e0040f85d65378bf4e5fdfcde2385a9b16870a303f638da34765569d0392180295997088e1f7730b3a970210ebdd22bb388b712a
7
- data.tar.gz: b5b269f698ae134d412dc9d8ff5e16d397da76480c88f9b92e984079f5edbaed3002f409e71ac4686e010fbd0a0bdcc460b70a42a7c503ea95e2001b665dd7a5
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
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.1'
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.1
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
- @strategy = self.class.strategy_class_for(string_or_class_or_object)&.new(self)
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)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strategic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh