Skip to content
Newer
Older
100644 767 lines (687 sloc) 16.7 KB
7d7d3e8 @ferrous26 Change ownership to The MacRuby Team and update copyrights
ferrous26 authored
1 /*
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
2 * MacRuby implementation of ENV.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
7d7d3e8 @ferrous26 Change ownership to The MacRuby Team and update copyrights
ferrous26 authored
5 *
6 * Copyright (C) 2012, The MacRuby Team. All rights reserved.
9595725 update copyrights to 2011
Laurent Sansonetti authored
7 * Copyright (C) 2007-2011, Apple Inc. All rights reserved.
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
8 * Copyright (C) 1993-2007 Yukihiro Matsumoto
9 * Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 * Copyright (C) 2000 Information-technology Promotion Agency, Japan
11 */
12
d0898dd include/ruby/macruby.h -> macruby_internal.h
Laurent Sansonetti authored
13 #include "macruby_internal.h"
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
14 #include "ruby/st.h"
15 #include "ruby/util.h"
16 #include "ruby/node.h"
17 #include "vm.h"
18
59746d9 cleaning up a few things
Laurent Sansonetti authored
19 char ***_NSGetEnviron();
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
20
21 static VALUE envtbl;
22
23 static int path_tainted = -1;
24
25 static char **origenviron;
26 #define GET_ENVIRON() (*_NSGetEnviron())
27
28 static VALUE
29 to_hash(VALUE hash)
30 {
31 return rb_convert_type(hash, T_HASH, "Hash", "to_hash");
32 }
33
34 static VALUE
35 env_str_new(const char *ptr, long len)
36 {
37 VALUE str = rb_tainted_str_new(ptr, len);
38 rb_obj_freeze(str);
39 return str;
40 }
41
42 static VALUE
43 env_str_new2(const char *ptr)
44 {
45 if (ptr == NULL) {
46 return Qnil;
47 }
48 return env_str_new(ptr, strlen(ptr));
49 }
50
51 static VALUE
52 env_delete(VALUE obj, VALUE name)
53 {
54 rb_secure(4);
55 SafeStringValue(name);
56 const char *nam = RSTRING_PTR(name);
57 if (strlen(nam) != RSTRING_LEN(name)) {
58 rb_raise(rb_eArgError, "bad environment variable name");
59 }
60 const char *val = getenv(nam);
61 if (val != NULL) {
62 VALUE value = env_str_new2(val);
63 ruby_setenv(nam, 0);
64 if (strcmp(nam, PATH_ENV) == 0) {
65 path_tainted = 0;
66 }
67 return value;
68 }
69 return Qnil;
70 }
71
72 static VALUE
73 env_delete_m(VALUE obj, SEL sel, VALUE name)
74 {
75 VALUE val = env_delete(obj, name);
76 if (NIL_P(val) && rb_block_given_p()) {
77 rb_yield(name);
78 }
79 return val;
80 }
81
82 static VALUE
83 rb_f_getenv(VALUE obj, SEL sel, VALUE name)
84 {
85 rb_secure(4);
86 SafeStringValue(name);
87 const char *nam = RSTRING_PTR(name);
88 if (strlen(nam) != RSTRING_LEN(name)) {
89 rb_raise(rb_eArgError, "bad environment variable name");
90 }
91 const char *env = getenv(nam);
92 if (env != NULL) {
93 if (strcmp(nam, PATH_ENV) == 0 && !rb_env_path_tainted()) {
94 VALUE str = rb_str_new2(env);
95 rb_obj_freeze(str);
96 return str;
97 }
98 return env_str_new2(env);
99 }
100 return Qnil;
101 }
102
103 static VALUE
104 env_fetch(VALUE rcv, SEL sel, int argc, VALUE *argv)
105 {
106 rb_secure(4);
107
108 VALUE key, if_none;
109 rb_scan_args(argc, argv, "11", &key, &if_none);
110
111 const bool block_given = rb_block_given_p();
112 if (block_given && argc == 2) {
113 rb_warn("block supersedes default value argument");
114 }
115 SafeStringValue(key);
116 const char *nam = RSTRING_PTR(key);
117 if (strlen(nam) != RSTRING_LEN(key)) {
118 rb_raise(rb_eArgError, "bad environment variable name");
119 }
120 const char *env = getenv(nam);
121 if (env == NULL) {
122 if (block_given) {
123 return rb_yield(key);
124 }
125 if (argc == 1) {
126 rb_raise(rb_eKeyError, "key not found");
127 }
128 return if_none;
129 }
130 if (strcmp(nam, PATH_ENV) == 0 && !rb_env_path_tainted()) {
131 return rb_str_new2(env);
132 }
133 return env_str_new2(env);
134 }
135
136 static void
137 path_tainted_p(const char *path)
138 {
139 path_tainted = rb_path_check(path) ? 0 : 1;
140 }
141
142 int
143 rb_env_path_tainted(void)
144 {
145 if (path_tainted < 0) {
146 path_tainted_p(getenv(PATH_ENV));
147 }
148 return path_tainted;
149 }
150
151 void
152 ruby_setenv(const char *name, const char *value)
153 {
154 if (value != NULL) {
155 setenv(name, value, 1);
156 }
157 else {
158 unsetenv(name);
159 }
160 }
161
162 void
163 ruby_unsetenv(const char *name)
164 {
165 ruby_setenv(name, 0);
166 }
167
168 static VALUE
169 env_aset(VALUE obj, SEL sel, VALUE nm, VALUE val)
170 {
171 if (rb_safe_level() >= 4) {
172 rb_raise(rb_eSecurityError, "can't change environment variable");
173 }
174
175 if (NIL_P(val)) {
176 env_delete(obj, nm);
177 return Qnil;
178 }
179 StringValue(nm);
180 StringValue(val);
181 const char *name = RSTRING_PTR(nm);
182 const char *value = RSTRING_PTR(val);
183 if (strlen(name) != RSTRING_LEN(nm)) {
184 rb_raise(rb_eArgError, "bad environment variable name");
185 }
186 if (strlen(value) != RSTRING_LEN(val)) {
187 rb_raise(rb_eArgError, "bad environment variable value");
188 }
189
190 ruby_setenv(name, value);
191 if (strcmp(name, PATH_ENV) == 0) {
192 if (OBJ_TAINTED(val)) {
193 /* already tainted, no check */
194 path_tainted = 1;
195 return val;
196 }
197 else {
198 path_tainted_p(value);
199 }
200 }
201 return val;
202 }
203
204 static VALUE
205 env_keys(VALUE rcv, SEL sel)
206 {
207 rb_secure(4);
208
209 VALUE ary = rb_ary_new();
210 char **env = GET_ENVIRON();
211 while (*env != NULL) {
212 const char *s = strchr(*env, '=');
213 if (s != NULL) {
214 rb_ary_push(ary, env_str_new(*env, s - *env));
215 }
216 env++;
217 }
218 return ary;
219 }
220
221 static VALUE
222 env_each_key(VALUE ehash, SEL sel)
223 {
224 RETURN_ENUMERATOR(ehash, 0, 0);
225 VALUE keys = env_keys(Qnil, 0); /* rb_secure(4); */
226 for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
227 rb_yield(RARRAY_AT(keys, i));
228 RETURN_IF_BROKEN();
229 }
230 return ehash;
231 }
232
233 static VALUE
234 env_values(VALUE rcv, SEL sel)
235 {
236 rb_secure(4);
237
238 VALUE ary = rb_ary_new();
239 char **env = GET_ENVIRON();
240 while (*env != NULL) {
241 const char *s = strchr(*env, '=');
242 if (s != NULL) {
243 rb_ary_push(ary, env_str_new2(s + 1));
244 }
245 env++;
246 }
247 return ary;
248 }
249
250 static VALUE
251 env_each_value(VALUE ehash, SEL sel)
252 {
253 RETURN_ENUMERATOR(ehash, 0, 0);
254 VALUE values = env_values(Qnil, 0); /* rb_secure(4); */
255 for (long i = 0, count = RARRAY_LEN(values); i < count; i++) {
256 rb_yield(RARRAY_AT(values, i));
257 RETURN_IF_BROKEN();
258 }
259 return ehash;
260 }
261
262 static VALUE
263 env_each_pair(VALUE ehash, SEL sel)
264 {
265 RETURN_ENUMERATOR(ehash, 0, 0);
266
267 rb_secure(4);
268 VALUE ary = rb_ary_new();
269 char **env = GET_ENVIRON();
270 while (*env != NULL) {
271 const char *s = strchr(*env, '=');
272 if (s != NULL) {
273 rb_ary_push(ary, env_str_new(*env, s - *env));
274 rb_ary_push(ary, env_str_new2(s + 1));
275 }
276 env++;
277 }
278
279 for (long i = 0, count = RARRAY_LEN(ary); i < count; i += 2) {
280 rb_yield(rb_assoc_new(RARRAY_AT(ary, i), RARRAY_AT(ary, i + 1)));
281 RETURN_IF_BROKEN();
282 }
283 return ehash;
284 }
285
286 static VALUE
287 env_reject_bang(VALUE ehash, SEL sel)
288 {
289 RETURN_ENUMERATOR(ehash, 0, 0);
290 VALUE keys = env_keys(Qnil, 0); /* rb_secure(4); */
291 bool deleted = false;
292 for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
293 VALUE key = RARRAY_AT(keys, i);
294 VALUE val = rb_f_getenv(Qnil, 0, key);
295 if (!NIL_P(val)) {
296 VALUE v = rb_yield_values(2, key, val);
297 RETURN_IF_BROKEN();
298 if (RTEST(v)) {
299 rb_obj_untaint(key);
300 env_delete(Qnil, key);
301 deleted = true;
302 }
303 }
304 }
305 return deleted ? envtbl : Qnil;
306 }
307
308 static VALUE
309 env_delete_if(VALUE ehash, SEL sel)
310 {
311 RETURN_ENUMERATOR(ehash, 0, 0);
312 env_reject_bang(ehash, 0);
313 return envtbl;
314 }
315
316 static VALUE
317 env_values_at(VALUE rcv, SEL sel, int argc, VALUE *argv)
318 {
319 rb_secure(4);
320 VALUE result = rb_ary_new();
321 for (long i = 0; i < argc; i++) {
322 rb_ary_push(result, rb_f_getenv(Qnil, 0, argv[i]));
323 }
324 return result;
325 }
326
327 static VALUE
328 env_select(VALUE ehash, SEL sel)
329 {
330 RETURN_ENUMERATOR(ehash, 0, 0);
331 rb_secure(4);
332 VALUE result = rb_hash_new();
333 char **env = GET_ENVIRON();
334 while (*env != NULL) {
335 const char *s = strchr(*env, '=');
336 if (s != NULL) {
337 VALUE k = env_str_new(*env, s - *env);
338 VALUE v = env_str_new2(s + 1);
339 VALUE v2 = rb_yield_values(2, k, v);
340 RETURN_IF_BROKEN();
341 if (RTEST(v2)) {
342 rb_hash_aset(result, k, v);
343 }
344 }
345 env++;
346 }
347 return result;
348 }
349
350 static VALUE
2839b68 @Watson1978 implement Env#select!
Watson1978 authored
351 env_select_bang(VALUE ehash, SEL sel)
352 {
353 volatile VALUE keys;
354 long i;
355 int del = 0;
356
357 RETURN_ENUMERATOR(ehash, 0, 0);
358 keys = env_keys(Qnil, 0); /* rb_secure(4); */
359 for (i=0; i<RARRAY_LEN(keys); i++) {
360 VALUE val = rb_f_getenv(Qnil, 0, RARRAY_AT(keys, i));
361 if (!NIL_P(val)) {
362 if (!RTEST(rb_yield_values(2, RARRAY_AT(keys, i), val))) {
363 rb_obj_untaint(RARRAY_AT(keys, i));
364 env_delete(Qnil, RARRAY_PTR(keys)[i]);
365 del++;
366 }
367 }
368 }
369 if (del == 0) {
370 return Qnil;
371 }
372 return envtbl;
373 }
374
375 static VALUE
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
376 rb_env_clear_imp(VALUE rcv, SEL sel)
377 {
378 VALUE keys = env_keys(Qnil, 0); /* rb_secure(4); */
379 for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
380 VALUE val = rb_f_getenv(Qnil, 0, RARRAY_AT(keys, i));
381 if (!NIL_P(val)) {
382 env_delete(Qnil, RARRAY_AT(keys, i));
383 }
384 }
385 return envtbl;
386 }
387
388 VALUE
389 rb_env_clear(void)
390 {
391 return rb_env_clear_imp(Qnil, 0);
392 }
393
394 static VALUE
395 env_to_s(VALUE rcv, SEL sel)
396 {
397 return rb_usascii_str_new2("ENV");
398 }
399
400 static VALUE
401 env_inspect(VALUE rcv, SEL sel)
402 {
403 rb_secure(4);
404
405 VALUE str = rb_str_buf_new2("{");
406 char **env = GET_ENVIRON();
407 while (*env != NULL) {
408 const char *s = strchr(*env, '=');
409
410 if (env != GET_ENVIRON()) {
411 rb_str_buf_cat2(str, ", ");
412 }
413 if (s != NULL) {
414 rb_str_buf_cat2(str, "\"");
415 rb_str_buf_cat(str, *env, s - *env);
416 rb_str_buf_cat2(str, "\"=>");
417 VALUE i = rb_inspect(rb_str_new2(s + 1));
418 rb_str_buf_append(str, i);
419 }
420 env++;
421 }
422 rb_str_buf_cat2(str, "}");
423 OBJ_TAINT(str);
424
425 return str;
426 }
427
428 static VALUE
429 env_to_a(VALUE rcv, SEL sel)
430 {
431 rb_secure(4);
432
433 VALUE ary = rb_ary_new();
434 char **env = GET_ENVIRON();
435 while (*env != NULL) {
436 const char *s = strchr(*env, '=');
437 if (s != NULL) {
438 rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s - *env),
439 env_str_new2(s + 1)));
440 }
441 env++;
442 }
443 return ary;
444 }
445
446 static VALUE
447 env_none(VALUE rcv, SEL sel)
448 {
449 return Qnil;
450 }
451
452 static VALUE
453 env_size(VALUE rcv, SEL sel)
454 {
455 rb_secure(4);
456
457 char **env = GET_ENVIRON();
458 int i = 0;
459 while (env[i] != NULL) {
460 i++;
461 }
462 return INT2FIX(i);
463 }
464
465 static VALUE
466 env_empty_p(VALUE rcv, SEL sel)
467 {
468 rb_secure(4);
469
470 char **env = GET_ENVIRON();
471 if (env[0] == NULL) {
472 return Qtrue;
473 }
474 return Qfalse;
475 }
476
477 static VALUE
478 env_has_key(VALUE env, SEL sel, VALUE key)
479 {
480 rb_secure(4);
481
482 const char *s = StringValuePtr(key);
483 if (strlen(s) != RSTRING_LEN(key)) {
484 rb_raise(rb_eArgError, "bad environment variable name");
485 }
486 if (getenv(s) != NULL) {
487 return Qtrue;
488 }
489 return Qfalse;
490 }
491
492 static VALUE
493 env_assoc(VALUE env, SEL sel, VALUE key)
494 {
495 rb_secure(4);
496
497 const char *s = StringValuePtr(key);
498 if (strlen(s) != RSTRING_LEN(key)) {
499 rb_raise(rb_eArgError, "bad environment variable name");
500 }
501 const char *e = getenv(s);
502 if (e != NULL) {
503 return rb_assoc_new(key, rb_tainted_str_new2(e));
504 }
505 return Qnil;
506 }
507
508 static VALUE
509 env_has_value(VALUE dmy, SEL sel, VALUE obj)
510 {
511 rb_secure(4);
512
513 obj = rb_check_string_type(obj);
514 if (NIL_P(obj)) {
515 return Qnil;
516 }
517 char **env = GET_ENVIRON();
518 while (*env != NULL) {
519 const char *s = strchr(*env, '=');
520 if (s++ != NULL) {
521 const long len = strlen(s);
522 if (RSTRING_LEN(obj) == len
523 && strncmp(s, RSTRING_PTR(obj), len) == 0) {
524 return Qtrue;
525 }
526 }
527 env++;
528 }
529 return Qfalse;
530 }
531
532 static VALUE
13f1b83 Add selector to the implementation of `ENV#rassoc`
Thibault Martin-Lagardette authored
533 env_rassoc(VALUE dmy, SEL sel, VALUE obj)
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
534 {
535 rb_secure(4);
536
537 obj = rb_check_string_type(obj);
538 if (NIL_P(obj)) {
539 return Qnil;
540 }
541 char **env = GET_ENVIRON();
542 while (*env != NULL) {
543 const char *s = strchr(*env, '=');
544 if (s++ != NULL) {
545 const long len = strlen(s);
546 if (RSTRING_LEN(obj) == len
547 && strncmp(s, RSTRING_PTR(obj), len) == 0) {
548 return rb_assoc_new(rb_tainted_str_new(*env, s - *env - 1),
549 obj);
550 }
551 }
552 env++;
553 }
554 return Qnil;
555 }
556
557 static VALUE
558 env_key(VALUE dmy, SEL sel, VALUE value)
559 {
560 rb_secure(4);
561
562 StringValue(value);
563 char **env = GET_ENVIRON();
564 while (*env != NULL) {
565 const char *s = strchr(*env, '=');
566 if (s++ != NULL) {
567 const long len = strlen(s);
568 if (RSTRING_LEN(value) == len
569 && strncmp(s, RSTRING_PTR(value), len) == 0) {
570 return env_str_new(*env, s - *env - 1);
571 }
572 }
573 env++;
574 }
575 return Qnil;
576 }
577
578 static VALUE
579 env_index(VALUE dmy, SEL sel, VALUE value)
580 {
581 rb_warn("ENV.index is deprecated; use ENV.key");
582 return env_key(dmy, 0, value);
583 }
584
585 static VALUE
586 env_to_hash(VALUE rcv, SEL sel)
587 {
588 rb_secure(4);
589
590 VALUE hash = rb_hash_new();
591 char **env = GET_ENVIRON();
592 while (*env != NULL) {
593 const char *s = strchr(*env, '=');
594 if (s != NULL) {
595 rb_hash_aset(hash, env_str_new(*env, s - *env),
596 env_str_new2(s + 1));
597 }
598 env++;
599 }
600 return hash;
601 }
602
603 static VALUE
604 env_reject(VALUE rcv, SEL sel)
605 {
606 rb_secure(4);
607
608 RETURN_ENUMERATOR(rcv, 0, 0);
609
610 VALUE hash = rb_hash_new();
611 char **env = GET_ENVIRON();
612 while (*env != NULL) {
613 const char *s = strchr(*env, '=');
614 if (s != NULL) {
615 VALUE key = env_str_new(*env, s - *env);
616 VALUE val = env_str_new2(s + 1);
617 if (!RTEST(rb_yield_values(2, key, val))) {
618 rb_hash_aset(hash, key, val);
619 }
620 }
621 env++;
622 }
623 return hash;
624 }
625
626 static VALUE
627 env_shift(VALUE rcv, SEL sel)
628 {
629 rb_secure(4);
630
631 char **env = GET_ENVIRON();
632 if (*env != NULL) {
633 const char *s = strchr(*env, '=');
634 if (s != NULL) {
635 VALUE key = env_str_new(*env, s - *env);
636 VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
637 env_delete(Qnil, key);
638 return rb_assoc_new(key, val);
639 }
640 }
641 return Qnil;
642 }
643
644 static VALUE
645 env_invert(VALUE rcv, SEL sel)
646 {
647 rb_secure(4);
648
649 VALUE hash = rb_hash_new();
650 char **env = GET_ENVIRON();
651 while (*env != NULL) {
652 const char *s = strchr(*env, '=');
653 if (s != NULL) {
654 rb_hash_aset(hash, env_str_new2(s + 1),
655 env_str_new(*env, s - *env));
656 }
657 env++;
658 }
659 return hash;
660 }
661
662 static int
663 env_replace_i(VALUE key, VALUE val, VALUE keys)
664 {
665 if (key != Qundef) {
666 env_aset(Qnil, 0, key, val);
667 if (rb_ary_includes(keys, key)) {
668 rb_ary_delete(keys, key);
669 }
670 }
671 return ST_CONTINUE;
672 }
673
674 static VALUE
675 env_replace(VALUE env, SEL sel, VALUE hash)
676 {
677 VALUE keys = env_keys(Qnil, 0); /* rb_secure(4); */
678 if (env == hash) {
679 return env;
680 }
681 hash = to_hash(hash);
682 rb_hash_foreach(hash, env_replace_i, keys);
683
684 for (long i = 0, count = RARRAY_LEN(keys); i < count; i++) {
685 env_delete(env, RARRAY_AT(keys, i));
686 }
687 return env;
688 }
689
690 static int
e8a9d92 fix problems detected by the clang lto
Laurent Sansonetti authored
691 env_update_i(VALUE key, VALUE val, VALUE ctx)
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
692 {
693 if (key != Qundef) {
694 if (rb_block_given_p()) {
695 val = rb_yield_values(3, key, rb_f_getenv(Qnil, 0, key), val);
696 RETURN_IF_BROKEN();
697 }
698 env_aset(Qnil, 0, key, val);
699 }
700 return ST_CONTINUE;
701 }
702
703 static VALUE
704 env_update(VALUE env, SEL sel, VALUE hash)
705 {
706 rb_secure(4);
707 if (env == hash) {
708 return env;
709 }
710 hash = to_hash(hash);
711 rb_hash_foreach(hash, env_update_i, 0);
712 return env;
713 }
714
715 void
716 Init_ENV(void)
717 {
718 origenviron = GET_ENVIRON();
719 envtbl = rb_obj_alloc(rb_cObject);
720 rb_extend_object(envtbl, rb_mEnumerable);
721
722 VALUE klass = rb_singleton_class(envtbl);
723
724 rb_objc_define_method(klass, "[]", rb_f_getenv, 1);
725 rb_objc_define_method(klass, "fetch", env_fetch, -1);
726 rb_objc_define_method(klass, "[]=", env_aset, 2);
727 rb_objc_define_method(klass, "store", env_aset, 2);
728 rb_objc_define_method(klass, "each", env_each_pair, 0);
729 rb_objc_define_method(klass, "each_pair", env_each_pair, 0);
730 rb_objc_define_method(klass, "each_key", env_each_key, 0);
731 rb_objc_define_method(klass, "each_value", env_each_value, 0);
732 rb_objc_define_method(klass, "delete", env_delete_m, 1);
733 rb_objc_define_method(klass, "delete_if", env_delete_if, 0);
734 rb_objc_define_method(klass, "clear", rb_env_clear_imp, 0);
735 rb_objc_define_method(klass, "reject", env_reject, 0);
736 rb_objc_define_method(klass, "reject!", env_reject_bang, 0);
737 rb_objc_define_method(klass, "select", env_select, 0);
2839b68 @Watson1978 implement Env#select!
Watson1978 authored
738 rb_objc_define_method(klass, "select!", env_select_bang, 0);
208fcab moved the ENV stuff into a separate file
Laurent Sansonetti authored
739 rb_objc_define_method(klass, "shift", env_shift, 0);
740 rb_objc_define_method(klass, "invert", env_invert, 0);
741 rb_objc_define_method(klass, "replace", env_replace, 1);
742 rb_objc_define_method(klass, "update", env_update, 1);
743 rb_objc_define_method(klass, "inspect", env_inspect, 0);
744 rb_objc_define_method(klass, "rehash", env_none, 0);
745 rb_objc_define_method(klass, "to_a", env_to_a, 0);
746 rb_objc_define_method(klass, "to_s", env_to_s, 0);
747 rb_objc_define_method(klass, "key", env_key, 1);
748 rb_objc_define_method(klass, "index", env_index, 1);
749 rb_objc_define_method(klass, "size", env_size, 0);
750 rb_objc_define_method(klass, "length", env_size, 0);
751 rb_objc_define_method(klass, "empty?", env_empty_p, 0);
752 rb_objc_define_method(klass, "keys", env_keys, 0);
753 rb_objc_define_method(klass, "values", env_values, 0);
754 rb_objc_define_method(klass, "values_at", env_values_at, -1);
755 rb_objc_define_method(klass, "include?", env_has_key, 1);
756 rb_objc_define_method(klass, "member?", env_has_key, 1);
757 rb_objc_define_method(klass, "has_key?", env_has_key, 1);
758 rb_objc_define_method(klass, "has_value?", env_has_value, 1);
759 rb_objc_define_method(klass, "key?", env_has_key, 1);
760 rb_objc_define_method(klass, "value?", env_has_value, 1);
761 rb_objc_define_method(klass, "to_hash", env_to_hash, 0);
762 rb_objc_define_method(klass, "assoc", env_assoc, 1);
763 rb_objc_define_method(klass, "rassoc", env_rassoc, 1);
764
765 rb_define_global_const("ENV", envtbl);
766 }
Something went wrong with that request. Please try again.