1 | module Blueprint |
---|
2 | # Strips out most whitespace and can return a hash or string of parsed data |
---|
3 | class CSSParser |
---|
4 | attr_accessor :namespace |
---|
5 | attr_reader :css_output, :raw_data |
---|
6 | |
---|
7 | # ==== Options |
---|
8 | # * <tt>css_string</tt> String of CSS data |
---|
9 | # * <tt>options</tt> |
---|
10 | # * <tt>:namespace</tt> -- Namespace to use when generating output |
---|
11 | def initialize(css_string = "", options = {}) |
---|
12 | @raw_data = css_string |
---|
13 | @namespace = options[:namespace] || "" |
---|
14 | compress(@raw_data) |
---|
15 | end |
---|
16 | |
---|
17 | # returns string of CSS which can be saved to a file or otherwise |
---|
18 | def to_s |
---|
19 | @css_output |
---|
20 | end |
---|
21 | |
---|
22 | # returns a hash of all CSS data passed |
---|
23 | # |
---|
24 | # ==== Options |
---|
25 | # * <tt>data</tt> -- CSS string; defaults to string passed into the constructor |
---|
26 | def parse(data = nil) |
---|
27 | data ||= @raw_data |
---|
28 | |
---|
29 | # wrapper array holding hashes of css tags/rules |
---|
30 | css_out = [] |
---|
31 | # clear initial spaces |
---|
32 | data.strip_side_space!.strip_space! |
---|
33 | |
---|
34 | # split on end of assignments |
---|
35 | data.split('}').each_with_index do |assignments, index| |
---|
36 | # split again to separate tags from rules |
---|
37 | tags, styles = assignments.split('{').map{|a| a.strip_side_space!} |
---|
38 | unless styles.blank? |
---|
39 | # clean up tags and apply namespaces as needed |
---|
40 | tags.strip_selector_space! |
---|
41 | tags.gsub!(/\./, ".#{namespace}") unless namespace.blank? |
---|
42 | |
---|
43 | # split on semicolon to iterate through each rule |
---|
44 | rules = [] |
---|
45 | styles.split(";").each do |key_val_pair| |
---|
46 | unless key_val_pair.nil? |
---|
47 | # split by property/val and append to rules array with correct declaration |
---|
48 | property, value = key_val_pair.split(":", 2).map {|kv| kv.strip_side_space! } |
---|
49 | break unless property && value |
---|
50 | rules << "#{property}:#{value};" |
---|
51 | end |
---|
52 | end |
---|
53 | # now keeps track of index as hashes don't keep track of position |
---|
54 | # (which will be fixed in Ruby 1.9) |
---|
55 | unless tags.blank? || rules.to_s.blank? |
---|
56 | css_out << {:tags => tags, :rules => rules.join, :idx => index} |
---|
57 | end |
---|
58 | end |
---|
59 | end |
---|
60 | css_out |
---|
61 | end |
---|
62 | |
---|
63 | private |
---|
64 | |
---|
65 | def compress(data) |
---|
66 | @css_output = "" |
---|
67 | parse(data).flatten.sort_by {|i| i[:idx]}.each do |line| |
---|
68 | @css_output += "#{line[:tags]} {#{line[:rules]}}\n" |
---|
69 | end |
---|
70 | end |
---|
71 | end |
---|
72 | end |
---|