rubycli 0.1.2 → 0.1.4
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/CHANGELOG.md +25 -0
- data/README.ja.md +19 -4
- data/README.md +19 -4
- data/lib/rubycli/argument_mode_controller.rb +69 -0
- data/lib/rubycli/argument_parser.rb +53 -122
- data/lib/rubycli/arguments/token_stream.rb +41 -0
- data/lib/rubycli/arguments/value_converter.rb +74 -0
- data/lib/rubycli/cli.rb +9 -6
- data/lib/rubycli/command_line.rb +20 -4
- data/lib/rubycli/constant_capture.rb +50 -0
- data/lib/rubycli/documentation/comment_extractor.rb +52 -0
- data/lib/rubycli/documentation/metadata_parser.rb +838 -0
- data/lib/rubycli/documentation_registry.rb +10 -852
- data/lib/rubycli/environment.rb +8 -1
- data/lib/rubycli/eval_coercer.rb +16 -1
- data/lib/rubycli/version.rb +1 -1
- data/lib/rubycli.rb +196 -118
- metadata +8 -2
data/lib/rubycli/command_line.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Rubycli
|
|
4
4
|
module CommandLine
|
|
5
5
|
USAGE = <<~USAGE
|
|
6
|
-
Usage: rubycli [--new|-n] [--pre-script=<src>] [--json-args|-j | --eval-args|-e] <target-path> [<class-or-module>] [-- <cli-args>...]
|
|
6
|
+
Usage: rubycli [--new|-n] [--pre-script=<src>] [--json-args|-j | --eval-args|-e | --eval-lax|-E] <target-path> [<class-or-module>] [-- <cli-args>...]
|
|
7
7
|
|
|
8
8
|
Examples:
|
|
9
9
|
rubycli scripts/sample_runner.rb echo --message hello
|
|
@@ -15,7 +15,9 @@ module Rubycli
|
|
|
15
15
|
--pre-script=<src> Evaluate Ruby code and use its result as the exposed target (--init alias; also accepts space-separated form)
|
|
16
16
|
--json-args, -j Parse all following arguments strictly as JSON (no YAML literals)
|
|
17
17
|
--eval-args, -e Evaluate following arguments as Ruby code
|
|
18
|
-
|
|
18
|
+
--eval-lax, -E Evaluate as Ruby but fall back to raw strings when parsing fails
|
|
19
|
+
--auto-target, -a Auto-select the only callable constant when names don't match
|
|
20
|
+
(Note: --json-args cannot be combined with --eval-args or --eval-lax)
|
|
19
21
|
(Note: Every option that accepts a value understands both --flag=value and --flag value forms.)
|
|
20
22
|
|
|
21
23
|
When <class-or-module> is omitted, Rubycli infers it from the file name in CamelCase.
|
|
@@ -38,6 +40,8 @@ module Rubycli
|
|
|
38
40
|
new_flag = false
|
|
39
41
|
json_mode = false
|
|
40
42
|
eval_mode = false
|
|
43
|
+
eval_lax_mode = false
|
|
44
|
+
constant_mode = nil
|
|
41
45
|
pre_script_sources = []
|
|
42
46
|
|
|
43
47
|
loop do
|
|
@@ -71,7 +75,14 @@ module Rubycli
|
|
|
71
75
|
when '--eval-args', '-e'
|
|
72
76
|
eval_mode = true
|
|
73
77
|
args.shift
|
|
78
|
+
when '--eval-lax', '-E'
|
|
79
|
+
eval_mode = true
|
|
80
|
+
eval_lax_mode = true
|
|
81
|
+
args.shift
|
|
74
82
|
when '--print-result'
|
|
83
|
+
args.shift
|
|
84
|
+
when '--auto-target', '-a'
|
|
85
|
+
constant_mode = :auto
|
|
75
86
|
args.shift
|
|
76
87
|
when '--'
|
|
77
88
|
args.shift
|
|
@@ -95,7 +106,7 @@ module Rubycli
|
|
|
95
106
|
args.shift if args.first == '--'
|
|
96
107
|
|
|
97
108
|
if json_mode && eval_mode
|
|
98
|
-
warn '--json-args
|
|
109
|
+
warn '--json-args cannot be combined with --eval-args or --eval-lax'
|
|
99
110
|
return 1
|
|
100
111
|
end
|
|
101
112
|
|
|
@@ -106,13 +117,18 @@ module Rubycli
|
|
|
106
117
|
new: new_flag,
|
|
107
118
|
json: json_mode,
|
|
108
119
|
eval_args: eval_mode,
|
|
109
|
-
|
|
120
|
+
eval_lax: eval_lax_mode,
|
|
121
|
+
pre_scripts: pre_script_sources,
|
|
122
|
+
constant_mode: constant_mode
|
|
110
123
|
)
|
|
111
124
|
|
|
112
125
|
0
|
|
113
126
|
rescue Rubycli::Runner::PreScriptError => e
|
|
114
127
|
warn e.message
|
|
115
128
|
1
|
|
129
|
+
rescue Rubycli::Runner::Error => e
|
|
130
|
+
warn e.message
|
|
131
|
+
1
|
|
116
132
|
end
|
|
117
133
|
end
|
|
118
134
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubycli
|
|
4
|
+
# Observes constants defined while loading a file.
|
|
5
|
+
class ConstantCapture
|
|
6
|
+
def initialize
|
|
7
|
+
@captured = Hash.new { |hash, key| hash[key] = [] }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def capture(file)
|
|
11
|
+
trace = TracePoint.new(:class) do |tp|
|
|
12
|
+
location = tp.path
|
|
13
|
+
next unless location && same_file?(file, location)
|
|
14
|
+
|
|
15
|
+
constant_name = qualified_name_for(tp.self)
|
|
16
|
+
next unless constant_name
|
|
17
|
+
|
|
18
|
+
@captured[file] << constant_name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
trace.enable
|
|
22
|
+
yield
|
|
23
|
+
ensure
|
|
24
|
+
trace&.disable
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def constants_for(file)
|
|
28
|
+
Array(@captured[normalize(file)]).uniq
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def same_file?(target, candidate)
|
|
34
|
+
normalize(target) == normalize(candidate)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def normalize(file)
|
|
38
|
+
File.expand_path(file.to_s)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def qualified_name_for(target)
|
|
42
|
+
return nil unless target.respond_to?(:name)
|
|
43
|
+
|
|
44
|
+
name = target.name
|
|
45
|
+
return nil unless name && !name.empty? && !name.start_with?('#<')
|
|
46
|
+
|
|
47
|
+
name
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rubycli
|
|
4
|
+
module Documentation
|
|
5
|
+
# Extracts contiguous comment blocks that appear immediately before a method.
|
|
6
|
+
class CommentExtractor
|
|
7
|
+
def initialize
|
|
8
|
+
@file_cache = {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def extract(file, line_number)
|
|
12
|
+
return [] unless file && line_number
|
|
13
|
+
|
|
14
|
+
lines = cached_lines_for(file)
|
|
15
|
+
index = line_number - 2
|
|
16
|
+
block = []
|
|
17
|
+
|
|
18
|
+
while index >= 0
|
|
19
|
+
line = lines[index]
|
|
20
|
+
break unless comment_line?(line)
|
|
21
|
+
|
|
22
|
+
block << line
|
|
23
|
+
index -= 1
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
block.reverse.map { |line| strip_comment_prefix(line) }
|
|
27
|
+
rescue Errno::ENOENT
|
|
28
|
+
[]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def reset!
|
|
32
|
+
@file_cache.clear
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def cached_lines_for(file)
|
|
38
|
+
@file_cache[file] ||= File.readlines(file, chomp: true)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def comment_line?(line)
|
|
42
|
+
return false unless line
|
|
43
|
+
|
|
44
|
+
line.lstrip.start_with?('#')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def strip_comment_prefix(line)
|
|
48
|
+
line.lstrip.sub(/^#/, '').lstrip
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|