summaryrefslogtreecommitdiff
path: root/lib/soap/property.rb
diff options
context:
space:
mode:
authornahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-12-04 04:05:51 +0000
committernahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-12-04 04:05:51 +0000
commit20fa0df5cd7f297b1694b75b776516b51460ba55 (patch)
tree73cbdf22c4ea8ccf43fe55c69396885159db4aea /lib/soap/property.rb
parentb28a2a1ad645b21679d088c738d0e0ef70758a19 (diff)
* lib/soap/soap.rb: add SOAP::Env module for environment repository
such as HTTP_PROXY. * lib/soap/property.rb: property implementation. * lib/soap/streamHandler.rb, lib/soap/wsdlDriver.rb, lib/soap/rpc/driver.rb: use soap/property.rb. * lib/wsdl/importer.rb, lib/soap/wsdlDriver.rb, lib/soap/rpc/driver.rb: use SOAP::Env. * lib/soap/netHttpClient.rb: add basic_auth, ssl_config, and cookie management interface, but ignored for now. * lib/xsd/charset.rb: add XSD::Charset.encoding= interface to set wiredump charset explicitly. it was fixed to 'utf-8' when iconv or uconv module was found. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5104 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/soap/property.rb')
-rw-r--r--lib/soap/property.rb232
1 files changed, 232 insertions, 0 deletions
diff --git a/lib/soap/property.rb b/lib/soap/property.rb
new file mode 100644
index 0000000000..84fa876cae
--- /dev/null
+++ b/lib/soap/property.rb
@@ -0,0 +1,232 @@
+# soap/property.rb: SOAP4R - Property implementation.
+# Copyright (C) 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
+
+# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
+# redistribute it and/or modify it under the same terms of Ruby's license;
+# either the dual license version in 2003, or any later version.
+
+
+module SOAP
+
+
+class Property
+ include Enumerable
+
+ def initialize
+ @store = Hash.new
+ @hook = Hash.new
+ @self_hook = Array.new
+ @locked = false
+ end
+
+ # name: a Symbol, String or an Array
+ def [](name)
+ referent(name_to_a(name))
+ end
+
+ # name: a Symbol, String or an Array
+ # value: an Object
+ def []=(name, value)
+ hooks = assign(name_to_a(name), value)
+ normalized_name = normalize_name(name)
+ hooks.each do |hook|
+ hook.call(normalized_name, value)
+ end
+ value
+ end
+
+ # value: an Object
+ # key is generated by property
+ def <<(value)
+ self[generate_new_key] = value
+ end
+
+ # name: a Symbol, String or an Array. nil means hook to the root.
+ # hook: block which will be called with 2 args, name and value
+ def add_hook(name = nil, &hook)
+ if name.nil?
+ assign_self_hook(hook)
+ else
+ assign_hook(name_to_a(name), hook)
+ end
+ end
+
+ def each
+ @store.each do |key, value|
+ yield(key, value)
+ end
+ end
+
+ def empty?
+ @store.empty?
+ end
+
+ def keys
+ @store.keys
+ end
+
+ def values
+ @store.values
+ end
+
+ def lock(cascade = false)
+ if cascade
+ each_key do |key|
+ key.lock(cascade)
+ end
+ end
+ @locked = true
+ self
+ end
+
+ def unlock(cascade = false)
+ @locked = false
+ if cascade
+ each_key do |key|
+ key.unlock(cascade)
+ end
+ end
+ self
+ end
+
+ def locked?
+ @locked
+ end
+
+protected
+
+ def referent(ary)
+ key, rest = location_pair(ary)
+ if rest.empty?
+ local_referent(key)
+ else
+ deref_key(key).referent(rest)
+ end
+ end
+
+ def assign(ary, value)
+ key, rest = location_pair(ary)
+ if rest.empty?
+ local_assign(key, value)
+ local_hook(key)
+ else
+ local_hook(key) + deref_key(key).assign(rest, value)
+ end
+ end
+
+ def assign_hook(ary, hook)
+ key, rest = location_pair(ary)
+ if rest.empty?
+ local_assign_hook(key, hook)
+ else
+ deref_key(key).assign_hook(rest, hook)
+ end
+ end
+
+ def assign_self_hook(hook)
+ check_lock(nil)
+ @self_hook << hook
+ end
+
+private
+
+ def each_key
+ self.each do |key, value|
+ if propkey?(value)
+ yield(value)
+ end
+ end
+ end
+
+ def deref_key(key)
+ check_lock(key)
+ ref = @store[key] ||= self.class.new
+ unless propkey?(ref)
+ raise ArgumentError.new("key `#{key}' already defined as a value")
+ end
+ ref
+ end
+
+ def local_referent(key)
+ check_lock(key)
+ if propkey?(@store[key]) and @store[key].locked?
+ raise TypeError.new("cannot split any key from locked property")
+ end
+ @store[key]
+ end
+
+ def local_assign(key, value)
+ check_lock(key)
+ if @locked
+ if propkey?(value)
+ raise TypeError.new("cannot add any key to locked property")
+ elsif propkey?(@store[key])
+ raise TypeError.new("cannot override any key in locked property")
+ end
+ end
+ @store[key] = value
+ end
+
+ def local_assign_hook(key, hook)
+ check_lock(key)
+ @store[key] ||= nil
+ (@hook[key] ||= []) << hook
+ end
+
+ NO_HOOK = [].freeze
+ def local_hook(key)
+ @self_hook + (@hook[key] || NO_HOOK)
+ end
+
+ def check_lock(key)
+ if @locked and (key.nil? or !@store.key?(key))
+ raise TypeError.new("cannot add any key to locked property")
+ end
+ end
+
+ def propkey?(value)
+ value.is_a?(::SOAP::Property)
+ end
+
+ def name_to_a(name)
+ case name
+ when Symbol
+ [name]
+ when String
+ name.split(/\./)
+ when Array
+ name
+ else
+ raise ArgumentError.new("Unknown name #{name}(#{name.class})")
+ end
+ end
+
+ def location_pair(ary)
+ name, *rest = *ary
+ key = to_key(name)
+ return key, rest
+ end
+
+ def normalize_name(name)
+ name_to_a(name).collect { |key| to_key(key) }.join('.')
+ end
+
+ def to_key(name)
+ name.to_s.downcase.intern
+ end
+
+ def generate_new_key
+ if @store.empty?
+ "0"
+ else
+ (key_max + 1).to_s
+ end
+ end
+
+ def key_max
+ (@store.keys.max { |l, r| l.to_s.to_i <=> r.to_s.to_i }).to_s.to_i
+ end
+end
+
+
+end