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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +14 -8
  4. data/CHANGELOG.md +84 -4
  5. data/Gemfile +1 -1
  6. data/LICENSE +21 -0
  7. data/README.md +95 -3
  8. data/Rakefile +11 -13
  9. data/examples/01_basic_example.rb +28 -0
  10. data/examples/02_a_chainer_example.rb +66 -0
  11. data/examples/02_a_chainer_options_set.rb +8 -0
  12. data/examples/02_b_chained_example.rb +13 -0
  13. data/examples/03_a_chainer_plus_example.rb +34 -0
  14. data/examples/03_b_chained_plus_example.rb +17 -0
  15. data/examples/Examples.rake +7 -0
  16. data/examples/README.md +79 -0
  17. data/examples/libs/shell_helpers.rb +81 -0
  18. data/lib/rake-commander/base/class_auto_loader.rb +45 -7
  19. data/lib/rake-commander/base/class_helpers.rb +16 -61
  20. data/lib/rake-commander/base/class_inheritable.rb +122 -0
  21. data/lib/rake-commander/base/custom_error.rb +52 -0
  22. data/lib/rake-commander/base/object_helpers.rb +42 -0
  23. data/lib/rake-commander/base.rb +16 -2
  24. data/lib/rake-commander/option.rb +115 -25
  25. data/lib/rake-commander/options/arguments.rb +206 -94
  26. data/lib/rake-commander/options/description.rb +17 -0
  27. data/lib/rake-commander/options/error/base.rb +86 -0
  28. data/lib/rake-commander/options/error/handling.rb +106 -0
  29. data/lib/rake-commander/options/error/invalid_argument.rb +21 -0
  30. data/lib/rake-commander/options/error/invalid_option.rb +9 -0
  31. data/lib/rake-commander/options/error/missing_argument.rb +10 -0
  32. data/lib/rake-commander/options/error/missing_option.rb +48 -0
  33. data/lib/rake-commander/options/error/unknown_argument.rb +32 -0
  34. data/lib/rake-commander/options/error.rb +75 -10
  35. data/lib/rake-commander/options/name.rb +67 -23
  36. data/lib/rake-commander/options/result.rb +107 -0
  37. data/lib/rake-commander/options/set.rb +7 -1
  38. data/lib/rake-commander/options.rb +175 -102
  39. data/lib/rake-commander/patcher/README.md +79 -0
  40. data/lib/rake-commander/patcher/application/run_method.rb +46 -0
  41. data/lib/rake-commander/patcher/application/top_level_method.rb +74 -0
  42. data/lib/rake-commander/patcher/application.rb +16 -0
  43. data/lib/rake-commander/patcher/base.rb +45 -0
  44. data/lib/rake-commander/patcher/debug.rb +32 -0
  45. data/lib/rake-commander/patcher/helpers.rb +44 -0
  46. data/lib/rake-commander/patcher.rb +26 -0
  47. data/lib/rake-commander/rake_context/wrapper.rb +2 -0
  48. data/lib/rake-commander/rake_task.rb +50 -50
  49. data/lib/rake-commander/version.rb +1 -1
  50. data/lib/rake-commander.rb +4 -0
  51. data/rake-commander.gemspec +5 -2
  52. metadata +75 -7
  53. data/examples/basic.rb +0 -30
  54. 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: 79568da769a6523e7024fa641eb8d792b2fd4dfcc600f11f0cbf56e6bb1f45d9
4
- data.tar.gz: e8e55e77085b67e37fd9befdb1b0b77cd0f8403ff1c0ab939160c3659c0cd67f
3
+ metadata.gz: ce1bfcde79ef608b7e13c440c626ee3ace47ec5adf3088e6fc969bf85502cc59
4
+ data.tar.gz: f785888cff61578247dfb1fdfed6c4e44fd076180d8be0dd1e00bf14ac0f1700
5
5
  SHA512:
6
- metadata.gz: fe77e58170a2e2bed3c9d52202e8deaa039422bda0ded1284f0d8fb316c83a6609fffb6753d2387d573b0ed70c7d5a2c74b5d868e8a89f5ba96dfa2d472b8587
7
- data.tar.gz: f75fa6017995dd942cd37cc6494db0a0c9d5273eb28e1b9ef9fe7d909fa39abffc25b6aa681c05ba1dce868b2265fb0bf54f01c55a31fd4298aaf6f70f3b435c
6
+ metadata.gz: 5d998c21f52d117ff59e5eb066a43cd0c5a0939a4187af2c5ee1dc3cbaead328b65d71ad67e333adf426ab465926fd56fc5830e4e7a3a7b048602f02dea39344
7
+ data.tar.gz: 2afaaa3bb046e6de18b13fe4b0e762dead4ace9a14b3d097c2b6c37142e7e0e0d111f5eecd9846647e50a64f13cbf8491b291d7572fafaada91cdc408400d064
data/.gitignore CHANGED
@@ -1,3 +1,9 @@
1
+ # env files
2
+ .env*
3
+
4
+ # core development-only executables
5
+ /bin/raked*
6
+
1
7
  # it's a gem, ignore the lockfile
2
8
  Gemfile.lock
3
9
 
@@ -18,3 +24,5 @@ Gemfile.lock
18
24
  # rspec failure tracking
19
25
  .rspec_status
20
26
  scratch.rb
27
+
28
+ /.byebug_history
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: 15
25
+ Max: 10
24
26
  Metrics/PerceivedComplexity:
25
- Max: 15
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/SpaceInsideHashLiteralBraces:
53
- Enabled: false
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
- - Rake task parameters (see: https://stackoverflow.com/a/825832/4352306)
6
- - `OptionParser#parse` result (what to do with unknown ARGV `leftovers`)
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
- ## [0.1.2] - 2023-04-19
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
- - First commit
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
@@ -2,5 +2,5 @@ source "https://rubygems.org"
2
2
 
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
- # Specify your gem's dependencies in ecoportal-api.gemspec
5
+ # Specify your gem's dependencies in rake-commander.gemspec
6
6
  gemspec
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
- # Ecoportal::API
1
+ # RakeCommander
2
2
 
3
- Another way to define re-usable rake tasks and samples.
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 "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
- require "yard"
4
- require "redcarpet"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'yard'
4
+ require 'redcarpet'
5
5
 
6
- desc "run the specs"
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 "run rspec showing backtrace"
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 "run rspec stopping on first fail, and show backtrace"
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 "Yard: generate all the documentation"
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
@@ -0,0 +1,7 @@
1
+ require 'dotenv'
2
+ require 'dotenv/load'
3
+
4
+ require_relative '../lib/rake-commander'
5
+ RakeCommander::Patcher.debug = ENV['COMMANDER_DEBUG'] == "true"
6
+ Dir["#{__dir__}/*_example.rb"].sort.each {|file| require_relative file }
7
+ RakeCommander.self_load
@@ -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
+ ```