Skip to content

Fast and full featured CSS parser/writer for ruby

Notifications You must be signed in to change notification settings

immateriel/habaki

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fast and full featured CSS parser/writer for ruby.

Use WebKit based https://github.com/hackers-painters/katana-parser custom fork for low-level parsing, support CSS3 syntax.

Usage

require 'habaki'

css_data = %{
body {color: #444444;}
p {font-size: 0.9em}
p span {color: black}
span.tiny {font-size: 0.8em}
}

# parse full stylesheet
stylesheet = Habaki::Stylesheet.parse(css_data)
stylesheet.has_selector?("p")
# => true
stylesheet.has_selector?("a")
# => false

# remove a declaration
rule = stylesheet.find_by_selector("p").first
rule.declarations.remove_by_property("font-size")
stylesheet.to_s
# => "body {color: grey; }\np {}"

# add a declaration
rule = stylesheet.find_by_selector("body").first
rule.declarations.add_by_property("font-size", Habaki::Length.new(0.9, :em))
stylesheet.to_s
# => "body {color: grey; font-size: 0.9em; }\np {}"

# compact empty declarations
stylesheet.compact!
stylesheet.to_s
# => "body {color: grey; font-size: 0.9em; }"

# add rule
rule = stylesheet.rules.add_by_selector("p")
# => "body {color: #444444; font-size: 0.9em; }\np {}"
decl = rule.declarations.add_by_property("text-indent", Habaki::Length.new(1.4, :em))
stylesheet.to_s
# => "body {color: #444444; font-size: 0.9em; }\np {text-indent: 1.4em; }"

# check declaration validity
decl.check
# => true
decl = rule.declarations.add_by_property("color", Habaki::Ident.new("invalid"))
stylesheet.to_s
# => "body {color: #444444; font-size: 0.9em; }\np {text-indent: 1.4em; color: invalid; }"
decl.check
# => false

# advanced check
matcher = Habaki::FormalSyntax::Matcher.new(Habaki::Declarations.parse("border: 1px solid #ff000;").first)
matcher.match
# => true
matcher.matches.map(&:to_s)
# => ["border: 1px => <length>", "border: solid => solid", "border: #ff0000 => <hex-color>"]

# parse declarations only
decls = Habaki::Declarations.parse("font-size: 1em; color: black;")
decls.to_s
# => "font-size: 1em; color: black; "

# parse selectors only
sels = Habaki::Selectors.parse("div, p, span")
sels.to_s
# => "div,p,span"

# advanced selector matching
require 'nokogiri'
html_data = %{
    <html><body>
    <p>text <span>black</span></p>
    <p><span class="tiny">tiny black</span></p>
    </body></html>
    }
doc = Nokogiri::HTML.parse(html_data)
rules = stylesheet.find_matching_rules(Habaki::Visitor::NokogiriElement.new(doc.root.at("//body")))
rules.length
# => 1
rules.first.to_s
# => "body {color: #444444; }"

rules = stylesheet.find_matching_rules(Habaki::Visitor::NokogiriElement.new(doc.root.search("//span")[0]))
rules.length
# => 1
rules.first.to_s
# => "p span {color: black; }"

rules = stylesheet.find_matching_rules(Habaki::Visitor::NokogiriElement.new(doc.root.search("//span")[1]))
rules.length
# => 2
rules.map(&:to_s)
# => ["p span {color: black; }", "span.tiny {font-size: 0.8em; }"]

# get matching declarations for elements
declarations = stylesheet.find_matching_declarations(Habaki::Visitor::NokogiriElement.new(doc.root.search("//span")[1]))
declarations.to_s
# => color: black; font-size: 0.8em;

TODO

  • parser/writer: implement @page pseudo class
  • parser: attribute match type (case sensitive, insensitive)
  • parser: implement @keyframes
  • parser: implement :host()
  • parser: parse comments

About

Fast and full featured CSS parser/writer for ruby

Resources

Stars

Watchers

Forks

Packages

No packages published