From c04393679da2c25c82c7eacb1db681627b1522c9 Mon Sep 17 00:00:00 2001 From: Konstantin Makarchev Date: Sat, 22 Jun 2013 22:34:35 +0400 Subject: [PATCH] ENV variable --- lib-topaz/bootstrap.rb | 1 + lib-topaz/env.rb | 161 ++++++++++++++++++ lib-topaz/errno.rb | 3 + spec/tags/core/env/assoc_tags.txt | 3 - spec/tags/core/env/clear_tags.txt | 1 - spec/tags/core/env/delete_if_tags.txt | 4 - spec/tags/core/env/each_key_tags.txt | 2 - spec/tags/core/env/each_pair_tags.txt | 3 - spec/tags/core/env/each_tags.txt | 3 - spec/tags/core/env/each_value_tags.txt | 2 - spec/tags/core/env/element_reference_tags.txt | 3 - spec/tags/core/env/element_set_tags.txt | 5 - spec/tags/core/env/empty_tags.txt | 2 - spec/tags/core/env/fetch_tags.txt | 4 - spec/tags/core/env/has_key_tags.txt | 2 - spec/tags/core/env/has_value_tags.txt | 2 - spec/tags/core/env/include_tags.txt | 2 - spec/tags/core/env/index_tags.txt | 2 - spec/tags/core/env/inspect_tags.txt | 1 - spec/tags/core/env/invert_tags.txt | 1 - spec/tags/core/env/keep_if_tags.txt | 4 - spec/tags/core/env/key_tags.txt | 4 - spec/tags/core/env/keys_tags.txt | 1 - spec/tags/core/env/length_tags.txt | 1 - spec/tags/core/env/member_tags.txt | 2 - spec/tags/core/env/rassoc_tags.txt | 3 - spec/tags/core/env/reject_tags.txt | 10 -- spec/tags/core/env/replace_tags.txt | 1 - spec/tags/core/env/select_tags.txt | 6 - spec/tags/core/env/shift_tags.txt | 2 - spec/tags/core/env/size_tags.txt | 1 - spec/tags/core/env/store_tags.txt | 10 -- spec/tags/core/env/to_a_tags.txt | 1 - spec/tags/core/env/to_hash_tags.txt | 1 - spec/tags/core/env/to_s_tags.txt | 1 - spec/tags/core/env/update_tags.txt | 2 - spec/tags/core/env/value_tags.txt | 2 - spec/tags/core/env/values_at_tags.txt | 1 - spec/tags/core/env/values_tags.txt | 1 - topaz/objects/envobject.py | 54 ++++-- topaz/objspace.py | 10 ++ 41 files changed, 217 insertions(+), 108 deletions(-) create mode 100644 lib-topaz/env.rb delete mode 100644 spec/tags/core/env/assoc_tags.txt delete mode 100644 spec/tags/core/env/clear_tags.txt delete mode 100644 spec/tags/core/env/delete_if_tags.txt delete mode 100644 spec/tags/core/env/each_pair_tags.txt delete mode 100644 spec/tags/core/env/each_tags.txt delete mode 100644 spec/tags/core/env/element_reference_tags.txt delete mode 100644 spec/tags/core/env/element_set_tags.txt delete mode 100644 spec/tags/core/env/empty_tags.txt delete mode 100644 spec/tags/core/env/has_key_tags.txt delete mode 100644 spec/tags/core/env/has_value_tags.txt delete mode 100644 spec/tags/core/env/include_tags.txt delete mode 100644 spec/tags/core/env/index_tags.txt delete mode 100644 spec/tags/core/env/inspect_tags.txt delete mode 100644 spec/tags/core/env/invert_tags.txt delete mode 100644 spec/tags/core/env/keep_if_tags.txt delete mode 100644 spec/tags/core/env/key_tags.txt delete mode 100644 spec/tags/core/env/length_tags.txt delete mode 100644 spec/tags/core/env/member_tags.txt delete mode 100644 spec/tags/core/env/rassoc_tags.txt delete mode 100644 spec/tags/core/env/reject_tags.txt delete mode 100644 spec/tags/core/env/replace_tags.txt delete mode 100644 spec/tags/core/env/select_tags.txt delete mode 100644 spec/tags/core/env/shift_tags.txt delete mode 100644 spec/tags/core/env/size_tags.txt delete mode 100644 spec/tags/core/env/store_tags.txt delete mode 100644 spec/tags/core/env/to_s_tags.txt delete mode 100644 spec/tags/core/env/update_tags.txt delete mode 100644 spec/tags/core/env/value_tags.txt diff --git a/lib-topaz/bootstrap.rb b/lib-topaz/bootstrap.rb index ae1cd9e08..895d69ba0 100644 --- a/lib-topaz/bootstrap.rb +++ b/lib-topaz/bootstrap.rb @@ -11,6 +11,7 @@ load_bootstrap.call("comparable.rb") load_bootstrap.call("enumerable.rb") load_bootstrap.call("enumerator.rb") +load_bootstrap.call("env.rb") load_bootstrap.call("errno.rb") load_bootstrap.call("file.rb") load_bootstrap.call("fixnum.rb") diff --git a/lib-topaz/env.rb b/lib-topaz/env.rb new file mode 100644 index 000000000..96795585e --- /dev/null +++ b/lib-topaz/env.rb @@ -0,0 +1,161 @@ +class << ENV + def to_hash + {}.tap{ |h| self.each { |k, v| h[k] = v } } + end + + def empty? + self.size == 0 + end + + def replace(hash) + hash = Topaz.convert_type(hash, Hash, :to_hash) + self.clear + hash.each { |k, v| self[k] = v } + self + end + + def update(hash, &block) + hash = Topaz.convert_type(hash, Hash, :to_hash) + hash.each do |k, v| + if block && self[k] + self[k] = yield(k, self[k], v) + else + self[k] = v + end + end + self + end + + def clear + self.each_key { |k| self[k] = nil } + end + + def values + self.map { |_, v| v } + end + + def keys + self.map { |k, _| k } + end + + def value?(value) + self.each_value { |v| return true if v == value } + false + end + alias has_value? value? + + def key(value) + self.each { |k, v| return k if v == value } + nil + end + alias index key + + def each_value(&block) + return enum_for(:each_value) unless block + self.each { |_, v| yield(v) } + end + + def each_key(&block) + return enum_for(:each_key) unless block + self.each { |k, _| yield(k) } + end + + def assoc(key) + key = Topaz.convert_type(key, String, :to_str) + self.each { |k, v| return [k, v] if key == k } + nil + end + + def rassoc(value) + value = Topaz.convert_type(value, String, :to_str) + self.each { |k, v| return [k, v] if value == v } + nil + end + + def select!(&block) + return enum_for(:select!) unless block + modified = false + self.each do |key, value| + unless yield(key, value) + delete(key) + modified = true + end + end + modified ? self : nil + end + + def keep_if(&block) + return enum_for(:keep_if) unless block + select!(&block) + self + end + + def reject!(&block) + return enum_for(:reject!) unless block + modified = false + self.each do |key, value| + if yield(key, value) + delete(key) + modified = true + end + end + modified ? self : nil + end + + def delete_if(&block) + return enum_for(:delete_if) unless block + reject!(&block) + self + end + + def fetch(key, *args, &block) + val = self[key] + return val if val + return yield(key) if block + return args[0] if args.size == 1 + raise KeyError.new("key not found") + end + + def to_s + 'ENV' + end + + def inspect + to_hash.inspect + end + + def shift + self.each do |k, v| + delete(k) + return [k, v] + end + nil + end + + def values_at(*keys) + keys.map { |k| self[k] } + end + + def invert + {}.tap { |h| self.each { |k, v| h[v] = k } } + end + + def select(&block) + return enum_for(:select) unless block + to_hash.keep_if(&block) + end + + def reject(&block) + return enum_for(:reject) unless block + to_hash.delete_if(&block) + end + + def delete(key, &block) + key = Topaz.convert_type(key, String, :to_str) + if val = self[key] + self[key] = nil + return val + end + block ? yield(key) : nil + end +end diff --git a/lib-topaz/errno.rb b/lib-topaz/errno.rb index 3948fcccc..78cd6e386 100644 --- a/lib-topaz/errno.rb +++ b/lib-topaz/errno.rb @@ -16,4 +16,7 @@ class EISDIR < SystemCallError class ENOTEMPTY < SystemCallError end + + class EINVAL < SystemCallError + end end diff --git a/spec/tags/core/env/assoc_tags.txt b/spec/tags/core/env/assoc_tags.txt deleted file mode 100644 index d5fff5107..000000000 --- a/spec/tags/core/env/assoc_tags.txt +++ /dev/null @@ -1,3 +0,0 @@ -fails:ENV.assoc returns an array of the key and value of the environment variable with the given key -fails:ENV.assoc returns nil if no environment variable with the given key exists -fails:ENV.assoc returns the key element coerced with #to_str diff --git a/spec/tags/core/env/clear_tags.txt b/spec/tags/core/env/clear_tags.txt deleted file mode 100644 index 128262a78..000000000 --- a/spec/tags/core/env/clear_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:ENV.clear deletes all environment variables diff --git a/spec/tags/core/env/delete_if_tags.txt b/spec/tags/core/env/delete_if_tags.txt deleted file mode 100644 index 97f27512a..000000000 --- a/spec/tags/core/env/delete_if_tags.txt +++ /dev/null @@ -1,4 +0,0 @@ -fails:ENV.delete_if deletes pairs if the block returns true -fails:ENV.delete_if returns ENV even if nothing deleted -fails:ENV.delete_if returns an Enumerator if no block given -fails:ENV.delete_if deletes pairs through enumerator diff --git a/spec/tags/core/env/each_key_tags.txt b/spec/tags/core/env/each_key_tags.txt index 59c6140e4..d7299092f 100644 --- a/spec/tags/core/env/each_key_tags.txt +++ b/spec/tags/core/env/each_key_tags.txt @@ -1,3 +1 @@ -fails:ENV.each_key returns each key -fails:ENV.each_key returns an Enumerator if called without a block fails:ENV.each_key returns keys in the locale encoding diff --git a/spec/tags/core/env/each_pair_tags.txt b/spec/tags/core/env/each_pair_tags.txt deleted file mode 100644 index 50f4676e5..000000000 --- a/spec/tags/core/env/each_pair_tags.txt +++ /dev/null @@ -1,3 +0,0 @@ -fails:ENV.each_pair returns each pair -fails:ENV.each_pair returns an Enumerator if called without a block -fails:ENV.each_pair uses the locale encoding diff --git a/spec/tags/core/env/each_tags.txt b/spec/tags/core/env/each_tags.txt deleted file mode 100644 index 66c9efa3c..000000000 --- a/spec/tags/core/env/each_tags.txt +++ /dev/null @@ -1,3 +0,0 @@ -fails:ENV.each returns each pair -fails:ENV.each returns an Enumerator if called without a block -fails:ENV.each uses the locale encoding diff --git a/spec/tags/core/env/each_value_tags.txt b/spec/tags/core/env/each_value_tags.txt index 7f8309a6a..07a1921ce 100644 --- a/spec/tags/core/env/each_value_tags.txt +++ b/spec/tags/core/env/each_value_tags.txt @@ -1,3 +1 @@ -fails:ENV.each_value returns each value -fails:ENV.each_value returns an Enumerator if called without a block fails:ENV.each_value uses the locale encoding diff --git a/spec/tags/core/env/element_reference_tags.txt b/spec/tags/core/env/element_reference_tags.txt deleted file mode 100644 index c818d35f6..000000000 --- a/spec/tags/core/env/element_reference_tags.txt +++ /dev/null @@ -1,3 +0,0 @@ -fails:ENV.[] returns the specified environment variable -fails:ENV.[] returns only frozen values -fails:ENV.[] uses the locale encoding diff --git a/spec/tags/core/env/element_set_tags.txt b/spec/tags/core/env/element_set_tags.txt deleted file mode 100644 index e92aadb68..000000000 --- a/spec/tags/core/env/element_set_tags.txt +++ /dev/null @@ -1,5 +0,0 @@ -fails:ENV.[]= returns the value -fails:ENV.[]= deletes the environment variable when the value is nil -fails:ENV.[]= raises Errno::EINVAL when the key contains the '=' character -fails:ENV.[]= raises Errno::EINVAL when the key is an empty string -fails:ENV.[]= does nothing when the key is not a valid environment variable key and the value is nil diff --git a/spec/tags/core/env/empty_tags.txt b/spec/tags/core/env/empty_tags.txt deleted file mode 100644 index 90d745d55..000000000 --- a/spec/tags/core/env/empty_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.empty? return true if the Environment is empty -fails:ENV.empty? returns false if not empty diff --git a/spec/tags/core/env/fetch_tags.txt b/spec/tags/core/env/fetch_tags.txt index 431d994ee..15d95ca4c 100644 --- a/spec/tags/core/env/fetch_tags.txt +++ b/spec/tags/core/env/fetch_tags.txt @@ -1,6 +1,2 @@ -fails:ENV.fetch returns a value -fails:ENV.fetch raises IndexError for an invalid key -fails:ENV.fetch provides the given default parameter -fails:ENV.fetch provides a default value from a block fails:ENV.fetch warns on block and default parameter given fails:ENV.fetch uses the locale encoding diff --git a/spec/tags/core/env/has_key_tags.txt b/spec/tags/core/env/has_key_tags.txt deleted file mode 100644 index e629970d3..000000000 --- a/spec/tags/core/env/has_key_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.has_key? returns true if ENV has the key -fails:ENV.has_key? return false if ENV doesn't include the key diff --git a/spec/tags/core/env/has_value_tags.txt b/spec/tags/core/env/has_value_tags.txt deleted file mode 100644 index 736fd6c56..000000000 --- a/spec/tags/core/env/has_value_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.has_value? returns true if ENV has the value -fails:ENV.has_value? returns false if ENV doesn't have the value diff --git a/spec/tags/core/env/include_tags.txt b/spec/tags/core/env/include_tags.txt deleted file mode 100644 index 97c110ce3..000000000 --- a/spec/tags/core/env/include_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.include? returns true if ENV has the key -fails:ENV.include? return false if ENV doesn't include the key diff --git a/spec/tags/core/env/index_tags.txt b/spec/tags/core/env/index_tags.txt deleted file mode 100644 index 48426af20..000000000 --- a/spec/tags/core/env/index_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.index returns the index associated with the passed value -fails:ENV.index returns nil if the passed value is not found diff --git a/spec/tags/core/env/inspect_tags.txt b/spec/tags/core/env/inspect_tags.txt deleted file mode 100644 index 34ea76c60..000000000 --- a/spec/tags/core/env/inspect_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:ENV.inspect returns a String that looks like a Hash with real data diff --git a/spec/tags/core/env/invert_tags.txt b/spec/tags/core/env/invert_tags.txt deleted file mode 100644 index 119383841..000000000 --- a/spec/tags/core/env/invert_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:ENV.invert returns a hash with ENV.keys as the values and vice versa diff --git a/spec/tags/core/env/keep_if_tags.txt b/spec/tags/core/env/keep_if_tags.txt deleted file mode 100644 index f5f0c56a8..000000000 --- a/spec/tags/core/env/keep_if_tags.txt +++ /dev/null @@ -1,4 +0,0 @@ -fails:ENV.keep_if deletes pairs if the block returns false -fails:ENV.keep_if returns ENV even if nothing deleted -fails:ENV.keep_if returns an Enumerator if no block given -fails:ENV.keep_if deletes pairs through enumerator diff --git a/spec/tags/core/env/key_tags.txt b/spec/tags/core/env/key_tags.txt deleted file mode 100644 index 06d1e91c5..000000000 --- a/spec/tags/core/env/key_tags.txt +++ /dev/null @@ -1,4 +0,0 @@ -fails:ENV.key? returns true if ENV has the key -fails:ENV.key? return false if ENV doesn't include the key -fails:ENV.key returns the index associated with the passed value -fails:ENV.key returns nil if the passed value is not found diff --git a/spec/tags/core/env/keys_tags.txt b/spec/tags/core/env/keys_tags.txt index 302d57a3c..7a73a59ba 100644 --- a/spec/tags/core/env/keys_tags.txt +++ b/spec/tags/core/env/keys_tags.txt @@ -1,2 +1 @@ -fails:ENV.keys returns all the keys fails:ENV.keys returns the keys in the locale encoding diff --git a/spec/tags/core/env/length_tags.txt b/spec/tags/core/env/length_tags.txt deleted file mode 100644 index 30d373de5..000000000 --- a/spec/tags/core/env/length_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:ENV.length returns the number of ENV entries diff --git a/spec/tags/core/env/member_tags.txt b/spec/tags/core/env/member_tags.txt deleted file mode 100644 index 1736548c7..000000000 --- a/spec/tags/core/env/member_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.member? returns true if ENV has the key -fails:ENV.member? return false if ENV doesn't include the key diff --git a/spec/tags/core/env/rassoc_tags.txt b/spec/tags/core/env/rassoc_tags.txt deleted file mode 100644 index 8102dec35..000000000 --- a/spec/tags/core/env/rassoc_tags.txt +++ /dev/null @@ -1,3 +0,0 @@ -fails:ENV.rassoc returns an array of the key and value of the environment variable with the given value -fails:ENV.rassoc returns nil if no environment variable with the given value exists -fails:ENV.rassoc returns the value element coerced with #to_str diff --git a/spec/tags/core/env/reject_tags.txt b/spec/tags/core/env/reject_tags.txt deleted file mode 100644 index c5b919d35..000000000 --- a/spec/tags/core/env/reject_tags.txt +++ /dev/null @@ -1,10 +0,0 @@ -fails:ENV.reject! rejects entries based on key -fails:ENV.reject! rejects entries based on value -fails:ENV.reject! returns itself or nil -fails:ENV.reject! returns an Enumerator if called without a block -fails:ENV.reject! doesn't raise if empty -fails:ENV.reject rejects entries based on key -fails:ENV.reject rejects entries based on value -fails:ENV.reject returns a Hash -fails:ENV.reject returns an Enumerator if called without a block -fails:ENV.reject doesn't raise if empty diff --git a/spec/tags/core/env/replace_tags.txt b/spec/tags/core/env/replace_tags.txt deleted file mode 100644 index 5de30beaf..000000000 --- a/spec/tags/core/env/replace_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:ENV.replace replaces ENV with a Hash diff --git a/spec/tags/core/env/select_tags.txt b/spec/tags/core/env/select_tags.txt deleted file mode 100644 index 442567774..000000000 --- a/spec/tags/core/env/select_tags.txt +++ /dev/null @@ -1,6 +0,0 @@ -fails:ENV.select! removes environment variables for which the block returns true -fails:ENV.select! returns self if any changes were made -fails:ENV.select! returns nil if no changes were made -fails:ENV.select! returns an Enumerator if called without a block -fails:ENV.select returns a Hash of names and values for which block return true -fails:ENV.select returns an Enumerator when no block is given diff --git a/spec/tags/core/env/shift_tags.txt b/spec/tags/core/env/shift_tags.txt deleted file mode 100644 index 22127de35..000000000 --- a/spec/tags/core/env/shift_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.shift returns a pair and deletes it -fails:ENV.shift returns nil if ENV.empty? diff --git a/spec/tags/core/env/size_tags.txt b/spec/tags/core/env/size_tags.txt deleted file mode 100644 index 9aa4f5468..000000000 --- a/spec/tags/core/env/size_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:ENV.size returns the number of ENV entries diff --git a/spec/tags/core/env/store_tags.txt b/spec/tags/core/env/store_tags.txt deleted file mode 100644 index 67b2d4ba7..000000000 --- a/spec/tags/core/env/store_tags.txt +++ /dev/null @@ -1,10 +0,0 @@ -fails:ENV.store sets the environment variable to the given value -fails:ENV.store returns the value -fails:ENV.store deletes the environment variable when the value is nil -fails:ENV.store coerces the key argument with #to_str -fails:ENV.store coerces the value argument with #to_str -fails:ENV.store raises TypeError when the key is not coercible to String -fails:ENV.store raises TypeError when the value is not coercible to String -fails:ENV.store raises Errno::EINVAL when the key contains the '=' character -fails:ENV.store raises Errno::EINVAL when the key is an empty string -fails:ENV.store does nothing when the key is not a valid environment variable key and the value is nil diff --git a/spec/tags/core/env/to_a_tags.txt b/spec/tags/core/env/to_a_tags.txt index 83ddabdf9..85c1b08e4 100644 --- a/spec/tags/core/env/to_a_tags.txt +++ b/spec/tags/core/env/to_a_tags.txt @@ -1,2 +1 @@ -fails:ENV.to_a returns the ENV as an array fails:ENV.to_a returns the entries in the locale encoding diff --git a/spec/tags/core/env/to_hash_tags.txt b/spec/tags/core/env/to_hash_tags.txt index 5343601ae..8a33ef6d2 100644 --- a/spec/tags/core/env/to_hash_tags.txt +++ b/spec/tags/core/env/to_hash_tags.txt @@ -1,3 +1,2 @@ -fails:ENV.to_hash returns the ENV as a hash fails:ENV.to_hash uses the locale encoding for keys fails:ENV.to_hash uses the locale encoding for values diff --git a/spec/tags/core/env/to_s_tags.txt b/spec/tags/core/env/to_s_tags.txt deleted file mode 100644 index 37fb5c310..000000000 --- a/spec/tags/core/env/to_s_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:ENV.to_s returns "ENV" diff --git a/spec/tags/core/env/update_tags.txt b/spec/tags/core/env/update_tags.txt deleted file mode 100644 index c53fad98b..000000000 --- a/spec/tags/core/env/update_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.update add the parameter hash to ENV -fails:ENV.update yields key, the old value and the new value when replacing entries diff --git a/spec/tags/core/env/value_tags.txt b/spec/tags/core/env/value_tags.txt deleted file mode 100644 index d807de697..000000000 --- a/spec/tags/core/env/value_tags.txt +++ /dev/null @@ -1,2 +0,0 @@ -fails:ENV.value? returns true if ENV has the value -fails:ENV.value? returns false if ENV doesn't have the value diff --git a/spec/tags/core/env/values_at_tags.txt b/spec/tags/core/env/values_at_tags.txt index 745505e88..834c37d3c 100644 --- a/spec/tags/core/env/values_at_tags.txt +++ b/spec/tags/core/env/values_at_tags.txt @@ -1,2 +1 @@ -fails:ENV.values_at returns an array of the values referenced by the parameters as keys fails:ENV.values_at uses the locale encoding diff --git a/spec/tags/core/env/values_tags.txt b/spec/tags/core/env/values_tags.txt index 4f8d124cd..0fccc99cc 100644 --- a/spec/tags/core/env/values_tags.txt +++ b/spec/tags/core/env/values_tags.txt @@ -1,2 +1 @@ -fails:ENV.values returns an array of the values fails:ENV.values uses the locale encoding diff --git a/topaz/objects/envobject.py b/topaz/objects/envobject.py index bcb62104d..b3ed49090 100644 --- a/topaz/objects/envobject.py +++ b/topaz/objects/envobject.py @@ -1,11 +1,14 @@ import os from topaz.module import ClassDef +from topaz.coerce import Coerce from topaz.objects.objectobject import W_Object +from topaz.modules.enumerable import Enumerable class W_EnvObject(W_Object): classdef = ClassDef("EnviromentVariables", W_Object.classdef) + classdef.include_module(Enumerable) @classdef.setup_class def setup_class(cls, space, w_cls): @@ -23,26 +26,53 @@ def method_subscript(self, space, key): val = os.environ[key] except KeyError: return space.w_nil - return space.newstr_fromstr(val) + return space.newstr_fromstr_frozen(val) - @classdef.method("[]=", key="str", value="str") - def method_subscript_assign(self, space, key, value): + @classdef.method("store", key="str") + @classdef.method("[]=", key="str") + def method_subscript_assign(self, space, key, w_value): if "\0" in key: raise space.error(space.w_ArgumentError, "bad environment variable name") + if w_value is space.w_nil: + try: + del os.environ[key] + except: + pass + return space.w_nil + if "=" in key or key is "": + raise space.errno_error("EINVAL", "Invalid argument - setenv") + value = Coerce.str(space, w_value) if "\0" in value: raise space.error(space.w_ArgumentError, "bad environment variable value") os.environ[key] = value - return space.newstr_fromstr(value) + return w_value + + @classdef.method("each_pair") + @classdef.method("each") + def method_each(self, space, block): + if block is None: + return space.send(self, "enum_for", [space.newsymbol("each")]) + for k, v in os.environ.items(): + space.invoke_block(block, [space.newarray([ + space.newstr_fromstr_frozen(k), + space.newstr_fromstr_frozen(v) + ])]) + return self + + @classdef.method("length") + @classdef.method("size") + def method_size(self, space): + return space.newint(len(os.environ.items())) - @classdef.method("delete", key="str") - def method_delete(self, space, key, block=None): + @classdef.method("key?", key="str") + @classdef.method("has_key?", key="str") + @classdef.method("member?", key="str") + @classdef.method("include?", key="str") + def method_includep(self, space, key): if "\0" in key: raise space.error(space.w_ArgumentError, "bad environment variable name") try: - val = os.environ[key] + os.environ[key] except KeyError: - if block is not None: - space.invoke_block(block, [space.newstr_fromstr(key)]) - return space.w_nil - del os.environ[key] - return space.newstr_fromstr(val) + return space.newbool(False) + return space.newbool(True) diff --git a/topaz/objspace.py b/topaz/objspace.py index 0231dac83..adc7c2a5f 100644 --- a/topaz/objspace.py +++ b/topaz/objspace.py @@ -381,6 +381,12 @@ def newstr_fromstr(self, strvalue): assert strvalue is not None return W_StringObject.newstr_fromstr(self, strvalue) + def newstr_fromstr_frozen(self, strvalue): + assert strvalue is not None + w_str = W_StringObject.newstr_fromstr(self, strvalue) + self.send(w_str, "freeze") + return w_str + def newstr_fromstrs(self, strs_w): return W_StringObject.newstr_fromstrs(self, strs_w) @@ -665,6 +671,10 @@ def error(self, w_type, msg="", optargs=None): assert isinstance(w_exc, W_ExceptionObject) return RubyError(w_exc) + def errno_error(self, name, msg=""): + w_type = self.find_const(self.find_const(self.w_object, "Errno"), name) + return self.error(w_type, msg) + def hash_w(self, w_obj): return self.int_w(self.send(w_obj, "hash"))