Class: CssParser::RuleSet
- Inherits:
-
Object
- Object
- CssParser::RuleSet
- Extended by:
- Forwardable
- Defined in:
- lib/css_parser/rule_set.rb
Defined Under Namespace
Classes: Declarations
Constant Summary collapse
- RE_ELEMENTS_AND_PSEUDO_ELEMENTS =
Patterns for specificity calculations
/((^|[\s+>]+)\w+|:(first-line|first-letter|before|after))/i.freeze
- RE_NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES =
/(\.\w+)|(\[\w+)|(:(link|first-child|lang))/i.freeze
- BACKGROUND_PROPERTIES =
['background-color', 'background-image', 'background-repeat', 'background-position', 'background-size', 'background-attachment'].freeze
- LIST_STYLE_PROPERTIES =
['list-style-type', 'list-style-position', 'list-style-image'].freeze
- FONT_STYLE_PROPERTIES =
['font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', 'font-family'].freeze
- BORDER_STYLE_PROPERTIES =
['border-width', 'border-style', 'border-color'].freeze
- BORDER_PROPERTIES =
['border', 'border-left', 'border-right', 'border-top', 'border-bottom'].freeze
- NUMBER_OF_DIMENSIONS =
4
- DIMENSIONS =
[ ['margin', %w[margin-top margin-right margin-bottom margin-left]], ['padding', %w[padding-top padding-right padding-bottom padding-left]], ['border-color', %w[border-top-color border-right-color border-bottom-color border-left-color]], ['border-style', %w[border-top-style border-right-style border-bottom-style border-left-style]], ['border-width', %w[border-top-width border-right-width border-bottom-width border-left-width]] ].freeze
- WHITESPACE_REPLACEMENT =
'___SPACE___'
- COLON =
Tokens for parse_declarations!
':'.freeze
- SEMICOLON =
';'.freeze
- LPAREN =
'('.freeze
- RPAREN =
')'.freeze
- IMPORTANT =
'!important'.freeze
Instance Attribute Summary collapse
-
#filename ⇒ Object
the local or remote location.
-
#offset ⇒ Object
readonly
optional field for storing source reference File offset range.
-
#selectors ⇒ Object
readonly
Array of selector strings.
-
#specificity ⇒ Object
Integer with the specificity to use for this RuleSet.
Instance Method Summary collapse
- #add_declaration! ⇒ Object (also: #[]=)
-
#create_background_shorthand! ⇒ Object
Looks for long format CSS background properties (e.g.
background-color
) and converts them into a shorthand CSSbackground
property. -
#create_border_shorthand! ⇒ Object
Combine border-color, border-style and border-width into border Should be run after create_dimensions_shorthand!.
-
#create_dimensions_shorthand! ⇒ Object
Looks for long format CSS dimensional properties (margin, padding, border-color, border-style and border-width) and converts them into shorthand CSS properties.
-
#create_font_shorthand! ⇒ Object
Looks for long format CSS font properties (e.g.
font-weight
) and tries to convert them into a shorthand CSSfont
property. -
#create_list_style_shorthand! ⇒ Object
Looks for long format CSS list-style properties (e.g.
list-style-type
) and converts them into a shorthand CSSlist-style
property. -
#create_shorthand! ⇒ Object
Create shorthand declarations (e.g.
margin
orfont
) whenever possible. -
#create_shorthand_properties!(properties, shorthand_property) ⇒ Object
Combine several properties into a shorthand one.
-
#declarations_to_s(options = {}) ⇒ Object
Return all declarations as a string.
- #delete ⇒ Object (also: #remove_declaration!)
-
#each_declaration ⇒ Object
Iterate through declarations.
-
#each_selector(options = {}) ⇒ Object
Iterate through selectors.
-
#expand_background_shorthand! ⇒ Object
Convert shorthand background declarations (e.g.
background: url("chess.png") gray 50% repeat fixed;
) into their constituent parts. -
#expand_border_shorthand! ⇒ Object
Split shorthand border declarations (e.g.
border: 1px red;
) Additional splitting happens in expand_dimensions_shorthand!. -
#expand_dimensions_shorthand! ⇒ Object
Split shorthand dimensional declarations (e.g.
margin: 0px auto;
) into their constituent parts. -
#expand_font_shorthand! ⇒ Object
Convert shorthand font declarations (e.g.
font: 300 italic 11px/14px verdana, helvetica, sans-serif;
) into their constituent parts. -
#expand_list_style_shorthand! ⇒ Object
Convert shorthand list-style declarations (e.g.
list-style: lower-alpha outside;
) into their constituent parts. -
#expand_shorthand! ⇒ Object
Split shorthand declarations (e.g.
margin
orfont
) into their constituent parts. - #extract_background_size_from(value) ⇒ Object
-
#get_value(property) ⇒ Object
(also: #[])
Get the value of a property.
-
#initialize(*args, selectors: nil, block: nil, offset: nil, filename: nil, specificity: nil) ⇒ RuleSet
constructor
rubocop:disable Metrics/ParameterLists.
-
#to_s ⇒ Object
Return the CSS rule set as a string.
Constructor Details
#initialize(*args, selectors: nil, block: nil, offset: nil, filename: nil, specificity: nil) ⇒ RuleSet
rubocop:disable Metrics/ParameterLists
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/css_parser/rule_set.rb', line 252 def initialize(*args, selectors: nil, block: nil, offset: nil, filename: nil, specificity: nil) # rubocop:disable Metrics/ParameterLists if args.any? if selectors || block || offset || filename || specificity raise ArgumentError, "don't mix positional and keyword arguments" end warn '[DEPRECATION] positional arguments are deprecated use keyword instead.', uplevel: 1 case args.length when 2 selectors, block = args when 3 selectors, block, specificity = args when 4 filename, offset, selectors, block = args when 5 filename, offset, selectors, block, specificity = args else raise ArgumentError end end @selectors = [] @specificity = specificity unless offset.nil? == filename.nil? raise ArgumentError, 'require both offset and filename or no offset and no filename' end @offset = offset @filename = filename parse_selectors!(selectors) if selectors parse_declarations!(block) end |
Instance Attribute Details
#filename ⇒ Object
the local or remote location
236 237 238 |
# File 'lib/css_parser/rule_set.rb', line 236 def filename @filename end |
#offset ⇒ Object (readonly)
optional field for storing source reference File offset range
234 235 236 |
# File 'lib/css_parser/rule_set.rb', line 234 def offset @offset end |
#selectors ⇒ Object (readonly)
Array of selector strings.
239 240 241 |
# File 'lib/css_parser/rule_set.rb', line 239 def selectors @selectors end |
#specificity ⇒ Object
Integer with the specificity to use for this RuleSet.
242 243 244 |
# File 'lib/css_parser/rule_set.rb', line 242 def specificity @specificity end |
Instance Method Details
#add_declaration! ⇒ Object Also known as: []=
248 |
# File 'lib/css_parser/rule_set.rb', line 248 def_delegators :declarations, :add_declaration!, :delete |
#create_background_shorthand! ⇒ Object
Looks for long format CSS background properties (e.g. background-color
) and converts them into a shorthand CSS background
property.
Leaves properties declared !important alone.
539 540 541 542 543 544 545 546 547 548 549 550 |
# File 'lib/css_parser/rule_set.rb', line 539 def create_background_shorthand! # :nodoc: # When we have a background-size property we must separate it and distinguish it from # background-position by preceding it with a backslash. In this case we also need to # have a background-position property, so we set it if it's missing. # http://www.w3schools.com/cssref/css3_pr_background.asp if (declaration = declarations['background-size']) && !declaration.important declarations['background-position'] ||= '0% 0%' declaration.value = "/ #{declaration.value}" end create_shorthand_properties! BACKGROUND_PROPERTIES, 'background' end |
#create_border_shorthand! ⇒ Object
Combine border-color, border-style and border-width into border Should be run after create_dimensions_shorthand!
TODO: this is extremely similar to create_background_shorthand! and should be combined
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 |
# File 'lib/css_parser/rule_set.rb', line 556 def create_border_shorthand! # :nodoc: values = BORDER_STYLE_PROPERTIES.map do |property| next unless (declaration = declarations[property]) next if declaration.important # can't merge if any value contains a space (i.e. has multiple values) # we temporarily remove any spaces after commas for the check (inside rgba, etc...) next if declaration.value.gsub(/,\s/, ',').strip =~ /\s/ declaration.value end.compact return if values.size != BORDER_STYLE_PROPERTIES.size BORDER_STYLE_PROPERTIES.each do |property| declarations.delete(property) end declarations['border'] = values.join(' ') end |
#create_dimensions_shorthand! ⇒ Object
Looks for long format CSS dimensional properties (margin, padding, border-color, border-style and border-width) and converts them into shorthand CSS properties.
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 |
# File 'lib/css_parser/rule_set.rb', line 578 def create_dimensions_shorthand! # :nodoc: return if declarations.size < NUMBER_OF_DIMENSIONS DIMENSIONS.each do |property, dimensions| values = [:top, :right, :bottom, :left].each_with_index.with_object({}) do |(side, index), result| next unless (declaration = declarations[dimensions[index]]) result[side] = declaration.value end # All four dimensions must be present next if values.size != dimensions.size new_value = values.values_at(*compute_dimensions_shorthand(values)).join(' ').strip declarations[property] = new_value unless new_value.empty? # Delete the longhand values dimensions.each { |d| declarations.delete(d) } end end |
#create_font_shorthand! ⇒ Object
Looks for long format CSS font properties (e.g. font-weight
) and tries to convert them into a shorthand CSS font
property. All font properties must be present in order to create a shorthand declaration.
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
# File 'lib/css_parser/rule_set.rb', line 602 def create_font_shorthand! # :nodoc: return unless FONT_STYLE_PROPERTIES.all? { |prop| declarations.key?(prop) } new_value = String.new ['font-style', 'font-variant', 'font-weight'].each do |property| unless declarations[property].value == 'normal' new_value << declarations[property].value << ' ' end end new_value << declarations['font-size'].value unless declarations['line-height'].value == 'normal' new_value << '/' << declarations['line-height'].value end new_value << ' ' << declarations['font-family'].value declarations['font'] = new_value.gsub(/\s+/, ' ') FONT_STYLE_PROPERTIES.each { |prop| declarations.delete(prop) } end |
#create_list_style_shorthand! ⇒ Object
Looks for long format CSS list-style properties (e.g. list-style-type
) and converts them into a shorthand CSS list-style
property.
Leaves properties declared !important alone.
629 630 631 |
# File 'lib/css_parser/rule_set.rb', line 629 def create_list_style_shorthand! # :nodoc: create_shorthand_properties! LIST_STYLE_PROPERTIES, 'list-style' end |
#create_shorthand! ⇒ Object
Create shorthand declarations (e.g. margin
or font
) whenever possible.
505 506 507 508 509 510 511 512 |
# File 'lib/css_parser/rule_set.rb', line 505 def create_shorthand! create_background_shorthand! create_dimensions_shorthand! # border must be shortened after dimensions create_border_shorthand! create_font_shorthand! create_list_style_shorthand! end |
#create_shorthand_properties!(properties, shorthand_property) ⇒ Object
Combine several properties into a shorthand one
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
# File 'lib/css_parser/rule_set.rb', line 515 def create_shorthand_properties!(properties, shorthand_property) # :nodoc: values = [] properties_to_delete = [] properties.each do |property| next unless (declaration = declarations[property]) next if declaration.important values << declaration.value properties_to_delete << property end return if values.length <= 1 properties_to_delete.each do |property| declarations.delete(property) end declarations[shorthand_property] = values.join(' ') end |
#declarations_to_s(options = {}) ⇒ Object
Return all declarations as a string.
322 323 324 |
# File 'lib/css_parser/rule_set.rb', line 322 def declarations_to_s( = {}) declarations.to_s() end |
#delete ⇒ Object Also known as: remove_declaration!
248 |
# File 'lib/css_parser/rule_set.rb', line 248 def_delegators :declarations, :add_declaration!, :delete |
#each_declaration ⇒ Object
Iterate through declarations.
315 316 317 318 319 |
# File 'lib/css_parser/rule_set.rb', line 315 def each_declaration # :yields: property, value, is_important declarations.each do |property_name, value| yield property_name, value.value, value.important end end |
#each_selector(options = {}) ⇒ Object
Iterate through selectors.
Options
-
force_important
– boolean
Example
ruleset.each_selector do |sel, dec, spec|
...
end
305 306 307 308 309 310 311 312 |
# File 'lib/css_parser/rule_set.rb', line 305 def each_selector( = {}) # :yields: selector, declarations, specificity decs = declarations.to_s() if @specificity @selectors.each { |sel| yield sel.strip, decs, @specificity } else @selectors.each { |sel| yield sel.strip, decs, CssParser.calculate_specificity(sel) } end end |
#expand_background_shorthand! ⇒ Object
Convert shorthand background declarations (e.g. background: url("chess.png") gray 50% repeat fixed;
) into their constituent parts.
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/css_parser/rule_set.rb', line 345 def # :nodoc: return unless (declaration = declarations['background']) value = declaration.value.dup replacement = if value.match(CssParser::RE_INHERIT) BACKGROUND_PROPERTIES.to_h { |key| [key, 'inherit'] } else { 'background-image' => value.slice!(CssParser::RE_IMAGE), 'background-attachment' => value.slice!(CssParser::RE_SCROLL_FIXED), 'background-repeat' => value.slice!(CssParser::RE_REPEAT), 'background-color' => value.slice!(CssParser::RE_COLOUR), 'background-size' => extract_background_size_from(value), 'background-position' => value.slice!(CssParser::RE_BACKGROUND_POSITION) } end declarations.replace_declaration!('background', replacement, preserve_importance: true) end |
#expand_border_shorthand! ⇒ Object
Split shorthand border declarations (e.g. border: 1px red;
) Additional splitting happens in expand_dimensions_shorthand!
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
# File 'lib/css_parser/rule_set.rb', line 375 def # :nodoc: BORDER_PROPERTIES.each do |k| next unless (declaration = declarations[k]) value = declaration.value.dup replacement = { "#{k}-width" => value.slice!(CssParser::RE_BORDER_UNITS), "#{k}-color" => value.slice!(CssParser::RE_COLOUR), "#{k}-style" => value.slice!(CssParser::RE_BORDER_STYLE) } declarations.replace_declaration!(k, replacement, preserve_importance: true) end end |
#expand_dimensions_shorthand! ⇒ Object
Split shorthand dimensional declarations (e.g. margin: 0px auto;
) into their constituent parts. Handles margin, padding, border-color, border-style and border-width.
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
# File 'lib/css_parser/rule_set.rb', line 393 def # :nodoc: DIMENSIONS.each do |property, (top, right, bottom, left)| next unless (declaration = declarations[property]) value = declaration.value.dup # RGB and HSL values in borders are the only units that can have spaces (within params). # We cheat a bit here by stripping spaces after commas in RGB and HSL values so that we # can split easily on spaces. # # TODO: rgba, hsl, hsla value.gsub!(RE_COLOUR) { |c| c.gsub(/(\s*,\s*)/, ',') } matches = split_value_preserving_function_whitespace(value) case matches.length when 1 values = matches.to_a * 4 when 2 values = matches.to_a * 2 when 3 values = matches.to_a values << matches[1] # left = right when 4 values = matches.to_a else raise ArgumentError, "Cannot parse #{value}" end replacement = [top, right, bottom, left].zip(values).to_h declarations.replace_declaration!(property, replacement, preserve_importance: true) end end |
#expand_font_shorthand! ⇒ Object
Convert shorthand font declarations (e.g. font: 300 italic 11px/14px verdana, helvetica, sans-serif;
) into their constituent parts.
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/css_parser/rule_set.rb', line 430 def # :nodoc: return unless (declaration = declarations['font']) # reset properties to 'normal' per http://www.w3.org/TR/CSS21/fonts.html#font-shorthand font_props = { 'font-style' => 'normal', 'font-variant' => 'normal', 'font-weight' => 'normal', 'font-size' => 'normal', 'line-height' => 'normal' } value = declaration.value.dup value.gsub!(%r{/\s+}, '/') # handle spaces between font size and height shorthand (e.g. 14px/ 16px) in_fonts = false matches = value.scan(/"(?:.*[^"])"|'(?:.*[^'])'|(?:\w[^ ,]+)/) matches.each do |m| m.strip! m.gsub!(/;$/, '') if in_fonts if font_props.key?('font-family') font_props['font-family'] += ", #{m}" else font_props['font-family'] = m end elsif m =~ /normal|inherit/i ['font-style', 'font-weight', 'font-variant'].each do |font_prop| font_props[font_prop] ||= m end elsif m =~ /italic|oblique/i font_props['font-style'] = m elsif m =~ /small-caps/i font_props['font-variant'] = m elsif m =~ /[1-9]00$|bold|bolder|lighter/i font_props['font-weight'] = m elsif m =~ CssParser::FONT_UNITS_RX if m.include?('/') font_props['font-size'], font_props['line-height'] = m.split('/', 2) else font_props['font-size'] = m end in_fonts = true end end declarations.replace_declaration!('font', font_props, preserve_importance: true) end |
#expand_list_style_shorthand! ⇒ Object
Convert shorthand list-style declarations (e.g. list-style: lower-alpha outside;
) into their constituent parts.
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/css_parser/rule_set.rb', line 485 def # :nodoc: return unless (declaration = declarations['list-style']) value = declaration.value.dup replacement = if value =~ CssParser::RE_INHERIT LIST_STYLE_PROPERTIES.to_h { |key| [key, 'inherit'] } else { 'list-style-type' => value.slice!(CssParser::RE_LIST_STYLE_TYPE), 'list-style-position' => value.slice!(CssParser::RE_INSIDE_OUTSIDE), 'list-style-image' => value.slice!(CssParser::URI_RX_OR_NONE) } end declarations.replace_declaration!('list-style', replacement, preserve_importance: true) end |
#expand_shorthand! ⇒ Object
Split shorthand declarations (e.g. margin
or font
) into their constituent parts.
332 333 334 335 336 337 338 339 |
# File 'lib/css_parser/rule_set.rb', line 332 def # border must be expanded before dimensions end |
#extract_background_size_from(value) ⇒ Object
367 368 369 370 371 |
# File 'lib/css_parser/rule_set.rb', line 367 def extract_background_size_from(value) size = value.slice!(CssParser::RE_BACKGROUND_SIZE) size.sub(%r{^\s*/\s*}, '') if size end |
#get_value(property) ⇒ Object Also known as: []
Get the value of a property
289 290 291 292 293 |
# File 'lib/css_parser/rule_set.rb', line 289 def get_value(property) return '' unless (value = declarations[property]) "#{value};" end |
#to_s ⇒ Object
Return the CSS rule set as a string.
327 328 329 |
# File 'lib/css_parser/rule_set.rb', line 327 def to_s "#{@selectors.join(',')} { #{declarations} }" end |