I'm writing a simple ruby parser for CSS files and I'm kind of stumped on how I can get a block of CSS (that is, a selector and everything between curly braces immediately following it) as a ruby object on which I can perform my dark and nasty magic.

Ideally, I would like to get a ruby hash with each attribute / value and the selector. Is there any clear and easy to understand way how to do this?

有帮助吗?

解决方案

As mentioned in the comments it's silly to do it yourself beyond a fun exercise. I'd read the css file into a string and then scan it with regular expressions.

Ruby - Convert File to String

http://www.ruby-doc.org/core-1.9.3/String.html#method-i-scan

for testing the regex: http://rubular.com/

其他提示

Everyone should write a parser.

This should get you started...

require 'parslet'
require 'ostruct'
require 'pp'

class Parser < Parslet::Parser
  rule(:opencurl)   { str('{') }
  rule(:closecurl)  { str('}') }
  rule(:space)      { str(' ') }
  rule(:space?)     { space.maybe }
  rule(:comma)      { str(',') }
  rule(:semi)       { str(';') }
  rule(:colon)      { str(':') }
  rule(:eol)        { str("\r").maybe >> str("\n") }
  rule(:eol?)       { eol.maybe }
  rule(:indent?)    { str(" ").repeat(0) }
  rule(:ws?)        {indent? >> eol? >> indent?}

  rule(:value)      { (semi.absent? >> any).repeat(1).as(:value) } #cheating

  rule(:word)       { match['a-zA-Z0-9'].repeat(1) }
  rule(:property)   { (word >> (str("-") >> word).repeat(0)).as(:property) }
  rule(:setting)    { (indent? >> property >> colon >> indent? >> value >> semi  >> eol?) }
  rule(:body?)      { setting.repeat(0).as(:body) }
  rule(:block)      { opencurl >> ws? >> body? >> ws? >> closecurl >> ws? }
  rule(:selector_expression)   { (opencurl.absent? >> any).repeat(1) } #cheating
  rule(:scope)      { ws? >> selector_expression.as("selector") >> indent? >> block.as(:settings) }

  rule(:css?)       { (eol.repeat(0) >> scope).repeat(0) } 
  root(:css?)
end  

class MyTransform < Parslet::Transform
  rule(:property => simple(:p), :value => simple(:v)) { OpenStruct.new(p:p,v:v) }
  rule(:body => sequence(:b)) { b.each_with_object({}){|i,o| o[i.p] = i.v} }
end 

css = <<-css
  h2{ background-image: url(abc);}
  #bob { 
  background-image: url(abc);
  background-color: red;
}
css

par = Parser.new.parse(css)
tar = MyTransform.new.apply(par) 
pp tar

Outputs:

[{"selector"=>"h2", :settings=>{"background-image"=>"url(abc)"}},
 {"selector"=>"#bob ",
  :settings=>
   {"background-image"=>"url(abc)", "background-color"=>"red"}}]
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top