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.
- data/.gitignore +3 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +27 -0
- data/README.rdoc +10 -0
- data/Rakefile +2 -0
- data/examples/temp.rb +38 -0
- data/examples/test-lessify.rb +4 -0
- data/examples/test.css +16 -0
- data/lessify.gemspec +23 -0
- data/lib/lessify.rb +3 -0
- data/lib/lessify/less_node.rb +97 -0
- data/lib/lessify/lessify.rb +38 -0
- data/lib/lessify/version.rb +3 -0
- data/spec/less_node_spec.rb +98 -0
- data/spec/lessify_spec.rb +30 -0
- data/spec/spec_helper.rb +20 -0
- metadata +108 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -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
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
data/examples/temp.rb
ADDED
@@ -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 }
|
data/examples/test.css
ADDED
data/lessify.gemspec
ADDED
@@ -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
|
data/lib/lessify.rb
ADDED
@@ -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,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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|