thor_enhance 0.2.0 → 0.3.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: b07825b4f1216de172d6ce7b7ec2052bccee6793c38ceca8b50f094bcbf3deae
4
- data.tar.gz: 4458ad58f0148f4a77da324893a538e40c1def979eb26305cdb2e005afa500f7
3
+ metadata.gz: 921021cfeb7e6d2528aa29efeeeb0b282208b08cecef9dff992dd421696f13d6
4
+ data.tar.gz: e43f824f5d32922d71c385722b50f31f34a7c7912eb2e6b93e1cb507e7e9f8e3
5
5
  SHA512:
6
- metadata.gz: a10dfebf316a1ad8a5c6b63a91f90b7fe95391b3f40379bbe37dcfd2e89f9cffe8d48a975fa147210a229376ec736927301eaa042def05a146960646ac0e81ba
7
- data.tar.gz: 0d96db3833f42a605f7c341dd8a0a43788f1d447767df9d632a0950543bec63f05adc620b8c298b46184e44f236ac39692ecafe7cf857c091261ecda005e3031
6
+ metadata.gz: 74090f01c075d963fbffd046cb4f3968901cb5683d8bf1f1f91a181de618e75f1ec20368fd0d04815ed76962f00c12a409c24639e03e7c80b647e6ad980ddafd
7
+ data.tar.gz: 2d815c6bc7957019524de7785b4678d8b10ccaa38f9d172ea383f21241cfaf80cf9601573d859140c7e4b29b9d14cdc3ce5f492c3a2bd282f8b5be33100e81eb
data/CHANGELOG.md CHANGED
@@ -5,22 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
9
8
 
10
- ## [0.2.0] - 2022-06-18
9
+ ## [0.3.0]
10
+ - remove `warn` hook in favor of enriched `deprecate` hook
11
+ - method name validation on entry
12
+ - Add examples and better documentation
11
13
 
12
- ### Added
13
- - New feature 1
14
- - New feature 2
15
-
16
- ### Changed
17
- - Changed feature 1
18
- - Changed feature 2
19
-
20
- ### Removed
21
- - Removed feature 1
22
- - Removed feature 2
23
-
24
- ### Fixed
25
- - Bug fix 1
26
- - Bug fix 2
14
+ ## [0.2.0]
15
+ - Stable Release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- thor_enhance (0.2.0)
4
+ thor_enhance (0.3.0)
5
5
  thor (~> 1.3)
6
6
 
7
7
  GEM
