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
- FONT_WEIGHT_PROPERTIES =
['font-style', 'font-weight', 'font-variant'].freeze
- BORDER_STYLE_PROPERTIES =
['border-width', 'border-style', 'border-color'].freeze
- BORDER_PROPERTIES =
['border', 'border-left', 'border-right', 'border-top', 'border-bottom'].freeze
- DIMENSION_DIRECTIONS =
[:top, :right, :bottom, :left].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 CSSbackgroundproperty. -
#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 CSSfontproperty. -
#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-styleproperty. -
#create_shorthand! ⇒ Object
Create shorthand declarations (e.g.
marginorfont) 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.
marginorfont) 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
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 287 288 289 290 291 |
# File 'lib/css_parser/rule_set.rb', line 257 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
241 242 243 |
# File 'lib/css_parser/rule_set.rb', line 241 def filename @filename end |
#offset ⇒ Object (readonly)
optional field for storing source reference File offset range
239 240 241 |
# File 'lib/css_parser/rule_set.rb', line 239 def offset @offset end |
#selectors ⇒ Object (readonly)
Array of selector strings.
244 245 246 |
# File 'lib/css_parser/rule_set.rb', line 244 def selectors @selectors end |
#specificity ⇒ Object
Integer with the specificity to use for this RuleSet.
247 248 249 |
# File 'lib/css_parser/rule_set.rb', line 247 def specificity @specificity end |
Instance Method Details
#add_declaration! ⇒ Object Also known as: []=
253 |
# File 'lib/css_parser/rule_set.rb', line 253 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.
544 545 546 547 548 549 550 551 552 553 554 555 |
# File 'lib/css_parser/rule_set.rb', line 544 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
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
# File 'lib/css_parser/rule_set.rb', line 561 def create_border_shorthand! # :nodoc: values = BORDER_STYLE_PROPERTIES.filter_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 /\s/.match?(declaration.value.gsub(/,\s/, ',').strip) declaration.value end 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.
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
# File 'lib/css_parser/rule_set.rb', line 583 def create_dimensions_shorthand! # :nodoc: return if declarations.size < NUMBER_OF_DIMENSIONS DIMENSIONS.each do |property, dimensions| values = DIMENSION_DIRECTIONS.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.
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
# File 'lib/css_parser/rule_set.rb', line 607 def create_font_shorthand! # :nodoc: return unless FONT_STYLE_PROPERTIES.all? { |prop| declarations.key?(prop) } new_value = +'' ['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.
634 635 636 |
# File 'lib/css_parser/rule_set.rb', line 634 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.
510 511 512 513 514 515 516 517 |
# File 'lib/css_parser/rule_set.rb', line 510 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
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
# File 'lib/css_parser/rule_set.rb', line 520 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.
327 328 329 |
# File 'lib/css_parser/rule_set.rb', line 327 def declarations_to_s( = {}) declarations.to_s() end |
#delete ⇒ Object Also known as: remove_declaration!
253 |
# File 'lib/css_parser/rule_set.rb', line 253 def_delegators :declarations, :add_declaration!, :delete |
#each_declaration ⇒ Object
Iterate through declarations.
320 321 322 323 324 |
# File 'lib/css_parser/rule_set.rb', line 320 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
310 311 312 313 314 315 316 317 |
# File 'lib/css_parser/rule_set.rb', line 310 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.
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/css_parser/rule_set.rb', line 350 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!
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/css_parser/rule_set.rb', line 380 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.
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 427 428 429 430 431 |
# File 'lib/css_parser/rule_set.rb', line 398 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.
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 480 481 482 483 484 |
# File 'lib/css_parser/rule_set.rb', line 435 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 /normal|inherit/i.match?(m) FONT_WEIGHT_PROPERTIES.each do |font_prop| font_props[font_prop] ||= m end elsif /italic|oblique/i.match?(m) font_props['font-style'] = m elsif /small-caps/i.match?(m) font_props['font-variant'] = m elsif /[1-9]00$|bold|bolder|lighter/i.match?(m) font_props['font-weight'] = m elsif CssParser::FONT_UNITS_RX.match?(m) 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.
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'lib/css_parser/rule_set.rb', line 490 def # :nodoc: return unless (declaration = declarations['list-style']) value = declaration.value.dup replacement = if CssParser::RE_INHERIT.match?(value) 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.
337 338 339 340 341 342 343 344 |
# File 'lib/css_parser/rule_set.rb', line 337 def # border must be expanded before dimensions end |
#extract_background_size_from(value) ⇒ Object
372 373 374 375 376 |
# File 'lib/css_parser/rule_set.rb', line 372 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
294 295 296 297 298 |
# File 'lib/css_parser/rule_set.rb', line 294 def get_value(property) return '' unless (value = declarations[property]) "#{value};" end |
#to_s ⇒ Object
Return the CSS rule set as a string.
332 333 334 |
# File 'lib/css_parser/rule_set.rb', line 332 def to_s "#{@selectors.join(',')} { #{declarations} }" end |