lib/csl/node.rb in csl-1.0.0.pre3 vs lib/csl/node.rb in csl-1.0.0.pre4
- old
+ new
@@ -1,39 +1,39 @@
module CSL
-
+
class Node
-
+
extend Forwardable
-
+
include Enumerable
include Comparable
-
+
include Treelike
include PrettyPrinter
-
-
+
+
class << self
def inherited(subclass)
types << subclass
subclass.nesting.each do |klass|
klass.types << subclass if klass < Node
end
end
-
+
def types
@types ||= Set.new
end
-
+
def default_attributes
@default_attributes ||= {}
end
-
+
def constantize(name)
- pattern = /#{name.to_s.tr('-', '')}$/i
+ pattern = /:#{name.to_s.tr('-', '')}$/i
klass = types.detect { |t| t.matches?(pattern) }
-
+
case
when !klass.nil?
klass
when nesting[-2].respond_to?(:constantize)
nesting[-2].constantize(name)
@@ -46,20 +46,20 @@
# passed-in name pattern
def match?(name_pattern)
name_pattern === name
end
alias matches? match?
-
+
# Returns a new node with the passed in name and attributes.
def create(name, attributes = {}, &block)
klass = constantize(name)
- node = (klass || Node).new(attributes, &block)
+ node = (klass || Node).new(attributes, &block)
node.nodename = name
node
end
-
+
def create_attributes(attributes)
if const?(:Attributes)
const_get(:Attributes).new(default_attributes.merge(attributes))
else
default_attributes.merge(attributes)
@@ -99,31 +99,31 @@
end
def values
super.compact
end
-
+
# def to_a
# keys.zip(values_at(*keys)).reject { |k,v| v.nil? }
# end
-
+
# @return [Boolean] true if all the attribute values are nil;
# false otherwise.
def empty?
values.compact.empty?
end
-
+
def fetch(key, default = nil)
value = keys.include?(key.to_sym) && send(:'[]', key)
-
- if block_given?
+
+ if block_given?
value || yield(key)
else
value || default
end
end
-
+
# Merges the current with the passed-in attributes.
#
# @param other [#each_pair] the other attributes
# @return [self]
def merge(other)
@@ -160,18 +160,18 @@
attr_reader :attributes
def_delegators :attributes, :[], :[]=, :values, :values_at, :length, :size
-
+
def initialize(attributes = {})
@attributes = self.class.create_attributes(attributes)
@children = self.class.create_children
-
+
yield self if block_given?
end
-
+
# Iterates through the Node's attributes
def each
if block_given?
attributes.each_pair(&Proc.new)
self
@@ -184,11 +184,11 @@
# Returns true if the node contains an attribute with the passed-in name;
# false otherwise.
def attribute?(name)
attributes.fetch(name, false)
end
-
+
# Returns true if the node contains any attributes (ignores nil values);
# false otherwise.
def has_attributes?
!attributes.empty?
end
@@ -200,11 +200,11 @@
def save_to(path, options = {})
File.open(path, 'w:UTF-8') do |f|
f << (options[:compact] ? to_xml : pretty_print)
end
-
+
self
end
# Tests whether or not the Name matches the passed-in node name and
# attribute conditions; if a Hash is passed as a single argument,
@@ -229,11 +229,11 @@
# @param conditions [Hash] the conditions
#
# @return [Boolean] whether or not the query matches the node
def match?(name = nodename, conditions = {})
name, conditions = match_conditions_for(name, conditions)
-
+
return false unless name === nodename
return true if conditions.empty?
conditions.values.zip(
attributes.values_at(*conditions.keys)).all? do |condition, value|
@@ -263,14 +263,14 @@
# @param conditions [Hash] the conditions
#
# @return [Boolean] whether or not the query matches the node exactly
def exact_match?(name = nodename, conditions = {})
name, conditions = match_conditions_for(name, conditions)
-
+
return false unless name === nodename
return true if conditions.empty?
-
+
conditions.values_at(*attributes.keys).zip(
attributes.values_at(*attributes.keys)).all? do |condition, value|
condition === value
end
end
@@ -279,44 +279,44 @@
def <=>(other)
[nodename, attributes, children] <=> [other.nodename, other.attributes, other.children]
rescue
nil
end
-
+
# Returns the node' XML tags (including attribute assignments) as an
# array of strings.
def tags
if has_children?
tags = []
tags << "<#{[nodename, *attribute_assignments].join(' ')}>"
-
+
tags << children.map { |node|
node.respond_to?(:tags) ? node.tags : [node.to_s]
}.flatten(1)
-
+
tags << "</#{nodename}>"
tags
else
["<#{[nodename, *attribute_assignments].join(' ')}/>"]
end
end
-
+
def inspect
"#<#{[self.class.name, *attribute_assignments].join(' ')} children=[#{children.count}]>"
end
-
+
alias to_s pretty_print
-
+
private
-
+
def attribute_assignments
each_pair.map { |name, value|
value.nil? ? nil: [name, value.to_s.inspect].join('=')
}.compact
end
-
+
def match_conditions_for(name, conditions)
case name
when Hash
conditions, name = name, nodename
when Symbol
@@ -325,19 +325,19 @@
[name, conditions.symbolize_keys]
end
end
-
-
+
+
class TextNode < Node
-
+
has_no_children
class << self
undef_method :attr_children
-
+
# @override
def create(name, attributes = {}, &block)
klass = constantize(name)
node = (klass || TextNode).new(attributes, &block)
@@ -345,23 +345,26 @@
node
end
end
attr_accessor :text
- alias to_s text
+ def to_s
+ text.to_s.strip
+ end
+
# TextNodes quack like a string.
# def_delegators :to_s, *String.instance_methods(false).reject do |m|
# m.to_s =~ /^\W|!$|(?:^(?:hash|eql?|to_s|length|size|inspect)$)/
# end
- #
+ #
# String.instance_methods(false).select { |m| m.to_s =~ /!$/ }.each do |m|
# define_method(m) do
# content.send(m) if content.respond_to?(m)
# end
# end
-
+
def initialize(argument = '')
case
when argument.is_a?(Hash)
super
when argument.respond_to?(:to_s)
@@ -370,21 +373,25 @@
yield self if block_given?
else
raise ArgumentError, "failed to create text node from #{argument.inspect}"
end
end
-
+
def textnode?
true
end
-
+
+ def empty?
+ text.nil? || text.empty?
+ end
+
def tags
["<#{attribute_assignments.unshift(nodename).join(' ')}>#{text}</#{nodename}>"]
end
-
+
def inspect
"#<#{[self.class.name, text.inspect, *attribute_assignments].join(' ')}>"
end
-
+
end
-
+
end
\ No newline at end of file