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.
@@ -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
- (Note: --json-args and --eval-args are mutually exclusive)
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 and --eval-args cannot be used at the same time'
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
- pre_scripts: pre_script_sources
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