@@ -12,7 +12,14 @@ def self.attributes
1212 @@attributes
1313 end
1414
15- def self . attribute ( name , *selectors , converter : Converters ::DefaultValueConverter , validator : Validators ::DefaultValidator )
15+ def self . required_attributes
16+ @@attributes . select { |a | a [ :required ] }
17+ end
18+
19+ def self . attribute ( name , *selectors , required : false , converter : Converters ::DefaultValueConverter , validator : Validators ::DefaultValidator )
20+ @@attributes ||= [ ]
21+ @@attributes << { name : name , selectors : selectors , required : required , converter : converter , validator : validator }
22+
1623 define_method ( name ) do
1724 selectors
1825 . lazy
@@ -22,15 +29,27 @@ def self.attribute(name, *selectors, converter: Converters::DefaultValueConverte
2229 end
2330
2431 define_method ( "#{ name } =" ) do |value |
25- validator . validate ( value ) || raise ( Errors ::StyleInvalidPropertyValue , "Invalid value for #{ name } : #{ value } " )
32+ ( required && value . nil? ) &&
33+ raise ( Errors ::StyleRequiredPropertyValue , "Required value #{ name } " )
34+
35+ validator . validate ( value ) ||
36+ raise ( Errors ::StyleInvalidPropertyValue , "Invalid value for #{ name } : '#{ value . nil? ? "nil" : value } '" )
37+
38+ encoded_value = converter . encode ( value )
2639
2740 selectors . map do |attribute_xpath |
28- encoded_value = converter . encode ( value ) . to_s
2941 if ( existing_attribute = node . at_xpath ( attribute_xpath ) )
30- existing_attribute . value = encoded_value
31- next value
42+ if encoded_value . nil?
43+ existing_attribute . remove
44+ else
45+ existing_attribute . value = encoded_value
46+ end
47+
48+ next encoded_value
3249 end
3350
51+ next encoded_value if encoded_value . nil?
52+
3453 node_xpath , attribute = attribute_xpath . split ( "/@" )
3554
3655 created_node =
@@ -40,7 +59,8 @@ def self.attribute(name, *selectors, converter: Converters::DefaultValueConverte
4059 # find the child node
4160 parent_node . at_xpath ( child_xpath ) ||
4261 # or create the child node
43- Nokogiri ::XML ::Node . new ( child_xpath , parent_node ) . tap { |created_child_node | parent_node << created_child_node }
62+ Nokogiri ::XML ::Node . new ( child_xpath , parent_node )
63+ . tap { |created_child_node | parent_node << created_child_node }
4464 end
4565
4666 created_node . set_attribute ( attribute , encoded_value )
@@ -67,9 +87,9 @@ def initialize(configuration, node, **attributes)
6787
6888 attr_accessor :node
6989
70- attribute :id , "./@w:styleId"
71- attribute :name , "./w:name/@w:val" , "./w:next/@w:val"
72- attribute :type , ".//@w:type"
90+ attribute :id , "./@w:styleId" , required : true
91+ attribute :name , "./w:name/@w:val" , "./w:next/@w:val" , required : true
92+ attribute :type , ".//@w:type" , required : true , validator : Validators :: ValueValidator . new ( "paragraph" , "character" , "table" , "numbering" )
7393 attribute :keep_next , "./w:pPr/w:keepNext/@w:val" , converter : Converters ::BooleanConverter
7494 attribute :keep_lines , "./w:pPr/w:keepLines/@w:val" , converter : Converters ::BooleanConverter
7595 attribute :page_break_before , "./w:pPr/w:pageBreakBefore/@w:val" , converter : Converters ::BooleanConverter
@@ -112,6 +132,16 @@ def initialize(configuration, node, **attributes)
112132 attribute :vertical_alignment , "./w:rPr/w:vertAlign/@w:val"
113133 attribute :lang , "./w:rPr/w:lang/@w:val"
114134
135+ def valid?
136+ self . class . required_attributes . all? do |a |
137+ validator = a [ :validator ]
138+ attribute_name = a [ :name ]
139+ attribute_value = self . send ( attribute_name )
140+
141+ validator &.validate ( attribute_value )
142+ end
143+ end
144+
115145 def to_xml
116146 node . to_xml
117147 end
0 commit comments