data/docs/command.md ADDED
@@ -0,0 +1,54 @@
1
+ # Command Method Injection
2
+
3
+ Command Method injection allows you to easily enrich Thor Commands with additional data.
4
+
5
+ ## When to use:
6
+ This should be used when you want to enrich your command data. This data can then be retrieved by using the [ThorEnhance::Tree](tree.md) class.
7
+
8
+ ## How to use
9
+
10
+ Additional configuration is needed prior to loading the your Thor instance
11
+
12
+ ```ruby
13
+ # thor_enhance_config.rb
14
+ ThorEnhance.configure do |c|
15
+ # Adds `example` method to the command
16
+ # Value can be anything and is a repeatable command
17
+ c.add_command_method_enhance "example", repeatable: true
18
+
19
+ # Adds `validate` method to the command
20
+ # Value must be one of :some or :thing
21
+ c.add_command_method_enhance "validate", enum: [:some, :thing]
22
+
23
+ # Adds `enhace` method to the command
24
+ # Value must be of type CustomClass
25
+ # It is repeatble and required
26
+ c.add_command_method_enhance "enhance", allowed_klasses: [CustomClass], repeatable: true, required: true
27
+ end
28
+ ```
29
+ The `add_option_enhance` takes the name as argument 1 followed by options.
30
+
31
+ The available options are:
32
+
33
+ **enums**:
34
+ - When provided, the value of the `name` must be a value in the `enums` array
35
+ EX: `publish: true` succeeds. `publish: :fail` fails.
36
+ - Default: `nil`
37
+
38
+ **allowed_klasses**
39
+ - When provided, this is expected to be an array of class types the value can be.
40
+ - Default: `nil`
41
+
42
+ **required**
43
+ - When flag is set to true, this option will be required on all `method_option` immediately. An error is raised if validation fails
44
+ - Default: `false`
45
+
46
+ **repeatable**
47
+ - When flag is set to true, this option will allow the same command to reference the method multiple times. The value will be retreable as an Array from [ThorEnhance::Tree](tree.md) class.
48
+ - Default: `false`
49
+
50
+ # Examples:
51
+
52
+ [Basic Example](../examples/basic_example.md)
53
+ [Basic Example with Subcommand](../examples/basic_example_with_subcommand.md)
54
+
data/docs/hooks.md ADDED
@@ -0,0 +1,59 @@
1
+ # Hooks:
2
+
3
+ Hooks allow you to slowly deprecate options over time. There are three basic Hooks available on every method_option
4
+
5
+ ## Arguments:
6
+ Both `deprecate` and `hook` are expected to be a `proc`. The input arguments will be `input, options`
7
+
8
+ ### Argument: Input
9
+ The `input` argument is the first argument. It is the value that the user inputted. When there is no user input, the hook will not run.
10
+
11
+ ### Argument: Option
12
+ The `option` argument is the second argument. It is the `Thor::Option` struct for that existing method. The instance will have all ThorEnhance methods available.
13
+
14
+ ## Deprecate:
15
+ The `deprecate` hook is available on every `method_option`. It expects a `Proc` class. The returned value from the proc is expected as either an Hash or a String.
16
+
17
+ This hook should be used when you want to either immediately depreacte a method or over time deprecate a command while migrating to a new command. The decision to raise or warn is dynamic in real time.
18
+
19
+ ### When returned an String
20
+ If the method option is provided, it will raise `ThorEnhance::OptionDeprecated` every time
21
+
22
+ ### When returned a Hash
23
+ **hash[:raise]**: Expected a boolean value on weather to raise or warn. When true, it will raise `ThorEnhance::OptionDeprecated`. When false it will send WARNING to console
24
+ **hash[:warn]**: Console message used when `:raise` is false. Does not output when `:raise` is true
25
+ **hash[:msg]**: Message for both raise and warn. This should a short message on how to migrate to new command or syntax
26
+
27
+ ```ruby
28
+ # When provided `--value1 "string"`:
29
+ # This will raise `ThorEnhance::OptionDeprecated` with a message that looks like:
30
+ # Passing value for option --value1 is deprecated. Provided `string`. Please migrate to `--value4`
31
+ method_option :value1, type: :string, deprecate: ->(input, option) { "Please migrate to `--value4`" }
32
+
33
+ # When provided `--value2 "string"` and deprecated criteria is not met:
34
+ # This will send a WARNING message to the console. It will resemble:
35
+ # Passing value for option --value1 is deprecated. Provided `string`. Please migrate to `--value4`
36
+ method_option :value2, type: :string, deprecate: ->(input, option) { { raise: Date.today > Date.today, warn: "This option will deprecate after #{Date.today}", msg: "Please migrate to --value4"} }
37
+
38
+ # When provided `--value3 "string"` and deprecated criteria is:
39
+ # This will raise `ThorEnhance::OptionDeprecated` with a message that looks like:
40
+ # Passing value for option --value3 is deprecated. Provided `string`. Please migrate to `--value4`
41
+ method_option :value3, type: :string, deprecate: ->(input, option) { { raise: true, warn: "This option will deprecate after #{Date.today}", msg: "Please migrate to --value4"} }
42
+ ```
43
+
44
+ ## Hook
45
+ The `hook` hook is available on every `method_option`. It expects a `Proc` class. No return value is expected. When the input is provided, custom code can get executed
46
+
47
+ ```ruby
48
+ # When provided `--value1 "string"`:
49
+ # This will raise `ThorEnhance::OptionDeprecated` with a message that looks like:
50
+ # Passing value for option --value1 is deprecated. Provided `string`. Please migrate to `--value4`
51
+ method_option :value1, type: :string, hook: ->(input, option) { Kernel.puts "#{input} is a good choice for #{option.name}" }
52
+ ```
53
+
54
+ ---
55
+
56
+ # Examples
57
+
58
+ For examples, [please navigate here](../examples/hooks.md)
59
+
@@ -0,0 +1,52 @@
1
+ # Method Option Injection
2
+
3
+ Method option injection allows you to easily add additional flags to the `method_option` for commands. You can set them as required for every option. You can even set allowable values or allowable classes
4
+
5
+ ## When to use:
6
+ This should be used when you want to enrich your command data. This data can then be retrieved by using the [ThorEnhance::Tree](tree.md) class.
7
+
8
+ ## How to use
9
+
10
+ Additional configuration is needed prior to loading the your Thor instance
11
+
12
+ ```ruby
13
+ # thor_enhance_config.rb
14
+ ThorEnhance.configure do |c|
15
+ # Adds `classify` method to the option class
16
+ # Value of classify must be one of the enums
17
+ # It is not a required field on every method
18
+ c.add_option_enhance "classify", allowed_klasses: [String, Symbol, NilClass], required: false
19
+
20
+ # Adds `publish` method to the option
21
+ # Value of classify must be one of the enums
22
+ # It is a required field on every option
23
+ c.add_option_enhance :publish, enums: [true, false], required: true
24
+
25
+ # Adds `avoid method to the option
26
+ # Value is not restricted to any type or enum
27
+ # Not a required field
28
+ c.add_option_enhance :avoid
29
+ end
30
+ ```
31
+ The `add_option_enhance` takes the name as argument 1 followed by options.
32
+
33
+ The available options are:
34
+
35
+ **enums**:
36
+ - When provided, the value of the `name` must be a value in the `enums` array
37
+ EX: `publish: true` succeeds. `publish: :fail` fails.
38
+ - Default: `nil`
39
+
40
+ **allowed_klasses**
41
+ - When provided, this is expected to be an array of class types the value can be.
42
+ - Default: `nil`
43
+
44
+ **required**
45
+ - When flag is set to true, this option will be required on all `method_option` immediately. An error is raised if validation fails
46
+ - Default: `false`
47
+
48
+ # Examples:
49
+
50
+ [Basic Example](../examples/basic_example.md)
51
+ [Basic Example with Subcommand](../examples/basic_example_with_subcommand.md)
52
+
data/docs/tree.md ADDED
@@ -0,0 +1,42 @@
1
+ # ThorEnhance::Tree
2
+
3
+ The thor tree is a powerful tool to do introspection on all Thor commands within a repo.
4
+
5
+ ## How to use:
6
+
7
+ MyTestClass definitiona can be found in [spec_helper.rb](../spec/spec_helper.rb)
8
+
9
+ ```ruby
10
+ require "thor_enhance"
11
+
12
+ tree = ThorEnhance::Tree.tree(base: MyTestClass)
13
+
14
+ # View all commands on parent tree:
15
+ tree.children.map(&:command)
16
+
17
+ # View all commands including subcommands
18
+
19
+ def iterate_base(base:)
20
+ tree.map do |name, object|
21
+ if object.children?
22
+ iterate_base(base: object)
23
+ else
24
+ object.command
25
+ end
26
+ end.flatten
27
+ end
28
+
29
+ iterate_base(base: tree)
30
+
31
+ # View specific command
32
+ command = tree["test_meth"].command
33
+
34
+ # View specific sub command
35
+ sub_command_innard = tree["sub"].children["innard"].command
36
+
37
+ # View Options on specific command
38
+ command.options
39
+
40
+ # View specific Option on specific command
41
+ sub_command_innard.options[:t]
42
+ ```
@@ -0,0 +1,47 @@
1
+ ```ruby
2
+ # thor_enhance_config.rb
3
+
4
+ require "thor_enhance"
5
+
6
+ ThorEnhance.configure do |c|
7
+ # Adds `classify` method to the option class
8
+ # Value of classify must be one of the enums
9
+ # It is not a required field on every method
10
+ c.add_option_enhance "classify", enums: [:allowed, :future, :existing], required: false
11
+
12
+ # Adds `publish` method to the option
13
+ # Value of classify must be one of the enums
14
+ # It is a required field on every option
15
+ c.add_option_enhance :publish, enums: [true, false], required: true
16
+
17
+ # Adds `example` method to the command
18
+ # Value can be anything and is a repeatable command
19
+ c.add_command_method_enhance "example", repeatable: true
20
+ end
21
+ ```
22
+
23
+ ```ruby
24
+ # thor_cli.rb
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+ require "thor_enhance_config"
29
+
30
+ class ThorEnhancement < Thor
31
+
32
+ dec "test", "Testing method"
33
+ example "thor_cli.rb test --value 'This is rad'"
34
+ example "thor_cli.rb test"
35
+ method_option :value, type: :string, publish: true
36
+ def test
37
+ command = ThorEnhance::Tree.tree(base: self.class)["test"].command
38
+ # example was set as `repeatable` so it gets returned as an array
39
+ command.example.each { puts _1 }
40
+
41
+ command.options[:value].publish == true
42
+ command.options[:value].classify == nil
43
+ end
44
+ end
45
+
46
+ ThorEnhancement.start
47
+ ```
@@ -0,0 +1,73 @@
1
+ ```ruby
2
+ # thor_enhance_config.rb
3
+
4
+ require "thor_enhance"
5
+
6
+ ThorEnhance.configure do |c|
7
+ # Adds `classify` method to the option class
8
+ # Value of classify must be one of the enums
9
+ # It is not a required field on every method
10
+ c.add_option_enhance :classify, allowed_klasses: [Symbol], required: false
11
+
12
+ # Adds `publish` method to the option
13
+ # Value of classify must be one of the enums
14
+ # It is a required field on every option
15
+ c.add_option_enhance "publish", allowed_klasses: [TrueClass, FalseClass], required: true
16
+
17
+ # Adds `example` method to the command
18
+ # Value can be anything and is a repeatable command
19
+ c.add_command_method_enhance :example, repeatable: true
20
+ end
21
+ ```
22
+
23
+ ```ruby
24
+ # thor_cli.rb
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+ require "thor_enhance_config"
29
+
30
+ class ThorEnhancement < Thor
31
+
32
+ dec "test", "Testing method"
33
+ example "thor_cli.rb test --value 'This is rad'"
34
+ example "thor_cli.rb test"
35
+ method_option :value, type: :string, publish: true
36
+ def test
37
+ command = ThorEnhance::Tree.tree(base: self.class)["test"].command
38
+ # example was set as `repeatable` so it gets returned as an array
39
+ command.example.each { puts _1 }
40
+
41
+ command.options[:value].publish == true
42
+ command.options[:value].classify == nil
43
+ end
44
+
45
+ class SubCommand < Thor
46
+ desc "sub_command", "Command for SubCommand"
47
+ example "bin/thor sub_command innard -t something -s better"
48
+ example "bin/thor sub_command innard -s better"
49
+ example "bin/thor sub_command innard"
50
+
51
+ method_option :t, type: :string, classify: :allowed, publish: true
52
+ method_option :s, type: :string, classify: :erase, publish: false
53
+ def sub_command
54
+ parent = ThorEnhance::Tree.tree(base: self.class)["sub"]
55
+ parent.example.each { puts _1 } # 1 example
56
+
57
+ command = parent.children["sub_command"].command
58
+ command.children? == false
59
+
60
+ command.example.each { puts _1 } # 3 examples
61
+
62
+ command.options[:t].publish == true
63
+ command.options[:t].classify == :allowed
64
+ end
65
+ end
66
+
67
+ desc "sub", "Submodule command line"
68
+ example "bin/thor sub ***"
69
+ subcommand "sub", SubCommand
70
+ end
71
+
72
+ ThorEnhancement.start
73
+ ```
data/examples/hooks.md ADDED
@@ -0,0 +1,57 @@
1
+ # Hook Examples
2
+
3
+ For more information on how to use hooks, [view documentation here](../docs/hooks.md)
4
+
5
+ ```ruby
6
+ # thor_enhance_config.rb
7
+
8
+ require "thor_enhance"
9
+
10
+ ThorEnhance.configure do |c|
11
+ # Adds `classify` method to the option class
12
+ # Value of classify must be one of the enums
13
+ # It is not a required field on every method
14
+ c.add_option_enhance "classify", enums: [:allowed, :future, :existing], required: false
15
+
16
+ # Adds `publish` method to the option
17
+ # Value of classify must be one of the enums
18
+ # It is a required field on every option
19
+ c.add_option_enhance :publish, enums: [true, false], required: true
20
+
21
+ # Adds `example` method to the command
22
+ # Value can be anything and is a repeatable command
23
+ c.add_command_method_enhance "example", repeatable: true
24
+ end
25
+ ```
26
+
27
+ ```ruby
28
+ # thor_cli.rb
29
+
30
+ require "rubygems"
31
+ require "bundler/setup"
32
+ require "thor_enhance_config"
33
+
34
+ VERSION = Gem::Version.new("1.2.3")
35
+ MAX_VERSION = Gem::Version.new("2.0.0")
36
+ class ThorEnhancement < Thor
37
+
38
+ dec "test", "Testing method"
39
+ example "thor_cli.rb test --value 'This is rad'"
40
+ example "thor_cli.rb test"
41
+ method_option :value, type: :string, publish: true, deprecate: ->(input, option) { { raise: VERSION > MAX_VERSION, warn: "This option will deprecate with version #{MAX_VERSION}", msg: "Please migrate to --value4"} }
42
+
43
+ # Deprecate hook
44
+ method_option :option, type: :string, publish: false,
45
+ method_option :test, type: :string, publish: false,
46
+ def test
47
+ command = ThorEnhance::Tree.tree(base: self.class)["test"].command
48
+ # example was set as `repeatable` so it gets returned as an array
49
+ command.example.each { puts _1 }
50
+
51
+ command.options[:value].publish == true
52
+ command.options[:value].classify == nil
53
+ end
54
+ end
55
+
56
+ ThorEnhancement.start
57
+ ```
@@ -23,13 +23,23 @@ module ThorEnhance
23
23
  input_tags = [option.switch_name] + option.aliases
24
24
  next unless input_tags.any? { raw_args.include?(_1) }
25
25
 
26
- proc_value = proclamation.(given_value)
26
+ proc_value = proclamation.(given_value, option)
27
27
 
28
- case object[:behavior]
29
- when :raise
30
- raise ThorEnhance::OptionDeprecated, "Passing value for option #{option.switch_name} is deprecated. Provided `#{given_value}`. #{proc_value}"
31
- when :warn
32
- Kernel.warn("WARNING: Provided `#{given_value}` for option #{option.switch_name}. #{proc_value}")
28
+ if object[:behavior] == :request
29
+ if Hash === proc_value && proc_value.keys.sort == [:raise, :warn, :msg].sort
30
+ warn_msg = proc_value[:warn].to_s
31
+ msg = proc_value[:msg].to_s
32
+ if proc_value[:raise]
33
+ raise ThorEnhance::OptionDeprecated, "Passing value for option #{option.switch_name} is deprecated. " \
34
+ "Provided `#{given_value}`. #{proc_value[:msg]}"
35
+ else
36
+ Kernel.warn("WARNING: Provided `#{given_value}` for option #{option.switch_name}. " \
37
+ "#{proc_value[:warn]}. #{proc_value[:msg]}")
38
+ end
39
+ else
40
+ raise ThorEnhance::OptionDeprecated, "Passing value for option #{option.switch_name} is deprecated. " \
41
+ "Provided `#{given_value}`. #{proc_value}"
42
+ end
33
43
  end
