lessify 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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