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
@@ -0,0 +1,44 @@
1
+ class RakeCommander
2
+ module Patcher
3
+ # Helpers to patch
4
+ module Helpers
5
+ # For a given method `meth` it gives the index of the parameter `arg_name`
6
+ # @return [Integer, NilClass] the position of `arg_name` in parameters.
7
+ def method_argument_idx(meth, arg_name)
8
+ arg_name = arg_name.to_sym
9
+ meth.parameters.each_with_index do |(_type, name), i|
10
+ return i if name == arg_name
11
+ end
12
+ end
13
+
14
+ # Its usage only makes sense if you extended an existing method you are patching.
15
+ # Therefore it is expected that `super` exists, so the original parameters definition
16
+ # of the method can be accessed.
17
+ # @note although the signature of a method can change through different versions
18
+ # the name of the parameters is generally preserved (specially when they are core parameters).
19
+ # @example
20
+ # module Rake
21
+ # class Application
22
+ # def init(*args)
23
+ # args = RakeCommander::Patcher.change_method_argument(:argv, method: method(__method__), args: args) do |value|
24
+ # RakeCommander.argv_rake_native_arguments(value)
25
+ # end
26
+ # super(*args)
27
+ # end
28
+ # end
29
+ # end
30
+ #
31
+ # @param arg_name [Symbol, String] the name of the parameter as it reads in the original method.
32
+ # @param method [Method] the extended method (not its `super` method)
33
+ # @return [Array] the original arguments where `arg_name` has been changed.
34
+ def change_method_argument(arg_name, method:, args:)
35
+ raise ArgumentError, 'Expecting block' unless block_given?
36
+ raise ArgumentError, "Expecting Method. Given #{method.class}" unless method.is_a?(Method)
37
+ if idx = method_argument_idx(method.super_method, arg_name.to_sym)
38
+ args[idx] = yield(args[idx])
39
+ end
40
+ args
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'patcher/helpers'
2
+ require_relative 'patcher/debug'
3
+ require_relative 'patcher/base'
4
+ require_relative 'patcher/application'
5
+
6
+ class RakeCommander
7
+ module Patcher
8
+ extend RakeCommander::Patcher::Helpers
9
+ include RakeCommander::Patcher::Base
10
+
11
+ class << self
12
+ def patch_include(base)
13
+ base.send :include, Application
14
+ end
15
+
16
+ def debug=(value)
17
+ @debug = !!value
18
+ end
19
+
20
+ def debug?
21
+ @debug = false unless instance_variable_defined?(:@debug)
22
+ @debug
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,6 +1,8 @@
1
1
  class RakeCommander
2
2
  module RakeContext
3
3
  class Wrapper
4
+ include Rake::DSL
5
+
4
6
  # Allows to interact with rake
5
7
  # @note this prevents subclass overlap methods to be used
6
8
  def context(object = global_instance, &block)
@@ -3,65 +3,52 @@ require_relative 'rake_context/wrapper'
3
3
  class RakeCommander
4
4
  module RakeTask
5
5
  NAMESPACE_DELIMITER = /:/.freeze
6
- RAKE_END_COMMAND = '--'.freeze
7
6
  INHERITABLE_ATTRS = [:namespace].freeze
8
7
 
9
8
  class << self
10
9
  def included(base)
11
10
  super(base)
11
+ base.extend RakeCommander::Base::ClassHelpers
12
+ base.extend RakeCommander::Base::ClassInheritable
12
13
  base.extend ClassMethods
13
- base.inheritable_attrs(*INHERITABLE_ATTRS)
14
+ base.attr_inheritable(*INHERITABLE_ATTRS)
14
15
  end
15
16
  end
16
17
 
17
18
  module ClassMethods
18
- include RakeCommander::Base::ClassHelpers
19
-
20
19
  # The rake context wrapper (to invoke rake commands)
21
20
  def rake
22
21
  @rake ||= RakeCommander::RakeContext::Wrapper.new
23
22
  end
24
23
 
25
- # Does the final rake `task` definition
26
- def install_task(&task_method)
27
- raise "Expected task_block." unless task_method
28
-
29
- # ensure options are parsed before calling task
30
- # and that ARGV is only parsed after `--`
31
- task_method = invoke_options_before_task(&task_method) if options?
32
-
33
- if namespaced?
34
- namespaced do
35
- rake.desc desc
36
- rake.task task, &task_method
37
- end
38
- else
39
- rake.desc desc
40
- rake.task task, &task_method
41
- end
24
+ # Give a description to the task
25
+ # @return [String] the description of the task
26
+ def desc(str = :not_used)
27
+ return @desc if str == :not_used
28
+ @desc = str.to_s
42
29
  end
