duxml 0.8.8 → 0.8.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/validate_xml +30 -30
- data/lib/duxml.rb +76 -76
- data/lib/duxml/doc.rb +108 -91
- data/lib/duxml/doc/element.rb +250 -250
- data/lib/duxml/doc/lazy_ox.rb +167 -167
- data/lib/duxml/doc/node_set.rb +38 -38
- data/lib/duxml/meta.rb +72 -72
- data/lib/duxml/meta/grammar.rb +133 -133
- data/lib/duxml/meta/grammar/pattern.rb +111 -111
- data/lib/duxml/meta/grammar/pattern/attr_name_pattern.rb +36 -36
- data/lib/duxml/meta/grammar/pattern/attr_val_pattern.rb +36 -36
- data/lib/duxml/meta/grammar/pattern/child_pattern.rb +60 -60
- data/lib/duxml/meta/grammar/pattern/text_pattern.rb +31 -31
- data/lib/duxml/meta/grammar/pattern_maker.rb +68 -68
- data/lib/duxml/meta/grammar/relax_ng.rb +39 -39
- data/lib/duxml/meta/grammar/relax_ng/attrs_rule.rb +58 -58
- data/lib/duxml/meta/grammar/relax_ng/children_rule.rb +82 -82
- data/lib/duxml/meta/grammar/relax_ng/value_rule.rb +44 -44
- data/lib/duxml/meta/grammar/rule.rb +58 -58
- data/lib/duxml/meta/grammar/rule/attrs_rule.rb +77 -77
- data/lib/duxml/meta/grammar/rule/children_rule.rb +135 -135
- data/lib/duxml/meta/grammar/rule/text_rule.rb +39 -39
- data/lib/duxml/meta/grammar/rule/value_rule.rb +110 -110
- data/lib/duxml/meta/grammar/spreadsheet.rb +34 -34
- data/lib/duxml/meta/history.rb +88 -88
- data/lib/duxml/meta/history/add.rb +30 -30
- data/lib/duxml/meta/history/change.rb +70 -70
- data/lib/duxml/meta/history/change_attr.rb +33 -33
- data/lib/duxml/meta/history/change_text.rb +32 -32
- data/lib/duxml/meta/history/error.rb +24 -24
- data/lib/duxml/meta/history/new_attr.rb +32 -32
- data/lib/duxml/meta/history/new_text.rb +36 -36
- data/lib/duxml/meta/history/qualify_error.rb +21 -21
- data/lib/duxml/meta/history/remove.rb +27 -27
- data/lib/duxml/meta/history/undo.rb +23 -23
- data/lib/duxml/meta/history/validate_error.rb +20 -20
- data/lib/duxml/reportable.rb +28 -28
- data/lib/duxml/ruby_ext/fixnum.rb +55 -55
- data/lib/duxml/ruby_ext/module.rb +11 -11
- data/lib/duxml/ruby_ext/object.rb +13 -13
- data/lib/duxml/ruby_ext/regexp.rb +19 -19
- data/lib/duxml/ruby_ext/string.rb +37 -37
- data/lib/duxml/saxer.rb +75 -75
- metadata +12 -12
data/lib/duxml/meta/grammar.rb
CHANGED
@@ -1,134 +1,134 @@
|
|
1
|
-
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
-
|
3
|
-
require File.expand_path(File.dirname(__FILE__) + '/../reportable')
|
4
|
-
require File.expand_path(File.dirname(__FILE__) + '/grammar/spreadsheet')
|
5
|
-
require File.expand_path(File.dirname(__FILE__) + '/grammar/pattern_maker')
|
6
|
-
require File.expand_path(File.dirname(__FILE__) + '/grammar/rule/children_rule')
|
7
|
-
require File.expand_path(File.dirname(__FILE__) + '/grammar/rule/attrs_rule')
|
8
|
-
require File.expand_path(File.dirname(__FILE__) + '/grammar/rule/value_rule')
|
9
|
-
require File.expand_path(File.dirname(__FILE__) + '/../doc/lazy_ox')
|
10
|
-
require File.expand_path(File.dirname(__FILE__) + '/grammar/rule/text_rule')
|
11
|
-
require File.expand_path(File.dirname(__FILE__) + '/grammar/relax_ng')
|
12
|
-
require 'forwardable'
|
13
|
-
|
14
|
-
module Duxml
|
15
|
-
# module shares name with <grammar> to activate its methods when that XML Element is encountered in a Meta file
|
16
|
-
module Grammar
|
17
|
-
include Reportable
|
18
|
-
include Duxml
|
19
|
-
include Spreadsheet
|
20
|
-
include PatternMaker
|
21
|
-
include LazyOx
|
22
|
-
include RelaxNG
|
23
|
-
end
|
24
|
-
# contains Duxml::Rules and can apply them by validating XML or qualifying user input
|
25
|
-
# reporting Duxml::Errors to History as needed
|
26
|
-
class GrammarClass
|
27
|
-
extend Forwardable
|
28
|
-
include Grammar
|
29
|
-
|
30
|
-
# @param rules [[RuleClass]] optional, can initialize grammar with rules
|
31
|
-
def initialize(rules=[])
|
32
|
-
@rules = rules
|
33
|
-
end
|
34
|
-
|
35
|
-
def_delegators :@rules, :<<, :[], :each
|
36
|
-
attr_reader :rules
|
37
|
-
alias_method :nodes, :rules
|
38
|
-
end
|
39
|
-
|
40
|
-
module Grammar
|
41
|
-
# @param path [String] path of grammar file; can be in .xlsx, .csv or Duxml GrammarClass file
|
42
|
-
# @return [GrammarClass, Element] XML Element named <grammar> and GrammarClass object are functionally equivalent
|
43
|
-
def self.import(path)
|
44
|
-
if %w(.xlsx .csv).include?(File.extname path)
|
45
|
-
doc = Spreadsheet.sheet_to_xml path
|
46
|
-
File.write(File.basename(path)+'.xml', Ox.dump(doc)) #TODO make optional!
|
47
|
-
doc
|
48
|
-
else
|
49
|
-
Ox.parse_obj(File.read path)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# @return [Doc] returns self as XML document
|
54
|
-
def xml
|
55
|
-
Element.new('grammar') << rules.collect do |rule| rule.xml end
|
56
|
-
end
|
57
|
-
|
58
|
-
# @return [History] history that this grammar is currently reporting to
|
59
|
-
def history
|
60
|
-
@observer_peers.first.first if @observer_peers and @observer_peers.any? and @observer_peers.first.any?
|
61
|
-
end
|
62
|
-
|
63
|
-
# @return [Boolean] whether or not any rules have been defined yet in this grammar
|
64
|
-
def defined?
|
65
|
-
!rules.empty?
|
66
|
-
end
|
67
|
-
|
68
|
-
# @param obj [Object] object that will observe this grammar's rules, usually the History
|
69
|
-
def add_observer(obj, sym=nil)
|
70
|
-
super(obj, sym || :update)
|
71
|
-
@rules.each do |r| r.add_observer(obj, :update)end
|
72
|
-
end
|
73
|
-
|
74
|
-
# @return [String] lists XML schema and content rules in order of precedence
|
75
|
-
def description
|
76
|
-
"grammar follows: \n" +
|
77
|
-
rules.collect do |change_or_error|
|
78
|
-
change_or_error.description
|
79
|
-
end.join("\n")
|
80
|
-
end
|
81
|
-
|
82
|
-
# @return [String] formatted to appear in tight spaces e.g. debugger
|
83
|
-
def inspect
|
84
|
-
"#<#{self.class.to_s} #{object_id}: @rules=#{rules.size}>"
|
85
|
-
end
|
86
|
-
|
87
|
-
# @return [String] 'grammar'
|
88
|
-
def name
|
89
|
-
'grammar'
|
90
|
-
end
|
91
|
-
|
92
|
-
# @param node [Duxml::Object] applies grammar rules to all relationships of the given object
|
93
|
-
# @result [Boolean] whether all rules qualified
|
94
|
-
def validate(node)
|
95
|
-
rels = get_relationships(node)
|
96
|
-
results = rels.collect do |rel|
|
97
|
-
qualify rel
|
98
|
-
end
|
99
|
-
any_disqualified = results.any? do |qualified| !qualified end
|
100
|
-
!any_disqualified
|
101
|
-
end # def validate
|
102
|
-
|
103
|
-
# @param change_or_pattern [Duxml::Change, Duxml::Pattern] applies applicable rule type and subject
|
104
|
-
# to given change_or_pattern and generates errors when disqualified
|
105
|
-
# @return [Boolean] false if any rule disqualifies; true if they all pass
|
106
|
-
def qualify(change_or_pattern)
|
107
|
-
return true unless self.defined?
|
108
|
-
rules = get_rule(change_or_pattern)
|
109
|
-
|
110
|
-
# define behaviors for when there are no rules applying to a given pattern
|
111
|
-
if rules.empty?
|
112
|
-
|
113
|
-
if change_or_pattern.respond_to?(:text) or
|
114
|
-
change_or_pattern.respond_to?(:value) or
|
115
|
-
change_or_pattern.subject.is_a?(Doc)
|
116
|
-
return true
|
117
|
-
end
|
118
|
-
report(:ValidateError, change_or_pattern)
|
119
|
-
return false
|
120
|
-
end
|
121
|
-
results = rules.collect do |rule|
|
122
|
-
rule.qualify change_or_pattern
|
123
|
-
end
|
124
|
-
!results.any? do |qualified| !qualified end
|
125
|
-
end # def qualify
|
126
|
-
|
127
|
-
# @param change_or_pattern [Duxml::Change, Duxml::Pattern] change or pattern to be qualified
|
128
|
-
# @return [Array[Duxml::Rule]] rules that match the pattern type (e.g. :change_content => :content_rule)
|
129
|
-
# and subject (e.g. change_or_pattern.subject.type => 'blobs' && rule.subject => 'blobs')
|
130
|
-
def get_rule(change_or_pattern)
|
131
|
-
rules.select do |rule| rule.applies_to?(change_or_pattern) end
|
132
|
-
end # def get_rules
|
133
|
-
end # module Grammar
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../reportable')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/grammar/spreadsheet')
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + '/grammar/pattern_maker')
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + '/grammar/rule/children_rule')
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + '/grammar/rule/attrs_rule')
|
8
|
+
require File.expand_path(File.dirname(__FILE__) + '/grammar/rule/value_rule')
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + '/../doc/lazy_ox')
|
10
|
+
require File.expand_path(File.dirname(__FILE__) + '/grammar/rule/text_rule')
|
11
|
+
require File.expand_path(File.dirname(__FILE__) + '/grammar/relax_ng')
|
12
|
+
require 'forwardable'
|
13
|
+
|
14
|
+
module Duxml
|
15
|
+
# module shares name with <grammar> to activate its methods when that XML Element is encountered in a Meta file
|
16
|
+
module Grammar
|
17
|
+
include Reportable
|
18
|
+
include Duxml
|
19
|
+
include Spreadsheet
|
20
|
+
include PatternMaker
|
21
|
+
include LazyOx
|
22
|
+
include RelaxNG
|
23
|
+
end
|
24
|
+
# contains Duxml::Rules and can apply them by validating XML or qualifying user input
|
25
|
+
# reporting Duxml::Errors to History as needed
|
26
|
+
class GrammarClass
|
27
|
+
extend Forwardable
|
28
|
+
include Grammar
|
29
|
+
|
30
|
+
# @param rules [[RuleClass]] optional, can initialize grammar with rules
|
31
|
+
def initialize(rules=[])
|
32
|
+
@rules = rules
|
33
|
+
end
|
34
|
+
|
35
|
+
def_delegators :@rules, :<<, :[], :each
|
36
|
+
attr_reader :rules
|
37
|
+
alias_method :nodes, :rules
|
38
|
+
end
|
39
|
+
|
40
|
+
module Grammar
|
41
|
+
# @param path [String] path of grammar file; can be in .xlsx, .csv or Duxml GrammarClass file
|
42
|
+
# @return [GrammarClass, Element] XML Element named <grammar> and GrammarClass object are functionally equivalent
|
43
|
+
def self.import(path)
|
44
|
+
if %w(.xlsx .csv).include?(File.extname path)
|
45
|
+
doc = Spreadsheet.sheet_to_xml path
|
46
|
+
File.write(File.basename(path)+'.xml', Ox.dump(doc)) #TODO make optional!
|
47
|
+
doc
|
48
|
+
else
|
49
|
+
Ox.parse_obj(File.read path)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Doc] returns self as XML document
|
54
|
+
def xml
|
55
|
+
Element.new('grammar') << rules.collect do |rule| rule.xml end
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [History] history that this grammar is currently reporting to
|
59
|
+
def history
|
60
|
+
@observer_peers.first.first if @observer_peers and @observer_peers.any? and @observer_peers.first.any?
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [Boolean] whether or not any rules have been defined yet in this grammar
|
64
|
+
def defined?
|
65
|
+
!rules.empty?
|
66
|
+
end
|
67
|
+
|
68
|
+
# @param obj [Object] object that will observe this grammar's rules, usually the History
|
69
|
+
def add_observer(obj, sym=nil)
|
70
|
+
super(obj, sym || :update)
|
71
|
+
@rules.each do |r| r.add_observer(obj, :update)end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [String] lists XML schema and content rules in order of precedence
|
75
|
+
def description
|
76
|
+
"grammar follows: \n" +
|
77
|
+
rules.collect do |change_or_error|
|
78
|
+
change_or_error.description
|
79
|
+
end.join("\n")
|
80
|
+
end
|
81
|
+
|
82
|
+
# @return [String] formatted to appear in tight spaces e.g. debugger
|
83
|
+
def inspect
|
84
|
+
"#<#{self.class.to_s} #{object_id}: @rules=#{rules.size}>"
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [String] 'grammar'
|
88
|
+
def name
|
89
|
+
'grammar'
|
90
|
+
end
|
91
|
+
|
92
|
+
# @param node [Duxml::Object] applies grammar rules to all relationships of the given object
|
93
|
+
# @result [Boolean] whether all rules qualified
|
94
|
+
def validate(node)
|
95
|
+
rels = get_relationships(node)
|
96
|
+
results = rels.collect do |rel|
|
97
|
+
qualify rel
|
98
|
+
end
|
99
|
+
any_disqualified = results.any? do |qualified| !qualified end
|
100
|
+
!any_disqualified
|
101
|
+
end # def validate
|
102
|
+
|
103
|
+
# @param change_or_pattern [Duxml::Change, Duxml::Pattern] applies applicable rule type and subject
|
104
|
+
# to given change_or_pattern and generates errors when disqualified
|
105
|
+
# @return [Boolean] false if any rule disqualifies; true if they all pass
|
106
|
+
def qualify(change_or_pattern)
|
107
|
+
return true unless self.defined?
|
108
|
+
rules = get_rule(change_or_pattern)
|
109
|
+
|
110
|
+
# define behaviors for when there are no rules applying to a given pattern
|
111
|
+
if rules.empty?
|
112
|
+
|
113
|
+
if change_or_pattern.respond_to?(:text) or
|
114
|
+
change_or_pattern.respond_to?(:value) or
|
115
|
+
change_or_pattern.subject.is_a?(Doc)
|
116
|
+
return true
|
117
|
+
end
|
118
|
+
report(:ValidateError, change_or_pattern)
|
119
|
+
return false
|
120
|
+
end
|
121
|
+
results = rules.collect do |rule|
|
122
|
+
rule.qualify change_or_pattern
|
123
|
+
end
|
124
|
+
!results.any? do |qualified| !qualified end
|
125
|
+
end # def qualify
|
126
|
+
|
127
|
+
# @param change_or_pattern [Duxml::Change, Duxml::Pattern] change or pattern to be qualified
|
128
|
+
# @return [Array[Duxml::Rule]] rules that match the pattern type (e.g. :change_content => :content_rule)
|
129
|
+
# and subject (e.g. change_or_pattern.subject.type => 'blobs' && rule.subject => 'blobs')
|
130
|
+
def get_rule(change_or_pattern)
|
131
|
+
rules.select do |rule| rule.applies_to?(change_or_pattern) end
|
132
|
+
end # def get_rules
|
133
|
+
end # module Grammar
|
134
134
|
end # module Duxml
|
@@ -1,112 +1,112 @@
|
|
1
|
-
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
-
|
3
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../ruby_ext/string')
|
4
|
-
|
5
|
-
module Duxml
|
6
|
-
# Patterns represent a relationship between a specific XML Element and
|
7
|
-
# a specific or hypothetical attribute, attribute value, text value or child Element
|
8
|
-
# For example, given an XML Element: '<element attr='value'/>', there exists a valid PatternClass
|
9
|
-
# that represents the relationship betweeen <element> and the attribute value 'value'
|
10
|
-
# There can also exists a hypothetical relationship between <element> and a new child <child/> that
|
11
|
-
# is defined as an allowed child Element in the Rules that apply to this Element.
|
12
|
-
module Pattern; end
|
13
|
-
|
14
|
-
# as an object, a Pattern consists of a subject and may or may not have an object
|
15
|
-
# a Pattern without an object represents a childless empty node with no attributes
|
16
|
-
# this class must be subclassed to be used; there is one for each type of XML relationship
|
17
|
-
# that an Element can have up to one degree of separation, that is, grandparent relationships are not considered
|
18
|
-
# and neither are the attributes of children
|
19
|
-
class PatternClass
|
20
|
-
include Pattern
|
21
|
-
@subject
|
22
|
-
|
23
|
-
# @param subj [Element] specific Element that is the subject of this pattern
|
24
|
-
def initialize(subj)
|
25
|
-
@subject = subj
|
26
|
-
end
|
27
|
-
|
28
|
-
attr_reader :subject
|
29
|
-
end
|
30
|
-
|
31
|
-
module Pattern
|
32
|
-
include Duxml
|
33
|
-
|
34
|
-
def xml
|
35
|
-
p = Element.new(simple_name)
|
36
|
-
instance_variables.each do |sym|
|
37
|
-
val = instance_variable_get(sym)
|
38
|
-
if val.respond_to?(:nodes)
|
39
|
-
d = Element.new(sym.to_s) << val
|
40
|
-
p << d
|
41
|
-
else
|
42
|
-
p[sym.to_s[1..-1].to_sym] = val.to_s unless sym == :@observer_peers
|
43
|
-
end
|
44
|
-
end
|
45
|
-
p
|
46
|
-
end
|
47
|
-
|
48
|
-
# @return [String] nmtoken name of this pattern without namespace prefix e.g. ChildPattern.new(parent, child).name => 'child_pattern'
|
49
|
-
def simple_name
|
50
|
-
name.split(':').last
|
51
|
-
end
|
52
|
-
|
53
|
-
# @return [Boolean] if either subject or object points to a name/type i.e. not an Element
|
54
|
-
def abstract?
|
55
|
-
subject.is_a?(String) or object.nil?
|
56
|
-
end
|
57
|
-
|
58
|
-
# @return [Boolean] if both subject and at least one object point to an actual XML Element
|
59
|
-
def concrete?
|
60
|
-
!abstract?
|
61
|
-
end
|
62
|
-
|
63
|
-
# @return [String] nmtoken name of this pattern e.g. ChildPattern.new(parent, child).name => 'duxml:child_pattern'
|
64
|
-
def name
|
65
|
-
c = self.class.to_s
|
66
|
-
return c.nmtokenize unless c.include?('::')
|
67
|
-
a = c.split('::')
|
68
|
-
a[-2..-1].collect do |word|
|
69
|
-
word.nmtokenize
|
70
|
-
end.join(':')
|
71
|
-
end
|
72
|
-
|
73
|
-
# returns relationship description as string by subtracting super class name
|
74
|
-
# (e.g. 'pattern' or 'rule') from simple_class
|
75
|
-
# Duxml::ChildrenRule#relationship => 'children'
|
76
|
-
# Duxml::TextPattern#relationship => 'text'
|
77
|
-
# can be overridden if class name does not match human-readable string
|
78
|
-
# @return [String] single word to describe relationship of subject to object
|
79
|
-
def relationship
|
80
|
-
simple_name.split('_').first
|
81
|
-
end
|
82
|
-
|
83
|
-
# @return [String] "#{object.description} is #{relationship} of #{subject.description}"
|
84
|
-
def description
|
85
|
-
"#{object.description} is #{relationship} of #{subject.description}"
|
86
|
-
end
|
87
|
-
|
88
|
-
# @return [Element] will only return non-nil value when pattern represents relationship with a child Element
|
89
|
-
def object
|
90
|
-
return @object if instance_variable_defined?(:@object)
|
91
|
-
instance_variables.each do |var|
|
92
|
-
target = instance_variable_get(var)
|
93
|
-
return target unless target.is_a?(String) or target == subject
|
94
|
-
end
|
95
|
-
nil
|
96
|
-
end
|
97
|
-
|
98
|
-
# @param pattern [Duxml::Pattern] pattern or any subclass object
|
99
|
-
# @return [Fixnum] first applies <=> to subjects, and if equal, applies <=> to objects
|
100
|
-
def <=>(pattern)
|
101
|
-
return 1 unless pattern.respond_to?(:subject)
|
102
|
-
case subject <=> pattern.subject
|
103
|
-
when -1 then
|
104
|
-
-1
|
105
|
-
when 0 then
|
106
|
-
object <=> pattern.object
|
107
|
-
else
|
108
|
-
-1
|
109
|
-
end
|
110
|
-
end # def <=>
|
111
|
-
end # module Pattern
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../ruby_ext/string')
|
4
|
+
|
5
|
+
module Duxml
|
6
|
+
# Patterns represent a relationship between a specific XML Element and
|
7
|
+
# a specific or hypothetical attribute, attribute value, text value or child Element
|
8
|
+
# For example, given an XML Element: '<element attr='value'/>', there exists a valid PatternClass
|
9
|
+
# that represents the relationship betweeen <element> and the attribute value 'value'
|
10
|
+
# There can also exists a hypothetical relationship between <element> and a new child <child/> that
|
11
|
+
# is defined as an allowed child Element in the Rules that apply to this Element.
|
12
|
+
module Pattern; end
|
13
|
+
|
14
|
+
# as an object, a Pattern consists of a subject and may or may not have an object
|
15
|
+
# a Pattern without an object represents a childless empty node with no attributes
|
16
|
+
# this class must be subclassed to be used; there is one for each type of XML relationship
|
17
|
+
# that an Element can have up to one degree of separation, that is, grandparent relationships are not considered
|
18
|
+
# and neither are the attributes of children
|
19
|
+
class PatternClass
|
20
|
+
include Pattern
|
21
|
+
@subject
|
22
|
+
|
23
|
+
# @param subj [Element] specific Element that is the subject of this pattern
|
24
|
+
def initialize(subj)
|
25
|
+
@subject = subj
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :subject
|
29
|
+
end
|
30
|
+
|
31
|
+
module Pattern
|
32
|
+
include Duxml
|
33
|
+
|
34
|
+
def xml
|
35
|
+
p = Element.new(simple_name)
|
36
|
+
instance_variables.each do |sym|
|
37
|
+
val = instance_variable_get(sym)
|
38
|
+
if val.respond_to?(:nodes)
|
39
|
+
d = Element.new(sym.to_s) << val
|
40
|
+
p << d
|
41
|
+
else
|
42
|
+
p[sym.to_s[1..-1].to_sym] = val.to_s unless sym == :@observer_peers
|
43
|
+
end
|
44
|
+
end
|
45
|
+
p
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [String] nmtoken name of this pattern without namespace prefix e.g. ChildPattern.new(parent, child).name => 'child_pattern'
|
49
|
+
def simple_name
|
50
|
+
name.split(':').last
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Boolean] if either subject or object points to a name/type i.e. not an Element
|
54
|
+
def abstract?
|
55
|
+
subject.is_a?(String) or object.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Boolean] if both subject and at least one object point to an actual XML Element
|
59
|
+
def concrete?
|
60
|
+
!abstract?
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [String] nmtoken name of this pattern e.g. ChildPattern.new(parent, child).name => 'duxml:child_pattern'
|
64
|
+
def name
|
65
|
+
c = self.class.to_s
|
66
|
+
return c.nmtokenize unless c.include?('::')
|
67
|
+
a = c.split('::')
|
68
|
+
a[-2..-1].collect do |word|
|
69
|
+
word.nmtokenize
|
70
|
+
end.join(':')
|
71
|
+
end
|
72
|
+
|
73
|
+
# returns relationship description as string by subtracting super class name
|
74
|
+
# (e.g. 'pattern' or 'rule') from simple_class
|
75
|
+
# Duxml::ChildrenRule#relationship => 'children'
|
76
|
+
# Duxml::TextPattern#relationship => 'text'
|
77
|
+
# can be overridden if class name does not match human-readable string
|
78
|
+
# @return [String] single word to describe relationship of subject to object
|
79
|
+
def relationship
|
80
|
+
simple_name.split('_').first
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [String] "#{object.description} is #{relationship} of #{subject.description}"
|
84
|
+
def description
|
85
|
+
"#{object.description} is #{relationship} of #{subject.description}"
|
86
|
+
end
|
87
|
+
|
88
|
+
# @return [Element] will only return non-nil value when pattern represents relationship with a child Element
|
89
|
+
def object
|
90
|
+
return @object if instance_variable_defined?(:@object)
|
91
|
+
instance_variables.each do |var|
|
92
|
+
target = instance_variable_get(var)
|
93
|
+
return target unless target.is_a?(String) or target == subject
|
94
|
+
end
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
|
98
|
+
# @param pattern [Duxml::Pattern] pattern or any subclass object
|
99
|
+
# @return [Fixnum] first applies <=> to subjects, and if equal, applies <=> to objects
|
100
|
+
def <=>(pattern)
|
101
|
+
return 1 unless pattern.respond_to?(:subject)
|
102
|
+
case subject <=> pattern.subject
|
103
|
+
when -1 then
|
104
|
+
-1
|
105
|
+
when 0 then
|
106
|
+
object <=> pattern.object
|
107
|
+
else
|
108
|
+
-1
|
109
|
+
end
|
110
|
+
end # def <=>
|
111
|
+
end # module Pattern
|
112
112
|
end # module Duxml
|