ukiryu 0.1.0 → 0.1.1
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/.github/workflows/docs.yml +63 -0
- data/.github/workflows/links.yml +99 -0
- data/.github/workflows/rake.yml +19 -0
- data/.github/workflows/release.yml +27 -0
- data/.gitignore +18 -4
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +213 -0
- data/Gemfile +12 -8
- data/README.adoc +613 -0
- data/Rakefile +2 -2
- data/docs/assets/logo.svg +1 -0
- data/exe/ukiryu +11 -0
- data/lib/ukiryu/action/base.rb +77 -0
- data/lib/ukiryu/cache.rb +199 -0
- data/lib/ukiryu/cli.rb +133 -307
- data/lib/ukiryu/cli_commands/base_command.rb +155 -0
- data/lib/ukiryu/cli_commands/commands_command.rb +120 -0
- data/lib/ukiryu/cli_commands/commands_command.rb.fixed +40 -0
- data/lib/ukiryu/cli_commands/config_command.rb +249 -0
- data/lib/ukiryu/cli_commands/describe_command.rb +326 -0
- data/lib/ukiryu/cli_commands/describe_command.rb.fixed +254 -0
- data/lib/ukiryu/cli_commands/exec_inline_command.rb.fixed +180 -0
- data/lib/ukiryu/cli_commands/extract_command.rb +84 -0
- data/lib/ukiryu/cli_commands/info_command.rb +156 -0
- data/lib/ukiryu/cli_commands/list_command.rb +70 -0
- data/lib/ukiryu/cli_commands/opts_command.rb +106 -0
- data/lib/ukiryu/cli_commands/opts_command.rb.fixed +105 -0
- data/lib/ukiryu/cli_commands/response_formatter.rb +240 -0
- data/lib/ukiryu/cli_commands/run_command.rb +375 -0
- data/lib/ukiryu/cli_commands/run_file_command.rb +215 -0
- data/lib/ukiryu/cli_commands/system_command.rb +90 -0
- data/lib/ukiryu/cli_commands/validate_command.rb +87 -0
- data/lib/ukiryu/cli_commands/version_command.rb +16 -0
- data/lib/ukiryu/cli_commands/which_command.rb +166 -0
- data/lib/ukiryu/command_builder.rb +205 -0
- data/lib/ukiryu/config/env_provider.rb +64 -0
- data/lib/ukiryu/config/env_schema.rb +63 -0
- data/lib/ukiryu/config/override_resolver.rb +68 -0
- data/lib/ukiryu/config/type_converter.rb +59 -0
- data/lib/ukiryu/config.rb +249 -0
- data/lib/ukiryu/errors.rb +3 -0
- data/lib/ukiryu/executable_locator.rb +114 -0
- data/lib/ukiryu/execution/command_info.rb +64 -0
- data/lib/ukiryu/execution/metadata.rb +97 -0
- data/lib/ukiryu/execution/output.rb +144 -0
- data/lib/ukiryu/execution/result.rb +194 -0
- data/lib/ukiryu/execution.rb +15 -0
- data/lib/ukiryu/execution_context.rb +251 -0
- data/lib/ukiryu/executor.rb +76 -493
- data/lib/ukiryu/extractors/base_extractor.rb +63 -0
- data/lib/ukiryu/extractors/extractor.rb +150 -0
- data/lib/ukiryu/extractors/help_parser.rb +188 -0
- data/lib/ukiryu/extractors/native_extractor.rb +47 -0
- data/lib/ukiryu/io.rb +196 -0
- data/lib/ukiryu/logger.rb +544 -0
- data/lib/ukiryu/models/argument.rb +28 -0
- data/lib/ukiryu/models/argument_definition.rb +119 -0
- data/lib/ukiryu/models/arguments.rb +113 -0
- data/lib/ukiryu/models/command_definition.rb +176 -0
- data/lib/ukiryu/models/command_info.rb +37 -0
- data/lib/ukiryu/models/components.rb +107 -0
- data/lib/ukiryu/models/env_var_definition.rb +30 -0
- data/lib/ukiryu/models/error_response.rb +41 -0
- data/lib/ukiryu/models/execution_metadata.rb +31 -0
- data/lib/ukiryu/models/execution_report.rb +236 -0
- data/lib/ukiryu/models/exit_codes.rb +74 -0
- data/lib/ukiryu/models/flag_definition.rb +67 -0
- data/lib/ukiryu/models/option_definition.rb +102 -0
- data/lib/ukiryu/models/output_info.rb +25 -0
- data/lib/ukiryu/models/platform_profile.rb +153 -0
- data/lib/ukiryu/models/routing.rb +211 -0
- data/lib/ukiryu/models/search_paths.rb +39 -0
- data/lib/ukiryu/models/success_response.rb +85 -0
- data/lib/ukiryu/models/tool_definition.rb +145 -0
- data/lib/ukiryu/models/tool_metadata.rb +82 -0
- data/lib/ukiryu/models/validation_result.rb +80 -0
- data/lib/ukiryu/models/version_compatibility.rb +152 -0
- data/lib/ukiryu/models/version_detection.rb +39 -0
- data/lib/ukiryu/models.rb +23 -0
- data/lib/ukiryu/options/base.rb +95 -0
- data/lib/ukiryu/options_builder/formatter.rb +87 -0
- data/lib/ukiryu/options_builder/validator.rb +43 -0
- data/lib/ukiryu/options_builder.rb +311 -0
- data/lib/ukiryu/platform.rb +6 -6
- data/lib/ukiryu/registry.rb +143 -183
- data/lib/ukiryu/response/base.rb +217 -0
- data/lib/ukiryu/runtime.rb +179 -0
- data/lib/ukiryu/schema_validator.rb +8 -10
- data/lib/ukiryu/shell/bash.rb +3 -3
- data/lib/ukiryu/shell/cmd.rb +4 -4
- data/lib/ukiryu/shell/fish.rb +1 -1
- data/lib/ukiryu/shell/powershell.rb +3 -3
- data/lib/ukiryu/shell/sh.rb +1 -1
- data/lib/ukiryu/shell/zsh.rb +1 -1
- data/lib/ukiryu/shell.rb +146 -39
- data/lib/ukiryu/thor_ext.rb +208 -0
- data/lib/ukiryu/tool.rb +649 -258
- data/lib/ukiryu/tool_index.rb +224 -0
- data/lib/ukiryu/tools/base.rb +381 -0
- data/lib/ukiryu/tools/class_generator.rb +132 -0
- data/lib/ukiryu/tools/executable_finder.rb +29 -0
- data/lib/ukiryu/tools/generator.rb +154 -0
- data/lib/ukiryu/tools.rb +109 -0
- data/lib/ukiryu/type.rb +28 -43
- data/lib/ukiryu/validation/constraints.rb +281 -0
- data/lib/ukiryu/validation/validator.rb +188 -0
- data/lib/ukiryu/validation.rb +21 -0
- data/lib/ukiryu/version.rb +1 -1
- data/lib/ukiryu/version_detector.rb +51 -0
- data/lib/ukiryu.rb +31 -15
- data/ukiryu-proposal.md +2952 -0
- data/ukiryu.gemspec +18 -14
- metadata +137 -5
- data/.github/workflows/test.yml +0 -143
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'shell'
|
|
4
|
+
require_relative 'type'
|
|
5
|
+
require_relative 'cache'
|
|
6
|
+
require_relative 'options_builder/formatter'
|
|
7
|
+
require_relative 'options_builder/validator'
|
|
8
|
+
|
|
9
|
+
module Ukiryu
|
|
10
|
+
# Builds structured option classes from tool profile metadata
|
|
11
|
+
#
|
|
12
|
+
# This module dynamically creates option classes based on YAML profile definitions,
|
|
13
|
+
# providing type-safe option building with shell serialization capabilities.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# # Get options class for a command
|
|
17
|
+
# options_class = Ukiryu::OptionsBuilder.for(:imagemagick, :convert)
|
|
18
|
+
# options = options_class.new
|
|
19
|
+
# options.inputs = ["input.png"]
|
|
20
|
+
# options.output = "output.jpg"
|
|
21
|
+
# options.resize = "50x50"
|
|
22
|
+
#
|
|
23
|
+
# # Serialize to shell command
|
|
24
|
+
# shell_args = options.to_shell(type: :bash)
|
|
25
|
+
module OptionsBuilder
|
|
26
|
+
class << self
|
|
27
|
+
# Get the options classes cache (bounded LRU cache)
|
|
28
|
+
#
|
|
29
|
+
# @return [Cache] the options classes cache
|
|
30
|
+
def option_classes_cache
|
|
31
|
+
@option_classes_cache ||= Cache.new(max_size: 100, ttl: 3600)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get or create an options class for a tool command
|
|
35
|
+
#
|
|
36
|
+
# @param tool_name [String, Symbol] the tool name
|
|
37
|
+
# @param command_name [String, Symbol] the command name
|
|
38
|
+
# @return [Class] the dynamically generated options class
|
|
39
|
+
def for(tool_name, command_name)
|
|
40
|
+
tool_name_sym = tool_name.to_sym
|
|
41
|
+
command_name_sym = command_name.to_sym
|
|
42
|
+
|
|
43
|
+
# Check if we've already created this class
|
|
44
|
+
cache_key = [tool_name_sym, command_name_sym]
|
|
45
|
+
cached = option_classes_cache[cache_key]
|
|
46
|
+
return cached if cached
|
|
47
|
+
|
|
48
|
+
# Get the tool and command profile
|
|
49
|
+
tool = Tool.get(tool_name_sym)
|
|
50
|
+
command_def = tool.command_definition(command_name_sym)
|
|
51
|
+
|
|
52
|
+
raise ArgumentError, "Unknown command: #{command_name} for tool: #{tool_name}" unless command_def
|
|
53
|
+
|
|
54
|
+
# Create the options class
|
|
55
|
+
options_class = create_options_class(tool_name_sym, command_name_sym, command_def)
|
|
56
|
+
option_classes_cache[cache_key] = options_class
|
|
57
|
+
options_class
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Clear the options class cache (mainly for testing)
|
|
61
|
+
#
|
|
62
|
+
# @api private
|
|
63
|
+
def clear_cache
|
|
64
|
+
option_classes_cache.clear
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Convert an options object to a hash for backward compatibility
|
|
68
|
+
#
|
|
69
|
+
# @param options [Object] an options object created by the options class
|
|
70
|
+
# @return [Hash] the options as a hash
|
|
71
|
+
def to_hash(options)
|
|
72
|
+
hash = {}
|
|
73
|
+
|
|
74
|
+
# Get the command definition from the options class
|
|
75
|
+
command_def = options.class.command_def
|
|
76
|
+
return {} unless command_def
|
|
77
|
+
|
|
78
|
+
# Extract all argument values
|
|
79
|
+
(command_def.arguments || []).each do |arg_def|
|
|
80
|
+
attr_name = arg_def.name
|
|
81
|
+
value = options.send(attr_name)
|
|
82
|
+
hash[attr_name.to_sym] = value unless value.nil?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Extract all option values
|
|
86
|
+
(command_def.options || []).each do |opt_def|
|
|
87
|
+
attr_name = opt_def.name
|
|
88
|
+
value = options.send(attr_name)
|
|
89
|
+
hash[attr_name.to_sym] = value unless value.nil?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Extract all flag values
|
|
93
|
+
(command_def.flags || []).each do |flag_def|
|
|
94
|
+
attr_name = flag_def.name
|
|
95
|
+
value = options.send(attr_name)
|
|
96
|
+
# Only include flags that are true
|
|
97
|
+
hash[attr_name.to_sym] = value if value
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Extract all post_option values
|
|
101
|
+
(command_def.post_options || []).each do |opt_def|
|
|
102
|
+
attr_name = opt_def.name
|
|
103
|
+
value = options.send(attr_name)
|
|
104
|
+
hash[attr_name.to_sym] = value unless value.nil?
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Include extra_args if present (for manual option injection)
|
|
108
|
+
hash[:extra_args] = options.extra_args if options.respond_to?(:extra_args) && !options.extra_args.nil?
|
|
109
|
+
|
|
110
|
+
hash
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Create a dynamic options class from command definition
|
|
114
|
+
#
|
|
115
|
+
# @param tool_name [Symbol] the tool name
|
|
116
|
+
# @param command_name [Symbol] the command name
|
|
117
|
+
# @param command_def [Hash] the command definition from profile
|
|
118
|
+
# @return [Class] the generated options class
|
|
119
|
+
def create_options_class(tool_name, command_name, command_def)
|
|
120
|
+
# Capture values in closure for singleton methods
|
|
121
|
+
cmd_def = command_def
|
|
122
|
+
t_name = tool_name
|
|
123
|
+
c_name = command_name
|
|
124
|
+
|
|
125
|
+
Class.new do
|
|
126
|
+
# Define class methods with closure access
|
|
127
|
+
singleton_class.send(:define_method, :command_def) do
|
|
128
|
+
cmd_def
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
singleton_class.send(:define_method, :tool_name) do
|
|
132
|
+
t_name
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
singleton_class.send(:define_method, :command_name) do
|
|
136
|
+
c_name
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Define attribute accessors for each argument and option
|
|
140
|
+
OptionsBuilder.define_accessors(self, command_def)
|
|
141
|
+
|
|
142
|
+
# Define to_shell method for serialization
|
|
143
|
+
OptionsBuilder.define_to_shell_method(self, command_def)
|
|
144
|
+
|
|
145
|
+
# Define validation method
|
|
146
|
+
OptionsBuilder::Validator.define_validation_method(self, command_def)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Define attribute accessors for arguments and options
|
|
151
|
+
#
|
|
152
|
+
# @param klass [Class] the class to define accessors on
|
|
153
|
+
# @param command_def [CommandDefinition] the command definition
|
|
154
|
+
def define_accessors(klass, command_def)
|
|
155
|
+
# Define accessors for arguments
|
|
156
|
+
(command_def.arguments || []).each do |arg_def|
|
|
157
|
+
attr_name = arg_def.name
|
|
158
|
+
# Create getter and setter
|
|
159
|
+
klass.define_method(attr_name) do
|
|
160
|
+
instance_variable_get("@#{attr_name}")
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
klass.define_method("#{attr_name}=") do |value|
|
|
164
|
+
# For variadic arguments, validate each element
|
|
165
|
+
validated = if arg_def.variadic && value.is_a?(Array)
|
|
166
|
+
value.map { |v| Type.validate(v, arg_def.type || :string, arg_def) }
|
|
167
|
+
else
|
|
168
|
+
Type.validate(value, arg_def.type || :string, arg_def)
|
|
169
|
+
end
|
|
170
|
+
instance_variable_set("@#{attr_name}", validated)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Define accessors for options
|
|
175
|
+
(command_def.options || []).each do |opt_def|
|
|
176
|
+
attr_name = opt_def.name
|
|
177
|
+
klass.define_method(attr_name) do
|
|
178
|
+
instance_variable_get("@#{attr_name}")
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
klass.define_method("#{attr_name}=") do |value|
|
|
182
|
+
# Skip if nil (optional option not set)
|
|
183
|
+
return if value.nil?
|
|
184
|
+
|
|
185
|
+
# Validate and coerce the value
|
|
186
|
+
validated = Type.validate(value, opt_def.type || :string, opt_def)
|
|
187
|
+
instance_variable_set("@#{attr_name}", validated)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Define accessors for flags
|
|
192
|
+
(command_def.flags || []).each do |flag_def|
|
|
193
|
+
attr_name = flag_def.name
|
|
194
|
+
klass.define_method(attr_name) do
|
|
195
|
+
instance_variable_get("@#{attr_name}")
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
klass.define_method("#{attr_name}=") do |value|
|
|
199
|
+
instance_variable_set("@#{attr_name}", !!value)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Define accessors for post_options
|
|
204
|
+
(command_def.post_options || []).each do |opt_def|
|
|
205
|
+
attr_name = opt_def.name
|
|
206
|
+
klass.define_method(attr_name) do
|
|
207
|
+
instance_variable_get("@#{attr_name}")
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
klass.define_method("#{attr_name}=") do |value|
|
|
211
|
+
return if value.nil?
|
|
212
|
+
|
|
213
|
+
validated = Type.validate(value, opt_def.type || :string, opt_def)
|
|
214
|
+
instance_variable_set("@#{attr_name}", validated)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Define to_shell method for command serialization
|
|
220
|
+
#
|
|
221
|
+
# @param klass [Class] the class to define the method on
|
|
222
|
+
# @param command_def [CommandDefinition] the command definition
|
|
223
|
+
def define_to_shell_method(klass, command_def)
|
|
224
|
+
klass.define_method(:to_shell) do |shell_type: :bash|
|
|
225
|
+
shell_type = shell_type.to_sym
|
|
226
|
+
shell_class = Shell.class_for(shell_type)
|
|
227
|
+
shell_instance = shell_class.new
|
|
228
|
+
|
|
229
|
+
args = []
|
|
230
|
+
|
|
231
|
+
# Add subcommand if present
|
|
232
|
+
args << command_def.subcommand if command_def.subcommand
|
|
233
|
+
|
|
234
|
+
# Add options (before arguments)
|
|
235
|
+
(command_def.options || []).each do |opt_def|
|
|
236
|
+
attr_name = opt_def.name
|
|
237
|
+
value = instance_variable_get("@#{attr_name}")
|
|
238
|
+
next if value.nil? # Skip unset options
|
|
239
|
+
|
|
240
|
+
formatted = Formatter.format_option(opt_def, value, shell_instance)
|
|
241
|
+
Array(formatted).each { |a| args << a unless a.nil? || a.empty? }
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Add flags
|
|
245
|
+
(command_def.flags || []).each do |flag_def|
|
|
246
|
+
attr_name = flag_def.name
|
|
247
|
+
value = instance_variable_get("@#{attr_name}")
|
|
248
|
+
|
|
249
|
+
# Use default if not set
|
|
250
|
+
value = flag_def.default if value.nil?
|
|
251
|
+
next unless value
|
|
252
|
+
|
|
253
|
+
formatted = Formatter.format_flag(flag_def, shell_instance)
|
|
254
|
+
Array(formatted).each { |f| args << f unless f.nil? || f.empty? }
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Separate "last" positioned argument from other arguments
|
|
258
|
+
arguments = command_def.arguments || []
|
|
259
|
+
last_arg = arguments.find { |a| ['last', :last].include?(a.position) }
|
|
260
|
+
regular_args = arguments.reject { |a| ['last', :last].include?(a.position) }
|
|
261
|
+
|
|
262
|
+
# Add regular positional arguments (in order)
|
|
263
|
+
regular_args.sort_by do |a|
|
|
264
|
+
pos = a.position
|
|
265
|
+
pos.is_a?(Integer) ? pos : (pos || 99)
|
|
266
|
+
end.each do |arg_def|
|
|
267
|
+
attr_name = arg_def.name
|
|
268
|
+
value = instance_variable_get("@#{attr_name}")
|
|
269
|
+
next if value.nil?
|
|
270
|
+
|
|
271
|
+
if arg_def.variadic
|
|
272
|
+
Array(value).each do |v|
|
|
273
|
+
args << Formatter.format_arg(v, arg_def, shell_instance)
|
|
274
|
+
end
|
|
275
|
+
else
|
|
276
|
+
args << Formatter.format_arg(value, arg_def, shell_instance)
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Add post_options (between regular args and last arg)
|
|
281
|
+
(command_def.post_options || []).each do |opt_def|
|
|
282
|
+
attr_name = opt_def.name
|
|
283
|
+
value = instance_variable_get("@#{attr_name}")
|
|
284
|
+
next if value.nil?
|
|
285
|
+
|
|
286
|
+
formatted = Formatter.format_option(opt_def, value, shell_instance)
|
|
287
|
+
Array(formatted).each { |a| args << a unless a.nil? || a.empty? }
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Add the "last" positioned argument (typically output)
|
|
291
|
+
if last_arg
|
|
292
|
+
attr_name = last_arg.name
|
|
293
|
+
value = instance_variable_get("@#{attr_name}")
|
|
294
|
+
if value
|
|
295
|
+
if last_arg.variadic
|
|
296
|
+
Array(value).each do |v|
|
|
297
|
+
args << Formatter.format_arg(v, last_arg, shell_instance)
|
|
298
|
+
end
|
|
299
|
+
else
|
|
300
|
+
args << Formatter.format_arg(value, last_arg, shell_instance)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Join into command string
|
|
306
|
+
shell_instance.join(*args)
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|
data/lib/ukiryu/platform.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Ukiryu
|
|
|
20
20
|
:linux
|
|
21
21
|
else
|
|
22
22
|
# Try to determine from RbConfig
|
|
23
|
-
host_os = RbConfig::CONFIG[
|
|
23
|
+
host_os = RbConfig::CONFIG['host_os']
|
|
24
24
|
case host_os
|
|
25
25
|
when /mswin|mingw|windows/i
|
|
26
26
|
:windows
|
|
@@ -47,21 +47,21 @@ module Ukiryu
|
|
|
47
47
|
#
|
|
48
48
|
# @return [Boolean]
|
|
49
49
|
def windows?
|
|
50
|
-
Gem.win_platform? || RbConfig::CONFIG[
|
|
50
|
+
Gem.win_platform? || RbConfig::CONFIG['host_os'] =~ /mswin|mingw|windows/i
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
# Check if running on macOS
|
|
54
54
|
#
|
|
55
55
|
# @return [Boolean]
|
|
56
56
|
def macos?
|
|
57
|
-
RbConfig::CONFIG[
|
|
57
|
+
RbConfig::CONFIG['host_os'] =~ /darwin|mac os/i
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
# Check if running on Linux
|
|
61
61
|
#
|
|
62
62
|
# @return [Boolean]
|
|
63
63
|
def linux?
|
|
64
|
-
RbConfig::CONFIG[
|
|
64
|
+
RbConfig::CONFIG['host_os'] =~ /linux/i
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
# Check if running on a Unix-like system (macOS or Linux)
|
|
@@ -77,8 +77,8 @@ module Ukiryu
|
|
|
77
77
|
# @return [Array<String>] array of directory paths
|
|
78
78
|
def executable_search_paths
|
|
79
79
|
@executable_search_paths ||= begin
|
|
80
|
-
path_sep = windows? ?
|
|
81
|
-
(ENV[
|
|
80
|
+
path_sep = windows? ? ';' : ':'
|
|
81
|
+
(ENV['PATH'] || '').split(path_sep)
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|