43
30
 
44
31
  # Give a name to the task
45
32
  # @return [Symbol] the task name
46
- def task(name = nil)
47
- return @task if name.nil?
33
+ def task(name = :not_used)
34
+ return @task if name == :not_used
48
35
  @task = name.to_sym
49
36
  end
50
37
 
51
- # Give a description to the task
52
- # @return [String] the description of the task
53
- def desc(str = nil)
54
- return @desc if str.nil?
55
- @desc = str.to_s
56
- end
57
-
58
38
  # It can be hierarchical by using `NAMESPACE_DELIMITER`
59
39
  # @return [String] the namespace defined for this `RakeCommander` class.
60
- def namespace(name = nil)
61
- return @namespace if name.nil?
40
+ def namespace(name = :not_used)
41
+ return @namespace if name == :not_used
62
42
  @namespace = namespace_str(name)
63
43
  end
64
44
 
45
+ # It gives the task full name (including namespacing)
46
+ # @return [String]
47
+ def task_fullname
48
+ "#{namespace}:#{task}"
49
+ end
50
+ alias_method :name, :task_fullname
51
+
65
52
  # Is this rake context namespaced?
66
53
  # @note Rake allows to namespace tasks (i.e. `task :"run:this"`)
67
54
  # Although supported by this integration, namespace detection
@@ -81,6 +68,28 @@ class RakeCommander
81
68
  rake.namespace top, &block
82
69
  end
83
70
 
71
+ # Does the final rake `task` definition
72
+ # @note although it will exist, the task won't be listed with `rake -T`
73
+ # unless it has a description (`desc`).
74
+ # @note this method is extended by some modules
75
+ # 1. `RakeCommander::Options::Result`: Ensure options are parsed before calling task
76
+ # 2. `RakeCommander::Options::Arguments`: `exit(0)` when `Rake` interprets the full `ARGV`
77
+ # rather than stopping at the delimiter (`--`)
78
+ # @return [@see Rake::Task] same results as if you used `task :name {}` or `namespace :space {}`
79
+ def install_task(&task_method)
80
+ raise "Expected task_block." unless task_method
81
+
82
+ if namespaced?
83
+ namespaced do
84
+ rake.desc desc
85
+ rake.task task, &task_method
86
+ end
87
+ else
88
+ rake.desc desc
89
+ rake.task task, &task_method
90
+ end
91
+ end
92
+
84
93
  protected
85
94
 
86
95
  # Converstion of `namespace` name to string
@@ -95,7 +104,15 @@ class RakeCommander
95
104
  # @return [String, NilClass] generic banner for options
96
105
  def task_options_banner
97
106
  str_space = respond_to?(:namespace)? "#{namespace}:" : ''
98
- str_task = respond_to?(:task) ? "Usage: #{str_space}#{task} -- [options]" : nil
107
+ respond_to?(:task) ? "Usage: #{str_space}#{task} -- [options]" : nil
108
+ end
109
+
110
+ # Offer a wrapper to build the task conext througout all inheritance chain.
111
+ # @note
112
+ # - This method offers children classes a way to add their on middleware.
113
+ # @return [Proc] our wrapped task block.
114
+ def task_context(&task_method)
115
+ task_method
99
116
  end
100
117
 
101
118
  private
@@ -113,23 +130,6 @@ class RakeCommander
113
130
  proc { namespace name, &block }
114
131
  end
115
132
  end
116
-
117
- # Rake command ends at `--` (`RAKE_END_COMMAND`).
118
- # We only want to parse the options that come afterwards
119
- # @note without this approach, it will throw `OptionParser::InvalidOption` error
120
- # @return [Proc]
121
- def invoke_options_before_task(&task_method)
122
- object = eval('self', task_method.binding, __FILE__, __LINE__)
123
- return task_method unless object.is_a?(self)
124
- proc do |*args|
125
- argv = ARGV
126
- if idx = argv.index(RAKE_END_COMMAND)
127
- argv = argv[idx+1..-1]
128
- end
129
- object.options(argv)
130
- task_method.call(*args)
131
- end
132
- end
133
133
  end
134
134
 
135
135
  def initialize
@@ -1,3 +1,3 @@
1
1
  class RakeCommander
2
- VERSION = '0.1.2'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
@@ -1,9 +1,13 @@
1
1
  require 'rake'
2
2
  require_relative 'rake-commander/base'
3
+ require_relative 'rake-commander/patcher'
3
4
 
