rake-commander 0.1.2 → 0.2.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/.gitignore +8 -0
- data/.rubocop.yml +14 -8
- data/CHANGELOG.md +84 -4
- data/Gemfile +1 -1
- data/LICENSE +21 -0
- data/README.md +95 -3
- data/Rakefile +11 -13
- data/examples/01_basic_example.rb +28 -0
- data/examples/02_a_chainer_example.rb +66 -0
- data/examples/02_a_chainer_options_set.rb +8 -0
- data/examples/02_b_chained_example.rb +13 -0
- data/examples/03_a_chainer_plus_example.rb +34 -0
- data/examples/03_b_chained_plus_example.rb +17 -0
- data/examples/Examples.rake +7 -0
- data/examples/README.md +79 -0
- data/examples/libs/shell_helpers.rb +81 -0
- data/lib/rake-commander/base/class_auto_loader.rb +45 -7
- data/lib/rake-commander/base/class_helpers.rb +16 -61
- data/lib/rake-commander/base/class_inheritable.rb +122 -0
- data/lib/rake-commander/base/custom_error.rb +52 -0
- data/lib/rake-commander/base/object_helpers.rb +42 -0
- data/lib/rake-commander/base.rb +16 -2
- data/lib/rake-commander/option.rb +115 -25
- data/lib/rake-commander/options/arguments.rb +206 -94
- data/lib/rake-commander/options/description.rb +17 -0
- data/lib/rake-commander/options/error/base.rb +86 -0
- data/lib/rake-commander/options/error/handling.rb +106 -0
- data/lib/rake-commander/options/error/invalid_argument.rb +21 -0
- data/lib/rake-commander/options/error/invalid_option.rb +9 -0
- data/lib/rake-commander/options/error/missing_argument.rb +10 -0
- data/lib/rake-commander/options/error/missing_option.rb +48 -0
- data/lib/rake-commander/options/error/unknown_argument.rb +32 -0
- data/lib/rake-commander/options/error.rb +75 -10
- data/lib/rake-commander/options/name.rb +67 -23
- data/lib/rake-commander/options/result.rb +107 -0
- data/lib/rake-commander/options/set.rb +7 -1
- data/lib/rake-commander/options.rb +175 -102
- data/lib/rake-commander/patcher/README.md +79 -0
- data/lib/rake-commander/patcher/application/run_method.rb +46 -0
- data/lib/rake-commander/patcher/application/top_level_method.rb +74 -0
- data/lib/rake-commander/patcher/application.rb +16 -0
- data/lib/rake-commander/patcher/base.rb +45 -0
- data/lib/rake-commander/patcher/debug.rb +32 -0
- data/lib/rake-commander/patcher/helpers.rb +44 -0
- data/lib/rake-commander/patcher.rb +26 -0
- data/lib/rake-commander/rake_context/wrapper.rb +2 -0
- data/lib/rake-commander/rake_task.rb +50 -50
- data/lib/rake-commander/version.rb +1 -1
- data/lib/rake-commander.rb +4 -0
- data/rake-commander.gemspec +5 -2
- metadata +75 -7
- data/examples/basic.rb +0 -30
- data/lib/rake-commander/options/error_rely.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce1bfcde79ef608b7e13c440c626ee3ace47ec5adf3088e6fc969bf85502cc59
|
4
|
+
data.tar.gz: f785888cff61578247dfb1fdfed6c4e44fd076180d8be0dd1e00bf14ac0f1700
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d998c21f52d117ff59e5eb066a43cd0c5a0939a4187af2c5ee1dc3cbaead328b65d71ad67e333adf426ab465926fd56fc5830e4e7a3a7b048602f02dea39344
|
7
|
+
data.tar.gz: 2afaaa3bb046e6de18b13fe4b0e762dead4ace9a14b3d097c2b6c37142e7e0e0d111f5eecd9846647e50a64f13cbf8491b291d7572fafaada91cdc408400d064
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -17,17 +17,21 @@ Metrics/MethodLength:
|
|
17
17
|
Max: 50
|
18
18
|
Metrics/ClassLength:
|
19
19
|
Max: 200
|
20
|
+
Metrics/ModuleLength:
|
21
|
+
Max: 200
|
20
22
|
Metrics/AbcSize:
|
21
23
|
Max: 50
|
22
24
|
Metrics/CyclomaticComplexity:
|
23
|
-
Max:
|
25
|
+
Max: 10
|
24
26
|
Metrics/PerceivedComplexity:
|
25
|
-
Max:
|
27
|
+
Max: 10
|
26
28
|
|
27
29
|
ParameterLists:
|
28
30
|
Max: 5
|
29
31
|
CountKeywordArgs: false
|
30
32
|
|
33
|
+
Style/Alias:
|
34
|
+
EnforcedStyle: prefer_alias_method
|
31
35
|
Style/StringLiterals:
|
32
36
|
Enabled: false
|
33
37
|
Style/FrozenStringLiteralComment:
|
@@ -49,12 +53,8 @@ Style/ClassAndModuleChildren:
|
|
49
53
|
Style/OptionalBooleanParameter:
|
50
54
|
Enabled: false
|
51
55
|
|
52
|
-
Layout/
|
53
|
-
|
54
|
-
Layout/SpaceInsideBlockBraces:
|
55
|
-
Enabled: false
|
56
|
-
Layout/SpaceAroundOperators:
|
57
|
-
Enabled: false
|
56
|
+
Layout/HashAlignment:
|
57
|
+
EnforcedColonStyle: table
|
58
58
|
Layout/ExtraSpacing:
|
59
59
|
AllowForAlignment: true
|
60
60
|
Layout/AccessModifierIndentation:
|
@@ -63,6 +63,12 @@ Layout/DotPosition:
|
|
63
63
|
EnforcedStyle: trailing
|
64
64
|
Layout/MultilineMethodCallIndentation:
|
65
65
|
EnforcedStyle: indented
|
66
|
+
Layout/SpaceInsideHashLiteralBraces:
|
67
|
+
Enabled: false
|
68
|
+
Layout/SpaceInsideBlockBraces:
|
69
|
+
Enabled: false
|
70
|
+
Layout/SpaceAroundOperators:
|
71
|
+
Enabled: false
|
66
72
|
Layout/FirstHashElementIndentation:
|
67
73
|
Enabled: false
|
68
74
|
Layout/EmptyLineAfterGuardClause:
|
data/CHANGELOG.md
CHANGED
@@ -2,13 +2,93 @@
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
4
|
## TO DO
|
5
|
-
-
|
6
|
-
|
5
|
+
- Option results
|
6
|
+
- Include the symbol name keys (configurable). Note that dash will be replaced by underscore.
|
7
|
+
- Type Coertions
|
8
|
+
- Add a way to define/redefine a set and use them.
|
9
|
+
- Add more supported type_coertions as native to the gem (i.e. `Symbol`)
|
10
|
+
- Add support [for `ActiveRecord::Enum`](https://apidock.com/rails/ActiveRecord/Enum)
|
11
|
+
- Option definitions
|
12
|
+
- Order: `where: [:tail, :top]` and `[after, before]: :option_name`
|
13
|
+
- Configuration: allow to define option override behaviour and whether it should trigger an exception
|
14
|
+
- Error handlers
|
15
|
+
- See if it would be possible to parse all the valid options so we get all the valid results before some error is raised. Although this can be achieved with `OptionParser#order!`, it destroys switches; which would require to give it two parsing shots whenever there is an error.
|
16
|
+
- It should be ensured that the parsed options results object is remains the same.
|
17
|
+
- Think about options that modify other options. Technically this should be hold only at behaviour level
|
18
|
+
- This would allow to make the order of the options irrelevant when it comes to modify error handling behaviour via options themselves.
|
19
|
+
- Rake task parameters (see: https://stackoverflow.com/a/825832/4352306 & https://stackoverflow.com/a/825832/4352306)
|
20
|
+
- Add `enhance` functionality (when a task is invoked it runs before it; declared with `task` as well)
|
21
|
+
- Add `no_short` option (which should give the result of that option with the option name key)
|
22
|
+
- Add `on_option` handler at instance level, so within a `task` definition, we can decide certain things, such as if the functionality should be active when the `self.class` does not have that option.
|
23
|
+
* This is specially useful to be able to extend through inheritance chain, where we extend `task` (rather than redefining it), but we don't want options we removed (with `option_remove`) to throw unexpected results.
|
24
|
+
* Example: `on_option(:t, defined: true) {|option| do-stuff}` <- block to be called only if the option is defined in the class (alternative: `defined: :only`)
|
25
|
+
* Example: `on_option(:t, defined: false) {|option| do-stuff}` <- block to be called regardless the option exists (alternative: `defined: :ignore`)
|
26
|
+
* Example: `on_options(:t, :s, present: true) {|options| do-stuff}` <- block to be called only when the option `:t` and `:s` are both present in the parsed `options` result.
|
27
|
+
- Once this has been done, think about it being a hash-alike object with methods for the option names (i.e. `options.debug?`)
|
7
28
|
|
8
|
-
##
|
29
|
+
## DISCARDED IMPROVENTS
|
30
|
+
- Option to globally enable/disable the 2nd patch?
|
31
|
+
* That would make this gem completely useless.
|
32
|
+
|
33
|
+
## [0.2.1] - 2023-04-xx
|
9
34
|
|
10
35
|
### Added
|
11
|
-
|
36
|
+
### Fixed
|
37
|
+
### Changed
|
38
|
+
|
39
|
+
|
40
|
+
## [0.2.0] - 2023-04-28
|
41
|
+
|
42
|
+
### Added
|
43
|
+
- Better support for `RakeCommander::Options::Set`
|
44
|
+
- `RakeCommander::Options::options_use` accepts it as a parameter.
|
45
|
+
- Added `override` parameter to specify if this should override clashed option names.
|
46
|
+
- `RakeCommander::Options::class_resolver` to define the `RakeCommander::Option` class.
|
47
|
+
- Serves the purpose to ease class extension through inheritance.
|
48
|
+
- Ability to reopen options without changing the order.
|
49
|
+
- `RakeCommander::Options::option_reopen` which upserts (adds if not existing).
|
50
|
+
- New parameter `reopen` to `RakeCommander::Options::option` (redirects to the above method).
|
51
|
+
- Automatic option shortcuts (`implicit_shorts`) show in help and only when applicable.
|
52
|
+
- These are added automatically by `OptionParser`
|
53
|
+
- `OptionParser` leftovers trigger an error by default.
|
54
|
+
- This behaviour can be disabled or modified via callback/block by using `RakeCommander::Options:Error::error_on_leftovers`.
|
55
|
+
- Description auto **multi-line**
|
56
|
+
- Currently based on `RakeCommander::Options::Description::DESC_MAX_LENGTH`
|
57
|
+
- `RakeCommander::Options#remove_option`
|
58
|
+
- `RakeCommander::Options::Error::Base` and children can be raised using different methods (see `RakeCommander::Options::Error` for examples).
|
59
|
+
- The **task** `name` that raised the error is included in the message.
|
60
|
+
- `RakeCommander::Options::Error::Handling` which provides **configurability** around actions on specific option errors with a default to a general options parsing error.
|
12
61
|
|
13
62
|
### Fixed
|
63
|
+
- `RakeCommander::Base::ClassAutoLoader`
|
64
|
+
- Register excluded child classes (singleton classes) into their own property,
|
65
|
+
rather than in the `autoloaded_children` (they are not autoloaded).
|
66
|
+
- Missing `rake` dependency in gemspec file.
|
67
|
+
- Boolean switch detection (pre-parse arguments) and parsing
|
68
|
+
- It adds support for boolean option names such as `--[no-]verbose`
|
69
|
+
- Error messaging. There were missing cases, specially with implicit short options.
|
70
|
+
- `RakeCommander::Options`
|
71
|
+
- `#option_reopen` fixed
|
72
|
+
- **Inheritance fixed**
|
73
|
+
|
14
74
|
### Changed
|
75
|
+
- Development: examples invokation via `Rake`
|
76
|
+
- Refactored `RakeCommander::Options` to acquire functionality through extension.
|
77
|
+
- `attr_inheritable` and `inheritable_class_var` are the new names of previous methods
|
78
|
+
- Behaviour has been changed, so you define if it should `dup` the variables, and you can pass a `block` to do the `dup` yourself. They won **NOT** `freeze` anymore, as we are mostly working at class level.
|
79
|
+
|
80
|
+
## [0.1.4] - 2023-04-20
|
81
|
+
|
82
|
+
### Fixed
|
83
|
+
- `rubocop` offenders
|
84
|
+
- Added implicity `exit(0)` when wrapping the `task` block
|
85
|
+
|
86
|
+
## [0.1.3] - 2023-04-20
|
87
|
+
|
88
|
+
### Fixed
|
89
|
+
- Reference to repo and gem
|
90
|
+
|
91
|
+
## [0.1.2] - 2023-04-19
|
92
|
+
|
93
|
+
### Added
|
94
|
+
- First commit
|
data/Gemfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2023 Oscar Segura
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
-
#
|
1
|
+
# RakeCommander
|
2
2
|
|
3
|
-
|
3
|
+
Classing rake tasks with options. Creating re-usable tasks, options and samples thereof.
|
4
|
+
|
5
|
+
## Introduction
|
6
|
+
|
7
|
+
Rake commander is a way to declare **rake tasks** with re-usable classes. It enhances the command line syntax, as tasks can come with their own **options**, inherit them, re-use declared options sets, modify/re-open or even remove them.
|
8
|
+
|
9
|
+
Although the `OptionParser` ruby native class is used for parsing the options, the declaration of options, additionally to the ones of `OptionParser` comes with some **opinionated improvements** and amendments:
|
10
|
+
|
11
|
+
1. It is possible to declare options as `required`
|
12
|
+
* This is additional to required option arguments.
|
13
|
+
* Options are inheritable (they get a custom `deep_dup`)
|
14
|
+
2. An option can have a `default` value.
|
15
|
+
* Which can optionally be automatically used when the option accepts or requires an argument.
|
16
|
+
3. Options parsing raises specific option errors. For a given task/class, each error type can have its own handler or preferred action.
|
17
|
+
* Defined error handling is inheritable and can be redefined.
|
4
18
|
|
5
19
|
## Installation
|
6
20
|
|
@@ -20,9 +34,87 @@ Or install it yourself as:
|
|
20
34
|
|
21
35
|
## Usage
|
22
36
|
|
37
|
+
See [**the `examples`**](https://github.com/rellampec/rake-commander/tree/main/examples).
|
38
|
+
|
39
|
+
```
|
40
|
+
rake -T examples
|
41
|
+
```
|
42
|
+
|
43
|
+
Go through the [basic example](https://github.com/rellampec/rake-commander/blob/main/examples/01_basic_example.rb).
|
44
|
+
|
45
|
+
```
|
46
|
+
rake examples:basic -- -h
|
47
|
+
rake examples:basic -- -z -e prod
|
48
|
+
```
|
49
|
+
* The double dash `--` is used to tell to rake-commander where the options section starts.
|
50
|
+
|
51
|
+
At the same time the double dash delimiter seems to make rake ignore anything that comes afterwards. Without loading rake commander, you could try:
|
52
|
+
|
53
|
+
```
|
54
|
+
$ rake --trace rspec
|
55
|
+
** Invoke spec (first_time)
|
56
|
+
** Execute spec
|
57
|
+
rspec logging and results
|
58
|
+
```
|
59
|
+
|
60
|
+
And then re-try with
|
61
|
+
|
62
|
+
```
|
63
|
+
$ rake rspec -- --trace
|
64
|
+
rspec logging and results
|
65
|
+
```
|
66
|
+
|
67
|
+
* The `--trace` option is being natively ignored by `rake` due to the preceding double dash (` -- `).
|
68
|
+
|
69
|
+
|
70
|
+
### Syntax
|
71
|
+
|
72
|
+
### Declaring and using Task Options
|
73
|
+
|
74
|
+
It supports most of options syntax of the native `OptionParser` but for a couple of exceptions perhaps:
|
75
|
+
1. It does **NOT** support definitions or parsing of shortcuts with **embedded argument** (i.e. `-nNAME`).
|
76
|
+
2. It does **NOT** support definitions that include equal sign (i.e. `name=NAME`, `n=NAME`)
|
77
|
+
|
78
|
+
An argument should be explicitly declared in the `name` part:
|
79
|
+
|
80
|
+
```
|
81
|
+
option :n, '--name NAME'
|
82
|
+
```
|
83
|
+
|
84
|
+
### Command Line
|
85
|
+
|
86
|
+
Although it is planned to extend the syntax, the current version shares the options through all tasks (declared as `RakeCommander` classes) that are invoked in the same command line.
|
87
|
+
|
88
|
+
```
|
89
|
+
rake [rake-options] task1 task2 -- [shared-task-options]
|
90
|
+
```
|
91
|
+
|
92
|
+
The double dash ` -- ` delimiter allows to modify the `ARGV` parsing behaviour of `rake`, giving room for **opinionated enhanced syntax**. Anything that comes before the double dash is feed to standard `rake`, and anything after `--` are parsed as option tasks via `rake commander`.
|
93
|
+
|
94
|
+
```
|
95
|
+
<rake part> -- [tasks options part]
|
96
|
+
```
|
97
|
+
|
98
|
+
## `rake` full support
|
99
|
+
|
100
|
+
Work has been done with the aim of providing a full patch on `rake`, provided that the main invocation command remains as `rake`.
|
101
|
+
|
102
|
+
To preserve `rake` as invocation command, though, the patch needs to relaunch the rake application when it has already started. The reason is that `rake` has already pre-parsed `ARGV` when `rake-commander` is loaded (i.e. from a `Rakefile`) and has identified as tasks things that are part of the task options.
|
103
|
+
|
104
|
+
* For compatibility with tasks declared using `RakeCommander`, the rake application is always relaunched. Anything that does not belong to task options should not be feed to rake tasks declared with rake commander classes.
|
105
|
+
|
106
|
+
### Patching `Rake`
|
107
|
+
|
108
|
+
The two patches:
|
109
|
+
|
110
|
+
1. Rake commander does come with a neat patch to the [`Rake::Application#run` method](https://github.com/ruby/rake/blob/48e798484babf725b0562cc417986da513e5d0ae/lib/rake/application.rb#L79) to clean up the `ARGV` before the rake application starts. But it kicks in too late...
|
111
|
+
2. For this reason a more arguable patch has been applied to [`Rake::Application#top_level` method](https://github.com/ruby/rake/blob/48e798484babf725b0562cc417986da513e5d0ae/lib/rake/application.rb#L131), where the rake application is relaunched.
|
112
|
+
|
113
|
+
For further details please see [`RakeCommander::Patcher`](https://github.com/rellampec/rake-commander/blob/main/lib/rake-commander/patcher).
|
114
|
+
|
23
115
|
|
24
116
|
## Development
|
25
117
|
|
26
118
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
27
119
|
|
28
|
-
For more info on available `Rake` tasks: `rake -T`
|
120
|
+
For more info on available `Rake` tasks: `rake -T` (or `bin/raked -T`)
|
data/Rakefile
CHANGED
@@ -1,32 +1,30 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'yard'
|
4
|
+
require 'redcarpet'
|
5
5
|
|
6
|
-
|
6
|
+
# Install examples and load `rake-commander`
|
7
|
+
Rake.add_rakelib 'examples'
|
8
|
+
|
9
|
+
desc 'run the specs'
|
7
10
|
RSpec::Core::RakeTask.new(:spec)
|
8
11
|
|
9
|
-
desc
|
12
|
+
desc 'run rspec showing backtrace'
|
10
13
|
RSpec::Core::RakeTask.new(:spec_trace) do |task|
|
11
14
|
task.rspec_opts = ['--backtrace']
|
12
15
|
end
|
13
16
|
|
14
|
-
desc
|
17
|
+
desc 'run rspec stopping on first fail, and show backtrace'
|
15
18
|
RSpec::Core::RakeTask.new(:spec_fast) do |task|
|
16
19
|
task.rspec_opts = ['--fail-fast', '--backtrace']
|
17
20
|
end
|
18
21
|
|
19
22
|
# default task name is yard
|
20
|
-
desc
|
23
|
+
desc 'Yard: generate all the documentation'
|
21
24
|
YARD::Rake::YardocTask.new(:doc) do |t|
|
22
25
|
#t.files = ['lib/**/*.rb']
|
23
26
|
end
|
24
27
|
|
25
|
-
desc "Examples: Run examples (rake examples[basic] -- -h)"
|
26
|
-
task :examples, [:sample] do |t, args|
|
27
|
-
require_relative "examples/#{args[:sample]}"
|
28
|
-
end
|
29
|
-
|
30
28
|
task default: [:spec]
|
31
29
|
task rspec_trace: :spec_trace
|
32
30
|
task rspec_fast: :spec_fast
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class RakeCommander::Custom::BasicExample < RakeCommander
|
2
|
+
namespace :examples
|
3
|
+
|
4
|
+
desc 'A simple example to get started'
|
5
|
+
task :basic
|
6
|
+
|
7
|
+
#banner "Usage: basic:example -- [options]"
|
8
|
+
option '-w', :show_time, TrueClass, desc: 'Displays the local time'
|
9
|
+
option :z, '--timezone', TrueClass, default: false, required: true
|
10
|
+
option :o, '--hello NAME', String, desc: 'It greets.'
|
11
|
+
option '-s', '--say [SOMETHING]', "It says 'something'", default: %q(I don't know what to "say"...)
|
12
|
+
option :d, '--folder NAME', default: '.', desc: 'Source local folder', required: true
|
13
|
+
option '-e', :'--enviro ENV', 'The target environment to run this task', required: true
|
14
|
+
option :v, :debug, TrueClass, 'Shows the parsed options'
|
15
|
+
option :V, '[no-]verbose', 'Verbosity', TrueClass
|
16
|
+
#option :f, :folder, required: false, reopen: true
|
17
|
+
|
18
|
+
def task(*_args)
|
19
|
+
puts "Hello #{options[:o]}!!" if options[:o]
|
20
|
+
if options[:v]
|
21
|
+
puts 'We got these options:'
|
22
|
+
pp options
|
23
|
+
end
|
24
|
+
puts Time.now.strftime('%d %b at %H:%M') if options[:w]
|
25
|
+
puts Time.now.zone if options[:z]
|
26
|
+
puts options[:s] if options.key?(:s)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative 'libs/shell_helpers'
|
2
|
+
require_relative '02_a_chainer_options_set'
|
3
|
+
|
4
|
+
class RakeCommander::Custom::Chainer < RakeCommander
|
5
|
+
include Examples::Libs::ShellHelpers
|
6
|
+
TARGET_TASK = 'examples:chained'.freeze
|
7
|
+
|
8
|
+
namespace :examples
|
9
|
+
|
10
|
+
task :chainer
|
11
|
+
desc "Uses rake (or raked) to invoke #{TARGET_TASK}"
|
12
|
+
|
13
|
+
# When an option as a default value defined, it is added to `options` result
|
14
|
+
# even when the option was not invoked
|
15
|
+
options_with_defaults true
|
16
|
+
|
17
|
+
# Loads the otions from a pre-defined options set
|
18
|
+
options_use RakeCommander::Custom::ChainerOptionsSet
|
19
|
+
# Redefines the description of the option `:chain`
|
20
|
+
option_reopen :chain, desc: "Calls: '< rake|raked > #{TARGET_TASK} task'"
|
21
|
+
# Adds some option of its own
|
22
|
+
str_desc = "The method used to shell the call to examples:chained."
|
23
|
+
str_desc << " Options: #{SHELL_METHODS.join(', ')}"
|
24
|
+
option '-m', 'method [METHOD]', default: 'system', desc: str_desc
|
25
|
+
|
26
|
+
def task(*_args)
|
27
|
+
if options[:c]
|
28
|
+
cmd = "#{subcommand_base} -- #{subcommand_arguments.join(' ')}"
|
29
|
+
puts "Calling --> '#{cmd}'"
|
30
|
+
shell(cmd, method: options[:m])
|
31
|
+
else
|
32
|
+
puts "Nothing to do :|"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def subcommand_base
|
37
|
+
with = options[:w] == 'raked' ? 'bin\raked' : 'rake'
|
38
|
+
"#{with} #{self.class::TARGET_TASK}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def subcommand_arguments
|
42
|
+
[].tap do |args|
|
43
|
+
if options.key?(:s)
|
44
|
+
str_opt = "--say"
|
45
|
+
str_opt << " \"#{options[:s]}\"" if options[:s]
|
46
|
+
args << str_opt
|
47
|
+
end
|
48
|
+
args << "--debug" if options[:b]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def puts(str)
|
55
|
+
return super unless options[:b]
|
56
|
+
super "#{app_id} #{str} #{thread_id}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def app_id
|
60
|
+
"(#{self.class.task_fullname}: #{Rake.application.object_id})"
|
61
|
+
end
|
62
|
+
|
63
|
+
def thread_id
|
64
|
+
"(PID: #{Process.pid} ++ Thread: #{Thread.current.object_id})"
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class RakeCommander::Custom::ChainerOptionsSet < RakeCommander::Options::Set
|
2
|
+
name :chainer_options
|
3
|
+
|
4
|
+
option :c, :chain, TrueClass, desc: "Calls: '< rake|raked > chained-task task'"
|
5
|
+
option :w, '--with CALLER', default: 'rake', desc: "Specifies if should invoke with 'rake' or 'raked'"
|
6
|
+
option '-s', "It makes the chained-task say 'something'", name: '--say [SOMETHING]'
|
7
|
+
option '-b', '--debug', TrueClass, 'Whether to add additional context information to messages'
|
8
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class RakeCommander::Custom::Chained < RakeCommander::Custom::Chainer
|
2
|
+
#namespace :examples # <-- inherited
|
3
|
+
desc 'A task you want to chain to'
|
4
|
+
task :chained
|
5
|
+
|
6
|
+
option_reopen :s, "It says 'something'", default: %q(I don't know what to "say"...)
|
7
|
+
option_remove :c, :w, :method
|
8
|
+
|
9
|
+
def task(*_args)
|
10
|
+
puts "Called !!"
|
11
|
+
puts options[:s] if options[:s]
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class RakeCommander::Custom::ChainerPlus < RakeCommander::Custom::Chainer
|
2
|
+
TARGET_TASK = 'examples:chained_plus'.freeze
|
3
|
+
|
4
|
+
desc "Uses rake (or raked) to invoke #{TARGET_TASK}"
|
5
|
+
task :chainer_plus
|
6
|
+
|
7
|
+
# Disable using defaults when options are not invoked.
|
8
|
+
options_with_defaults false
|
9
|
+
|
10
|
+
# Update option description
|
11
|
+
option_reopen :chain, desc: "Calls: '< rake|raked > #{TARGET_TASK} task'"
|
12
|
+
# Extend with new options
|
13
|
+
option :e, '--exit-on-error', TrueClass, \
|
14
|
+
desc: "Whether #{TARGET_TASK} should just exit on 'missing argument' error (or raise an exception)"
|
15
|
+
option :o, '--hello NAME', String, desc: 'It greets.'
|
16
|
+
|
17
|
+
# Make it default to `exit 1` when there are errors
|
18
|
+
error_on_options false
|
19
|
+
# Let it trigger/raise the error when an unknown option is used!
|
20
|
+
error_on_options true, error: RakeCommander::Options::Error::InvalidArgument
|
21
|
+
|
22
|
+
def task(*_args)
|
23
|
+
puts "Hello #{options[:o]}!!" if options[:o]
|
24
|
+
options[:m] = :system unless options[:m]
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
# We add the extended arguments at the beginning
|
29
|
+
def subcommand_arguments
|
30
|
+
[].tap do |args|
|
31
|
+
args << '--exit-on-error' if options[:e]
|
32
|
+
end.concat(super)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'pp'
|
2
|
+
class RakeCommander::Custom::ChainedPlus < RakeCommander::Custom::Chained
|
3
|
+
desc 'A task+ you want to chain to'
|
4
|
+
task :chained_plus
|
5
|
+
|
6
|
+
option_remove :say
|
7
|
+
option :e, '--exit-on-error', TrueClass, desc: 'If it should just exit on "missing argument" error or raise an exception'
|
8
|
+
# Move option to the end, make **required** the argument (SOMETHING) as well as the option itself.
|
9
|
+
option :s, '--say SOMETHING', "It says 'something'", required: true
|
10
|
+
|
11
|
+
error_on_options error: RakeCommander::Options::Error::MissingArgument do |err, _argv, results, _leftovers|
|
12
|
+
msg = "Parsed results when 'missing argument' error was raised"
|
13
|
+
msg << "\non option '#{err.option.name_full}'" if err.option
|
14
|
+
puts "#{msg} => #{results.pretty_inspect}"
|
15
|
+
!results[:e]
|
16
|
+
end
|
17
|
+
end
|
data/examples/README.md
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
## Examples
|
2
|
+
|
3
|
+
* `RakeCommander` is loaded from the repo branch you are checked out.
|
4
|
+
|
5
|
+
The Rakefile `Examples.rake` has three lines that can serve as a guide. One were we require `rake-commander`, another where we define our `RakeCommander` classes, and one where we load them as actual `Rake` tasks.
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require_relative '../lib/rake-commander'
|
9
|
+
RakeCommander::Patcher.debug = ENV['COMMANDER_DEBUG'] == "true"
|
10
|
+
Dir["#{__dir__}/*_example.rb"].sort.each {|file| require_relative file }
|
11
|
+
RakeCommander.self_load
|
12
|
+
```
|
13
|
+
|
14
|
+
* To see the patches in action, you can add `COMMANDER_DEBUG=true` to a `.env` file
|
15
|
+
|
16
|
+
```
|
17
|
+
rake -T examples
|
18
|
+
```
|
19
|
+
|
20
|
+
### Basic Example
|
21
|
+
|
22
|
+
```
|
23
|
+
rake examples:basic -- -h
|
24
|
+
rake examples:basic -- -z -e prod
|
25
|
+
```
|
26
|
+
|
27
|
+
### Chainer && Chained Example
|
28
|
+
|
29
|
+
Two tasks where chainer calls chained through **a `shell` call to `rake`**.
|
30
|
+
|
31
|
+
* Read well the example before running it.
|
32
|
+
|
33
|
+
```
|
34
|
+
rake examples:chainer -- -h
|
35
|
+
rake examples:chained -- -h
|
36
|
+
```
|
37
|
+
|
38
|
+
### Chainer Plus and Chained Plus Example
|
39
|
+
|
40
|
+
Same as the previous example but these tasks inherit from the previous example, extending their behaviour and changing the options.
|
41
|
+
|
42
|
+
|
43
|
+
```
|
44
|
+
rake examples:chainer_plus -- -h
|
45
|
+
rake examples:chained_plus -- -h
|
46
|
+
```
|
47
|
+
|
48
|
+
#### Error handling mixed with options
|
49
|
+
|
50
|
+
The option `--exit-on-error` allows the error handler defined in `chained_plus` to decide if it should raise the error or just do an `exit 1`
|
51
|
+
|
52
|
+
* This is possible because the order that the options have been declared. Observe that they `--say` option has been removed and redefined **after** the option `--exit-on-error` has been defined.
|
53
|
+
* `OptionParser` **switches are processed in order** and, therefore, the error on `--say` only pops up after the `--exit on-error` option has been already parsed.
|
54
|
+
|
55
|
+
While this will raise the error (with a trace):
|
56
|
+
|
57
|
+
```
|
58
|
+
$ rake examples:chainer_plus -- --chain --say
|
59
|
+
Calling --> 'rake examples:chained_plus -- --say'
|
60
|
+
Parsed results when 'missing argument' error was raised
|
61
|
+
on option '--say SOMETHING' => {}
|
62
|
+
rake aborted!
|
63
|
+
RakeCommander::Options::Error::MissingArgument: (examples:chained_plus) missing required argument in option: --say SOMETHING (-s)
|
64
|
+
< here back trace>
|
65
|
+
Tasks: TOP => examples:chained_plus
|
66
|
+
(See full trace by running task with --trace)
|
67
|
+
* Failed to running 'rake examples:chained_plus -- --say'
|
68
|
+
```
|
69
|
+
|
70
|
+
This will only print the error with an `exit 1`:
|
71
|
+
|
72
|
+
```
|
73
|
+
$ rake examples:chainer_plus -- --chain --say --exit-on-error
|
74
|
+
Calling --> 'rake examples:chained_plus -- --exit-on-error --say'
|
75
|
+
Parsed results when 'missing argument' error was raised
|
76
|
+
on option '--say SOMETHING' => {:e=>true}
|
77
|
+
(examples:chained_plus) missing required argument in option: --say SOMETHING (-s)
|
78
|
+
* Failed to running 'rake examples:chained_plus -- --exit-on-error --say'
|
79
|
+
```
|