Class SOAP::Property
In: lib/soap/property.rb
Parent: Object

Property stream format:

  line separator is \r?\n.  1 line per a property.
  line which begins with '#' is a comment line.  empty line is ignored, too.
  key/value separator is ':' or '='.
  '\' as escape character.  but line separator cannot be escaped.
  \s at the head/tail of key/value are trimmed.

  '[' + key + ']' indicates property section.  for example,

    [aaa.bbb]
    ccc = ddd
    eee.fff = ggg
    []
    aaa.hhh = iii

  is the same as;

    aaa.bbb.ccc = ddd
    aaa.bbb.eee.fff = ggg
    aaa.hhh = iii

Methods

Included Modules

Enumerable

Classes and Modules

Module SOAP::Property::Util

Constants

FrozenError = (RUBY_VERSION >= "1.9.0") ? RuntimeError : TypeError
KEY_REGSRC = '([^=:\\\\]*(?:\\\\.[^=:\\\\]*)*)'
DEF_REGSRC = '\\s*' + KEY_REGSRC + '\\s*[=:]\\s*(.*)'
COMMENT_REGEXP = Regexp.new('^(?:#.*|)$')
CATDEF_REGEXP = Regexp.new("^\\[\\s*#{KEY_REGSRC}\\s*\\]$")
LINE_REGEXP = Regexp.new("^#{DEF_REGSRC}$")
NO_HOOK = [].freeze

Public Class methods

[Source]

    # File lib/soap/property.rb, line 51
51:   def self.load(stream)
52:     new.load(stream)
53:   end

[Source]

    # File lib/soap/property.rb, line 55
55:   def self.loadproperty(propname)
56:     new.loadproperty(propname)
57:   end

[Source]

    # File lib/soap/property.rb, line 59
59:   def initialize
60:     @store = Hash.new
61:     @hook = Hash.new
62:     @self_hook = Array.new
63:     @locked = false
64:   end

Public Instance methods

value: an Object key is generated by property

[Source]

     # File lib/soap/property.rb, line 122
122:   def <<(value)
123:     self[generate_new_key] = value
124:   end

name: a Symbol, String or an Array

[Source]

     # File lib/soap/property.rb, line 105
105:   def [](name)
106:     referent(name_to_a(name))
107:   end

name: a Symbol, String or an Array value: an Object

[Source]

     # File lib/soap/property.rb, line 111
111:   def []=(name, value)
112:     name_pair = name_to_a(name).freeze
113:     hooks = assign(name_pair, value)
114:     hooks.each do |hook|
115:       hook.call(name_pair, value)
116:     end
117:     value
118:   end

name: a Symbol, String or an Array; nil means hook to the root cascade: true/false; for cascading hook of sub key hook: block which will be called with 2 args, name and value

[Source]

     # File lib/soap/property.rb, line 129
129:   def add_hook(name = nil, cascade = false, &hook)
130:     if name == nil or name == true or name == false
131:       cascade = name
132:       assign_self_hook(cascade, &hook)
133:     else
134:       assign_hook(name_to_a(name), cascade, &hook)
135:     end
136:   end

[Source]

     # File lib/soap/property.rb, line 138
138:   def each
139:     @store.each do |key, value|
140:       yield(key, value)
141:     end
142:   end

[Source]

     # File lib/soap/property.rb, line 144
144:   def empty?
145:     @store.empty?
146:   end

[Source]

     # File lib/soap/property.rb, line 148
148:   def keys
149:     @store.keys
150:   end

[Source]

    # File lib/soap/property.rb, line 71
71:   def load(stream)
72:     key_prefix = ""
73:     stream.each_with_index do |line, lineno|
74:       line.sub!(/\r?\n\z/, '')
75:       case line
76:       when COMMENT_REGEXP
77:         next
78:       when CATDEF_REGEXP
79:         key_prefix = $1.strip
80:       when LINE_REGEXP
81:         key, value = $1.strip, $2.strip
82:         key = "#{key_prefix}.#{key}" unless key_prefix.empty?
83:         key, value = loadstr(key), loadstr(value)
84:         self[key] = value
85:       else
86:         raise TypeError.new(
87:           "property format error at line #{lineno + 1}: `#{line}'")
88:       end
89:     end
90:     self
91:   end

find property from $:.

[Source]

     # File lib/soap/property.rb, line 94
 94:   def loadproperty(propname)
 95:     return loadpropertyfile(propname) if File.file?(propname)
 96:     $:.each do |path|
 97:       if File.file?(file = File.join(path, propname))
 98:         return loadpropertyfile(file)
 99:       end
100:     end
101:     nil
102:   end

[Source]

     # File lib/soap/property.rb, line 156
156:   def lock(cascade = false)
157:     if cascade
158:       each_key do |key|
159:         key.lock(cascade)
160:       end
161:     end
162:     @locked = true
163:     self
164:   end

[Source]

     # File lib/soap/property.rb, line 176
176:   def locked?
177:     @locked
178:   end

[Source]

     # File lib/soap/property.rb, line 166