4
5
  class RakeCommander
5
6
  include RakeCommander::Base
7
+ include RakeCommander::Patcher
6
8
  end
7
9
 
8
10
  require_relative 'rake-commander/version'
9
11
  require_relative 'rake-commander/custom'
12
+
13
+ RakeCommander.self_load
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Oscar Segura Samper"]
9
9
  spec.email = ["oscar@ecoportal.co.nz"]
10
10
 
11
- spec.summary = 'The classed version of rake with task options. Create re-usable tasks and samples.'
12
- spec.homepage = "https://www.ecoportal.com"
11
+ spec.summary = 'Classing rake tasks with options. Creating re-usable tasks, options and samples thereof.'
12
+ spec.homepage = "https://github.com/rellampec/rake-commander"
13
13
  spec.licenses = %w[MIT]
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -22,8 +22,11 @@ Gem::Specification.new do |spec|
22
22
  spec.required_ruby_version = '>= 2.7.2'
23
23
 
24
24
  spec.add_development_dependency "bundler", ">= 2.4.9", "< 3"
25
+ spec.add_development_dependency 'dotenv', '>= 2.7.6', '< 3'
25
26
  spec.add_development_dependency "rake", ">= 13.0.6", "< 14"
26
27
  spec.add_development_dependency "redcarpet", ">= 3.6.0", "< 4"
27
28
  spec.add_development_dependency "rspec", ">= 3.10.0", "< 4"
28
29
  spec.add_development_dependency "yard", ">= 0.9.34", "< 1"
30
+
31
+ spec.add_dependency "rake", ">= 13.0.6", "< 14"
29
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rake-commander
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura Samper
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-19 00:00:00.000000000 Z
11
+ date: 2023-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,6 +30,26 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '3'
33
+ - !ruby/object:Gem::Dependency
34
+ name: dotenv
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 2.7.6
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '3'
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 2.7.6
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '3'
33
53
  - !ruby/object:Gem::Dependency
34
54
  name: rake
35
55
  requirement: !ruby/object:Gem::Requirement
@@ -110,6 +130,26 @@ dependencies:
110
130
  - - "<"
111
131
  - !ruby/object:Gem::Version
112
132
  version: '1'
133
+ - !ruby/object:Gem::Dependency
134
+ name: rake
135
+ requirement: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: 13.0.6
140
+ - - "<"
141
+ - !ruby/object:Gem::Version
142
+ version: '14'
143
+ type: :runtime
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: 13.0.6
150
+ - - "<"
151
+ - !ruby/object:Gem::Version
152
+ version: '14'
113
153
  description:
114
154
  email:
115
155
  - oscar@ecoportal.co.nz
@@ -123,26 +163,54 @@ files:
123
163
  - ".yardopts"
124
164
  - CHANGELOG.md
125
165
  - Gemfile
166
+ - LICENSE
126
167
  - README.md
127
168
  - Rakefile
128
- - examples/basic.rb
169
+ - examples/01_basic_example.rb
170
+ - examples/02_a_chainer_example.rb
171
+ - examples/02_a_chainer_options_set.rb
172
+ - examples/02_b_chained_example.rb
173
+ - examples/03_a_chainer_plus_example.rb
174
+ - examples/03_b_chained_plus_example.rb
175
+ - examples/Examples.rake
176
+ - examples/README.md
177
+ - examples/libs/shell_helpers.rb
129
178
  - lib/rake-commander.rb
130
179
  - lib/rake-commander/base.rb
131
180
  - lib/rake-commander/base/class_auto_loader.rb
132
181
  - lib/rake-commander/base/class_helpers.rb
182
+ - lib/rake-commander/base/class_inheritable.rb
183
+ - lib/rake-commander/base/custom_error.rb
184
+ - lib/rake-commander/base/object_helpers.rb
133
185
  - lib/rake-commander/custom.rb
134
186
  - lib/rake-commander/option.rb
135
187
  - lib/rake-commander/options.rb
136
188
  - lib/rake-commander/options/arguments.rb
189
+ - lib/rake-commander/options/description.rb
137
190
  - lib/rake-commander/options/error.rb
138
- - lib/rake-commander/options/error_rely.rb
191
+ - lib/rake-commander/options/error/base.rb
192
+ - lib/rake-commander/options/error/handling.rb
193
+ - lib/rake-commander/options/error/invalid_argument.rb
194
+ - lib/rake-commander/options/error/invalid_option.rb
195
+ - lib/rake-commander/options/error/missing_argument.rb
196
+ - lib/rake-commander/options/error/missing_option.rb
197
+ - lib/rake-commander/options/error/unknown_argument.rb
139
198
  - lib/rake-commander/options/name.rb