34
44
  end
35
45
  end
@@ -6,7 +6,7 @@ module ThorEnhance
6
6
  class Configuration
7
7
 
8
8
  # Order is important -- Ensure deoreacte is first
9
- HOOKERS = [DEPRECATE = :deprecate, WARNING = :warn, HOOK = :hook]
9
+ HOOKERS = [DEPRECATE = :deprecate, HOOK = :hook]
10
10
 
11
11
  class << self
12
12
  attr_accessor :allow_changes
@@ -41,8 +41,7 @@ module ThorEnhance
41
41
 
42
42
  def option_enhance
43
43
  @option_enhance ||= {
44
- WARNING => { allowed_klasses: [Proc], behavior: :warn, required: false },
45
- DEPRECATE => { allowed_klasses: [Proc], behavior: :raise, required: false },
44
+ DEPRECATE => { allowed_klasses: [Proc], behavior: :request, required: false },
46
45
  HOOK => { allowed_klasses: [Proc], behavior: nil, required: false },
47
46
  }
48
47
  end
@@ -64,6 +63,16 @@ module ThorEnhance
64
63
  private
65
64
 
66
65
  def add_to_variable(storage, methods, name, allowed_klasses, enums, required, repeatable = false)
66
+ # Reject if the name is not a Symbol or a string
67
+ if [String, Symbol].none? { _1 === name }
68
+ raise ArgumentError, "Invalid name type received. Received [#{name}] of type [#{name.class}]. Expected to be of type String or Symbol"
69
+ end
70
+
71
+ # If name contains characters other than upper or lower case letters and _ FAIL
72
+ unless name =~ /^[A-Za-z_]+$/
73
+ raise ArgumentError, "Invalid name received. Received [#{name}] does not match /^[A-Za-z_]+$/."
74
+ end
75
+
67
76
  if methods.include?(name.to_sym)
68
77
  raise OptionNotAllowed, "[#{name}] is not allowed as an enhancement"
69
78
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ThorEnhance
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thor_enhance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Taylor
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-21 00:00:00.000000000 Z
11
+ date: 2023-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -102,6 +102,13 @@ files:
102
102
  - bin/console
103
103
  - bin/setup
104
104
  - docker-compose.yml
105
+ - docs/command.md
106
+ - docs/hooks.md
107
+ - docs/method_option.md
108
+ - docs/tree.md
109
+ - examples/basic_example.md
110
+ - examples/example_with_subcommand.md
111
+ - examples/hooks.md
105
112
  - lib/thor_enhance.rb
106
113
  - lib/thor_enhance/command.rb
107
114
  - lib/thor_enhance/command_hook.rb