Class: Ukiryu::Environment

Inherits:
Object
  • Object
show all
Defined in:
lib/ukiryu/environment.rb

Overview

Environment represents a set of environment variables for command execution.

This class provides an immutable, functional-style interface for managing environment variables. All write operations return a new Environment instance, preserving the original.

Usage

Create from various sources:

env = Environment.system              # Empty environment
env = Environment.from_env            # Inherit current process ENV
env = Environment.new({ 'PATH' => '...' })  # From hash

Manipulate immutably:

new_env = env.set('VAR', 'value')
new_env = env.delete('VAR')
new_env = env.merge(other_env)

PATH utilities (Unix-style colon separator):

new_env = env.prepend_path('/new/bin')
new_env = env.append_path('/new/bin')
new_env = env.remove_path('/old/bin')

Convert to hash for execution:

hash = env.to_h

Constant Summary collapse

SEPARATOR =
':'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env = {}) ⇒ Environment

Create a new Environment instance

Parameters:

  • env (Hash{String => String}) (defaults to: {})

    initial environment variables



37
38
39
# File 'lib/ukiryu/environment.rb', line 37

def initialize(env = {})
  @env = env.dup.freeze
end

Class Method Details

.from_envEnvironment

Create an environment that inherits from the current process ENV

Returns:



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/ukiryu/environment.rb', line 51

def self.from_env
  # On Windows, ENV.to_h might not include PATH due to case sensitivity
  # issues. Ensure PATH is always included by explicitly checking for it.
  env_hash = ENV.to_h.dup

  # Ensure PATH is included (check case-insensitively on Windows)
  unless env_hash.key?('PATH')
    # Look for Path, path, etc. on Windows
    ENV.each_key do |key|
      if key.upcase == 'PATH'
        env_hash['PATH'] = ENV[key]
        break
      end
    end
  end

  new(env_hash)
end

.systemEnvironment

Create an empty environment (no inherited variables)

Returns:



44
45
46
# File 'lib/ukiryu/environment.rb', line 44

def self.system
  new({})
end

Instance Method Details

#==(other) ⇒ Boolean

Equality check

Parameters:

  • other (Object)

    object to compare

Returns:

  • (Boolean)

    true if equal



198
199
200
201
202
# File 'lib/ukiryu/environment.rb', line 198

def ==(other)
  return false unless other.is_a?(Environment)

  @env == other.instance_variable_get(:@env)
end

#[](key) ⇒ String?

Get a value from the environment

Parameters:

  • key (String, Symbol)

    the variable name

Returns:

  • (String, nil)

    the value or nil if not set



74
75
76
# File 'lib/ukiryu/environment.rb', line 74

def [](key)
  @env[key.to_s]
end

#append_path(additions) ⇒ Environment

Append one or more directories to PATH

Handles Unix-style colon-separated PATH. Directories are added to the end of PATH, so existing directories take precedence.

Parameters:

  • additions (String, Array<String>)

    directory or directories to append

Returns:



150
151
152
153
154
155
156
# File 'lib/ukiryu/environment.rb', line 150

def append_path(additions)
  additions_arr = Array(additions)
  additions_str = additions_arr.join(SEPARATOR)
  existing = @env['PATH'] || ''
  new_path = existing.empty? ? additions_str : "#{existing}#{SEPARATOR}#{additions_str}"
  self.class.new(@env.merge('PATH' => new_path))
end

#delete(key) ⇒ Environment

Delete a variable

Parameters:

  • key (String, Symbol)

    the variable name

Returns:

  • (Environment)

    new environment without the variable



113
114
115
116
117
# File 'lib/ukiryu/environment.rb', line 113

def delete(key)
  new_env = @env.dup
  new_env.delete(key.to_s)
  self.class.new(new_env)
end

#hashInteger

Hash representation for hashing (e.g., use in Hash as key)

Returns:

  • (Integer)

    hash value



214
215
216
# File 'lib/ukiryu/environment.rb', line 214

def hash
  @env.hash
end

#inspectString

