@@ -44,9 +44,7 @@ def value=(value)
4444 end
4545
4646 def to_s
47- return value unless important
48-
49- "#{ value } !important"
47+ important ? "#{ value } !important" : value
5048 end
5149
5250 def ==( other )
@@ -88,15 +86,11 @@ def []=(property, value)
8886
8987 if value . is_a? ( Value )
9088 declarations [ property ] = value
91- return
92- end
93-
94- if value . to_s . strip . empty?
95- delete ( property )
96- return
89+ elsif value . to_s . strip . empty?
90+ delete property
91+ else
92+ declarations [ property ] = Value . new ( value )
9793 end
98-
99- declarations [ property ] = Value . new ( value )
10094 end
10195 alias add_declaration! []=
10296
@@ -153,28 +147,31 @@ def replace_declaration!(property, replacements, preserve_importance: false)
153147
154148 # We should preserve subsequent declarations of the same properties
155149 # and prior important ones if replacement one is not important
156- replacements = replacement_declarations . each . with_object ( { } ) do |( key , value ) , result |
157- # Replacement property doesn't exist, adding
158- next result [ key ] = value unless declarations . key? ( key )
159-
160- # Replacement property is important while existing one is not,
161- # replacing unconditionally
162- if value . important && !declarations [ key ] . important
163- result [ key ] = value
150+ replacements = replacement_declarations . each . with_object ( { } ) do |( key , replacement ) , merged |
151+ existing = declarations [ key ]
152+
153+ # No existing -> set
154+ unless existing
155+ merged [ key ] = replacement
156+ next
157+ end
158+
159+ # Replacement more important than existing -> replace
160+ if replacement . important && !existing . important
161+ merged [ key ] = replacement
164162 replaced_index = replacement_keys . index ( key )
165163 replacement_keys . delete_at ( replaced_index )
166164 replacement_values . delete_at ( replaced_index )
167165 property_index -= 1 if replaced_index < property_index
168166 next
169167 end
170168
171- # Existing value is important while replacing is not, existing one
172- # takes precedence
173- next if !value . important && declarations [ key ] . important
169+ # Existing is more important than replacement -> keep
170+ next if !replacement . important && existing . important
174171
175- # Importance of existing and replacement values are the same,
172+ # Existing and replacement importance are the same,
176173 # value which is declared later wins
177- result [ key ] = value if property_index > replacement_keys . index ( key )
174+ merged [ key ] = replacement if property_index > replacement_keys . index ( key )
178175 end
179176
180177 return if replacements . empty?
@@ -245,9 +242,9 @@ def initialize(selectors, block, specificity = nil)
245242
246243 # Get the value of a property
247244 def get_value ( property )
248- return '' unless declarations . key? ( property )
245+ return '' unless ( value = declarations [ property ] )
249246
250- "#{ declarations [ property ] } ;"
247+ "#{ value } ;"
251248 end
252249 alias [] get_value
253250
@@ -301,19 +298,23 @@ def expand_shorthand!
301298 #
302299 # See http://www.w3.org/TR/CSS21/colors.html#propdef-background
303300 def expand_background_shorthand! # :nodoc:
304- return unless declarations . key? ( 'background' )
305-
306- value = declarations [ 'background' ] . value . dup
307-
308- replacement = BACKGROUND_PROPERTIES . map { |key | [ key , 'inherit' ] } . to_h if value . match ( CssParser ::RE_INHERIT )
309- replacement ||= {
310- 'background-image' => value . slice! ( Regexp . union ( CssParser ::URI_RX , CssParser ::RE_GRADIENT , /none/i ) ) ,
311- 'background-attachment' => value . slice! ( CssParser ::RE_SCROLL_FIXED ) ,
312- 'background-repeat' => value . slice! ( CssParser ::RE_REPEAT ) ,
313- 'background-color' => value . slice! ( CssParser ::RE_COLOUR ) ,
314- 'background-size' => extract_background_size_from ( value ) ,
315- 'background-position' => value . slice! ( CssParser ::RE_BACKGROUND_POSITION )
316- }
301+ return unless ( declaration = declarations [ 'background' ] )
302+
303+ value = declaration . value . dup
304+
305+ replacement =
306+ if value . match ( CssParser ::RE_INHERIT )
307+ BACKGROUND_PROPERTIES . map { |key | [ key , 'inherit' ] } . to_h
308+ else
309+ {
310+ 'background-image' => value . slice! ( CssParser ::RE_IMAGE ) ,
311+ 'background-attachment' => value . slice! ( CssParser ::RE_SCROLL_FIXED ) ,
312+ 'background-repeat' => value . slice! ( CssParser ::RE_REPEAT ) ,
313+ 'background-color' => value . slice! ( CssParser ::RE_COLOUR ) ,
314+ 'background-size' => extract_background_size_from ( value ) ,
315+ 'background-position' => value . slice! ( CssParser ::RE_BACKGROUND_POSITION )
316+ }
317+ end
317318
318319 declarations . replace_declaration! ( 'background' , replacement , preserve_importance : true )
319320 end
@@ -328,9 +329,9 @@ def extract_background_size_from(value)
328329 # Additional splitting happens in expand_dimensions_shorthand!
329330 def expand_border_shorthand! # :nodoc:
330331 BORDER_PROPERTIES . each do |k |
331- next unless declarations . key? ( k )
332+ next unless ( declaration = declarations [ k ] )
332333
333- value = declarations [ k ] . value . dup
334+ value = declaration . value . dup
334335
335336 replacement = {
336337 "#{ k } -width" => value . slice! ( CssParser ::RE_BORDER_UNITS ) ,
@@ -346,9 +347,9 @@ def expand_border_shorthand! # :nodoc:
346347 # into their constituent parts. Handles margin, padding, border-color, border-style and border-width.
347348 def expand_dimensions_shorthand! # :nodoc:
348349 DIMENSIONS . each do |property , ( top , right , bottom , left ) |
349- next unless declarations . key? ( property )
350+ next unless ( declaration = declarations [ property ] )
350351
351- value = declarations [ property ] . value . dup
352+ value = declaration . value . dup
352353
353354 # RGB and HSL values in borders are the only units that can have spaces (within params).
354355 # We cheat a bit here by stripping spaces after commas in RGB and HSL values so that we
@@ -369,38 +370,39 @@ def expand_dimensions_shorthand! # :nodoc:
369370 values << matches [ 1 ] # left = right
370371 when 4
371372 values = matches . to_a
373+ else
374+ raise ArgumentError , "Cannot parse #{ value } "
372375 end
373376
374377 t , r , b , l = values
378+ replacement = { top => t , right => r , bottom => b , left => l }
375379
376- declarations . replace_declaration! (
377- property ,
378- { top => t , right => r , bottom => b , left => l } ,
379- preserve_importance : true
380- )
380+ declarations . replace_declaration! ( property , replacement , preserve_importance : true )
381381 end
382382 end
383383
384384 # Convert shorthand font declarations (e.g. <tt>font: 300 italic 11px/14px verdana, helvetica, sans-serif;</tt>)
385385 # into their constituent parts.
386386 def expand_font_shorthand! # :nodoc:
387- return unless declarations . key? ( 'font' )
388-
389- font_props = { }
387+ return unless ( declaration = declarations [ 'font' ] )
390388
391389 # reset properties to 'normal' per http://www.w3.org/TR/CSS21/fonts.html#font-shorthand
392- [ 'font-style' , 'font-variant' , 'font-weight' , 'font-size' , 'line-height' ] . each do |prop |
393- font_props [ prop ] = 'normal'
394- end
390+ font_props = {
391+ 'font-style' => 'normal' ,
392+ 'font-variant' => 'normal' ,
393+ 'font-weight' => 'normal' ,
394+ 'font-size' => 'normal' ,
395+ 'line-height' => 'normal'
396+ }
395397
396- value = declarations [ 'font' ] . value . dup
398+ value = declaration . value . dup
397399 value . gsub! ( %r{/\s +} , '/' ) # handle spaces between font size and height shorthand (e.g. 14px/ 16px)
398400
399401 in_fonts = false
400402
401- matches = value . scan ( /("( .*[^"])"|'(.*[^'])'|(\w [^ ,]+) )/ )
402- matches . each do |match |
403- m = match [ 0 ] . to_s . strip
403+ matches = value . scan ( /"(?: .*[^"])"|'(?: .*[^'])'|(?: \w [^ ,]+)/ )
404+ matches . each do |m |
405+ m . strip!
404406 m . gsub! ( /;$/ , '' )
405407
406408 if in_fonts
@@ -411,7 +413,7 @@ def expand_font_shorthand! # :nodoc:
411413 end
412414 elsif m =~ /normal|inherit/i
413415 [ 'font-style' , 'font-weight' , 'font-variant' ] . each do |font_prop |
414- font_props [ font_prop ] = m unless font_props . key? ( font_prop )
416+ font_props [ font_prop ] || = m
415417 end
416418 elsif m =~ /italic|oblique/i
417419 font_props [ 'font-style' ] = m
@@ -420,8 +422,8 @@ def expand_font_shorthand! # :nodoc:
420422 elsif m =~ /[1-9]00$|bold|bolder|lighter/i
421423 font_props [ 'font-weight' ] = m
422424 elsif m =~ CssParser ::FONT_UNITS_RX
423- if m =~ %r{/}
424- font_props [ 'font-size' ] , font_props [ 'line-height' ] = m . split ( '/' )
425+ if m . include? ( '/' )
426+ font_props [ 'font-size' ] , font_props [ 'line-height' ] = m . split ( '/' , 2 )
425427 else
426428 font_props [ 'font-size' ] = m
427429 end
@@ -437,16 +439,20 @@ def expand_font_shorthand! # :nodoc:
437439 #
438440 # See http://www.w3.org/TR/CSS21/generate.html#lists
439441 def expand_list_style_shorthand! # :nodoc:
440- return unless declarations . key? ( 'list-style' )
441-
442- value = declarations [ 'list-style' ] . value . dup
443-
444- replacement = LIST_STYLE_PROPERTIES . map { |key | [ key , 'inherit' ] } . to_h if value =~ CssParser ::RE_INHERIT
445- replacement ||= {
446- 'list-style-type' => value . slice! ( CssParser ::RE_LIST_STYLE_TYPE ) ,
447- 'list-style-position' => value . slice! ( CssParser ::RE_INSIDE_OUTSIDE ) ,
448- 'list-style-image' => value . slice! ( Regexp . union ( CssParser ::URI_RX , /none/i ) )
449- }
442+ return unless ( declaration = declarations [ 'list-style' ] )
443+
444+ value = declaration . value . dup
445+
446+ replacement =
447+ if value =~ CssParser ::RE_INHERIT
448+ LIST_STYLE_PROPERTIES . map { |key | [ key , 'inherit' ] } . to_h
449+ else
450+ {
451+ 'list-style-type' => value . slice! ( CssParser ::RE_LIST_STYLE_TYPE ) ,
452+ 'list-style-position' => value . slice! ( CssParser ::RE_INSIDE_OUTSIDE ) ,
453+ 'list-style-image' => value . slice! ( CssParser ::URI_RX_OR_NONE )
454+ }
455+ end
450456
451457 declarations . replace_declaration! ( 'list-style' , replacement , preserve_importance : true )
452458 end
@@ -466,10 +472,11 @@ def create_shorthand_properties!(properties, shorthand_property) # :nodoc:
466472 values = [ ]
467473 properties_to_delete = [ ]
468474 properties . each do |property |
469- if declarations . key? ( property ) and not declarations [ property ] . important
470- values << declarations [ property ] . value
471- properties_to_delete << property
472- end
475+ next unless ( declaration = declarations [ property ] )
476+ next if declaration . important
477+
478+ values << declaration . value
479+ properties_to_delete << property
473480 end
474481
475482 return if values . length <= 1
@@ -490,12 +497,9 @@ def create_background_shorthand! # :nodoc:
490497 # background-position by preceding it with a backslash. In this case we also need to
491498 # have a background-position property, so we set it if it's missing.
492499 # http://www.w3schools.com/cssref/css3_pr_background.asp
493- if declarations . key? ( 'background-size' ) and not declarations [ 'background-size' ] . important
494- unless declarations . key? ( 'background-position' )
495- declarations [ 'background-position' ] = '0% 0%'
496- end
497-
498- declarations [ 'background-size' ] . value = "/ #{ declarations [ 'background-size' ] . value } "
500+ if ( declaration = declarations [ 'background-size' ] ) && !declaration . important
501+ declarations [ 'background-position' ] ||= '0% 0%'
502+ declaration . value = "/ #{ declaration . value } "
499503 end
500504
501505 create_shorthand_properties! BACKGROUND_PROPERTIES , 'background'
@@ -509,12 +513,15 @@ def create_border_shorthand! # :nodoc:
509513 values = [ ]
510514
511515 BORDER_STYLE_PROPERTIES . each do |property |
512- next unless declarations . key? ( property ) and not declarations [ property ] . important
516+ next unless ( declaration = declarations [ property ] )
517+ next if declaration . important
518+
513519 # can't merge if any value contains a space (i.e. has multiple values)
514520 # we temporarily remove any spaces after commas for the check (inside rgba, etc...)
515- return nil if declarations [ property ] . value . gsub ( /,\s / , ',' ) . strip =~ /\s /
521+ return nil if declaration . value . gsub ( /,\s / , ',' ) . strip =~ /\s /
522+
523+ values << declaration . value
516524
517- values << declarations [ property ] . value
518525 declarations . delete ( property )
519526 end
520527
@@ -530,9 +537,9 @@ def create_dimensions_shorthand! # :nodoc:
530537
531538 DIMENSIONS . each do |property , dimensions |
532539 values = [ :top , :right , :bottom , :left ] . each_with_index . with_object ( { } ) do |( side , index ) , result |
533- next unless declarations . key? ( dimensions [ index ] )
540+ next unless ( declaration = declarations [ dimensions [ index ] ] )
534541
535- result [ side ] = declarations [ dimensions [ index ] ] . value
542+ result [ side ] = declaration . value
536543 end
537544
538545 # All four dimensions must be present
@@ -604,10 +611,10 @@ def parse_declarations!(block) # :nodoc:
604611
605612 continuation = nil
606613 block . split ( /[;$]+/m ) . each do |decs |
607- decs = continuation ? continuation + decs : decs
614+ decs = ( continuation ? continuation + decs : decs )
608615 if decs =~ /\( [^)]*\Z / # if it has an unmatched parenthesis
609616 continuation = "#{ decs } ;"
610- elsif ( matches = decs . match ( /\s *(.[^:]*)\s *:\s *(.+?)(;?\s *\Z )/i ) )
617+ elsif ( matches = decs . match ( /\s *(.[^:]*)\s *:\s *(.+?)(?: ;?\s *\Z )/i ) )
611618 # skip end_of_declaration
612619 property = matches [ 1 ]
613620 value = matches [ 2 ]
0 commit comments