rake_options 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +277 -0
- data/Rakefile +8 -0
- data/lib/rake_options/argument_parser.rb +46 -0
- data/lib/rake_options/bracket_parser.rb +64 -0
- data/lib/rake_options/cli_parser.rb +43 -0
- data/lib/rake_options/errors.rb +8 -0
- data/lib/rake_options/hash_with_indifferent_access.rb +55 -0
- data/lib/rake_options/help_generator.rb +49 -0
- data/lib/rake_options/template_engine.rb +70 -0
- data/lib/rake_options/version.rb +5 -0
- data/lib/rake_options.rb +39 -0
- data/spec/integration/rake_options_integration_spec.rb +242 -0
- data/spec/rake_options/argument_parser_spec.rb +71 -0
- data/spec/rake_options/bracket_parser_spec.rb +86 -0
- data/spec/rake_options/cli_parser_spec.rb +108 -0
- data/spec/rake_options/help_generator_spec.rb +86 -0
- data/spec/rake_options/template_engine_spec.rb +112 -0
- data/spec/rake_options_spec.rb +86 -0
- data/spec/spec_helper.rb +15 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6d64b8c9debd762394889c921fc5a3c52f23618f3e1d33448c5f6337ab942edc
|
4
|
+
data.tar.gz: d24b0d7525cbb407047c86b61abca35ed3646a4f414272f1521900267a15673d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b896b635679be32725e5f480441fed874e4a853d3af99ce45b234d4dc5c42ed68ac1bc866879aa434fca4b04fad33b76db825ad9303580d997c8a58c8184fa19
|
7
|
+
data.tar.gz: 2d89ac0871af10c498ebfc23d2bc73c7644923fe14e8e2de2005c3195ff9ad995848e22e496da5f632e165a674b07bcf604b94cec14e5a808923a6c67c23d3d6
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 RakeCommander Contributors
|
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
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
# RakeOptions
|
2
|
+
|
3
|
+
RakeOptions is a Ruby gem that simplifies command line argument handling for rake tasks. It provides an intuitive API for parsing arguments with support for multiple notation styles and automatic help documentation generation.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'rake_options'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
gem install rake_options
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Basic CLI-Style Arguments
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'rake_options'
|
31
|
+
|
32
|
+
desc "Build with custom options"
|
33
|
+
task :build do
|
34
|
+
config = {
|
35
|
+
"with-mysql-lib" => "--with-mysql-lib $path",
|
36
|
+
"enable-feature" => "--enable-feature $name"
|
37
|
+
}
|
38
|
+
|
39
|
+
options = RakeOptions.command_line_args(config)
|
40
|
+
|
41
|
+
puts "MySQL lib path: #{options['with-mysql-lib']}"
|
42
|
+
puts "Feature: #{options['enable-feature']}"
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
Run with:
|
47
|
+
```bash
|
48
|
+
rake build -- --with-mysql-lib "/usr/local/mysql/lib" --enable-feature "caching"
|
49
|
+
```
|
50
|
+
|
51
|
+
### Bracket-Style Arguments
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
require 'rake_options'
|
55
|
+
|
56
|
+
desc "Deploy with bracket notation"
|
57
|
+
task :deploy do
|
58
|
+
config = {
|
59
|
+
"environment" => "[environment=$env]",
|
60
|
+
"region" => "[region=$region]"
|
61
|
+
}
|
62
|
+
|
63
|
+
options = RakeOptions.command_line_args(config, notation: :bracket)
|
64
|
+
|
65
|
+
puts "Deploying to #{options['environment']} in #{options['region']}"
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
Run with:
|
70
|
+
```bash
|
71
|
+
rake deploy [environment=production] [region=us-west-2]
|
72
|
+
```
|
73
|
+
|
74
|
+
### Multiple Variables in One Template
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
config = {
|
78
|
+
"database" => "--config $file --env $environment"
|
79
|
+
}
|
80
|
+
|
81
|
+
options = RakeOptions.command_line_args(config)
|
82
|
+
# Extracts both file and environment from: --config database.yml --env production
|
83
|
+
```
|
84
|
+
|
85
|
+
### Automatic Help Documentation
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
require 'rake_options'
|
89
|
+
|
90
|
+
readme_content = <<~HELP
|
91
|
+
Build Task Help
|
92
|
+
|
93
|
+
Available options:
|
94
|
+
--with-mysql-lib PATH Specify MySQL library path
|
95
|
+
--enable-feature NAME Enable a specific feature
|
96
|
+
HELP
|
97
|
+
|
98
|
+
RakeOptions.initialize_readme(readme_content)
|
99
|
+
|
100
|
+
desc "Build with help support"
|
101
|
+
task :build do
|
102
|
+
config = {
|
103
|
+
"with-mysql-lib" => "--with-mysql-lib $path",
|
104
|
+
"enable-feature" => "--enable-feature $name"
|
105
|
+
}
|
106
|
+
|
107
|
+
options = RakeOptions.command_line_args(config)
|
108
|
+
# Your build logic here
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
Run with:
|
113
|
+
```bash
|
114
|
+
rake build -- --help
|
115
|
+
```
|
116
|
+
|
117
|
+
### Hash Access with Strings or Symbols
|
118
|
+
|
119
|
+
The returned options hash supports both string and symbol key access:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
options = RakeOptions.command_line_args(config)
|
123
|
+
|
124
|
+
# Both work:
|
125
|
+
options['with-mysql-lib']
|
126
|
+
options[:with_mysql_lib]
|
127
|
+
```
|
128
|
+
|
129
|
+
## Configuration Format
|
130
|
+
|
131
|
+
The configuration hash maps symbolic names to template patterns:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
{
|
135
|
+
"key-name" => "template pattern with $variables"
|
136
|
+
}
|
137
|
+
```
|
138
|
+
|
139
|
+
- **Key**: The name you'll use to access the parsed value
|
140
|
+
- **Value**: A template string that defines how to extract the argument
|
141
|
+
- **Variables**: Prefixed with `$` to indicate where values should be extracted
|
142
|
+
|
143
|
+
### Template Examples
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
# Single variable
|
147
|
+
"mysql-path" => "--with-mysql-lib $path"
|
148
|
+
|
149
|
+
# Multiple variables
|
150
|
+
"database" => "--config $file --env $environment"
|
151
|
+
|
152
|
+
# Bracket notation
|
153
|
+
"region" => "[region=$value]"
|
154
|
+
```
|
155
|
+
|
156
|
+
## Notation Styles
|
157
|
+
|
158
|
+
### CLI Notation (default)
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
options = RakeOptions.command_line_args(config, notation: :cli)
|
162
|
+
```
|
163
|
+
|
164
|
+
Supports:
|
165
|
+
- `--flag value`
|
166
|
+
- `--flag "value with spaces"`
|
167
|
+
- Multiple flags in one command
|
168
|
+
|
169
|
+
### Bracket Notation
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
options = RakeOptions.command_line_args(config, notation: :bracket)
|
173
|
+
```
|
174
|
+
|
175
|
+
Supports:
|
176
|
+
- `[key=value]`
|
177
|
+
- `[key="value with spaces"]`
|
178
|
+
- Multiple bracket arguments
|
179
|
+
|
180
|
+
## Error Handling
|
181
|
+
|
182
|
+
RakeOptions provides clear error messages:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
# Invalid notation
|
186
|
+
RakeOptions.command_line_args(config, notation: :invalid)
|
187
|
+
# => InvalidNotationError: Invalid notation ':invalid'. Supported notations: :cli, :bracket
|
188
|
+
|
189
|
+
# Missing optional arguments return nil
|
190
|
+
options['missing-arg'] # => nil
|
191
|
+
```
|
192
|
+
|
193
|
+
## Troubleshooting
|
194
|
+
|
195
|
+
### Arguments not being parsed
|
196
|
+
|
197
|
+
**Problem**: Your arguments aren't being recognized.
|
198
|
+
|
199
|
+
**Solution**: Make sure you're using `--` to separate rake arguments from your custom arguments:
|
200
|
+
```bash
|
201
|
+
rake task -- --your-flag value
|
202
|
+
```
|
203
|
+
|
204
|
+
### Symbol vs String keys
|
205
|
+
|
206
|
+
**Problem**: Can't access values with symbol keys.
|
207
|
+
|
208
|
+
**Solution**: RakeOptions returns a `HashWithIndifferentAccess` that supports both:
|
209
|
+
```ruby
|
210
|
+
options[:key] # Works
|
211
|
+
options['key'] # Also works
|
212
|
+
options[:key_name] # Converts underscores to dashes automatically
|
213
|
+
options['key-name'] # Same value
|
214
|
+
```
|
215
|
+
|
216
|
+
### Help not displaying
|
217
|
+
|
218
|
+
**Problem**: `--help` flag doesn't show help.
|
219
|
+
|
220
|
+
**Solution**: Ensure `--help` is in ARGV before calling `command_line_args`:
|
221
|
+
```bash
|
222
|
+
rake task -- --help
|
223
|
+
```
|
224
|
+
|
225
|
+
### Quoted values not working
|
226
|
+
|
227
|
+
**Problem**: Values with spaces aren't being captured correctly.
|
228
|
+
|
229
|
+
**Solution**: Use quotes around values with spaces:
|
230
|
+
```bash
|
231
|
+
rake task -- --path "/path/with spaces"
|
232
|
+
```
|
233
|
+
|
234
|
+
### Template not matching
|
235
|
+
|
236
|
+
**Problem**: Template variables aren't extracting values.
|
237
|
+
|
238
|
+
**Solution**: Ensure your template matches the command line format exactly:
|
239
|
+
```ruby
|
240
|
+
# Template
|
241
|
+
"option" => "--option $value"
|
242
|
+
|
243
|
+
# Command line must match
|
244
|
+
rake task -- --option myvalue
|
245
|
+
```
|
246
|
+
|
247
|
+
## Requirements
|
248
|
+
|
249
|
+
- Ruby 2.7 or higher
|
250
|
+
|
251
|
+
## Development
|
252
|
+
|
253
|
+
After checking out the repo, run:
|
254
|
+
|
255
|
+
```bash
|
256
|
+
bundle install
|
257
|
+
```
|
258
|
+
|
259
|
+
Run tests:
|
260
|
+
|
261
|
+
```bash
|
262
|
+
rake spec
|
263
|
+
```
|
264
|
+
|
265
|
+
Build the gem:
|
266
|
+
|
267
|
+
```bash
|
268
|
+
gem build rake_options.gemspec
|
269
|
+
```
|
270
|
+
|
271
|
+
## Contributing
|
272
|
+
|
273
|
+
Bug reports and pull requests are welcome on GitHub.
|
274
|
+
|
275
|
+
## License
|
276
|
+
|
277
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE).
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "cli_parser"
|
4
|
+
require_relative "bracket_parser"
|
5
|
+
require_relative "errors"
|
6
|
+
|
7
|
+
module RakeOptions
|
8
|
+
class ArgumentParser
|
9
|
+
VALID_NOTATIONS = [:cli, :bracket].freeze
|
10
|
+
|
11
|
+
def initialize(config, notation)
|
12
|
+
@config = config
|
13
|
+
@notation = notation
|
14
|
+
validate_notation
|
15
|
+
end
|
16
|
+
|
17
|
+
# Parse ARGV and return structured options
|
18
|
+
# @return [Hash] Parsed options
|
19
|
+
def parse
|
20
|
+
parser = select_parser
|
21
|
+
parser.parse
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Select appropriate parser based on notation
|
27
|
+
# @return [CLIParser, BracketParser] Parser instance
|
28
|
+
def select_parser
|
29
|
+
case @notation
|
30
|
+
when :cli
|
31
|
+
CLIParser.new(@config)
|
32
|
+
when :bracket
|
33
|
+
BracketParser.new(@config)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Validate notation parameter
|
38
|
+
# @raise [InvalidNotationError] if notation is invalid
|
39
|
+
def validate_notation
|
40
|
+
return if VALID_NOTATIONS.include?(@notation)
|
41
|
+
|
42
|
+
raise InvalidNotationError,
|
43
|
+
"Invalid notation ':#{@notation}'. Supported notations: #{VALID_NOTATIONS.map { |n| ":#{n}" }.join(', ')}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RakeOptions
|
4
|
+
class BracketParser
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
# Parse bracket-style arguments from ARGV
|
10
|
+
# @param argv [Array] Command line arguments (defaults to ARGV)
|
11
|
+
# @return [Hash] Parsed values
|
12
|
+
def parse(argv = ARGV)
|
13
|
+
result = {}
|
14
|
+
|
15
|
+
# Extract all bracket arguments from argv
|
16
|
+
bracket_args = extract_bracket_args(argv)
|
17
|
+
|
18
|
+
# Match bracket args to config keys
|
19
|
+
@config.each do |key, _template|
|
20
|
+
# Look for matching bracket key
|
21
|
+
if bracket_args.key?(key)
|
22
|
+
result[key] = bracket_args[key]
|
23
|
+
else
|
24
|
+
result[key] = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Find all [key=value] patterns in argv
|
34
|
+
# @param argv [Array] Command line arguments
|
35
|
+
# @return [Hash] Extracted key-value pairs
|
36
|
+
def extract_bracket_args(argv)
|
37
|
+
result = {}
|
38
|
+
|
39
|
+
argv.each do |arg|
|
40
|
+
# Match [key=value] or [key="value"]
|
41
|
+
match = arg.match(/^\[([^=]+)=(.+)\]$/)
|
42
|
+
next unless match
|
43
|
+
|
44
|
+
key = match[1]
|
45
|
+
value = parse_bracket_value(match[2])
|
46
|
+
result[key] = value
|
47
|
+
end
|
48
|
+
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
# Handle quoted and unquoted values in brackets
|
53
|
+
# @param value [String] Value from bracket
|
54
|
+
# @return [String] Parsed value
|
55
|
+
def parse_bracket_value(value)
|
56
|
+
# Remove surrounding quotes if present
|
57
|
+
if value.start_with?('"') && value.end_with?('"')
|
58
|
+
value[1..-2]
|
59
|
+
else
|
60
|
+
value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "template_engine"
|
4
|
+
|
5
|
+
module RakeOptions
|
6
|
+
class CLIParser
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
@parsed_templates = {}
|
10
|
+
|
11
|
+
# Pre-parse all templates
|
12
|
+
@config.each do |key, template_str|
|
13
|
+
@parsed_templates[key] = TemplateEngine.parse_template(template_str)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Parse CLI-style arguments from ARGV
|
18
|
+
# @param argv [Array] Command line arguments (defaults to ARGV)
|
19
|
+
# @return [Hash] Parsed values
|
20
|
+
def parse(argv = ARGV)
|
21
|
+
result = {}
|
22
|
+
|
23
|
+
@config.each do |key, _template_str|
|
24
|
+
parsed_template = @parsed_templates[key]
|
25
|
+
extracted = TemplateEngine.extract_values(argv, parsed_template)
|
26
|
+
|
27
|
+
if extracted && !extracted.empty?
|
28
|
+
# For single variable templates, store the value directly
|
29
|
+
if extracted.size == 1
|
30
|
+
result[key] = extracted.values.first
|
31
|
+
else
|
32
|
+
# For multiple variables, store the hash
|
33
|
+
result[key] = extracted
|
34
|
+
end
|
35
|
+
else
|
36
|
+
result[key] = nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RakeOptions
|
4
|
+
class HashWithIndifferentAccess < Hash
|
5
|
+
def initialize(hash = {})
|
6
|
+
super()
|
7
|
+
hash.each do |key, value|
|
8
|
+
self[key] = value
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Override [] to handle both string and symbol keys
|
13
|
+
def [](key)
|
14
|
+
super(convert_key(key))
|
15
|
+
end
|
16
|
+
|
17
|
+
# Override []= to store with string keys
|
18
|
+
def []=(key, value)
|
19
|
+
super(convert_key(key), value)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Override fetch to handle both string and symbol keys
|
23
|
+
def fetch(key, *args, &block)
|
24
|
+
super(convert_key(key), *args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Override key? to handle both string and symbol keys
|
28
|
+
def key?(key)
|
29
|
+
super(convert_key(key))
|
30
|
+
end
|
31
|
+
|
32
|
+
alias_method :has_key?, :key?
|
33
|
+
alias_method :include?, :key?
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Convert key to string and normalize dashes/underscores
|
38
|
+
def convert_key(key)
|
39
|
+
key_str = key.to_s
|
40
|
+
# Try exact match first
|
41
|
+
return key_str if Hash.instance_method(:key?).bind(self).call(key_str)
|
42
|
+
|
43
|
+
# Try with underscores converted to dashes
|
44
|
+
dashed = key_str.tr("_", "-")
|
45
|
+
return dashed if Hash.instance_method(:key?).bind(self).call(dashed)
|
46
|
+
|
47
|
+
# Try with dashes converted to underscores
|
48
|
+
underscored = key_str.tr("-", "_")
|
49
|
+
return underscored if Hash.instance_method(:key?).bind(self).call(underscored)
|
50
|
+
|
51
|
+
# Return original if no match
|
52
|
+
key_str
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RakeOptions
|
4
|
+
class HelpGenerator
|
5
|
+
def initialize(config, readme_content = nil)
|
6
|
+
@config = config
|
7
|
+
@readme_content = readme_content
|
8
|
+
end
|
9
|
+
|
10
|
+
# Display help and exit
|
11
|
+
# @return [void]
|
12
|
+
def display_and_exit
|
13
|
+
puts generate_help_text
|
14
|
+
exit(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Create formatted help text
|
20
|
+
# @return [String] Formatted help text
|
21
|
+
def generate_help_text
|
22
|
+
if @readme_content
|
23
|
+
@readme_content
|
24
|
+
else
|
25
|
+
auto_generate_help
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Auto-generate help from config
|
30
|
+
# @return [String] Auto-generated help text
|
31
|
+
def auto_generate_help
|
32
|
+
help_text = "Available Options:\n\n"
|
33
|
+
|
34
|
+
@config.each do |key, template|
|
35
|
+
help_text += format_option(key, template)
|
36
|
+
end
|
37
|
+
|
38
|
+
help_text
|
39
|
+
end
|
40
|
+
|
41
|
+
# Format individual option for display
|
42
|
+
# @param key [String] Option key
|
43
|
+
# @param template [String] Template string
|
44
|
+
# @return [String] Formatted option line
|
45
|
+
def format_option(key, template)
|
46
|
+
" #{template.ljust(40)} (#{key})\n"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RakeOptions
|
4
|
+
class TemplateEngine
|
5
|
+
# Parse a template string into components
|
6
|
+
# @param template [String] Template like "--flag $variable"
|
7
|
+
# @return [Hash] Template structure with flag, variables, and pattern
|
8
|
+
def self.parse_template(template)
|
9
|
+
variables = identify_variables(template)
|
10
|
+
pattern = build_pattern(template, variables)
|
11
|
+
|
12
|
+
{
|
13
|
+
template: template,
|
14
|
+
variables: variables,
|
15
|
+
pattern: pattern
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Extract values from input based on template
|
20
|
+
# @param input [Array] Input tokens (ARGV)
|
21
|
+
# @param parsed_template [Hash] Parsed template structure
|
22
|
+
# @return [Hash, nil] Extracted variable values or nil if no match
|
23
|
+
def self.extract_values(input, parsed_template)
|
24
|
+
input_str = input.join(" ")
|
25
|
+
match = parsed_template[:pattern].match(input_str)
|
26
|
+
|
27
|
+
return nil unless match
|
28
|
+
|
29
|
+
result = {}
|
30
|
+
# Each variable creates 2 capture groups (quoted and unquoted)
|
31
|
+
# We need to pick the non-nil one
|
32
|
+
capture_index = 1
|
33
|
+
parsed_template[:variables].each do |var|
|
34
|
+
# Get both possible captures (quoted or unquoted)
|
35
|
+
quoted_value = match[capture_index]
|
36
|
+
unquoted_value = match[capture_index + 1]
|
37
|
+
|
38
|
+
result[var] = quoted_value || unquoted_value
|
39
|
+
capture_index += 2
|
40
|
+
end
|
41
|
+
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Find $variable placeholders in template
|
48
|
+
# @param template [String] Template string
|
49
|
+
# @return [Array<String>] List of variable names
|
50
|
+
def self.identify_variables(template)
|
51
|
+
template.scan(/\$(\w+)/).flatten
|
52
|
+
end
|
53
|
+
|
54
|
+
# Create regex pattern from template
|
55
|
+
# @param template [String] Template string
|
56
|
+
# @param variables [Array<String>] Variable names
|
57
|
+
# @return [Regexp] Regex pattern for matching
|
58
|
+
def self.build_pattern(template, variables)
|
59
|
+
# Replace $variables with capture groups that match:
|
60
|
+
# - Quoted strings: "value with spaces"
|
61
|
+
# - Unquoted values: value (non-whitespace)
|
62
|
+
pattern_str = template.gsub(/\$\w+/, '(?:"([^"]+)"|(\S+))')
|
63
|
+
|
64
|
+
# Escape special regex characters except our capture groups
|
65
|
+
pattern_str = pattern_str.gsub(/\s+/, '\s+')
|
66
|
+
|
67
|
+
Regexp.new(pattern_str)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/rake_options.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "rake_options/version"
|
4
|
+
require_relative "rake_options/errors"
|
5
|
+
require_relative "rake_options/argument_parser"
|
6
|
+
require_relative "rake_options/help_generator"
|
7
|
+
require_relative "rake_options/hash_with_indifferent_access"
|
8
|
+
|
9
|
+
module RakeOptions
|
10
|
+
class << self
|
11
|
+
attr_accessor :readme_content
|
12
|
+
|
13
|
+
# Parse command line arguments based on configuration
|
14
|
+
# @param config [Hash] Argument configuration mapping
|
15
|
+
# @param notation [Symbol] Notation style (:cli or :bracket)
|
16
|
+
# @return [HashWithIndifferentAccess] Parsed arguments with indifferent access
|
17
|
+
def command_line_args(config, notation: :cli)
|
18
|
+
# Check for --help flag
|
19
|
+
if ARGV.include?("--help")
|
20
|
+
help_generator = HelpGenerator.new(config, readme_content)
|
21
|
+
help_generator.display_and_exit
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse arguments
|
25
|
+
parser = ArgumentParser.new(config, notation)
|
26
|
+
result = parser.parse
|
27
|
+
|
28
|
+
# Wrap in HashWithIndifferentAccess
|
29
|
+
HashWithIndifferentAccess.new(result)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Initialize help documentation
|
33
|
+
# @param readme_content [String] Help text or README content
|
34
|
+
# @return [void]
|
35
|
+
def initialize_readme(content)
|
36
|
+
self.readme_content = content
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|