199
+ - lib/rake-commander/options/result.rb
140
200
  - lib/rake-commander/options/set.rb
201
+ - lib/rake-commander/patcher.rb
202
+ - lib/rake-commander/patcher/README.md
203
+ - lib/rake-commander/patcher/application.rb
204
+ - lib/rake-commander/patcher/application/run_method.rb
205
+ - lib/rake-commander/patcher/application/top_level_method.rb
206
+ - lib/rake-commander/patcher/base.rb
207
+ - lib/rake-commander/patcher/debug.rb
208
+ - lib/rake-commander/patcher/helpers.rb
141
209
  - lib/rake-commander/rake_context/wrapper.rb
142
210
  - lib/rake-commander/rake_task.rb
143
211
  - lib/rake-commander/version.rb
144
212
  - rake-commander.gemspec
145
- homepage: https://www.ecoportal.com
213
+ homepage: https://github.com/rellampec/rake-commander
146
214
  licenses:
147
215
  - MIT
148
216
  metadata: {}
@@ -164,6 +232,6 @@ requirements: []
164
232
  rubygems_version: 3.1.4
165
233
  signing_key:
166
234
  specification_version: 4
167
- summary: The classed version of rake with task options. Create re-usable tasks and
168
- samples.
235
+ summary: Classing rake tasks with options. Creating re-usable tasks, options and samples
236
+ thereof.
169
237
  test_files: []
data/examples/basic.rb DELETED
@@ -1,30 +0,0 @@
1
- require_relative File.join(__dir__, '../lib/rake-commander')
2
- class RakeCommander::Custom::Basic < RakeCommander
3
- namespace :examples
4
-
5
- desc 'A simple example to get started'
6
- task :basic
7
-
8
- #banner "Usage: basic:example -- [options]"
9
- option '-s', '--say [SOMETHING]', "It says 'something'", default: %q(I don't know what to "say"...)
10
- option :d, '--folder NAME', default: '.', desc: 'Source local folder', required: true
11
- option '-e', '--enviro ENV', 'The target environment to run this task', required: true
12
- option '-t', :show_time, TrueClass, desc: 'Displays the local time'
13
- option :v, :debug, TrueClass, 'Shows the parsed options'
14
-
15
- def task(*_args)
16
- if options[:v]
17
- puts 'We got these options:'
18
- pp options
19
- end
20
- puts Time.now.strftime('%d %b at %H:%M') if options[:t]
21
- puts options[:s] if options.key?(:s)
22
- end
23
- end
24
-
25
- RakeCommander.self_load
26
- Rake::Task[:'examples:basic'].invoke
27
- # ruby basic.rb -- -v -d /some/folder -t
28
-
29
- #RakeCommander::Custom::Basic.parse_options %w[--help]
30
- #RakeCommander::Custom::Basic.parse_options %w[-d]
@@ -1,58 +0,0 @@
1
- class RakeCommander
2
- module Options
3
- # Relies between OptionParser and RakeCommander errors
4
- class ErrorRely < StandardError
5
- extend RakeCommander::Options::Name
6
-
7
- OPTION_REGEX = /(?:argument|option): (?<option>.+)/i.freeze
8
-
9
- def initialize(value)
10
- case value
11
- when OptionParser::MissingArgument, OptionParser::InvalidArgument
12
- super(value.message)
13
- when String
14
- super(value)
15
- else
16
- raise ArgumentError, "Expecting String or OptionParser error. Given: #{value.class}"
17
- end
18
- end
19
-
20
- def name?
21
- option_sym.to_s.length > 1
22
- end
23
-
24
- def short?
25
- option_sym.to_s.length == 1
26
- end
27
-
28
- def option_sym
29
- return @option_sym if @option_sym
30
- return nil unless match = message.match(self.class::OPTION_REGEX)
31
- option = match[:option]
32
- @option_sym = \
33
- if option.length > 1
34
- self.class.name_word_sym(option)
35
- else
36
- self.class.short_sym(option)
37
- end
38
- end
39
-
40
- private
41
-
42
- def to_description(value)
43
- case value
44
- when Hash
45
- to_description(value.values.uniq)
46
- when Array
47
- value.map do |v|
48
- to_description(v)
49
- end.join(', ')
50
- when RakeCommander::Option
51
- "#{value.name_hyphen} (#{value.short_hyphen})"
52
- else
53
- value
54
- end
55
- end
56
- end
57
- end
58
- end