summaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-06-22 16:26:07 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-06-22 16:26:07 +0000
commitfdf213b71a4a9d1a48708516c6cfc6cc85da7c74 (patch)
tree72542cb5476a7ccf446fbf3c864842230b175e4a /hash.c
parent115410ecde172034fdbfdea703252dcfc6ea0468 (diff)
* hash.c (rb_hash_assoc): new method.
* hash.c (rb_hash_rassoc): ditto. * hash.c (rb_hash_flatten): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12587 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c147
1 files changed, 144 insertions, 3 deletions
diff --git a/hash.c b/hash.c
index 43d3ff2877..d5d0e3cb92 100644
--- a/hash.c
+++ b/hash.c
@@ -1517,6 +1517,103 @@ rb_hash_merge(VALUE hash1, VALUE hash2)
return rb_hash_update(rb_obj_dup(hash1), hash2);
}
+static int
+assoc_i(VALUE key, VALUE val, VALUE *args)
+{
+ if (key == Qundef) return ST_CONTINUE;
+ if (RTEST(rb_equal(args[0], key))) {
+ args[1] = rb_assoc_new(key, val);
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * hash.assoc(obj) -> an_array or nil
+ *
+ * Searches through the hash comparing _obj_ with the key using <code>==</code>.
+ * Returns the key-value pair (two elements array) or +nil+
+ * if no match is found. See <code>Array#assoc</code>.
+ *
+ * h = {"colors" => ["red", "blue", "green"],
+ * "letters" => ["a", "b", "c" ]}
+ * h.assoc("letters") #=> ["letters", ["a", "b", "c"]]
+ * h.assoc("foo") #=> nil
+ */
+
+VALUE
+rb_hash_assoc(VALUE hash, VALUE obj)
+{
+ VALUE args[2];
+
+ args[0] = obj;
+ args[1] = Qnil;
+ rb_hash_foreach(hash, assoc_i, (st_data_t)args);
+ return args[1];
+}
+
+static int
+rassoc_i(VALUE key, VALUE val, VALUE *args)
+{
+ if (key == Qundef) return ST_CONTINUE;
+ if (RTEST(rb_equal(args[0], val))) {
+ args[1] = rb_assoc_new(key, val);
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * hash.rassoc(key) -> an_array or nil
+ *
+ * Searches through the hash comparing _obj_ with the value using <code>==</code>.
+ * Returns the first key-value pair (two elements array) that matches. See
+ * also <code>Array#rassoc</code>.
+ *
+ * a = {1=> "one", 2 => "two", 3 => "three", "ii" => "two"}
+ * a.rassoc("two") #=> [2, "two"]
+ * a.rassoc("four") #=> nil
+ */
+
+VALUE
+rb_hash_rassoc(VALUE hash, VALUE obj)
+{
+ VALUE args[2];
+
+ args[0] = obj;
+ args[1] = Qnil;
+ rb_hash_foreach(hash, rassoc_i, (st_data_t)args);
+ return args[1];
+}
+
+/*
+ * call-seq:
+ * hash.flatten -> an_array
+ * hash.flatten(level) -> an_array
+ *
+ * Returns a new array that is a one-dimensional flattening of this
+ * hash. That is, for every key or value that is an array, extract
+ * its elements into the new array. Unlike Array#flatten, this
+ * method does not flatten recursively by default. If the optional
+ * <i>level</i> argument determins the level of recursion to flatten.
+ *
+ * a = {1=> "one", 2 => [2,"two"], 3 => "three"}
+ * a.flatten # => [1, "one", 2, [2, "two"], 3, "three"]
+ * a.flatten(2) # => [1, "one", 2, 2, "two", 3, "three"]
+ */
+
+static VALUE
+rb_hash_flatten(int argc, VALUE *argv, VALUE hash)
+{
+ VALUE ary, lv;
+
+ ary = rb_hash_to_a(hash);
+ rb_funcall2(ary, rb_intern("flatten!"), argc, argv);
+ return ary;
+}
+
static struct st_hash_type identhash = {
st_numcmp,
st_numhash,
@@ -2176,18 +2273,33 @@ env_has_key(VALUE env, VALUE key)
}
static VALUE
-env_has_value(VALUE dmy, VALUE value)
+env_assoc(VALUE env, VALUE key)
+{
+ char *s, *e;
+
+ rb_secure(4);
+ s = StringValuePtr(key);
+ if (strlen(s) != RSTRING_LEN(key))
+ rb_raise(rb_eArgError, "bad environment variable name");
+ e = getenv(s);
+ if (e) return rb_assoc_new(key, rb_tainted_str_new2(e));
+ return Qnil;
+}
+
+static VALUE
+env_has_value(VALUE dmy, VALUE obj)
{
char **env;
rb_secure(4);
- if (TYPE(value) != T_STRING) return Qfalse;
+ obj = rb_check_string_type(obj);
+ if (NIL_P(obj)) return Qnil;
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s++) {
long len = strlen(s);
- if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
+ if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
FREE_ENVIRON(environ);
return Qtrue;
}
@@ -2199,6 +2311,30 @@ env_has_value(VALUE dmy, VALUE value)
}
static VALUE
+env_rassoc(VALUE dmy, VALUE obj)
+{
+ char **env;
+
+ rb_secure(4);
+ obj = rb_check_string_type(obj);
+ if (NIL_P(obj)) return Qnil;
+ env = GET_ENVIRON(environ);
+ while (*env) {
+ char *s = strchr(*env, '=');
+ if (s++) {
+ long len = strlen(s);
+ if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
+ FREE_ENVIRON(environ);
+ return rb_assoc_new(rb_tainted_str_new(*env, s-*env-1), obj);
+ }
+ }
+ env++;
+ }
+ FREE_ENVIRON(environ);
+ return Qnil;
+}
+
+static VALUE
env_key(VALUE dmy, VALUE value)
{
char **env;
@@ -2407,6 +2543,9 @@ Init_Hash(void)
rb_define_method(rb_cHash,"replace", rb_hash_replace, 1);
rb_define_method(rb_cHash,"merge!", rb_hash_update, 1);
rb_define_method(rb_cHash,"merge", rb_hash_merge, 1);
+ rb_define_method(rb_cHash, "assoc", rb_hash_assoc, 1);
+ rb_define_method(rb_cHash, "rassoc", rb_hash_rassoc, 1);
+ rb_define_method(rb_cHash, "flatten", rb_hash_flatten, -1);
rb_define_method(rb_cHash,"include?", rb_hash_has_key, 1);
rb_define_method(rb_cHash,"member?", rb_hash_has_key, 1);
@@ -2460,6 +2599,8 @@ Init_Hash(void)
rb_define_singleton_method(envtbl,"key?", env_has_key, 1);
rb_define_singleton_method(envtbl,"value?", env_has_value, 1);
rb_define_singleton_method(envtbl,"to_hash", env_to_hash, 0);
+ rb_define_singleton_method(envtbl,"assoc", env_assoc, 1);
+ rb_define_singleton_method(envtbl,"rassoc", env_rassoc, 1);
rb_define_global_const("ENV", envtbl);
#else /* __MACOS__ */