166:   def unlock(cascade = false)
167:     @locked = false
168:     if cascade
169:       each_key do |key|
170:         key.unlock(cascade)
171:       end
172:     end
173:     self
174:   end

[Source]

     # File lib/soap/property.rb, line 152
152:   def values
153:     @store.values
154:   end

Protected Instance methods

[Source]

     # File lib/soap/property.rb, line 182
182:   def deref_key(key)
183:     check_lock(key)
184:     ref = @store[key] ||= self.class.new
185:     unless propkey?(ref)
186:       raise ArgumentError.new("key `#{key}' already defined as a value")
187:     end
188:     ref
189:   end

[Source]

     # File lib/soap/property.rb, line 199
199:   def local_assign(key, value)
200:     check_lock(key)
201:     if @locked
202:       if propkey?(value)
203:         raise FrozenError.new("cannot add any key to locked property")
204:       elsif propkey?(@store[key])
205:         raise FrozenError.new("cannot override any key in locked property")
206:       end
207:     end
208:     @store[key] = value
209:   end

[Source]

     # File lib/soap/property.rb, line 219
219:   def local_assign_hook(key, cascade, &hook)
220:     check_lock(key)
221:     @store[key] ||= nil
222:     (@hook[key] ||= []) << [hook, cascade]
223:   end

[Source]

     # File lib/soap/property.rb, line 211
211:   def local_hook(key, direct)
212:     hooks = []
213:     (@self_hook + (@hook[key] || NO_HOOK)).each do |hook, cascade|
214:       hooks << hook if direct or cascade
215:     end
216:     hooks
217:   end

[Source]

     # File lib/soap/property.rb, line 191
191:   def local_referent(key)
192:     check_lock(key)
193:     if propkey?(@store[key]) and @store[key].locked?
194:       raise FrozenError.new("cannot split any key from locked property")
195:     end
196:     @store[key]
197:   end

Private Instance methods

[Source]

     # File lib/soap/property.rb, line 235
235:   def assign(ary, value)
236:     ref = self
237:     hook = NO_HOOK
238:     ary[0..-2].each do |name|
239:       key = to_key(name)
240:       hook += ref.local_hook(key, false)
241:       ref = ref.deref_key(key)
242:     end
243:     last_key = to_key(ary.last)
244:     ref.local_assign(last_key, value)
245:     hook + ref.local_hook(last_key, true)
246:   end

[Source]

     # File lib/soap/property.rb, line 248
248:   def assign_hook(ary, cascade, &hook)
249:     ary[0..-2].inject(self) { |ref, name|
250:       ref.deref_key(to_key(name))
251:     }.local_assign_hook(to_key(ary.last), cascade, &hook)
252:   end

[Source]

     # File lib/soap/property.rb, line 254
254:   def assign_self_hook(cascade, &hook)
255:     check_lock(nil)
256:     @self_hook << [hook, cascade]
257:   end

[Source]

     # File lib/soap/property.rb, line 267
267:   def check_lock(key)
268:     if @locked and (key.nil? or !@store.key?(key))
269:       raise FrozenError.new("cannot add any key to locked property")
270:     end
271:   end

[Source]

     # File lib/soap/property.rb, line 259
259:   def each_key
260:     self.each do |key, value|
261:       if propkey?(value)
262:         yield(value)
263:       end
264:     end
265:   end

[Source]

     # File lib/soap/property.rb, line 294
294:   def generate_new_key
295:     if @store.empty?
296:       "0"
297:     else
298:       (key_max + 1).to_s
299:     end
300:   end

[Source]

     # File lib/soap/property.rb, line 302
302:   def key_max
303:     (@store.keys.max { |l, r| l.to_s.to_i <=> r.to_s.to_i }).to_s.to_i
304:   end

[Source]

     # File lib/soap/property.rb, line 306
306:   def loadpropertyfile(file)
307:     puts "find property at #{file}" if $DEBUG
308:     File.open(file) do |f|
309:       load(f)
310:     end
311:   end

[Source]

     # File lib/soap/property.rb, line 313
313:   def loadstr(str)
314:     str.gsub(/\\./) { |c| eval("\"#{c}\"") }
315:   end

[Source]

     # File lib/soap/property.rb, line 277
277:   def name_to_a(name)
278:     case name
279:     when Symbol
280:       [name]
281:     when String
282:       name.scan(/[^.\\]+(?:\\.[^.\\])*/)        # split with unescaped '.'
283:     when Array
284:       name
285:     else
286:       raise ArgumentError.new("Unknown name #{name}(#{name.class})")
287:     end
288:   end

[Source]

     # File lib/soap/property.rb, line 273
273:   def propkey?(value)
274:     value.is_a?(::SOAP::Property)
275:   end

[Source]

     # File lib/soap/property.rb, line 229
229:   def referent(ary)
230:     ary[0..-2].inject(self) { |ref, name|
231:       ref.deref_key(to_key(name))
232:     }.local_referent(to_key(ary.last))
233:   end

[Source]

     # File lib/soap/property.rb, line 290
290:   def to_key(name)
291:     name.to_s.downcase
292:   end

[Validate]