@@ -26,201 +26,6 @@ class RuleSet
26
26
27
27
WHITESPACE_REPLACEMENT = '___SPACE___'
28
28
29
- class Declarations
30
- class Value
31
- attr_reader :value
32
- attr_accessor :important
33
-
34
- def initialize ( value , important : nil )
35
- self . value = value
36
- @important = important unless important . nil?
37
- end
38
-
39
- def value = ( value )
40
- value = value . to_s . sub ( /\s *;\s *\Z / , '' )
41
- self . important = !value . slice! ( CssParser ::IMPORTANT_IN_PROPERTY_RX ) . nil?
42
- value . strip!
43
- raise ArgumentError , 'value is empty' if value . empty?
44
-
45
- @value = value . freeze
46
- end
47
-
48
- def to_s
49
- important ? "#{ value } !important" : value
50
- end
51
-
52
- def ==( other )
53
- return false unless other . is_a? ( self . class )
54
-
55
- value == other . value && important == other . important
56
- end
57
- end
58
-
59
- extend Forwardable
60
-
61
- def_delegators :declarations , :each , :each_value
62
-
63
- def initialize ( declarations = { } )
64
- self . declarations = { }
65
- declarations . each { |property , value | add_declaration! ( property , value ) }
66
- end
67
-
68
- # Add a CSS declaration
69
- # @param [#to_s] property that should be added
70
- # @param [Value, #to_s] value of the property
71
- #
72
- # @example
73
- # declarations['color'] = 'blue'
74
- #
75
- # puts declarations['color']
76
- # => #<CssParser::RuleSet::Declarations::Value:0x000000000305c730 @important=false, @order=1, @value="blue">
77
- #
78
- # @example
79
- # declarations['margin'] = '0px auto !important'
80
- #
81
- # puts declarations['margin']
82
- # => #<CssParser::RuleSet::Declarations::Value:0x00000000030c1838 @important=true, @order=2, @value="0px auto">
83
- #
84
- # If the property already exists its value will be over-written.
85
- # If the value is empty - property will be deleted
86
- def []=( property , value )
87
- property = normalize_property ( property )
88
-
89
- if value . is_a? ( Value )
90
- declarations [ property ] = value
91
- elsif value . to_s . strip . empty?
92
- delete property
93
- else
94
- declarations [ property ] = Value . new ( value )
95
- end
96
- rescue ArgumentError => e
97
- raise e . exception , "#{ property } #{ e . message } "
98
- end
99
- alias add_declaration! []=
100
-
101
- def []( property )
102
- declarations [ normalize_property ( property ) ]
103
- end
104
- alias get_value []
105
-
106
- def key? ( property )
107
- declarations . key? ( normalize_property ( property ) )
108
- end
109
-
110
- def size
111
- declarations . size
112
- end
113
-
114
- # Remove CSS declaration
115
- # @param [#to_s] property property to be removed
116
- #
117
- # @example
118
- # declarations.delete('color')
119
- def delete ( property )
120
- declarations . delete ( normalize_property ( property ) )
121
- end
122
- alias remove_declaration! delete
123
-
124
- # Replace CSS property with multiple declarations
125
- # @param [#to_s] property property name to be replaces
126
- # @param [Hash<String => [String, Value]>] replacements hash with properties to replace with
127
- #
128
- # @example
129
- # declarations = Declarations.new('line-height' => '0.25px', 'font' => 'small-caps', 'font-size' => '12em')
130
- # declarations.replace_declaration!('font', {'line-height' => '1px', 'font-variant' => 'small-caps', 'font-size' => '24px'})
131
- # declarations
132
- # => #<CssParser::RuleSet::Declarations:0x00000000029c3018
133
- # @declarations=
134
- # {"line-height"=>#<CssParser::RuleSet::Declarations::Value:0x00000000038ac458 @important=false, @value="1px">,
135
- # "font-variant"=>#<CssParser::RuleSet::Declarations::Value:0x00000000039b3ec8 @important=false, @value="small-caps">,
136
- # "font-size"=>#<CssParser::RuleSet::Declarations::Value:0x00000000029c2c80 @important=false, @value="12em">}>
137
- def replace_declaration! ( property , replacements , preserve_importance : false )
138
- property = normalize_property ( property )
139
- raise ArgumentError , "property #{ property } does not exist" unless key? ( property )
140
-
141
- replacement_declarations = self . class . new ( replacements )
142
-
143
- if preserve_importance
144
- importance = get_value ( property ) . important
145
- replacement_declarations . each_value { |value | value . important = importance }
146
- end
147
-
148
- replacement_keys = declarations . keys
149
- replacement_values = declarations . values
150
- property_index = replacement_keys . index ( property )
151
-
152
- # We should preserve subsequent declarations of the same properties
153
- # and prior important ones if replacement one is not important
154
- replacements = replacement_declarations . each . with_object ( { } ) do |( key , replacement ) , result |
155
- existing = declarations [ key ]
156
-
157
- # No existing -> set
158
- unless existing
159
- result [ key ] = replacement
160
- next
161
- end
162
-
163
- # Replacement more important than existing -> replace
164
- if replacement . important && !existing . important
165
- result [ key ] = replacement
166
- replaced_index = replacement_keys . index ( key )
167
- replacement_keys . delete_at ( replaced_index )
168
- replacement_values . delete_at ( replaced_index )
169
- property_index -= 1 if replaced_index < property_index
170
- next
171
- end
172
-
173
- # Existing is more important than replacement -> keep
174
- next if !replacement . important && existing . important
175
-
176
- # Existing and replacement importance are the same,
177
- # value which is declared later wins
178
- result [ key ] = replacement if property_index > replacement_keys . index ( key )
179
- end
180
-
181
- return if replacements . empty?
182
-
183
- replacement_keys . delete_at ( property_index )
184
- replacement_keys . insert ( property_index , *replacements . keys )
185
-
186
- replacement_values . delete_at ( property_index )
187
- replacement_values . insert ( property_index , *replacements . values )
188
-
189
- self . declarations = replacement_keys . zip ( replacement_values ) . to_h
190
- end
191
-
192
- def to_s ( options = { } )
193
- str = declarations . reduce ( String . new ) do |memo , ( prop , value ) |
194
- importance = options [ :force_important ] || value . important ? ' !important' : ''
195
- memo << "#{ prop } : #{ value . value } #{ importance } ; "
196
- end
197
- # TODO: Clean-up regexp doesn't seem to work
198
- str . gsub! ( /^[\s ^({)]+|[\n \r \f \t ]*|\s +$/mx , '' )
199
- str . strip!
200
- str
201
- end
202
-
203
- def ==( other )
204
- return false unless other . is_a? ( self . class )
205
-
206
- declarations == other . declarations && declarations . keys == other . declarations . keys
207
- end
208
-
209
- protected
210
-
211
- attr_reader :declarations
212
-
213
- private
214
-
215
- attr_writer :declarations
216
-
217
- def normalize_property ( property )
218
- property = property . to_s . downcase
219
- property . strip!
220
- property
221
- end
222
- end
223
-
224
29
extend Forwardable
225
30
226
31
# optional field for storing source reference
0 commit comments