strategic 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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