markdown_exec 3.0.4 → 3.0.6
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 +22 -0
- data/Gemfile.lock +1 -1
- data/bats/block-type-ux-act-init.bats +17 -0
- data/bats/block-type-ux-echo-hash-transform.bats +8 -0
- data/bats/block-type-ux-echo.bats +1 -1
- data/bats/block-type-ux-sources.bats +1 -1
- data/bats/block-type-ux-transform.bats +1 -1
- data/bats/import-conflict.bats +11 -0
- data/bats/import-duplicates.bats +53 -0
- data/bats/variable-expansion-multiline.bats +1 -1
- data/bin/bmde +4 -3
- data/docs/dev/block-type-ux-act-init.md +187 -0
- data/docs/dev/block-type-ux-auto.md +0 -1
- data/docs/dev/block-type-ux-default.md +2 -2
- data/docs/dev/block-type-ux-echo-hash-transform.md +40 -0
- data/docs/dev/block-type-ux-echo.md +3 -0
- data/docs/dev/block-type-ux-exec.md +0 -1
- data/docs/dev/block-type-ux-sources.md +1 -1
- data/docs/dev/block-type-ux-transform.md +5 -4
- data/docs/dev/command-substitution.md +1 -0
- data/docs/dev/import-conflict-0.md +12 -0
- data/docs/dev/import-conflict-1.md +7 -0
- data/docs/dev/import-duplicates-0.md +17 -0
- data/docs/dev/import-duplicates-1.md +13 -0
- data/docs/dev/load_code.md +1 -0
- data/docs/dev/no-active-elements.md +1 -0
- data/docs/dev/variable-expansion-multiline.md +4 -1
- data/docs/ux-blocks-examples.md +120 -0
- data/docs/ux-blocks-init-act.md +100 -0
- data/lib/command_result.rb +51 -0
- data/lib/command_result_alternatives.rb +233 -0
- data/lib/env_interface.rb +57 -0
- data/lib/fcb.rb +1 -1
- data/lib/hash_delegator.rb +207 -123
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/resize_terminal.rb +11 -5
- data/lib/ww.rb +4 -1
- metadata +16 -2
@@ -0,0 +1,120 @@
|
|
1
|
+
# UX Block Examples
|
2
|
+
|
3
|
+
This file contains a collection of unique UX block examples from the documentation.
|
4
|
+
|
5
|
+
## Basic Examples
|
6
|
+
|
7
|
+
### Simple Variable Display and Edit
|
8
|
+
```ux
|
9
|
+
init: Guest
|
10
|
+
name: USER_NAME
|
11
|
+
prompt: Enter your name
|
12
|
+
```
|
13
|
+
|
14
|
+
### Command Output Initialization
|
15
|
+
```ux
|
16
|
+
name: CURRENT_DIR
|
17
|
+
init: :exec
|
18
|
+
exec: basename $(pwd)
|
19
|
+
transform: :chomp
|
20
|
+
```
|
21
|
+
|
22
|
+
### Echo-based Initialization
|
23
|
+
```ux
|
24
|
+
name: SHELL_VERSION
|
25
|
+
init: :echo
|
26
|
+
echo: $SHELL
|
27
|
+
```
|
28
|
+
|
29
|
+
### Selection from Allowed Values
|
30
|
+
```ux
|
31
|
+
name: ENVIRONMENT
|
32
|
+
allow:
|
33
|
+
- development
|
34
|
+
- staging
|
35
|
+
- production
|
36
|
+
prompt: Select environment
|
37
|
+
```
|
38
|
+
|
39
|
+
## Validation Examples
|
40
|
+
|
41
|
+
### Email Validation
|
42
|
+
```ux
|
43
|
+
name: USER_EMAIL
|
44
|
+
prompt: Enter email address
|
45
|
+
validate: '(?<local>[^@]+)@(?<domain>[^@]+)'
|
46
|
+
transform: '%{local}@%{domain}'
|
47
|
+
```
|
48
|
+
|
49
|
+
### Version Number Validation
|
50
|
+
```ux
|
51
|
+
name: VERSION
|
52
|
+
prompt: Enter version number
|
53
|
+
validate: '(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)'
|
54
|
+
transform: '%{major}.%{minor}.%{patch}'
|
55
|
+
```
|
56
|
+
|
57
|
+
## Complex Examples
|
58
|
+
|
59
|
+
### Git Branch Selection with Validation
|
60
|
+
```ux
|
61
|
+
name: BRANCH_NAME
|
62
|
+
init: ":exec"
|
63
|
+
exec: "git branch --format='%(refname:short)'"
|
64
|
+
validate: "^(?<type>feature|bugfix|hotfix)/(?<ticket>[A-Z]+-\d+)-(?<desc>.+)$"
|
65
|
+
transform: "${type}/${ticket}-${desc}"
|
66
|
+
prompt: "Select or enter branch name"
|
67
|
+
```
|
68
|
+
|
69
|
+
### Environment Configuration with Dependencies
|
70
|
+
```ux
|
71
|
+
name: DATABASE_URL
|
72
|
+
require:
|
73
|
+
- ENVIRONMENT
|
74
|
+
- DB_HOST
|
75
|
+
- DB_PORT
|
76
|
+
format: "postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
77
|
+
```
|
78
|
+
|
79
|
+
### Multi-step Configuration
|
80
|
+
```ux
|
81
|
+
name: DEPLOY_CONFIG
|
82
|
+
require:
|
83
|
+
- ENVIRONMENT
|
84
|
+
- VERSION
|
85
|
+
init: ":echo"
|
86
|
+
echo: "Deploying ${VERSION} to ${ENVIRONMENT}"
|
87
|
+
act: ":exec"
|
88
|
+
exec: "deploy.sh ${ENVIRONMENT} ${VERSION}"
|
89
|
+
```
|
90
|
+
|
91
|
+
### Conditional Initialization
|
92
|
+
```ux
|
93
|
+
name: API_KEY
|
94
|
+
init: ":allow"
|
95
|
+
allow:
|
96
|
+
- ${PROD_API_KEY}
|
97
|
+
- ${STAGING_API_KEY}
|
98
|
+
- ${DEV_API_KEY}
|
99
|
+
require:
|
100
|
+
- ENVIRONMENT
|
101
|
+
```
|
102
|
+
|
103
|
+
### Formatted Output with Validation
|
104
|
+
```ux
|
105
|
+
name: PHONE_NUMBER
|
106
|
+
prompt: "Enter phone number"
|
107
|
+
validate: "(?<country>\d{1,3})(?<area>\d{3})(?<number>\d{7})"
|
108
|
+
transform: "+${country} (${area}) ${number}"
|
109
|
+
format: "Phone: ${PHONE_NUMBER}"
|
110
|
+
```
|
111
|
+
|
112
|
+
### Command Output with Transformation
|
113
|
+
```ux
|
114
|
+
name: GIT_STATUS
|
115
|
+
init: ":exec"
|
116
|
+
exec: "git status --porcelain"
|
117
|
+
validate: "(?<status>[AMDR])\s+(?<file>.+)"
|
118
|
+
transform: "${status}: ${file}"
|
119
|
+
format: "Changes: ${GIT_STATUS}"
|
120
|
+
```
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# UX Block Init and Act Keys
|
2
|
+
|
3
|
+
The `init` and `act` keys determine which other key is read for processing during initialization and activation respectively.
|
4
|
+
|
5
|
+
## Algorithm
|
6
|
+
|
7
|
+
1. **Init Phase** (when document is loaded) per FCB.init_source:
|
8
|
+
- If `init` is `false`: No initialization occurs
|
9
|
+
- If `init` is a string: That string becomes the initial value
|
10
|
+
- If `init` is `:allow`: First value from `allow` list is used
|
11
|
+
- If `init` is `:echo`: Value from `echo` key is evaluated and returned
|
12
|
+
- If `init` is `:exec`: Command from `exec` key is executed and stdout is returned
|
13
|
+
- If `init` is not present: Defaults to first available in order:
|
14
|
+
- `:allow` if `allow` exists
|
15
|
+
- `:default` if `default` exists
|
16
|
+
- `:echo` if `echo` exists
|
17
|
+
- `:exec` if `exec` exists
|
18
|
+
- `false` if none of the above exist
|
19
|
+
|
20
|
+
2. **Act Phase** (when block is activated) per FCB.act_source:
|
21
|
+
- If `act` is `false`: Block cannot be activated
|
22
|
+
- If `act` is `:allow`: User selects from `allow` list
|
23
|
+
- If `act` is `:echo`: Value from `echo` key is evaluated and returned
|
24
|
+
- If `act` is `:edit`: User is prompted for input
|
25
|
+
- If `act` is `:exec`: Command from `exec` key is executed and stdout is returned
|
26
|
+
- If `act` is not present: Defaults to:
|
27
|
+
- If `init` is `false`:
|
28
|
+
- First available in order: `:allow`, `:echo`, `:edit`, `:exec`
|
29
|
+
- Otherwise:
|
30
|
+
- `:allow` if `allow` exists
|
31
|
+
- `:edit` if `allow` does not exist
|
32
|
+
|
33
|
+
## Examples
|
34
|
+
|
35
|
+
### Echo on Init, Exec on Act
|
36
|
+
```ux
|
37
|
+
name: DEPLOY_CONFIG
|
38
|
+
init: :echo
|
39
|
+
echo: "Deploying ${VERSION} to ${ENVIRONMENT}"
|
40
|
+
act: :exec
|
41
|
+
exec: "deploy.sh ${ENVIRONMENT} ${VERSION}"
|
42
|
+
```
|
43
|
+
Behavior:
|
44
|
+
- On init: Evaluates echo string "Deploying ${VERSION} to ${ENVIRONMENT}"
|
45
|
+
- On act: Executes deploy.sh with environment and version parameters
|
46
|
+
|
47
|
+
### Allow on Init, Edit on Act
|
48
|
+
```ux
|
49
|
+
name: ENVIRONMENT
|
50
|
+
init: :allow
|
51
|
+
allow:
|
52
|
+
- development
|
53
|
+
- staging
|
54
|
+
- production
|
55
|
+
act: :edit
|
56
|
+
prompt: Select environment
|
57
|
+
```
|
58
|
+
Behavior:
|
59
|
+
- On init: Uses first allowed value (development)
|
60
|
+
- On act: Prompts user to select from allowed values
|
61
|
+
|
62
|
+
### Exec on Init, Echo on Act
|
63
|
+
```ux
|
64
|
+
name: CURRENT_DIR
|
65
|
+
init: :exec
|
66
|
+
exec: basename $(pwd)
|
67
|
+
act: :echo
|
68
|
+
echo: "Current directory: ${CURRENT_DIR}"
|
69
|
+
```
|
70
|
+
Behavior:
|
71
|
+
- On init: Executes basename command on current directory
|
72
|
+
- On act: Evaluates echo string with current directory value
|
73
|
+
|
74
|
+
### Allow on Both
|
75
|
+
```ux
|
76
|
+
name: API_KEY
|
77
|
+
init: :allow
|
78
|
+
allow:
|
79
|
+
- ${PROD_API_KEY}
|
80
|
+
- ${STAGING_API_KEY}
|
81
|
+
- ${DEV_API_KEY}
|
82
|
+
act: :allow
|
83
|
+
require:
|
84
|
+
- ENVIRONMENT
|
85
|
+
```
|
86
|
+
Behavior:
|
87
|
+
- On init: Uses first allowed API key
|
88
|
+
- On act: Shows menu of allowed API keys for selection
|
89
|
+
|
90
|
+
### Echo on Both
|
91
|
+
```ux
|
92
|
+
name: SHELL_VERSION
|
93
|
+
init: :echo
|
94
|
+
echo: $SHELL
|
95
|
+
act: :echo
|
96
|
+
echo: "Using shell: ${SHELL_VERSION}"
|
97
|
+
```
|
98
|
+
Behavior:
|
99
|
+
- On init: Gets shell value from environment
|
100
|
+
- On act: Evaluates echo string with current shell value
|
data/lib/command_result.rb
CHANGED
@@ -14,6 +14,45 @@
|
|
14
14
|
# result.new_field = 42
|
15
15
|
# result.new_field # => 42
|
16
16
|
# result.success? # => true
|
17
|
+
|
18
|
+
# require 'ostruct'
|
19
|
+
|
20
|
+
# class CommandResult < OpenStruct
|
21
|
+
# def initialize(**attributes)
|
22
|
+
# # Set defaults
|
23
|
+
# defaults = { exit_status: 0, stdout: '' }
|
24
|
+
# super(defaults.merge(attributes))
|
25
|
+
# end
|
26
|
+
|
27
|
+
# def failure?
|
28
|
+
# !success?
|
29
|
+
# end
|
30
|
+
|
31
|
+
# def success?
|
32
|
+
# exit_status.zero?
|
33
|
+
# end
|
34
|
+
|
35
|
+
# # intercept specific getters and setters
|
36
|
+
# def new_lines
|
37
|
+
# # read current value
|
38
|
+
# # binding.irb
|
39
|
+
# v = self[:new_lines]
|
40
|
+
# ww caller.deref[0..4], v
|
41
|
+
# v
|
42
|
+
# end
|
43
|
+
|
44
|
+
# # Intercept specific setter
|
45
|
+
# def new_lines=(value)
|
46
|
+
# ww caller.deref[0..4], value
|
47
|
+
# # binding.irb
|
48
|
+
# super(value)
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
17
56
|
class CommandResult
|
18
57
|
# @param attributes [Hash{Symbol=>Object}] initial named attributes
|
19
58
|
def initialize(**attributes)
|
@@ -32,6 +71,18 @@ class CommandResult
|
|
32
71
|
exit_status.zero?
|
33
72
|
end
|
34
73
|
|
74
|
+
def new_lines
|
75
|
+
value = @attributes[:new_lines]
|
76
|
+
ww caller.deref[0..4], value
|
77
|
+
value
|
78
|
+
end
|
79
|
+
|
80
|
+
# trap assignment to new_lines
|
81
|
+
def new_lines=(value)
|
82
|
+
ww caller.deref[0..4], value
|
83
|
+
@attributes[:new_lines] = value
|
84
|
+
end
|
85
|
+
|
35
86
|
def method_missing(name, *args)
|
36
87
|
key = name.to_s.chomp('=').to_sym
|
37
88
|
|
@@ -0,0 +1,233 @@
|
|
1
|
+
#!/usr/bin/env -S bundle exec ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# encoding=utf-8
|
5
|
+
|
6
|
+
# Alternative implementations of CommandResult that provide the same specs
|
7
|
+
|
8
|
+
# Option 1: Using OpenStruct as base with method overrides
|
9
|
+
require 'ostruct'
|
10
|
+
|
11
|
+
class CommandResultOpenStruct < OpenStruct
|
12
|
+
def initialize(**attributes)
|
13
|
+
# Set defaults
|
14
|
+
defaults = { exit_status: 0, stdout: '' }
|
15
|
+
super(defaults.merge(attributes))
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure?
|
19
|
+
!success?
|
20
|
+
end
|
21
|
+
|
22
|
+
def success?
|
23
|
+
exit_status.zero?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Intercept specific setter
|
27
|
+
def new_lines=(value)
|
28
|
+
warn caller.deref[0..4], value
|
29
|
+
super(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Option 2: Using instance variables with define_method
|
34
|
+
class CommandResultInstanceVars
|
35
|
+
def initialize(**attributes)
|
36
|
+
@exit_status = 0
|
37
|
+
@stdout = ''
|
38
|
+
|
39
|
+
attributes.each do |name, value|
|
40
|
+
instance_variable_set("@#{name}", value)
|
41
|
+
|
42
|
+
# Define getter and setter methods dynamically
|
43
|
+
self.class.define_method(name) do
|
44
|
+
instance_variable_get("@#{name}")
|
45
|
+
end
|
46
|
+
|
47
|
+
self.class.define_method("#{name}=") do |val|
|
48
|
+
instance_variable_set("@#{name}", val)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def failure?
|
54
|
+
!success?
|
55
|
+
end
|
56
|
+
|
57
|
+
def success?
|
58
|
+
exit_status.zero?
|
59
|
+
end
|
60
|
+
|
61
|
+
# Intercept specific setter
|
62
|
+
def new_lines=(value)
|
63
|
+
warn caller.deref[0..4], value
|
64
|
+
@new_lines = value
|
65
|
+
end
|
66
|
+
|
67
|
+
def method_missing(name, *args)
|
68
|
+
if name.to_s.end_with?('=')
|
69
|
+
# Setter
|
70
|
+
attr_name = name.to_s.chomp('=')
|
71
|
+
instance_variable_set("@#{attr_name}", args.first)
|
72
|
+
|
73
|
+
# Define methods for future use
|
74
|
+
self.class.define_method(attr_name) do
|
75
|
+
instance_variable_get("@#{attr_name}")
|
76
|
+
end
|
77
|
+
|
78
|
+
self.class.define_method(name) do |val|
|
79
|
+
instance_variable_set("@#{attr_name}", val)
|
80
|
+
end
|
81
|
+
else
|
82
|
+
# Getter
|
83
|
+
if instance_variable_defined?("@#{name}")
|
84
|
+
instance_variable_get("@#{name}")
|
85
|
+
else
|
86
|
+
super
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def respond_to_missing?(name, include_private = false)
|
92
|
+
attr_name = name.to_s.chomp('=').to_sym
|
93
|
+
instance_variable_defined?("@#{attr_name}") || super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Option 3: Using Struct with dynamic extension
|
98
|
+
class CommandResultStruct
|
99
|
+
def self.new(**attributes)
|
100
|
+
# Create a Struct class with the given attributes plus defaults
|
101
|
+
defaults = { exit_status: 0, stdout: '' }
|
102
|
+
all_attrs = defaults.merge(attributes)
|
103
|
+
|
104
|
+
struct_class = Struct.new(*all_attrs.keys, keyword_init: true) do
|
105
|
+
def failure?
|
106
|
+
!success?
|
107
|
+
end
|
108
|
+
|
109
|
+
def success?
|
110
|
+
exit_status.zero?
|
111
|
+
end
|
112
|
+
|
113
|
+
# Intercept specific setter
|
114
|
+
def new_lines=(value)
|
115
|
+
warn caller.deref[0..4], value
|
116
|
+
super(value)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Add dynamic attribute support
|
120
|
+
def method_missing(name, *args)
|
121
|
+
if name.to_s.end_with?('=')
|
122
|
+
# Add new attribute dynamically by recreating struct
|
123
|
+
attr_name = name.to_s.chomp('=').to_sym
|
124
|
+
current_attrs = to_h
|
125
|
+
current_attrs[attr_name] = args.first
|
126
|
+
|
127
|
+
# This is a limitation - we can't easily add new fields to existing Struct
|
128
|
+
# So this approach has constraints
|
129
|
+
super
|
130
|
+
else
|
131
|
+
super
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
struct_class.new(**all_attrs)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Option 4: Using SimpleDelegator with Hash
|
141
|
+
require 'delegate'
|
142
|
+
|
143
|
+
class CommandResultDelegator < SimpleDelegator
|
144
|
+
def initialize(**attributes)
|
145
|
+
defaults = { exit_status: 0, stdout: '' }
|
146
|
+
@hash = defaults.merge(attributes)
|
147
|
+
super(@hash)
|
148
|
+
end
|
149
|
+
|
150
|
+
def failure?
|
151
|
+
!success?
|
152
|
+
end
|
153
|
+
|
154
|
+
def success?
|
155
|
+
self[:exit_status].zero?
|
156
|
+
end
|
157
|
+
|
158
|
+
# Intercept specific setter
|
159
|
+
def new_lines=(value)
|
160
|
+
warn caller.deref[0..4], value
|
161
|
+
self[:new_lines] = value
|
162
|
+
end
|
163
|
+
|
164
|
+
def method_missing(name, *args)
|
165
|
+
key = name.to_s.chomp('=').to_sym
|
166
|
+
|
167
|
+
if name.to_s.end_with?('=') # setter
|
168
|
+
self[key] = args.first
|
169
|
+
elsif key?(key) # getter
|
170
|
+
self[key]
|
171
|
+
else
|
172
|
+
super
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def respond_to_missing?(name, include_private = false)
|
177
|
+
key = name.to_s.chomp('=').to_sym
|
178
|
+
key?(key) || super
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Option 5: Using refinements for cleaner method_missing
|
183
|
+
module AttributeAccess
|
184
|
+
refine Hash do
|
185
|
+
def method_missing(name, *args)
|
186
|
+
key = name.to_s.chomp('=').to_sym
|
187
|
+
|
188
|
+
if name.to_s.end_with?('=') # setter
|
189
|
+
self[key] = args.first
|
190
|
+
elsif key?(key) # getter
|
191
|
+
self[key]
|
192
|
+
else
|
193
|
+
super
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def respond_to_missing?(name, include_private = false)
|
198
|
+
key = name.to_s.chomp('=').to_sym
|
199
|
+
key?(key) || super
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
class CommandResultRefined
|
205
|
+
using AttributeAccess
|
206
|
+
|
207
|
+
def initialize(**attributes)
|
208
|
+
@attributes = { exit_status: 0, stdout: '' }.merge(attributes)
|
209
|
+
@attributes.extend(AttributeAccess::Hash)
|
210
|
+
end
|
211
|
+
|
212
|
+
def failure?
|
213
|
+
!success?
|
214
|
+
end
|
215
|
+
|
216
|
+
def success?
|
217
|
+
@attributes.exit_status.zero?
|
218
|
+
end
|
219
|
+
|
220
|
+
# Intercept specific setter
|
221
|
+
def new_lines=(value)
|
222
|
+
warn caller.deref[0..4], value
|
223
|
+
@attributes.new_lines = value
|
224
|
+
end
|
225
|
+
|
226
|
+
def method_missing(name, *args)
|
227
|
+
@attributes.send(name, *args)
|
228
|
+
end
|
229
|
+
|
230
|
+
def respond_to_missing?(name, include_private = false)
|
231
|
+
@attributes.respond_to?(name, include_private)
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'ww'
|
3
|
+
|
4
|
+
# A class that provides an interface to ENV variables with customizable getters and setters
|
5
|
+
class EnvInterface
|
6
|
+
class << self
|
7
|
+
# Get an environment variable with optional transformation
|
8
|
+
# @param key [String] The environment variable name
|
9
|
+
# @param default [Object] Default value if the variable is not set
|
10
|
+
# @param transform [Proc] Optional transformation to apply to the value
|
11
|
+
# @return [Object] The environment variable value
|
12
|
+
def get(key, default: nil, transform: nil)
|
13
|
+
ww key, \
|
14
|
+
value = ENV[key]
|
15
|
+
return default if value.nil?
|
16
|
+
|
17
|
+
transform ? transform.call(value) : value
|
18
|
+
end
|
19
|
+
|
20
|
+
# Set an environment variable with optional transformation
|
21
|
+
# @param key [String] The environment variable name
|
22
|
+
# @param value [Object] The value to set
|
23
|
+
# @param transform [Proc] Optional transformation to apply before setting
|
24
|
+
# @return [String] The set value
|
25
|
+
def set(key, value, transform: nil)
|
26
|
+
ww key, caller.deref[0..3], value
|
27
|
+
transformed_value = transform ? transform.call(value) : value
|
28
|
+
ENV[key] = transformed_value.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
# Check if an environment variable exists
|
32
|
+
# @param key [String] The environment variable name
|
33
|
+
# @return [Boolean] true if the variable exists
|
34
|
+
def exists?(key)
|
35
|
+
ENV.key?(key)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Delete an environment variable
|
39
|
+
# @param key [String] The environment variable name
|
40
|
+
# @return [String] The deleted value
|
41
|
+
def delete(key)
|
42
|
+
ENV.delete(key)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get all environment variables
|
46
|
+
# @return [Hash] All environment variables
|
47
|
+
def all
|
48
|
+
ENV.to_h
|
49
|
+
end
|
50
|
+
|
51
|
+
# Clear all environment variables
|
52
|
+
# @return [void]
|
53
|
+
def clear
|
54
|
+
ENV.clear
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/fcb.rb
CHANGED