class Sassificator
TODO:
- mediaquery inside of a mediaquery - done partically (only for one tree level deep) - images formating pattern setting - add convertor: all #_colors_ to rgb - MAJOR: formatting is done only for output sass_string, but not for sass_obj. Move formatting options applyment to object creation - write tests - had issue with [] brackets - test - had issue with asset-url asigning - test - background: asset-url('#{$brand}offersButton_on.png',image',image) 100% 50% no-repeat; background: asset-url('#{$brand}//offersButton_on.png) 100% 50% no-repeat; - issue with assigning same roles one after onother
Attributes
Public Class Methods
@param [Boolean] alphabethize_output true : Alphatehise the rules in output string @param [Boolean] colors_to_vars
true : sets all color to sass variables to the top of output string @param [Boolean] fromat_image_declarations true : formats images declarations to asset-url (for now at least - TODO: will be unified for any format) @param [Boolean] download_images true : downloads images to specified @output_path @param [String] image_assets_path Image asstes path in application @param [String] output_path Output path must be specified if download_images is set to true
# File lib/sassificator.rb, line 23 def initialize( param = {}) @alphabethize_output = (param[:alphabethize_output] != false) != false @colors_to_vars = (param[:colors_to_vars] != false) != false @fromat_image_declarations = (param[:fromat_image_declarations] != false) != false @download_images = (param[:download_images] != false) != false @image_assets_path = param[:image_assets_path] ? param[:image_assets_path] : '' @output_path = param[:output_path] ? param[:output_path] : "#{ENV['HOME']}/Desktop/sassificator_output/" end
Public Instance Methods
Returns a hash containing sass_object and sass_formated string REQUIRES A PROPERLY FROMATED INPUT CSS
@param [String] css A PROPERLY FROMATED INPUT CSS STRING | for now it’s NOT working with media_query’s inside of media_querys
# File lib/sassificator.rb, line 40 def get_sass_str_and_sass_obj(input_css_str) selectors_hash = css_to_hash input_css_str # 1. convert plain css to hash obj css_stack = objectize_css(selectors_hash) # 2. convert recieved hash to sass obj with relatons sassed_css_string = sass_obj_to_str(css_stack) # 3. get formatted string out sass_obj Hash[:sass_obj => css_stack, :sass_string => sassed_css_string] end
Private Instance Methods
# File lib/sassificator.rb, line 72 def css_to_hash (input_css) input_css = prepare_input_css(input_css) selectors_arr = remove_white_spaces_and_new_lines(input_css).gsub(/@media/,"\n@media").gsub(/(?<={{1}).+}(?=[\s\t\n]{0,}}{1})/,'').gsub(/(?<={{1}).+}(?=[\s\t\n]{0,}}{1})/,'').scan(/[^{^}]+(?=\{)/).map {|line| line.sub(/^\s+/,'').sub(/\s+$/,'')} rules_arr = remove_white_spaces_and_new_lines(input_css).gsub(/@media/,"\n@media").scan(/(((?<={{1}).+}(?=[\s\t\n]{0,}}{1})|(?<=\{)[^}]+\}{0,}[\\t\\n\s]{0,}(?=\}))|((?<=\{)[^}]+\}{0,}[\\t\\n\s]{0,}(?=\}))|(?<={{1}).+}(?=[\s\t\n]{0,}}{1}))/).map {|item| item.compact.uniq.join} #super-mega reg-exp that scans for normal rules as well as inlined media-query rule + make a single_string_items out of matched array groups return_hash = {} selectors_arr.each_with_index do |selector, index| unless return_hash[selector] return_hash[selector] = rules_arr[index.to_i] else return_hash[selector] = return_hash[selector] + ' ' + rules_arr[index.to_i] end end return_hash.each do |key,val| unless val.scan(/[^{^}]+(?=\{)/).size.zero? return_hash[key] = css_to_hash val end end return_hash end
# File lib/sassificator.rb, line 215 def format_color(sassed_str) #TODO: resolve the match for colors in format #sdsd formated_rule = sassed_str color_hash = {} sassed_str.scan(/rgba\([0-9\,\s\.]+\)|rgb\([0-9\,\s\.]+\)|#[0-9A-Za-z]+(?=;)/).each do|m| unless color_hash[m] color_hash[m] = '$color_'+color_hash.size.to_s formated_rule = formated_rule.gsub( Regexp.new(m.gsub(/\(/,'\(').gsub(/\)/,'\)').gsub(/\./,'\.')), color_hash[m] ) end end color_hash.invert.to_a.reverse_each {|m| formated_rule = m.join(":")+";\n" + formated_rule } formated_rule end
# File lib/sassificator.rb, line 172 def format_images (sassed_str) require 'net/http' formated_rule = sassed_str #TODO - move this to optional feature (file downloading) #TODO: optimise this - connect to global path path = @output_path Dir.mkdir(path) unless Dir.exist?(path) FileUtils.rm_rf(Dir.glob("#{@output_path}/*")) sassed_str.scan(/(url\((((http[s]{0,1}:\/\/)([a-z0-9].+\.[a-z]+).+)(\/.+)))\)/).each do |match| #TODO: optimize this - move mathched to variables for clarification of match formated_rule = formated_rule.sub(Regexp.new(match[0].gsub(/\(/,'\(').gsub(match[5],'')),'asset-url(\''+@image_assets_path) .sub( Regexp.new(match[5]),match[5].sub(/\//,'')+'\'') #TODO - move this to optional feature (file downloading) Net::HTTP.start(match[4]) do |http| #TODO - test get_url # forms relative url get_url = match[1].sub(Regexp.new("(http:\/\/||https:\/\/){1}#{match[4]}"),'') begin http.read_timeout = 20 resp = http.get(get_url) open(path+match[5], 'wb') do |file| begin file.write(resp.body) ensure file.close() end end rescue p "Fail on getting image #{match[1]}" end end end formated_rule end
# File lib/sassificator.rb, line 234 def format_mixin #TODO: combine similar rules blocks in mixins.. in some way..? end
# File lib/sassificator.rb, line 165 def format_sass (sassed_str) formated_sass_with_images = @fromat_image_declarations ? format_images(sassed_str) : sassed_str formated_sass_with_color = @colors_to_vars ? format_color(formated_sass_with_images) : sassed_str formated_sass_with_color end
# File lib/sassificator.rb, line 94 def objectize_css (uninitialized_childrens_hash, parent_node = nil) childrens_stack = {} uninitialized_childrens_hash.each { |selector,rule| #TODO: optimize pattern mathcing = thei are both matching same string match = /^[&.#\"\'\[\]=a-zA-Z-_0-9]{1,}(?=\s(?=[^,]{0,}$))/.match(selector).to_s #checks for childrens in selector sub_pat = /^[\.#]{0,1}[a-zA-Z-_0-9]{1,}(?=(\.|:|\[|#))/.match(selector).to_s #deals with pseudo elements #TODO : optimize this unless sub_pat.empty? unless selector.match(/,/) match = sub_pat selector = selector.sub( Regexp.new('^'+match) ,match+' &') end end unless match.empty? unless node = childrens_stack[match] node = CssNode.new childrens_stack[match] = node end node.uninitialized[selector.sub( Regexp.new('^'+match.sub( /\[/ ,'\[').sub(/\]/, '\]')+' ') ,'')] = rule node.parent = parent_node else if node = childrens_stack[selector] node.rule = node.rule + "\n\t" + rule.gsub(/;\s/,";\n\t") else node = CssNode.new if rule.is_a?(Hash) node.children = objectize_css( rule, node ) else node.rule = "\n\t"+rule.gsub(/;\s/,";\n\t") end childrens_stack[selector] = node end node.rule = node.rule.split(';').sort().join(';') + ';' if @alphabethize_output && !node.rule.empty? #alphabetize node.parent = parent_node end } childrens_stack.each { |node_selector,node| unless childrens_stack[node_selector].uninitialized.empty? childrens_stack[node_selector].children = objectize_css( childrens_stack[node_selector].uninitialized, node ) childrens_stack[node_selector].uninitialized = [] end } childrens_stack end
# File lib/sassificator.rb, line 66 def prepare_input_css(input_css) ## 1. reduses double :: pseudo selectors to : ## 2. removes empty rules input_css.gsub(/::/,':').gsub(/^.+{[\s\t\n]{0,}}/,'') end
# File lib/sassificator.rb, line 62 def remove_white_spaces_and_new_lines(line) line.gsub(/\n/,'').gsub(/\t/,'').gsub(/\s+(?=\})/,'').gsub(/(?<=\{)\s+/,'') end
# File lib/sassificator.rb, line 146 def sass_obj_to_str (css_stack) sassed_str = format_sass sass_stack_to_s(css_stack) sassed_str end
# File lib/sassificator.rb, line 152 def sass_stack_to_s (css_stack) str = '' css_stack.each { |node_key,node| unless node.children.empty? chldrn = node.children children_stack = sass_stack_to_s(chldrn) end str = str +"\n"+ node_key + " {\t" + ( node.rule ? node.rule : '') + ( children_stack ? children_stack.gsub(/^/,"\t") : '' ) +"\n\t}" } str end