String representation for debugging

Returns:

  • (String)

    summary of environment



207
208
209
# File 'lib/ukiryu/environment.rb', line 207

def inspect
  "#<Ukiryu::Environment keys=#{@env.keys.size}>"
end

#key?(key) ⇒ Boolean

Check if a key exists in the environment

Parameters:

  • key (String, Symbol)

    the variable name

Returns:

  • (Boolean)

    true if the key exists



82
83
84
# File 'lib/ukiryu/environment.rb', line 82

def key?(key)
  @env.key?(key.to_s)
end

#keysArray<String>

Get all keys in the environment

Returns:

  • (Array<String>)

    array of variable names



89
90
91
# File 'lib/ukiryu/environment.rb', line 89

def keys
  @env.keys
end

#merge(other) ⇒ Environment

Merge another environment or hash

Parameters:

  • other (Environment, Hash)

    the environment or hash to merge

Returns:



123
124
125
126
# File 'lib/ukiryu/environment.rb', line 123

def merge(other)
  other_hash = other.is_a?(Environment) ? other.to_h : other
  self.class.new(@env.merge(other_hash))
end

#path_arrayArray<String>

Get the PATH as an array

Returns:

  • (Array<String>)

    array of directories in PATH



190
191
192
# File 'lib/ukiryu/environment.rb', line 190

def path_array
  (@env['PATH'] || '').split(SEPARATOR)
end

#path_contains?(directory) ⇒ Boolean

Check if PATH contains a directory

Parameters:

  • directory (String)

    directory to check

Returns:

  • (Boolean)

    true if directory is in PATH



181
182
183
184
185
# File 'lib/ukiryu/environment.rb', line 181

def path_contains?(directory)
  return false unless @env['PATH']

  @env['PATH'].split(SEPARATOR).include?(directory)
end

#prepend_path(additions) ⇒ Environment

Prepend one or more directories to PATH

Handles Unix-style colon-separated PATH. Directories are added to the beginning of PATH, so they are searched first.

Parameters:

  • additions (String, Array<String>)

    directory or directories to prepend

Returns:



135
136
137
138
139
140
141
# File 'lib/ukiryu/environment.rb', line 135

def prepend_path(additions)
  additions_arr = Array(additions)
  additions_str = additions_arr.join(SEPARATOR)
  existing = @env['PATH'] || ''
  new_path = existing.empty? ? additions_str : "#{additions_str}#{SEPARATOR}#{existing}"
  self.class.new(@env.merge('PATH' => new_path))
end

#remove_path(directory) ⇒ Environment

Remove a directory from PATH

Removes all occurrences of the specified directory from PATH. Uses prefix matching to handle cases like removing ‘/opt’ which should also remove ‘/opt/bin’, ‘/opt/local/bin’, etc.

Parameters:

  • directory (String)

    directory prefix to remove

Returns:



166
167
168
169
170
171
172
173
174
175
# File 'lib/ukiryu/environment.rb', line 166

def remove_path(directory)
  existing = @env['PATH'] || ''
  # Remove trailing slash for consistent comparison
  dir = directory.end_with?('/') ? directory[0..-2] : directory
  path_parts = existing.split(SEPARATOR).reject do |part|
    part == dir || part.start_with?("#{dir}/")
  end
  new_path = path_parts.join(SEPARATOR)
  self.class.new(@env.merge('PATH' => new_path))
end

#set(key, value) ⇒ Environment

Set or update a variable

Parameters:

  • key (String, Symbol)

    the variable name

  • value (String)

    the value to set

Returns:

  • (Environment)

    new environment with the variable set



105
106
107
# File 'lib/ukiryu/environment.rb', line 105

def set(key, value)
  self.class.new(@env.merge(key.to_s => value.to_s))
end

#to_hHash{String => String}

Convert to a plain hash (for execution)

Returns:

  • (Hash{String => String})

    mutable copy of environment



96
97
98
# File 'lib/ukiryu/environment.rb', line 96

def to_h
  @env.dup
end