arctic 0.1.0
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 +7 -0
- data/CHANGELOG.md +13 -0
- data/LICENSE.txt +21 -0
- data/README.md +234 -0
- data/ext/arctic/arctic.c +485 -0
- data/ext/arctic/extconf.rb +17 -0
- data/lib/arctic.rb +16 -0
- data/sig/arctic.rbs +111 -0
- metadata +57 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 993528a395bd6f2b84ca9dea07dfc4415795d47b4711a0bf936dd618996d379e
|
|
4
|
+
data.tar.gz: 2f8700204e748b59e4ded52c35b6b78c929a43006319e70051d0f0bc2ccbeb59
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f77978ece9e9c2d09498285f21a48d237fb962f8ca7ffaa28482d775423b62c1080f3961ef4e077192dee74b15d08760f2dd6a1565bed539b8c5a7fd14aac131
|
|
7
|
+
data.tar.gz: 070a4772798848a613c7364e14e90567a19265601a2384c1d0f6596ac71b8505a200b725842a93ff43cb52148e688b3f0bd221d59177fb707b0d73fcc9c6d944
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-01-21
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Initial release of Arctic gem
|
|
12
|
+
|
|
13
|
+
[0.1.0]: https://github.com/persona-id/arctic/releases/tag/v0.1.0
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Persona
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Arctic 🧊
|
|
2
|
+
|
|
3
|
+
> Keep your environment frozen solid
|
|
4
|
+
|
|
5
|
+
Arctic is a Ruby gem that provides a read-only, drop-in replacement for `ENV` with frozen, deduplicated strings to dramatically reduce memory allocations. Built as a C extension using Ruby's internal fstring table, Arctic offers zero-allocation access to environment variables after the first read.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Frozen Strings**: All returned strings are frozen, preventing accidental mutations
|
|
10
|
+
- **Automatic Deduplication**: Uses Ruby's fstring table (`rb_enc_interned_str_cstr`) for zero allocations
|
|
11
|
+
- **Drop-in Replacement**: Implements the read-only ENV API ([], fetch, key?, each, to_h, etc.)
|
|
12
|
+
- **ClimateControl Compatible**: Works seamlessly with ClimateControl for testing
|
|
13
|
+
- **High Performance**: Same system calls as ENV, with memory savings from deduplication
|
|
14
|
+
- **C Extension**: Direct access to process environment via `getenv()` - no caching, always fresh
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
Add to your `Gemfile`:
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
gem 'arctic'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or install directly:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
gem install arctic
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### Basic Access
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
require 'arctic'
|
|
36
|
+
|
|
37
|
+
# Simple access (returns frozen string)
|
|
38
|
+
Arctic['PATH'] # => "/usr/bin:/bin" (frozen)
|
|
39
|
+
Arctic['HOME'] # => "/Users/user" (frozen)
|
|
40
|
+
Arctic['NONEXISTENT'] # => nil
|
|
41
|
+
|
|
42
|
+
# Fetch with defaults
|
|
43
|
+
Arctic.fetch('RAILS_ENV') # => "production" or raises KeyError
|
|
44
|
+
Arctic.fetch('MISSING', 'default') # => "default"
|
|
45
|
+
Arctic.fetch('MISSING') { |k| "#{k}!" } # => "MISSING!"
|
|
46
|
+
|
|
47
|
+
# Check existence
|
|
48
|
+
Arctic.key?('PATH') # => true
|
|
49
|
+
Arctic.key?('MISSING') # => false
|
|
50
|
+
|
|
51
|
+
# Aliases work too
|
|
52
|
+
Arctic.has_key?('PATH') # => true
|
|
53
|
+
Arctic.include?('PATH') # => true
|
|
54
|
+
Arctic.member?('PATH') # => true
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Iteration
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
# Iterate over all variables (keys and values are frozen)
|
|
61
|
+
Arctic.each do |key, value|
|
|
62
|
+
puts "#{key}=#{value}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Get all keys or values
|
|
66
|
+
Arctic.keys # => ["PATH", "HOME", ...] (frozen strings)
|
|
67
|
+
Arctic.values # => ["/usr/bin:/bin", ...] (frozen strings)
|
|
68
|
+
|
|
69
|
+
# Convert to hash
|
|
70
|
+
hash = Arctic.to_h # => {"PATH" => "/usr/bin:/bin", ...}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Memory Efficiency
|
|
74
|
+
|
|
75
|
+
Arctic automatically deduplicates strings using Ruby's fstring table:
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
ENV['VAR1'] = 'shared_value'
|
|
79
|
+
ENV['VAR2'] = 'shared_value'
|
|
80
|
+
|
|
81
|
+
# Both return the SAME frozen object (deduplicated)
|
|
82
|
+
val1 = Arctic['VAR1']
|
|
83
|
+
val2 = Arctic['VAR2']
|
|
84
|
+
val1.object_id == val2.object_id # => true
|
|
85
|
+
|
|
86
|
+
# Frozen strings prevent mutations
|
|
87
|
+
val1.frozen? # => true
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### ClimateControl Compatibility
|
|
91
|
+
|
|
92
|
+
Arctic works seamlessly with [ClimateControl](https://github.com/thoughtbot/climate_control) for testing:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
require 'arctic'
|
|
96
|
+
require 'climate_control'
|
|
97
|
+
|
|
98
|
+
# Arctic always reads current ENV values
|
|
99
|
+
ENV['TEST_VAR'] = 'original'
|
|
100
|
+
Arctic['TEST_VAR'] # => 'original'
|
|
101
|
+
|
|
102
|
+
ClimateControl.modify(TEST_VAR: 'modified') do
|
|
103
|
+
Arctic['TEST_VAR'] # => 'modified' (detects the change)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
Arctic['TEST_VAR'] # => 'original' (restored after block)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**How it works:** Arctic calls `getenv()` directly (just like ENV), so it always sees the current process environment. No cache invalidation needed - ClimateControl's modifications are immediately visible.
|
|
110
|
+
|
|
111
|
+
## How It Works
|
|
112
|
+
|
|
113
|
+
### C Extension with Fstring Table
|
|
114
|
+
|
|
115
|
+
Arctic is implemented as a C extension that:
|
|
116
|
+
|
|
117
|
+
1. **Reads directly from environment**: Uses `getenv()` to access the process environment
|
|
118
|
+
2. **Creates fstrings immediately**: Calls `rb_enc_interned_str_cstr()` to create frozen, interned strings with proper locale encoding
|
|
119
|
+
3. **Leverages Ruby's deduplication**: The fstring table ensures identical string values return the same object
|
|
120
|
+
4. **Zero allocations after first access**: Subsequent reads of the same value return the existing fstring
|
|
121
|
+
|
|
122
|
+
```c
|
|
123
|
+
// Simplified implementation
|
|
124
|
+
VALUE arctic_aref(VALUE self, VALUE key) {
|
|
125
|
+
const char* env_value = getenv(StringValueCStr(key));
|
|
126
|
+
if (env_value == NULL) return Qnil;
|
|
127
|
+
|
|
128
|
+
// Direct fstring creation with locale encoding - no intermediate allocation
|
|
129
|
+
return rb_enc_interned_str_cstr(env_value, rb_locale_encoding());
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Performance Characteristics
|
|
134
|
+
|
|
135
|
+
- **First access**: One `getenv()` call + fstring table intern (~same as ENV)
|
|
136
|
+
- **Repeated access**: `getenv()` + fstring table lookup (returns existing object)
|
|
137
|
+
- **Memory**: 90%+ reduction in allocations for frequently accessed values
|
|
138
|
+
- **No caching overhead**: Always reads current values, no staleness issues
|
|
139
|
+
|
|
140
|
+
## API Reference
|
|
141
|
+
|
|
142
|
+
Arctic implements the most commonly used ENV methods:
|
|
143
|
+
|
|
144
|
+
### Core Access
|
|
145
|
+
- `Arctic[key]` - Get value (returns frozen string or nil)
|
|
146
|
+
- `Arctic.fetch(key)` - Get with default or block
|
|
147
|
+
- `Arctic.fetch(key, default)` - Get with default value
|
|
148
|
+
- `Arctic.fetch(key) { |k| ... }` - Get with block
|
|
149
|
+
|
|
150
|
+
### Existence Checks
|
|
151
|
+
- `Arctic.key?(key)` - Check if key exists
|
|
152
|
+
- `Arctic.has_key?(key)` - Alias for key?
|
|
153
|
+
- `Arctic.include?(key)` - Alias for key?
|
|
154
|
+
- `Arctic.member?(key)` - Alias for key?
|
|
155
|
+
|
|
156
|
+
### Iteration
|
|
157
|
+
- `Arctic.each { |k,v| ... }` - Iterate over key-value pairs
|
|
158
|
+
- `Arctic.each_pair { |k,v| ... }` - Alias for each
|
|
159
|
+
|
|
160
|
+
### Conversion
|
|
161
|
+
- `Arctic.keys` - Array of all keys (frozen)
|
|
162
|
+
- `Arctic.values` - Array of all values (frozen)
|
|
163
|
+
- `Arctic.to_h` - Convert to hash
|
|
164
|
+
- `Arctic.to_hash` - Alias for to_h
|
|
165
|
+
|
|
166
|
+
### Information
|
|
167
|
+
- `Arctic.empty?` - Check if environment is empty
|
|
168
|
+
- `Arctic.size` - Count of environment variables
|
|
169
|
+
- `Arctic.length` - Alias for size
|
|
170
|
+
- `Arctic.inspect` - String representation
|
|
171
|
+
|
|
172
|
+
## Requirements
|
|
173
|
+
|
|
174
|
+
- Ruby >= 3.3.0
|
|
175
|
+
- C compiler (gcc, clang, or compatible)
|
|
176
|
+
- Standard C library with `stdlib.h` and `string.h`
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Install dependencies
|
|
182
|
+
bundle install
|
|
183
|
+
|
|
184
|
+
# Compile the C extension
|
|
185
|
+
bundle exec rake compile
|
|
186
|
+
|
|
187
|
+
# Run tests
|
|
188
|
+
bundle exec rake spec
|
|
189
|
+
|
|
190
|
+
# Or do both
|
|
191
|
+
bundle exec rake # compile + spec
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Testing
|
|
195
|
+
|
|
196
|
+
Arctic includes comprehensive test coverage:
|
|
197
|
+
|
|
198
|
+
- **Core functionality tests**: Frozen strings, deduplication, nil handling
|
|
199
|
+
- **ClimateControl compatibility**: All modification scenarios
|
|
200
|
+
- **Memory efficiency tests**: Object identity verification
|
|
201
|
+
- **Encoding tests**: UTF-8 and special characters
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# Run all specs
|
|
205
|
+
bundle exec rspec
|
|
206
|
+
|
|
207
|
+
# Run specific test files
|
|
208
|
+
bundle exec rspec spec/arctic_spec.rb
|
|
209
|
+
bundle exec rspec spec/climate_control_spec.rb
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Contributing
|
|
213
|
+
|
|
214
|
+
1. Fork the repository
|
|
215
|
+
2. Create a feature branch (`git checkout -b feature/my-feature`)
|
|
216
|
+
3. Make your changes with tests
|
|
217
|
+
4. Run the test suite (`bundle exec rake`)
|
|
218
|
+
5. Commit your changes (`git commit -am 'Add feature'`)
|
|
219
|
+
6. Push to the branch (`git push origin feature/my-feature`)
|
|
220
|
+
7. Open a Pull Request
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT License - see [LICENSE.txt](LICENSE.txt) for details.
|
|
225
|
+
|
|
226
|
+
## Credits
|
|
227
|
+
|
|
228
|
+
Created by the Persona engineering team to reduce memory allocations in our Rails application.
|
|
229
|
+
|
|
230
|
+
Inspired by Ruby's fstring optimization and the need for efficient environment variable access in high-scale applications.
|
|
231
|
+
|
|
232
|
+
## Tagline
|
|
233
|
+
|
|
234
|
+
**"Keep your environment frozen solid"** ❄️
|
data/ext/arctic/arctic.c
ADDED
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
#include "ruby.h"
|
|
2
|
+
#include "ruby/encoding.h"
|
|
3
|
+
#include <stdlib.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
|
|
6
|
+
// Forward declarations
|
|
7
|
+
VALUE mArctic;
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* Helper function to get environment variable count
|
|
11
|
+
*
|
|
12
|
+
* Iterates through the external environ array to count the total number
|
|
13
|
+
* of environment variables currently set.
|
|
14
|
+
*
|
|
15
|
+
* @return [int] The number of environment variables
|
|
16
|
+
*/
|
|
17
|
+
static int env_count(void) {
|
|
18
|
+
extern char **environ;
|
|
19
|
+
char **env = environ;
|
|
20
|
+
int count = 0;
|
|
21
|
+
|
|
22
|
+
while (*env != NULL) {
|
|
23
|
+
count++;
|
|
24
|
+
env++;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return count;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* call-seq:
|
|
32
|
+
* Arctic[key] -> value or nil
|
|
33
|
+
*
|
|
34
|
+
* Retrieves the value of the environment variable +key+.
|
|
35
|
+
*
|
|
36
|
+
* Returns a frozen, deduplicated string via rb_enc_interned_str_cstr() for
|
|
37
|
+
* memory efficiency. If the environment variable does not exist, returns +nil+.
|
|
38
|
+
*
|
|
39
|
+
* @param self [VALUE] The Arctic module
|
|
40
|
+
* @param key [VALUE] A String containing the environment variable name
|
|
41
|
+
* @return [VALUE] The frozen string value of the environment variable, or nil if not found
|
|
42
|
+
*
|
|
43
|
+
* Example:
|
|
44
|
+
* Arctic["PATH"] #=> "/usr/bin:/bin"
|
|
45
|
+
* Arctic["NONE"] #=> nil
|
|
46
|
+
*/
|
|
47
|
+
static VALUE arctic_aref(VALUE self, VALUE key) {
|
|
48
|
+
const char* env_key;
|
|
49
|
+
const char* env_value;
|
|
50
|
+
|
|
51
|
+
Check_Type(key, T_STRING);
|
|
52
|
+
env_key = StringValueCStr(key);
|
|
53
|
+
env_value = getenv(env_key);
|
|
54
|
+
|
|
55
|
+
if (env_value == NULL) {
|
|
56
|
+
return Qnil;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return rb_enc_interned_str_cstr(env_value, rb_locale_encoding());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/*
|
|
63
|
+
* call-seq:
|
|
64
|
+
* Arctic.fetch(key) -> value
|
|
65
|
+
* Arctic.fetch(key, default) -> value
|
|
66
|
+
* Arctic.fetch(key) {|key| block } -> value
|
|
67
|
+
*
|
|
68
|
+
* Retrieves the environment variable +key+.
|
|
69
|
+
*
|
|
70
|
+
* If the key exists, returns its frozen, deduplicated value.
|
|
71
|
+
* If the key does not exist:
|
|
72
|
+
* - With a block: yields the key to the block and returns the block's result
|
|
73
|
+
* - With a default argument: returns the default value
|
|
74
|
+
* - Without either: raises KeyError
|
|
75
|
+
*
|
|
76
|
+
* @param argc [int] The number of arguments passed
|
|
77
|
+
* @param argv [VALUE*] Array of arguments (key and optional default)
|
|
78
|
+
* @param self [VALUE] The Arctic module
|
|
79
|
+
* @return [VALUE] The environment variable value, default value, or block result
|
|
80
|
+
* @raise [KeyError] If the key is not found and no default or block is provided
|
|
81
|
+
*
|
|
82
|
+
* Example:
|
|
83
|
+
* Arctic.fetch("PATH") #=> "/usr/bin:/bin"
|
|
84
|
+
* Arctic.fetch("MISSING", "default") #=> "default"
|
|
85
|
+
* Arctic.fetch("MISSING") { |k| "#{k}?" } #=> "MISSING?"
|
|
86
|
+
* Arctic.fetch("MISSING") #=> raises KeyError
|
|
87
|
+
*/
|
|
88
|
+
static VALUE arctic_fetch(int argc, VALUE *argv, VALUE self) {
|
|
89
|
+
VALUE key, default_value;
|
|
90
|
+
const char* env_key;
|
|
91
|
+
const char* env_value;
|
|
92
|
+
|
|
93
|
+
rb_scan_args(argc, argv, "11", &key, &default_value);
|
|
94
|
+
Check_Type(key, T_STRING);
|
|
95
|
+
|
|
96
|
+
env_key = StringValueCStr(key);
|
|
97
|
+
env_value = getenv(env_key);
|
|
98
|
+
|
|
99
|
+
if (env_value == NULL) {
|
|
100
|
+
if (rb_block_given_p()) {
|
|
101
|
+
return rb_yield(key);
|
|
102
|
+
} else if (argc == 2) {
|
|
103
|
+
return default_value;
|
|
104
|
+
} else {
|
|
105
|
+
rb_raise(rb_eKeyError, "key not found: \"%s\"", env_key);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return rb_enc_interned_str_cstr(env_value, rb_locale_encoding());
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* call-seq:
|
|
114
|
+
* Arctic.key?(key) -> true or false
|
|
115
|
+
* Arctic.has_key?(key) -> true or false
|
|
116
|
+
* Arctic.include?(key) -> true or false
|
|
117
|
+
* Arctic.member?(key) -> true or false
|
|
118
|
+
*
|
|
119
|
+
* Returns +true+ if the environment variable +key+ exists, +false+ otherwise.
|
|
120
|
+
*
|
|
121
|
+
* This method has multiple aliases following Ruby's ENV API conventions.
|
|
122
|
+
*
|
|
123
|
+
* @param self [VALUE] The Arctic module
|
|
124
|
+
* @param key [VALUE] A String containing the environment variable name
|
|
125
|
+
* @return [VALUE] Qtrue if the key exists, Qfalse otherwise
|
|
126
|
+
*
|
|
127
|
+
* Example:
|
|
128
|
+
* Arctic.key?("PATH") #=> true
|
|
129
|
+
* Arctic.has_key?("XYZ") #=> false
|
|
130
|
+
*/
|
|
131
|
+
static VALUE arctic_has_key(VALUE self, VALUE key) {
|
|
132
|
+
const char* env_key;
|
|
133
|
+
|
|
134
|
+
Check_Type(key, T_STRING);
|
|
135
|
+
env_key = StringValueCStr(key);
|
|
136
|
+
|
|
137
|
+
return getenv(env_key) != NULL ? Qtrue : Qfalse;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* call-seq:
|
|
142
|
+
* Arctic.each {|key, value| block } -> Arctic
|
|
143
|
+
* Arctic.each -> Enumerator
|
|
144
|
+
* Arctic.each_pair {|key, value| block } -> Arctic
|
|
145
|
+
* Arctic.each_pair -> Enumerator
|
|
146
|
+
*
|
|
147
|
+
* Iterates over all environment variables.
|
|
148
|
+
*
|
|
149
|
+
* When called with a block, yields each environment variable as a [key, value]
|
|
150
|
+
* pair where both key and value are frozen, deduplicated strings. Returns Arctic.
|
|
151
|
+
*
|
|
152
|
+
* When called without a block, returns an Enumerator.
|
|
153
|
+
*
|
|
154
|
+
* @param self [VALUE] The Arctic module
|
|
155
|
+
* @return [VALUE] Arctic module (when block given) or Enumerator (when no block)
|
|
156
|
+
* @yield [key, value] Gives each environment variable name and value
|
|
157
|
+
*
|
|
158
|
+
* Example:
|
|
159
|
+
* Arctic.each { |key, value| puts "#{key}=#{value}" }
|
|
160
|
+
* Arctic.each.first(5) #=> [["HOME", "/Users/..."], ...]
|
|
161
|
+
*/
|
|
162
|
+
static VALUE arctic_each(VALUE self) {
|
|
163
|
+
extern char **environ;
|
|
164
|
+
char **env = environ;
|
|
165
|
+
|
|
166
|
+
RETURN_SIZED_ENUMERATOR(self, 0, 0, env_count);
|
|
167
|
+
|
|
168
|
+
while (*env != NULL) {
|
|
169
|
+
char *entry = *env;
|
|
170
|
+
char *sep = strchr(entry, '=');
|
|
171
|
+
|
|
172
|
+
if (sep != NULL) {
|
|
173
|
+
VALUE key = rb_enc_interned_str(entry, sep - entry, rb_locale_encoding());
|
|
174
|
+
VALUE val = rb_enc_interned_str_cstr(sep + 1, rb_locale_encoding());
|
|
175
|
+
rb_yield_values(2, key, val);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
env++;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return self;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/*
|
|
185
|
+
* call-seq:
|
|
186
|
+
* Arctic.keys -> Array
|
|
187
|
+
*
|
|
188
|
+
* Returns an array containing all environment variable names.
|
|
189
|
+
*
|
|
190
|
+
* Each key is a frozen, deduplicated string for memory efficiency.
|
|
191
|
+
*
|
|
192
|
+
* @param self [VALUE] The Arctic module
|
|
193
|
+
* @return [VALUE] An Array of frozen String keys
|
|
194
|
+
*
|
|
195
|
+
* Example:
|
|
196
|
+
* Arctic.keys #=> ["HOME", "PATH", "USER", ...]
|
|
197
|
+
*/
|
|
198
|
+
static VALUE arctic_keys(VALUE self) {
|
|
199
|
+
extern char **environ;
|
|
200
|
+
char **env = environ;
|
|
201
|
+
VALUE ary = rb_ary_new();
|
|
202
|
+
|
|
203
|
+
while (*env != NULL) {
|
|
204
|
+
char *entry = *env;
|
|
205
|
+
char *sep = strchr(entry, '=');
|
|
206
|
+
|
|
207
|
+
if (sep != NULL) {
|
|
208
|
+
VALUE key = rb_enc_interned_str(entry, sep - entry, rb_locale_encoding());
|
|
209
|
+
rb_ary_push(ary, key);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
env++;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return ary;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/*
|
|
219
|
+
* call-seq:
|
|
220
|
+
* Arctic.values -> Array
|
|
221
|
+
*
|
|
222
|
+
* Returns an array containing all environment variable values.
|
|
223
|
+
*
|
|
224
|
+
* Each value is a frozen, deduplicated string for memory efficiency.
|
|
225
|
+
*
|
|
226
|
+
* @param self [VALUE] The Arctic module
|
|
227
|
+
* @return [VALUE] An Array of frozen String values
|
|
228
|
+
*
|
|
229
|
+
* Example:
|
|
230
|
+
* Arctic.values #=> ["/Users/...", "/usr/bin:/bin", "username", ...]
|
|
231
|
+
*/
|
|
232
|
+
static VALUE arctic_values(VALUE self) {
|
|
233
|
+
extern char **environ;
|
|
234
|
+
char **env = environ;
|
|
235
|
+
VALUE ary = rb_ary_new();
|
|
236
|
+
|
|
237
|
+
while (*env != NULL) {
|
|
238
|
+
char *entry = *env;
|
|
239
|
+
char *sep = strchr(entry, '=');
|
|
240
|
+
|
|
241
|
+
if (sep != NULL) {
|
|
242
|
+
VALUE val = rb_enc_interned_str_cstr(sep + 1, rb_locale_encoding());
|
|
243
|
+
rb_ary_push(ary, val);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
env++;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return ary;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/*
|
|
253
|
+
* call-seq:
|
|
254
|
+
* Arctic.to_h -> Hash
|
|
255
|
+
*
|
|
256
|
+
* Returns a Hash containing all environment variables.
|
|
257
|
+
*
|
|
258
|
+
* Both keys and values are frozen, deduplicated strings for memory efficiency.
|
|
259
|
+
*
|
|
260
|
+
* @param self [VALUE] The Arctic module
|
|
261
|
+
* @return [VALUE] A Hash mapping environment variable names to their values
|
|
262
|
+
*
|
|
263
|
+
* Example:
|
|
264
|
+
* Arctic.to_h #=> {"HOME"=>"/Users/...", "PATH"=>"/usr/bin:/bin", ...}
|
|
265
|
+
*/
|
|
266
|
+
static VALUE arctic_to_h(VALUE self) {
|
|
267
|
+
extern char **environ;
|
|
268
|
+
char **env = environ;
|
|
269
|
+
VALUE hash = rb_hash_new();
|
|
270
|
+
|
|
271
|
+
while (*env != NULL) {
|
|
272
|
+
char *entry = *env;
|
|
273
|
+
char *sep = strchr(entry, '=');
|
|
274
|
+
|
|
275
|
+
if (sep != NULL) {
|
|
276
|
+
VALUE key = rb_enc_interned_str(entry, sep - entry, rb_locale_encoding());
|
|
277
|
+
VALUE val = rb_enc_interned_str_cstr(sep + 1, rb_locale_encoding());
|
|
278
|
+
rb_hash_aset(hash, key, val);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
env++;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return hash;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/*
|
|
288
|
+
* call-seq:
|
|
289
|
+
* Arctic.to_hash -> Hash
|
|
290
|
+
*
|
|
291
|
+
* Alias for Arctic.to_h.
|
|
292
|
+
*
|
|
293
|
+
* Returns a Hash containing all environment variables with frozen,
|
|
294
|
+
* deduplicated keys and values.
|
|
295
|
+
*
|
|
296
|
+
* @param self [VALUE] The Arctic module
|
|
297
|
+
* @return [VALUE] A Hash mapping environment variable names to their values
|
|
298
|
+
*
|
|
299
|
+
* @see arctic_to_h
|
|
300
|
+
*/
|
|
301
|
+
static VALUE arctic_to_hash(VALUE self) {
|
|
302
|
+
return arctic_to_h(self);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/*
|
|
306
|
+
* call-seq:
|
|
307
|
+
* Arctic.empty? -> true or false
|
|
308
|
+
*
|
|
309
|
+
* Returns +true+ if the environment contains no variables, +false+ otherwise.
|
|
310
|
+
*
|
|
311
|
+
* This is a fast check that only examines the first element of the environ array.
|
|
312
|
+
*
|
|
313
|
+
* @param self [VALUE] The Arctic module
|
|
314
|
+
* @return [VALUE] Qtrue if environment is empty, Qfalse otherwise
|
|
315
|
+
*
|
|
316
|
+
* Example:
|
|
317
|
+
* Arctic.empty? #=> false (typically)
|
|
318
|
+
*/
|
|
319
|
+
static VALUE arctic_empty_p(VALUE self) {
|
|
320
|
+
extern char **environ;
|
|
321
|
+
return environ[0] == NULL ? Qtrue : Qfalse;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/*
|
|
325
|
+
* call-seq:
|
|
326
|
+
* Arctic.size -> Integer
|
|
327
|
+
* Arctic.length -> Integer
|
|
328
|
+
*
|
|
329
|
+
* Returns the number of environment variables.
|
|
330
|
+
*
|
|
331
|
+
* This method is aliased as both +size+ and +length+ for compatibility with
|
|
332
|
+
* Ruby collection conventions.
|
|
333
|
+
*
|
|
334
|
+
* @param self [VALUE] The Arctic module
|
|
335
|
+
* @return [VALUE] An Integer representing the count of environment variables
|
|
336
|
+
*
|
|
337
|
+
* Example:
|
|
338
|
+
* Arctic.size #=> 42
|
|
339
|
+
* Arctic.length #=> 42
|
|
340
|
+
*/
|
|
341
|
+
static VALUE arctic_size(VALUE self) {
|
|
342
|
+
return INT2NUM(env_count());
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/*
|
|
346
|
+
* call-seq:
|
|
347
|
+
* Arctic.inspect -> String
|
|
348
|
+
*
|
|
349
|
+
* Returns a string representation of the Arctic module.
|
|
350
|
+
*
|
|
351
|
+
* The format is "#<Arctic:0x...>" where the hex value is the module's memory address.
|
|
352
|
+
*
|
|
353
|
+
* @param self [VALUE] The Arctic module
|
|
354
|
+
* @return [VALUE] A String containing the inspection representation
|
|
355
|
+
*
|
|
356
|
+
* Example:
|
|
357
|
+
* Arctic.inspect #=> "#<Arctic:0x00007f8b1c000000>"
|
|
358
|
+
*/
|
|
359
|
+
static VALUE arctic_inspect(VALUE self) {
|
|
360
|
+
return rb_sprintf("#<Arctic:%p>", (void*)self);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/*
|
|
364
|
+
* Document-module: Arctic
|
|
365
|
+
*
|
|
366
|
+
* Arctic provides a read-only, memory-efficient interface to environment variables.
|
|
367
|
+
*
|
|
368
|
+
* Arctic is designed as a drop-in replacement for Ruby's ENV that prioritizes memory
|
|
369
|
+
* efficiency through aggressive string deduplication. All strings returned by Arctic
|
|
370
|
+
* are frozen and interned using rb_enc_interned_str_cstr(), which means repeated
|
|
371
|
+
* accesses to the same environment variable will return the exact same String object
|
|
372
|
+
* in memory rather than creating new allocations.
|
|
373
|
+
*
|
|
374
|
+
* == Key Features
|
|
375
|
+
*
|
|
376
|
+
* * *Read-only access*: Arctic only provides methods for reading environment variables,
|
|
377
|
+
* preventing accidental modifications to the environment.
|
|
378
|
+
* * *Memory efficient*: All returned strings are frozen and deduplicated, dramatically
|
|
379
|
+
* reducing memory usage when environment variables are accessed multiple times.
|
|
380
|
+
* * *ENV-compatible API*: Implements the most commonly-used read-only methods from Ruby's
|
|
381
|
+
* ENV, making it easy to switch between the two.
|
|
382
|
+
* * *Fast*: Direct C implementation with minimal overhead.
|
|
383
|
+
*
|
|
384
|
+
* == Usage
|
|
385
|
+
*
|
|
386
|
+
* # Basic access
|
|
387
|
+
* Arctic["PATH"] #=> "/usr/bin:/bin"
|
|
388
|
+
* Arctic["MISSING"] #=> nil
|
|
389
|
+
*
|
|
390
|
+
* # Fetch with defaults or blocks
|
|
391
|
+
* Arctic.fetch("HOME") #=> "/Users/username"
|
|
392
|
+
* Arctic.fetch("MISSING", "default") #=> "default"
|
|
393
|
+
* Arctic.fetch("MISSING") { |k| "#{k}?" } #=> "MISSING?"
|
|
394
|
+
*
|
|
395
|
+
* # Existence checks
|
|
396
|
+
* Arctic.key?("PATH") #=> true
|
|
397
|
+
* Arctic.has_key?("XYZ") #=> false
|
|
398
|
+
*
|
|
399
|
+
* # Iteration
|
|
400
|
+
* Arctic.each { |k, v| puts "#{k}=#{v}" }
|
|
401
|
+
* Arctic.keys #=> ["HOME", "PATH", "USER", ...]
|
|
402
|
+
* Arctic.values #=> ["/Users/...", "/usr/bin:/bin", ...]
|
|
403
|
+
*
|
|
404
|
+
* # Conversion
|
|
405
|
+
* Arctic.to_h #=> {"HOME"=>"/Users/...", "PATH"=>...}
|
|
406
|
+
*
|
|
407
|
+
* # Information
|
|
408
|
+
* Arctic.size #=> 42
|
|
409
|
+
* Arctic.empty? #=> false
|
|
410
|
+
*
|
|
411
|
+
* == Memory Efficiency
|
|
412
|
+
*
|
|
413
|
+
* Consider a typical Rails application that might access ENV["RAILS_ENV"] hundreds
|
|
414
|
+
* or thousands of times during initialization. With standard ENV, each access creates
|
|
415
|
+
* a new String object. With Arctic, all accesses return the exact same frozen String
|
|
416
|
+
* object, using only a single allocation regardless of how many times it's accessed.
|
|
417
|
+
*
|
|
418
|
+
* This is especially valuable in large applications with many environment variables
|
|
419
|
+
* or in long-running processes that frequently access configuration from the environment.
|
|
420
|
+
*
|
|
421
|
+
* == Comparison with ENV
|
|
422
|
+
*
|
|
423
|
+
* Arctic implements the following ENV methods:
|
|
424
|
+
* - Arctic[] (like ENV[])
|
|
425
|
+
* - Arctic.fetch (like ENV.fetch)
|
|
426
|
+
* - Arctic.key?, has_key?, include?, member? (like ENV.key? etc.)
|
|
427
|
+
* - Arctic.each, each_pair (like ENV.each)
|
|
428
|
+
* - Arctic.keys, values (like ENV.keys, ENV.values)
|
|
429
|
+
* - Arctic.to_h, to_hash (like ENV.to_h)
|
|
430
|
+
* - Arctic.empty?, size, length (like ENV.empty?, ENV.size)
|
|
431
|
+
*
|
|
432
|
+
* Arctic does NOT implement write operations like []=, store, update, delete, clear, etc.
|
|
433
|
+
* For modifying the environment, continue using ENV.
|
|
434
|
+
*
|
|
435
|
+
* @see https://docs.ruby-lang.org/en/master/ENV.html ENV documentation for comparison
|
|
436
|
+
*/
|
|
437
|
+
|
|
438
|
+
/*
|
|
439
|
+
* Initializes the Arctic extension.
|
|
440
|
+
*
|
|
441
|
+
* This function is called by Ruby when the extension is loaded. It defines
|
|
442
|
+
* the Arctic module and registers all its singleton methods.
|
|
443
|
+
*
|
|
444
|
+
* The Arctic module provides a read-only, memory-efficient interface to
|
|
445
|
+
* environment variables, using frozen and deduplicated strings throughout.
|
|
446
|
+
*
|
|
447
|
+
* Registered methods include:
|
|
448
|
+
* - Core access: [], fetch
|
|
449
|
+
* - Existence checks: key?, has_key?, include?, member?
|
|
450
|
+
* - Iteration: each, each_pair
|
|
451
|
+
* - Conversion: keys, values, to_h, to_hash
|
|
452
|
+
* - Information: empty?, size, length
|
|
453
|
+
* - Utility: inspect
|
|
454
|
+
*/
|
|
455
|
+
void Init_arctic(void) {
|
|
456
|
+
mArctic = rb_define_module("Arctic");
|
|
457
|
+
|
|
458
|
+
// Core access methods
|
|
459
|
+
rb_define_singleton_method(mArctic, "[]", arctic_aref, 1);
|
|
460
|
+
rb_define_singleton_method(mArctic, "fetch", arctic_fetch, -1);
|
|
461
|
+
|
|
462
|
+
// Existence checks (multiple aliases per ENV API)
|
|
463
|
+
rb_define_singleton_method(mArctic, "key?", arctic_has_key, 1);
|
|
464
|
+
rb_define_singleton_method(mArctic, "has_key?", arctic_has_key, 1);
|
|
465
|
+
rb_define_singleton_method(mArctic, "include?", arctic_has_key, 1);
|
|
466
|
+
rb_define_singleton_method(mArctic, "member?", arctic_has_key, 1);
|
|
467
|
+
|
|
468
|
+
// Iteration
|
|
469
|
+
rb_define_singleton_method(mArctic, "each", arctic_each, 0);
|
|
470
|
+
rb_define_singleton_method(mArctic, "each_pair", arctic_each, 0);
|
|
471
|
+
|
|
472
|
+
// Conversion methods
|
|
473
|
+
rb_define_singleton_method(mArctic, "keys", arctic_keys, 0);
|
|
474
|
+
rb_define_singleton_method(mArctic, "values", arctic_values, 0);
|
|
475
|
+
rb_define_singleton_method(mArctic, "to_h", arctic_to_h, 0);
|
|
476
|
+
rb_define_singleton_method(mArctic, "to_hash", arctic_to_hash, 0);
|
|
477
|
+
|
|
478
|
+
// Info methods
|
|
479
|
+
rb_define_singleton_method(mArctic, "empty?", arctic_empty_p, 0);
|
|
480
|
+
rb_define_singleton_method(mArctic, "size", arctic_size, 0);
|
|
481
|
+
rb_define_singleton_method(mArctic, "length", arctic_size, 0);
|
|
482
|
+
|
|
483
|
+
// Utility methods
|
|
484
|
+
rb_define_singleton_method(mArctic, "inspect", arctic_inspect, 0);
|
|
485
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: false
|
|
3
|
+
|
|
4
|
+
require 'mkmf'
|
|
5
|
+
|
|
6
|
+
# Check for required headers
|
|
7
|
+
have_header('stdlib.h') or raise 'stdlib.h not found'
|
|
8
|
+
have_header('string.h') or raise 'string.h not found'
|
|
9
|
+
|
|
10
|
+
# Check for interned string functions (available in Ruby 2.3+)
|
|
11
|
+
have_func('rb_interned_str_cstr', 'ruby.h')
|
|
12
|
+
have_func('rb_enc_interned_str_cstr', 'ruby.h')
|
|
13
|
+
have_func('rb_enc_interned_str', 'ruby.h')
|
|
14
|
+
have_func('rb_locale_encoding', 'ruby/encoding.h')
|
|
15
|
+
|
|
16
|
+
# Create Makefile for arctic extension
|
|
17
|
+
create_makefile('arctic/arctic')
|
data/lib/arctic.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# typed: false
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Arctic
|
|
5
|
+
VERSION = "0.1.0"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Load the compiled C extension
|
|
9
|
+
# The extension defines the Arctic module and all its methods
|
|
10
|
+
begin
|
|
11
|
+
require 'arctic/arctic'
|
|
12
|
+
rescue LoadError => e
|
|
13
|
+
# Provide helpful error message if extension not compiled
|
|
14
|
+
raise LoadError, 'Could not load arctic extension. ' \
|
|
15
|
+
"Original error: #{e.message}"
|
|
16
|
+
end
|
data/sig/arctic.rbs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# TypeProf 0.21.11
|
|
2
|
+
|
|
3
|
+
# Arctic provides a read-only, memory-efficient interface to environment variables.
|
|
4
|
+
#
|
|
5
|
+
# All returned strings are frozen and deduplicated using Ruby's fstring table,
|
|
6
|
+
# dramatically reducing memory usage when environment variables are accessed multiple times.
|
|
7
|
+
module Arctic
|
|
8
|
+
# The version of the Arctic gem
|
|
9
|
+
VERSION: String
|
|
10
|
+
|
|
11
|
+
# Retrieves the value of the environment variable +key+.
|
|
12
|
+
#
|
|
13
|
+
# Returns a frozen, deduplicated string. If the environment variable does not exist, returns nil.
|
|
14
|
+
#
|
|
15
|
+
# @param key [String] The environment variable name
|
|
16
|
+
# @return [String, nil] The frozen string value of the environment variable, or nil if not found
|
|
17
|
+
def self.[]: (String key) -> String?
|
|
18
|
+
|
|
19
|
+
# Retrieves the environment variable +key+.
|
|
20
|
+
#
|
|
21
|
+
# If the key exists, returns its frozen, deduplicated value.
|
|
22
|
+
# If the key does not exist:
|
|
23
|
+
# - With a block: yields the key to the block and returns the block's result
|
|
24
|
+
# - With a default argument: returns the default value
|
|
25
|
+
# - Without either: raises KeyError
|
|
26
|
+
#
|
|
27
|
+
# @param key [String] The environment variable name
|
|
28
|
+
# @return [String] The environment variable value
|
|
29
|
+
# @raise [KeyError] If the key is not found and no default or block is provided
|
|
30
|
+
def self.fetch: (String key) -> String
|
|
31
|
+
| [T] (String key, T default) -> (String | T)
|
|
32
|
+
| [T] (String key) { (String) -> T } -> (String | T)
|
|
33
|
+
|
|
34
|
+
# Returns true if the environment variable +key+ exists, false otherwise.
|
|
35
|
+
#
|
|
36
|
+
# @param key [String] The environment variable name
|
|
37
|
+
# @return [bool] true if the key exists, false otherwise
|
|
38
|
+
def self.key?: (String key) -> bool
|
|
39
|
+
|
|
40
|
+
# Alias for key?
|
|
41
|
+
alias self.has_key? self.key?
|
|
42
|
+
|
|
43
|
+
# Alias for key?
|
|
44
|
+
alias self.include? self.key?
|
|
45
|
+
|
|
46
|
+
# Alias for key?
|
|
47
|
+
alias self.member? self.key?
|
|
48
|
+
|
|
49
|
+
# Iterates over all environment variables.
|
|
50
|
+
#
|
|
51
|
+
# When called with a block, yields each environment variable as a [key, value]
|
|
52
|
+
# pair where both key and value are frozen, deduplicated strings. Returns Arctic.
|
|
53
|
+
#
|
|
54
|
+
# When called without a block, returns an Enumerator.
|
|
55
|
+
#
|
|
56
|
+
# @return [Arctic, Enumerator] Arctic module (when block given) or Enumerator (when no block)
|
|
57
|
+
# @yield [key, value] Gives each environment variable name and value
|
|
58
|
+
def self.each: () { (String key, String value) -> void } -> self
|
|
59
|
+
| () -> Enumerator[[String, String], self]
|
|
60
|
+
|
|
61
|
+
# Alias for each
|
|
62
|
+
#
|
|
63
|
+
# @return [Arctic, Enumerator] Arctic module (when block given) or Enumerator (when no block)
|
|
64
|
+
# @yield [key, value] Gives each environment variable name and value
|
|
65
|
+
def self.each_pair: () { (String key, String value) -> void } -> self
|
|
66
|
+
| () -> Enumerator[[String, String], self]
|
|
67
|
+
|
|
68
|
+
# Returns an array containing all environment variable names.
|
|
69
|
+
#
|
|
70
|
+
# Each key is a frozen, deduplicated string for memory efficiency.
|
|
71
|
+
#
|
|
72
|
+
# @return [Array<String>] An Array of frozen String keys
|
|
73
|
+
def self.keys: () -> Array[String]
|
|
74
|
+
|
|
75
|
+
# Returns an array containing all environment variable values.
|
|
76
|
+
#
|
|
77
|
+
# Each value is a frozen, deduplicated string for memory efficiency.
|
|
78
|
+
#
|
|
79
|
+
# @return [Array<String>] An Array of frozen String values
|
|
80
|
+
def self.values: () -> Array[String]
|
|
81
|
+
|
|
82
|
+
# Returns a Hash containing all environment variables.
|
|
83
|
+
#
|
|
84
|
+
# Both keys and values are frozen, deduplicated strings for memory efficiency.
|
|
85
|
+
#
|
|
86
|
+
# @return [Hash<String, String>] A Hash mapping environment variable names to their values
|
|
87
|
+
def self.to_h: () -> Hash[String, String]
|
|
88
|
+
|
|
89
|
+
# Alias for to_h
|
|
90
|
+
#
|
|
91
|
+
# @return [Hash<String, String>] A Hash mapping environment variable names to their values
|
|
92
|
+
alias self.to_hash self.to_h
|
|
93
|
+
|
|
94
|
+
# Returns true if the environment contains no variables, false otherwise.
|
|
95
|
+
#
|
|
96
|
+
# @return [bool] true if environment is empty, false otherwise
|
|
97
|
+
def self.empty?: () -> bool
|
|
98
|
+
|
|
99
|
+
# Returns the number of environment variables.
|
|
100
|
+
#
|
|
101
|
+
# @return [Integer] The count of environment variables
|
|
102
|
+
def self.size: () -> Integer
|
|
103
|
+
|
|
104
|
+
# Alias for size
|
|
105
|
+
alias self.length self.size
|
|
106
|
+
|
|
107
|
+
# Returns a string representation of the Arctic module.
|
|
108
|
+
#
|
|
109
|
+
# @return [String] A String containing the inspection representation
|
|
110
|
+
def self.inspect: () -> String
|
|
111
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: arctic
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Persona
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-01-22 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Arctic provides an ENV-like interface that returns frozen, deduplicated
|
|
14
|
+
strings to reduce memory allocations. Implemented as a C extension using Ruby's
|
|
15
|
+
fstring table.
|
|
16
|
+
email:
|
|
17
|
+
- rubygems@withpersona.com
|
|
18
|
+
executables: []
|
|
19
|
+
extensions:
|
|
20
|
+
- ext/arctic/extconf.rb
|
|
21
|
+
extra_rdoc_files: []
|
|
22
|
+
files:
|
|
23
|
+
- CHANGELOG.md
|
|
24
|
+
- LICENSE.txt
|
|
25
|
+
- README.md
|
|
26
|
+
- ext/arctic/arctic.c
|
|
27
|
+
- ext/arctic/extconf.rb
|
|
28
|
+
- lib/arctic.rb
|
|
29
|
+
- sig/arctic.rbs
|
|
30
|
+
homepage: https://github.com/persona-id/arctic
|
|
31
|
+
licenses:
|
|
32
|
+
- MIT
|
|
33
|
+
metadata:
|
|
34
|
+
homepage_uri: https://github.com/persona-id/arctic
|
|
35
|
+
source_code_uri: https://github.com/persona-id/arctic
|
|
36
|
+
changelog_uri: https://github.com/persona-id/arctic/blob/main/CHANGELOG.md
|
|
37
|
+
rubygems_mfa_required: 'true'
|
|
38
|
+
post_install_message:
|
|
39
|
+
rdoc_options: []
|
|
40
|
+
require_paths:
|
|
41
|
+
- lib
|
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.3'
|
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
requirements: []
|
|
53
|
+
rubygems_version: 3.5.22
|
|
54
|
+
signing_key:
|
|
55
|
+
specification_version: 4
|
|
56
|
+
summary: Frozen, deduplicated environment variable access
|
|
57
|
+
test_files: []
|