Skip to content

Commit c5bcb57

Browse files
authored
Merge pull request #149 from ruby-docx/refactoring-extract-attribute-class
Refactor style.rb to introduce Attribute class
2 parents a765bb1 + c1f5fbf commit c5bcb57

File tree

1 file changed

+70
-47
lines changed

1 file changed

+70
-47
lines changed

lib/docx/elements/style.rb

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,64 +8,89 @@ module Elements
88
class Style
99
include Docx::SimpleInspect
1010

11-
@attributes = []
11+
class Attribute
12+
attr_reader :name, :selectors, :required, :converter, :validator
13+
14+
def initialize(name, selectors, required: false, converter:, validator:)
15+
@name = name
16+
@selectors = selectors
17+
@required = required
18+
@converter = converter || Converters::DefaultValueConverter
19+
@validator = validator || Validators::DefaultValidator
20+
end
1221

13-
class << self
14-
attr_accessor :attributes
22+
def required?
23+
required
24+
end
1525

16-
def required_attributes
17-
attributes.select { |a| a[:required] }
26+
def retrieve_from(style)
27+
selectors
28+
.lazy
29+
.filter_map { |node_xpath| style.node.at_xpath(node_xpath)&.value }
30+
.map { |value| converter.decode(value) }
31+
.first
1832
end
1933

20-
def attribute(name, *selectors, required: false, converter: Converters::DefaultValueConverter, validator: Validators::DefaultValidator)
21-
attributes << {name: name, selectors: selectors, required: required, converter: converter, validator: validator}
34+
def assign_to(style, value)
35+
(required && value.nil?) &&
36+
raise(Errors::StyleRequiredPropertyValue, "Required value #{name}")
2237

23-
define_method(name) do
24-
selectors
25-
.lazy
26-
.filter_map { |node_xpath| node.at_xpath(node_xpath)&.value }
27-
.map { |value| converter.decode(value) }
28-
.first
29-
end
38+
validator.validate(value) ||
39+
raise(Errors::StyleInvalidPropertyValue, "Invalid value for #{name}: '#{value.nil? ? "nil" : value}'")
3040

31-
define_method("#{name}=") do |value|
32-
(required && value.nil?) &&
33-
raise(Errors::StyleRequiredPropertyValue, "Required value #{name}")
41+
encoded_value = converter.encode(value)
3442

35-
validator.validate(value) ||
36-
raise(Errors::StyleInvalidPropertyValue, "Invalid value for #{name}: '#{value.nil? ? "nil" : value}'")
43+
selectors.map do |attribute_xpath|
44+
if (existing_attribute = style.node.at_xpath(attribute_xpath))
45+
if encoded_value.nil?
46+
existing_attribute.remove
47+
else
48+
existing_attribute.value = encoded_value.to_s
49+
end
3750

38-
encoded_value = converter.encode(value)
51+
next encoded_value
52+
end
3953

40-
selectors.map do |attribute_xpath|
41-
if (existing_attribute = node.at_xpath(attribute_xpath))
42-
if encoded_value.nil?
43-
existing_attribute.remove
44-
else
45-
existing_attribute.value = encoded_value.to_s
54+
next encoded_value if encoded_value.nil?
55+
56+
node_xpath, attribute = attribute_xpath.split("/@")
57+
58+
created_node =
59+
node_xpath
60+
.split("/")
61+
.reduce(style.node) do |parent_node, child_xpath|
62+
# find the child node
63+
parent_node.at_xpath(child_xpath) ||
64+
# or create the child node
65+
Nokogiri::XML::Node.new(child_xpath, parent_node)
66+
.tap { |created_child_node| parent_node << created_child_node }
4667
end
4768

48-
next encoded_value
49-
end
69+
created_node.set_attribute(attribute, encoded_value)
70+
end
71+
.first
72+
end
73+
end
74+
75+
@attributes = []
76+
77+
class << self
78+
attr_accessor :attributes
5079

51-
next encoded_value if encoded_value.nil?
80+
def required_attributes
81+
attributes.select(&:required?)
82+
end
5283

53-
node_xpath, attribute = attribute_xpath.split("/@")
84+
def attribute(name, *selectors, required: false, converter: nil, validator: nil)
85+
new_attribute = Attribute.new(name, selectors, required: required, converter: converter, validator: validator)
86+
attributes << new_attribute
5487

55-
created_node =
56-
node_xpath
57-
.split("/")
58-
.reduce(node) do |parent_node, child_xpath|
59-
# find the child node
60-
parent_node.at_xpath(child_xpath) ||
61-
# or create the child node
62-
Nokogiri::XML::Node.new(child_xpath, parent_node)
63-
.tap { |created_child_node| parent_node << created_child_node }
64-
end
88+
define_method(name) do
89+
new_attribute.retrieve_from(self)
90+
end
6591

66-
created_node.set_attribute(attribute, encoded_value)
67-
end
68-
.first
92+
define_method("#{name}=") do |value|
93+
new_attribute.assign_to(self, value)
6994
end
7095
end
7196

@@ -135,11 +160,9 @@ def initialize(configuration, node, **attributes)
135160

136161
def valid?
137162
self.class.required_attributes.all? do |a|
138-
validator = a[:validator]
139-
attribute_name = a[:name]
140-
attribute_value = self.send(attribute_name)
163+
attribute_value = a.retrieve_from(self)
141164

142-
validator&.validate(attribute_value)
165+
a.validator&.validate(attribute_value)
143166
end
144167
end
145168

0 commit comments

Comments
 (0)