class WADL::CheapSchema
A cheap way of defining an XML schema as Ruby classes and then parsing documents into instances of those classes.
Constants
- ATTRIBUTES
Attributes
attributes[R]
href[RW]
index_key[RW]
parent[RW]
Public Class Methods
as_collection(collection_name)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 77 def as_collection(collection_name) @names[:collection] = collection_name end
as_member(member_name)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 81 def as_member(member_name) @names[:member] = member_name end
contents_are_mixed_data()
click to toggle source
# File lib/wadl/cheap_schema.rb, line 85 def contents_are_mixed_data @contents_are_mixed_data = true end
dereferencing_attr_accessor(*symbols)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 137 def dereferencing_attr_accessor(*symbols) define_dereferencing_accessors(symbols, 'dereference.attributes["%s"]', 'dereference.attributes["%s"] = value' ) end
dereferencing_instance_accessor(*symbols)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 129 def dereferencing_instance_accessor(*symbols) define_dereferencing_accessors(symbols, 'd, v = dereference, :@%s; ' << 'd.instance_variable_get(v) if d.instance_variable_defined?(v)', 'dereference.instance_variable_set(:@%s, value)' ) end
from_element(parent, element, need_finalization)
click to toggle source
Turn an XML element into an instance of this class.
# File lib/wadl/cheap_schema.rb, line 179 def from_element(parent, element, need_finalization) attributes = element.attributes me = new me.parent = parent @collections.each { |name, klass| me.instance_variable_set("@#{klass.names[:collection]}", []) } if may_be_reference? and href = attributes['href'] # Handle objects that are just references to other objects # somewhere above this one in the hierarchy href = href.dup href.sub!(/\A#/, '') or warn "Warning: HREF #{href} should be ##{href}" me.attributes['href'] = href else # Handle this element's attributes @required_attributes.each { |name| name = name.to_s raise ArgumentError, %Q{Missing required attribute "#{name}" in element: #{element}} unless attributes[name] me.attributes[name] = attributes[name] me.index_key = attributes[name] if name == @index_attribute } @attributes.each { |name| name = name.to_s me.attributes[name] = attributes[name] me.index_key = attributes[name] if name == @index_attribute } end # Handle this element's children. if @contents_are_mixed_data me.instance_variable_set(:@contents, element.children) else element.each_element { |child| if klass = @members[child.name] || @collections[child.name] object = klass.from_element(me, child, need_finalization) if klass == @members[child.name] instance_variable_name = "@#{klass.names[:member]}" if me.instance_variable_defined?(instance_variable_name) raise "#{name} can only have one #{klass.name}, but several were specified in element: #{element}" end me.instance_variable_set(instance_variable_name, object) else me.instance_variable_get("@#{klass.names[:collection]}") << object end end } end need_finalization << me if me.respond_to?(:finalize_creation) me end
has_attributes(*names)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 144 def has_attributes(*names) has_required_or_attributes(names, @attributes) end
has_many(*classes)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 96 def has_many(*classes) classes.each { |klass| @collections[klass.names[:element]] = klass collection_name = klass.names[:collection] dereferencing_instance_accessor(collection_name) # Define a method for finding a specific element of this # collection. class_eval " def find_#{klass.names[:element]}(*args, &block) block ||= begin name = args.shift.to_s lambda { |match| match.matches?(name) } end auto_dereference = args.shift auto_dereference = true if auto_dereference.nil? match = #{collection_name}.find { |_match| block[_match] || ( #{klass}.may_be_reference? && auto_dereference && block[_match.dereference] ) } match && auto_dereference ? match.dereference : match end ", __FILE__, __LINE__ + 1 } end
has_one(*classes)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 89 def has_one(*classes) classes.each { |klass| @members[klass.names[:element]] = klass dereferencing_instance_accessor(klass.names[:member]) } end
has_required(*names)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 148 def has_required(*names) has_required_or_attributes(names, @required_attributes) end
in_document(element_name)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 71 def in_document(element_name) @names[:element] = element_name @names[:member] = element_name @names[:collection] = element_name + 's' end
inherit(from)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 50 def inherit(from) init ATTRIBUTES.each { |attr| value = from.send(attr) instance_variable_set("@#{attr}", value.dup) if value } %w[may_be_reference contents_are_mixed_data].each { |attr| instance_variable_set("@#{attr}", from.instance_variable_get("@#{attr}")) } end
inherited(klass)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 63 def inherited(klass) klass.inherit(self) end
init()
click to toggle source
# File lib/wadl/cheap_schema.rb, line 45 def init @names, @members, @collections = {}, {}, {} @required_attributes, @attributes = [], [] end
may_be_reference()
click to toggle source
# File lib/wadl/cheap_schema.rb, line 152 def may_be_reference @may_be_reference = true find_method_name = "find_#{names[:element]}" class_eval " def dereference return self unless href = attributes['href'] unless @referenced p = self until @referenced || !p begin p = p.parent end until !p || p.respond_to?(:#{find_method_name}) @referenced = p.#{find_method_name}(href, false) if p end end dereference_with_context(@referenced) if @referenced end ", __FILE__, __LINE__ + 1 end
may_be_reference?()
click to toggle source
# File lib/wadl/cheap_schema.rb, line 67 def may_be_reference? @may_be_reference end
new()
click to toggle source
# File lib/wadl/cheap_schema.rb, line 269 def initialize @attributes, @contents, @referenced = {}, nil, nil end
Private Class Methods
define_dereferencing_accessors(symbols, getter, setter)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 245 def define_dereferencing_accessors(symbols, getter, setter) symbols.each { |name| name = name.to_s class_eval " def #{name}; #{getter % name}; end def #{name}=(value); #{setter % name}; end ", __FILE__, __LINE__ + 1 unless name =~ /\W/ } end
has_required_or_attributes(names, var)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 256 def has_required_or_attributes(names, var) names.each { |name| var << name @index_attribute ||= name.to_s name == :href ? attr_accessor(name) : dereferencing_attr_accessor(name) } end
Public Instance Methods
dereference()
click to toggle source
A null implementation so that foo.dereference will always return the “real” object.
# File lib/wadl/cheap_schema.rb, line 285 def dereference self end
dereference_with_context(referent)
click to toggle source
This object is a reference to another object. This method returns an object that acts like the other object, but also contains any neccessary context about this object. See the ResourceAndAddress implementation, in which a dereferenced resource contains information about the parent of the resource that referenced it (otherwise, there's no way to build the URI).
# File lib/wadl/cheap_schema.rb, line 279 def dereference_with_context(referent) referent end
each_attribute() { |attr, val| ... }
click to toggle source
# File lib/wadl/cheap_schema.rb, line 295 def each_attribute [self.class.required_attributes, self.class.attributes].each { |list| list.each { |attr| val = attributes[attr.to_s] yield attr, val if val } } end
each_collection() { |collection| ... }
click to toggle source
# File lib/wadl/cheap_schema.rb, line 311 def each_collection self.class.collections.each_value { |collection_class| collection = send(collection_class.names[:collection]) yield collection if collection && !collection.empty? } end
each_member() { |member| ... }
click to toggle source
# File lib/wadl/cheap_schema.rb, line 304 def each_member self.class.members.each_value { |member_class| member = send(member_class.names[:member]) yield member if member } end
matches?(name)
click to toggle source
Returns whether or not the given name matches this object. By default, checks the index key for this class.
# File lib/wadl/cheap_schema.rb, line 291 def matches?(name) index_key == name end
paths(level = default = 0)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 318 def paths(level = default = 0) klass, paths = self.class, [] return paths if klass.may_be_reference? && attributes['href'] if klass == Resource path = attributes['path'] paths << [level, path] if path elsif klass == HTTPMethod paths << [level] end each_member { |member| paths.concat(member.paths(level)) } each_collection { |collection| collection.each { |member| paths.concat(member.paths(level + 1)) } } if default memo = [] paths.map { |_level, _path| if _path memo.slice!(_level..-1) memo[_level] = _path nil # ignore else memo.join('/') end }.compact else paths end end
to_s(indent = 0, is_collection = false)
click to toggle source
# File lib/wadl/cheap_schema.rb, line 355 def to_s(indent = 0, is_collection = false) klass = self.class a = ' ' i = a * indent s = "#{is_collection ? a * (indent - 1) + '- ' : i}#{klass.name}\n" if klass.may_be_reference? and href = attributes['href'] s << "#{i}= href=#{href}\n" else each_attribute { |attr, val| s << "#{i}* #{attr}=#{val}\n" } each_member { |member| s << member.to_s(indent + 1) } each_collection { |collection| s << "#{i}> Collection of #{collection.size} #{collection.class}(s)\n" collection.each { |member| s << member.to_s(indent + 2, true) } } if @contents && !@contents.empty? sep = '-' * 80 s << "#{sep}\n#{@contents.join(' ').strip}\n#{sep}\n" end end s end