module Blueprint
# Strips out most whitespace and can return a hash or string of parsed data
class CSSParser
attr_accessor :namespace
attr_reader :css_output, :raw_data
# ==== Options
# * css_string String of CSS data
# * options
# * :namespace -- Namespace to use when generating output
def initialize(css_string = "", options = {})
@raw_data = css_string
@namespace = options[:namespace] || ""
compress(@raw_data)
end
# returns string of CSS which can be saved to a file or otherwise
def to_s
@css_output
end
# returns a hash of all CSS data passed
#
# ==== Options
# * data -- CSS string; defaults to string passed into the constructor
def parse(data = nil)
data ||= @raw_data
# wrapper array holding hashes of css tags/rules
css_out = []
# clear initial spaces
data.strip_side_space!.strip_space!
# split on end of assignments
data.split('}').each_with_index do |assignments, index|
# split again to separate tags from rules
tags, styles = assignments.split('{').map{|a| a.strip_side_space!}
unless styles.blank?
# clean up tags and apply namespaces as needed
tags.strip_selector_space!
tags.gsub!(/\./, ".#{namespace}") unless namespace.blank?
# split on semicolon to iterate through each rule
rules = []
styles.split(';').each do |key_val_pair|
unless key_val_pair.nil?
# split by property/val and append to rules array with correct declaration
property, value = key_val_pair.split(':').map{|kv| kv.strip_side_space!}
break unless property && value
rules << "#{property}:#{value};"
end
end
# now keeps track of index as hashes don't keep track of position (which will be fixed in Ruby 1.9)
css_out << {:tags => tags, :rules => rules.to_s, :idx => index} unless tags.blank? || rules.to_s.blank?
end
end
css_out
end
private
def compress(data)
@css_output = ""
parse(data).flatten.sort_by {|i| i[:idx]}.each do |line|
@css_output += "#{line[:tags]} {#{line[:rules]}}\n"
end
end
end
end