lessify 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format documentation
3
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in lessify.gemspec
4
+ gemspec
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lessify (0.1)
5
+ css_parser
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ css_parser (1.1.4)
11
+ diff-lcs (1.1.2)
12
+ rspec (2.3.0)
13
+ rspec-core (~> 2.3.0)
14
+ rspec-expectations (~> 2.3.0)
15
+ rspec-mocks (~> 2.3.0)
16
+ rspec-core (2.3.1)
17
+ rspec-expectations (2.3.0)
18
+ diff-lcs (~> 1.1.2)
19
+ rspec-mocks (2.3.0)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ css_parser
26
+ lessify!
27
+ rspec
@@ -0,0 +1,10 @@
1
+ ==lessify
2
+ Gem to convert CSS files into SCSS files (LessCSS format)
3
+
4
+ ==Usage
5
+ TODO
6
+
7
+ ==Dependencies
8
+ * css_parser
9
+
10
+
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,38 @@
1
+ require 'lessify'
2
+
3
+ # This is not a real example.
4
+ # Part of this code should be folded into the lessify gem
5
+
6
+ rootNode = LessNode.new("*", nil)
7
+ dec_hash = { }
8
+ nodes = []
9
+
10
+ parser = CssParser::Parser.new
11
+ parser.load_uri!(ARGV[0] || 'test.css')
12
+ parser.each_selector do |selector, declarations, specificity|
13
+ node = rootNode.add_child(selector, declarations)
14
+ nodes.push(node)
15
+ dec_array = node.dec_array
16
+ dec_array.each { |d|
17
+ val = dec_hash[d] || 0
18
+ dec_hash[d] = (val+1)
19
+ }
20
+ end
21
+
22
+ if ARGV[0] == 'style.css'
23
+ rootNode.move("#outer-container", "#outer-glow-top")
24
+ rootNode.move("#outer-container", "#container")
25
+ rootNode.move("#container", "#container-pattern")
26
+ rootNode.move("#container-pattern", "#top-navigation")
27
+ rootNode.move("#top-navigation", "#topnav")
28
+
29
+ rootNode.move("#container-pattern", "#header")
30
+ rootNode.move("#header", "#slider")
31
+ rootNode.move("#slider", "#slider-navigation")
32
+
33
+ rootNode.move("#container-pattern", "#footer")
34
+ end
35
+
36
+ #puts rootNode.to_string("", { 'tab' => ' ', 'print_declarations'=> true })
37
+
38
+ dec_hash.each { |k,v| puts "#{k}\t=> #{v}" if v>3 }
@@ -0,0 +1,4 @@
1
+ require 'lessify'
2
+
3
+ l = Lessify.new(:file => 'test.css')
4
+ puts l.to_scss
@@ -0,0 +1,16 @@
1
+ #def {
2
+ a: 5; b:10;
3
+ }
4
+
5
+ #abc li ul {
6
+ c: 20;
7
+ }
8
+
9
+ #abc li table {
10
+ d: 30;
11
+ }
12
+
13
+ #abc {
14
+ blah: "Arial";
15
+ }
16
+
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "lessify/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "lessify"
7
+ s.version = Lessify::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Asif Sheikh"]
10
+ s.email = ["mail@asif.in"]
11
+ s.homepage = "https://github.com/tsycho/lessify"
12
+ s.summary = %q{Convert CSS files to SCSS files (LessCSS framework)}
13
+ s.description = %q{Converts the flat structure of CSS files into heirarchical SCSS files. Also analyzes the various CSS tags to identify repeated patterns for potential extraction into mixins.}
14
+
15
+ s.rubyforge_project = "lessify"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ s.add_dependency "css_parser"
22
+ s.add_development_dependency "rspec"
23
+ end
@@ -0,0 +1,3 @@
1
+ require 'lessify/less_node'
2
+ require 'lessify/lessify'
3
+
@@ -0,0 +1,97 @@
1
+
2
+ class LessNode
3
+ attr_accessor :selector, :parent, :child_nodes, :declarations, :dec_array
4
+
5
+ def initialize(selector, parent, declarations = "")
6
+ @selector = selector
7
+ @parent = parent
8
+ @declarations = declarations.strip
9
+ @child_nodes = []
10
+ update_declarations_array
11
+ parent.child_nodes.push(self) unless parent.nil?
12
+ end
13
+
14
+ def update_declarations_array
15
+ @dec_array = declarations.split(";").map { |d| d.strip }
16
+ end
17
+
18
+ def has_child?(selector)
19
+ @child_nodes.map { |cnode| cnode.selector == selector }.reduce(:|)
20
+ end
21
+
22
+ def child(selector)
23
+ @child_nodes.find { |cnode| cnode.selector == selector }
24
+ end
25
+
26
+ def add_child(selector_string, declarations)
27
+ selectors = selector_string.strip.split(" ")
28
+ node = self
29
+ selectors.each do |sel|
30
+ if node.has_child?(sel)
31
+ node = node.child(sel)
32
+ else
33
+ newNode = LessNode.new(sel, node)
34
+ node = newNode
35
+ end
36
+ end
37
+ node.declarations += (" " + declarations.strip)
38
+ node.declarations.strip!
39
+ node.update_declarations_array
40
+ return node
41
+ end
42
+
43
+ def to_scss(prefix = "", options = {})
44
+ tab = options['tab'] || "\t"
45
+ print_declarations = options[:print_declarations]
46
+ print_declarations = true if print_declarations.nil?
47
+
48
+ str = prefix + selector + " {"
49
+ if (@child_nodes.size==0) && (!print_declarations || declarations.strip.size==0)
50
+ str += "}\n"
51
+ else
52
+ str += "\n"
53
+ str += (prefix + tab + declarations + "\n") if (print_declarations && declarations.strip.size>0)
54
+ @child_nodes.each { |cnode| str += cnode.to_scss(prefix + tab, options) }
55
+ str += prefix + "}\n"
56
+ end
57
+ end
58
+
59
+ # Search through the tree for selector
60
+ def find(selector)
61
+ node = child(selector)
62
+ return node unless node.nil?
63
+ @child_nodes.each { |cnode|
64
+ n = cnode.find(selector)
65
+ return n unless n.nil?
66
+ }
67
+ return nil
68
+ end
69
+
70
+ def move(sel_parent, sel_child)
71
+ parent_node = find(sel_parent)
72
+ raise "#{sel_parent} not found" if parent_node.nil?
73
+
74
+ child_node = find(sel_child)
75
+ raise "#{sel_child} not found" if child_node.nil?
76
+
77
+ node = parent_node
78
+ until node.nil?
79
+ raise "Move will create a cycle in the tree" if node == child_node
80
+ node = node.parent
81
+ end
82
+ child_node.parent.child_nodes.delete(child_node)
83
+ parent_node.child_nodes.push(child_node)
84
+ child_node.parent = parent_node
85
+ end
86
+
87
+ def print_ancestry(selector)
88
+ node = find(selector)
89
+ puts "Printing ancestry for #{node}..."
90
+ until node.nil?
91
+ puts "\t#{node.to_s}"
92
+ node = node.parent
93
+ end
94
+ end
95
+
96
+ end
97
+
@@ -0,0 +1,38 @@
1
+ require 'lessify'
2
+ require 'css_parser'
3
+
4
+ class Lessify
5
+ include CssParser
6
+ attr_accessor :parser, :root, :nodes
7
+
8
+ # options are parsed in the following order:
9
+ # if :file is given, the file is loaded and parsed
10
+ # else, if :url is given, the url is loaded and parsed
11
+ # else, if :css is given, the css is directly parsed
12
+ # One of the above should be present, else constructor will throw an error
13
+ def initialize(options = {})
14
+
15
+ @parser = CssParser::Parser.new
16
+
17
+ if options[:file] != nil
18
+ @parser.load_file!(options[:file])
19
+ elsif options[:url] != nil
20
+ @parser.load_uri!(options[:url])
21
+ elsif options[:css] != nil
22
+ @parser.add_block!(options[:css])
23
+ else
24
+ raise "Lessify::initialize load error => options should contain one of :file, :url or :css"
25
+ end
26
+
27
+ @root = LessNode.new("*", nil)
28
+ @nodes = []
29
+ @parser.each_selector do |selector, declarations, specificity|
30
+ node = @root.add_child(selector, declarations)
31
+ @nodes.push(node)
32
+ end
33
+ end
34
+
35
+ def to_scss(options={})
36
+ return @root.to_scss("", options)
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ module Lessify
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe LessNode do
4
+
5
+ before(:each) do
6
+ @node = LessNode.new("*", nil)
7
+ declarations = " aaa: a1; bbb: b2; "
8
+ @node2 = LessNode.new("node2", @node, declarations)
9
+ @node3 = @node.add_child("node2 node3", declarations)
10
+ @node3 = @node.add_child("node2 node3", "ccc: c3;")
11
+ end
12
+
13
+ it "should create a new LessNode object with default parameters" do
14
+ node = LessNode.new("*", nil)
15
+ node.selector.should == "*"
16
+ node.parent.should be_nil
17
+ node.declarations.should == ""
18
+ node.dec_array.should == []
19
+ node.child_nodes.should == []
20
+ end
21
+
22
+ it "should create parent-child relationships when a child node is added" do
23
+ @node2.parent.should == @node
24
+ @node.child_nodes[0].should == @node2
25
+ end
26
+
27
+ it "should load declarations, and remove extraneous whitespace, from constructor" do
28
+ @node2.declarations.should == "aaa: a1; bbb: b2;"
29
+ @node2.dec_array.size.should == 2
30
+ @node2.dec_array[0].should == "aaa: a1"
31
+ @node2.dec_array[1].should == "bbb: b2"
32
+ end
33
+
34
+ it "should load and append declarations, and remove extraneous whitespace, from add_child" do
35
+ @node3.declarations.should == "aaa: a1; bbb: b2; ccc: c3;"
36
+ @node3.dec_array.size.should == 3
37
+ @node3.dec_array[0].should == "aaa: a1"
38
+ @node3.dec_array[1].should == "bbb: b2"
39
+ @node3.dec_array[2].should == "ccc: c3"
40
+ end
41
+
42
+ it "should add child nodes heirarchically" do
43
+ @node.child_nodes.should == [@node2]
44
+ @node2.child_nodes.should == [@node3]
45
+ @node3.parent.should == @node2
46
+ end
47
+
48
+ it "should be able to find nodes" do
49
+ @node.has_child?("node2").should be_true
50
+ @node2.has_child?("node3").should be_true
51
+ @node.has_child?("node3").should be_false
52
+
53
+ @node.child("node2").should == @node2
54
+ @node.child("node3").should be_nil
55
+ @node2.child("node3").should == @node3
56
+
57
+ @node.find("node2").should == @node2
58
+ @node.find("node3").should == @node3
59
+ end
60
+
61
+ it "should be able to move nodes when the move is legal" do
62
+ new_node = LessNode.new("newNode", @node)
63
+ @node.move("node2", "newNode")
64
+ @node2.has_child?("newNode").should be_true
65
+ @node2.child("newNode").should == new_node
66
+ new_node.parent.should == @node2
67
+ end
68
+
69
+ it "should raise error if an illegal move is tried" do
70
+ lambda { @node.move("node3", "node2") }.should raise_error RuntimeError
71
+ end
72
+
73
+ it "should not create duplicates or fail if a child node is moved to its parent" do
74
+ @node.move("node2", "node3")
75
+ @node2.child_nodes.size.should == 1
76
+ @node2.child_nodes[0] == @node3
77
+ @node3.parent.should == @node2
78
+ end
79
+
80
+ it "should print SCSS without declarations if print_declarations=>false" do
81
+ @node3.to_scss("", :print_declarations => false).should match generate_regex_pattern(["node3", "{", "}"])
82
+ @node2.to_scss("", :print_declarations => false).should match generate_regex_pattern(["node2", "{", "node3", "{", "}", "}"])
83
+ @node.to_scss( "", :print_declarations => false).should match generate_regex_pattern(['\\*', "{", "node2", "{", "node3", "{", "}", "}", "}"])
84
+
85
+ @node.selector = "node"
86
+ @node.to_scss( "", :print_declarations => false).should match generate_regex_pattern(['node', "{", "node2", "{", "node3", "{", "}", "}", "}"])
87
+ end
88
+
89
+ it "should print SCSS with declarations" do
90
+ @node3.to_scss("").should match generate_regex_pattern(["node3", "{", "aaa: a1;", "bbb: b2;", "ccc: c3;", "}"])
91
+ @node2.to_scss("").should match generate_regex_pattern(["node2", "{", "aaa: a1;", "bbb: b2;", "node3", "{", "aaa: a1;", "bbb: b2;", "ccc: c3;", "}", "}"])
92
+ end
93
+
94
+ it "should print SCSS with prefix" do
95
+ @node3.to_scss("--", :print_declarations => false).should match generate_regex_pattern(["--node3", "{", "}"])
96
+ @node3.to_scss("--").should match generate_regex_pattern(["--node3", "{", "--", "aaa: a1;", "bbb: b2;", "ccc: c3;", "--}"])
97
+ end
98
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lessify do
4
+
5
+ it "should load css" do
6
+ lessify = Lessify.new(:css => '#test { aaa: 11; }')
7
+ lessify.should_not be_nil
8
+ end
9
+
10
+ it "should fail if options doesn't contain :css, :file and :url" do
11
+ lambda { Lessify.new }.should raise_error RuntimeError
12
+ end
13
+
14
+ it "should print SCSS" do
15
+ css = <<CSSRAW
16
+ #a b c { abc: 1; }
17
+ #a b d { abd: 2; }
18
+ #a d { ad: 3; }
19
+ #e { e: 4; }
20
+ CSSRAW
21
+
22
+ lessify = Lessify.new( :css => css )
23
+ pattern_without_declarations = generate_regex_pattern([ '\\*', '{', '#a', '{', 'b', '{', 'c', '{', '}', 'd', '{', '}', '}', 'd', '{', '}', '}', '#e', '{', '}', '}' ])
24
+ lessify.to_scss(:print_declarations => false).should match pattern_without_declarations
25
+ #puts lessify.to_scss(:print_declarations => false)
26
+
27
+ pattern = generate_regex_pattern([ '\\*', '{', '#a', '{', 'b', '{', 'c', '{', 'abc: 1;', '}', 'd', '{', 'abd: 2;', '}', '}', 'd', '{', 'ad: 3;', '}', '}', '#e', '{', 'e: 4;', '}', '}' ])
28
+ lessify.to_scss.should match pattern
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ require 'css_parser'
2
+ require 'lessify'
3
+
4
+ RSpec.configure do |config|
5
+ # == Mock Framework
6
+ #
7
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
8
+ #
9
+ # config.mock_with :mocha
10
+ # config.mock_with :flexmock
11
+ # config.mock_with :rr
12
+ config.mock_with :rspec
13
+
14
+ end
15
+
16
+ def generate_regex_pattern(str_array)
17
+ pattern = '^\s*' + str_array.join('\s*') + '\s*$'
18
+ return Regexp.new(pattern)
19
+ end
20
+
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lessify
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 1
9
+ version: 0.1.1
10
+ platform: ruby
11
+ authors:
12
+ - Asif Sheikh
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-11 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: css_parser
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ description: Converts the flat structure of CSS files into heirarchical SCSS files. Also analyzes the various CSS tags to identify repeated patterns for potential extraction into mixins.
47
+ email:
48
+ - mail@asif.in
49
+ executables: []
50
+
51
+ extensions: []
52
+
53
+ extra_rdoc_files: []
54
+
55
+ files:
56
+ - .gitignore
57
+ - .rspec
58
+ - Gemfile
59
+ - Gemfile.lock
60
+ - README.rdoc
61
+ - Rakefile
62
+ - examples/temp.rb
63
+ - examples/test-lessify.rb
64
+ - examples/test.css
65
+ - lessify.gemspec
66
+ - lib/lessify.rb
67
+ - lib/lessify/less_node.rb
68
+ - lib/lessify/lessify.rb
69
+ - lib/lessify/version.rb
70
+ - spec/less_node_spec.rb
71
+ - spec/lessify_spec.rb
72
+ - spec/spec_helper.rb
73
+ has_rdoc: true
74
+ homepage: https://github.com/tsycho/lessify
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options: []
79
+
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project: lessify
101
+ rubygems_version: 1.3.7
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Convert CSS files to SCSS files (LessCSS framework)
105
+ test_files:
106
+ - spec/less_node_spec.rb
107
+ - spec/lessify_spec.rb
108
+ - spec/spec_helper.rb