less 0.8.8 → 1.2.21

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.
Files changed (88) hide show
  1. data/CHANGELOG +62 -0
  2. data/README.md +24 -6
  3. data/Rakefile +28 -37
  4. data/VERSION +1 -1
  5. data/bin/lessc +41 -11
  6. data/less.gemspec +85 -16
  7. data/lib/less/command.rb +47 -28
  8. data/lib/less/engine/grammar/common.tt +29 -0
  9. data/lib/less/engine/grammar/entity.tt +144 -0
  10. data/lib/less/engine/grammar/less.tt +341 -0
  11. data/lib/less/engine/nodes/element.rb +281 -0
  12. data/lib/less/engine/nodes/entity.rb +79 -0
  13. data/lib/less/engine/nodes/function.rb +93 -0
  14. data/lib/less/engine/nodes/literal.rb +171 -0
  15. data/lib/less/engine/nodes/property.rb +232 -0
  16. data/lib/less/engine/nodes/ruleset.rb +12 -0
  17. data/lib/less/engine/nodes/selector.rb +44 -0
  18. data/lib/less/engine/nodes.rb +9 -0
  19. data/lib/less/engine.rb +44 -140
  20. data/lib/less/ext.rb +60 -0
  21. data/lib/less.rb +25 -13
  22. data/spec/command_spec.rb +3 -7
  23. data/spec/css/accessors.css +18 -0
  24. data/spec/css/big.css +3768 -0
  25. data/spec/css/colors.css +14 -0
  26. data/spec/css/comments.css +9 -0
  27. data/spec/css/css-3.css +21 -0
  28. data/spec/css/css.css +50 -0
  29. data/spec/css/dash-prefix.css +12 -0
  30. data/spec/css/functions.css +6 -0
  31. data/spec/css/import-with-extra-paths.css +8 -0
  32. data/spec/css/import-with-partial-in-extra-path.css +6 -0
  33. data/spec/css/import.css +12 -0
  34. data/spec/css/lazy-eval.css +1 -0
  35. data/spec/css/mixins-args.css +32 -0
  36. data/spec/css/mixins.css +28 -0
  37. data/spec/css/operations.css +28 -0
  38. data/spec/css/parens.css +20 -0
  39. data/spec/css/rulesets.css +17 -0
  40. data/spec/css/scope.css +11 -0
  41. data/spec/css/selectors.css +13 -0
  42. data/spec/css/strings.css +12 -0
  43. data/spec/css/variables.css +8 -0
  44. data/spec/css/whitespace.css +7 -0
  45. data/spec/engine_spec.rb +107 -15
  46. data/spec/less/accessors.less +20 -0
  47. data/spec/less/big.less +1264 -0
  48. data/spec/less/colors.less +35 -0
  49. data/spec/less/comments.less +46 -0
  50. data/spec/less/css-3.less +52 -0
  51. data/spec/less/css.less +104 -0
  52. data/spec/less/dash-prefix.less +21 -0
  53. data/spec/less/exceptions/mixed-units-error.less +3 -0
  54. data/spec/less/exceptions/name-error-1.0.less +3 -0
  55. data/spec/less/exceptions/syntax-error-1.0.less +3 -0
  56. data/spec/less/extra_import_path/extra.less +1 -0
  57. data/spec/less/extra_import_path/import/import-test-a.css +1 -0
  58. data/spec/less/extra_import_path/import/import-test-a.less +4 -0
  59. data/spec/less/functions.less +6 -0
  60. data/spec/less/hidden.less +25 -0
  61. data/spec/less/import/import-test-a.less +2 -0
  62. data/spec/less/import/import-test-b.less +8 -0
  63. data/spec/less/import/import-test-c.less +7 -0
  64. data/spec/less/import/import-test-d.css +1 -0
  65. data/spec/less/import-with-extra-paths.less +4 -0
  66. data/spec/less/import.less +8 -0
  67. data/spec/less/lazy-eval.less +6 -0
  68. data/spec/less/literal-css.less +11 -0
  69. data/spec/less/mixins-args.less +59 -0
  70. data/spec/less/mixins.less +43 -0
  71. data/spec/less/operations.less +39 -0
  72. data/spec/less/parens.less +26 -0
  73. data/spec/less/rulesets.less +30 -0
  74. data/spec/less/scope.less +32 -0
  75. data/spec/less/selectors.less +24 -0
  76. data/spec/less/strings.less +14 -0
  77. data/spec/less/variables.less +29 -0
  78. data/spec/less/whitespace.less +34 -0
  79. data/spec/spec.css +50 -25
  80. data/spec/spec_helper.rb +4 -1
  81. metadata +96 -15
  82. data/lib/less/tree.rb +0 -82
  83. data/spec/css/less-0.8.5.css +0 -24
  84. data/spec/css/less-0.8.6.css +0 -24
  85. data/spec/css/less-0.8.7.css +0 -24
  86. data/spec/css/less-0.8.8.css +0 -25
  87. data/spec/spec.less +0 -128
  88. data/spec/tree_spec.rb +0 -5
@@ -0,0 +1,14 @@
1
+ #yelow #short { color: #ffeeaa; }
2
+ #yelow #long { color: #ffeeaa; }
3
+ #yelow #rgba { color: rgba(255, 238, 170, 0.1); }
4
+ #blue #short { color: #0000ff; }
5
+ #blue #long { color: #0000ff; }
6
+ #blue #rgba { color: rgba(0, 0, 255, 0.1); }
7
+ #overflow .a { color: #000000; }
8
+ #overflow .b { color: #ffffff; }
9
+ #overflow .c { color: #ffffff; }
10
+ #overflow .d { color: #00ff00; }
11
+ #grey {
12
+ color: #c8c8c8;
13
+ background-color: #323232;
14
+ }
@@ -0,0 +1,9 @@
1
+ #comments {
2
+ color: red;
3
+ background-color: orange;
4
+ font-size: 12px;
5
+ content: "content";
6
+ border: 1px solid black;
7
+ padding: 0;
8
+ margin: 2em;
9
+ }
@@ -0,0 +1,21 @@
1
+ .comma-delimited {
2
+ background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
3
+ text-shadow: -1px -1px 1px red, 6px 5px 5px yellow;
4
+ -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset;
5
+ }
6
+ @font-face {
7
+ font-family: Headline;
8
+ src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg");
9
+ }
10
+ .other { -moz-transform: translate(0, 11em) rotate(-90deg); }
11
+ p:not([class*="lead"]) { color: black; }
12
+ input[type="text"].class#id[attr=32]:not(1) { color: white; }
13
+ div#id.class[a=1][b=2].class:not(1) { color: white; }
14
+ ul.comma > li:not(:only-child)::after { color: white; }
15
+ ol.comma > li:nth-last-child(2)::after { color: white; }
16
+ li:nth-child(4n+1) { color: white; }
17
+ li:nth-child(-5n) { color: white; }
18
+ li:nth-child(n+1) { color: white; }
19
+ li:nth-child(-n+2) { color: white; }
20
+ a[href^="http://"], a[href$="http://"] { color: black; }
21
+ p::before { color: black; }
data/spec/css/css.css ADDED
@@ -0,0 +1,50 @@
1
+ div { color: black; }
2
+ div { width: 99%; }
3
+ * { min-width: 45em; }
4
+ h1 { color: none; }
5
+ h2 > a > p { color: none; }
6
+ h3 { color: none; }
7
+ div.class { color: blue; }
8
+ div#id { color: green; }
9
+ .class#id { color: purple; }
10
+ .one.two.three { color: grey; }
11
+ @media print { font-size: 3em; }
12
+ @media screen { font-size: 10px; }
13
+ @font-face {
14
+ font-family: 'Garamond Pro';
15
+ src: url("/fonts/garamond-pro.ttf");
16
+ }
17
+ a:hover { color: #999999; }
18
+ a:link { color: #999999; }
19
+ p { text-transform: none; }
20
+ p:first-child { text-transform: none; }
21
+ q:lang(no) { quotes: none; }
22
+ p + h1 { font-size: 2.2em; }
23
+ input[type="text"] { font-weight: normal; }
24
+ h2[title] { font-size: 100%; }
25
+ [disabled] { color: transparent; }
26
+ #shorthands {
27
+ border: 1px solid #000000;
28
+ font: 12px/16px Arial;
29
+ margin: 1px 0;
30
+ padding: 0 auto;
31
+ background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
32
+ }
33
+ #more-shorthands {
34
+ margin: 0;
35
+ padding: 1px 0 2px 0;
36
+ font: normal small/20px 'Trebuchet MS', Verdana, sans-serif;
37
+ }
38
+ .misc {
39
+ -moz-border-radius: 2px;
40
+ display: -moz-inline-stack;
41
+ width: 0.1em;
42
+ background-color: #009998;
43
+ background-image: url(images/image.jpg);
44
+ background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue));
45
+ }
46
+ #important {
47
+ color: red !important;
48
+ width: 100% !important;
49
+ height: 20px ! important;
50
+ }
@@ -0,0 +1,12 @@
1
+ .test1 {
2
+ background-image: -moz-linear-gradient(top, bottom, from(#030303), to(#010101));
3
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#030303), to(#010101));
4
+ }
5
+ .test2 {
6
+ background-image: -moz-linear-gradient(top, bottom, from(#020202), to(#010101));
7
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#020202), to(#010101));
8
+ }
9
+ .test3 {
10
+ background-image: -moz-linear-gradient(top, bottom, from(red), to(green));
11
+ background-image: -webkit-gradient(linear, left top, left bottom, from(red), to(green));
12
+ }
@@ -0,0 +1,6 @@
1
+ #functions {
2
+ color: #999999;
3
+ width: 16;
4
+ height: undefined("self");
5
+ border-width: 5;
6
+ }
@@ -0,0 +1,8 @@
1
+ #css { color: yellow; }
2
+ #import { color: red; }
3
+ .mixin {
4
+ height: 10px;
5
+ color: red;
6
+ }
7
+ body { font-size: 0.75em; }
8
+ h2 { font-size: 2em; }
@@ -0,0 +1,6 @@
1
+ .mixin { font-size: 0.75em; }
2
+ #import-test {
3
+ font-size: 0.75em;
4
+ width: 10px;
5
+ height: 30%;
6
+ }
@@ -0,0 +1,12 @@
1
+ #css { color: yellow; }
2
+ #import { color: red; }
3
+ .mixin {
4
+ height: 10px;
5
+ color: red;
6
+ }
7
+ #import-test {
8
+ height: 10px;
9
+ color: red;
10
+ width: 10px;
11
+ height: 30%;
12
+ }
@@ -0,0 +1 @@
1
+ .lazy-eval { width: 100%; }
@@ -0,0 +1,32 @@
1
+ .two-args {
2
+ color: blue;
3
+ width: 10px;
4
+ height: 99%;
5
+ }
6
+ .one-arg {
7
+ width: 15px;
8
+ height: 49%;
9
+ }
10
+ .no-parens {
11
+ width: 5px;
12
+ height: 49%;
13
+ }
14
+ .no-args {
15
+ width: 5px;
16
+ height: 49%;
17
+ }
18
+ .var-args {
19
+ width: 45;
20
+ height: 17%;
21
+ }
22
+ .multi-mix {
23
+ width: 10px;
24
+ height: 29%;
25
+ margin: 4;
26
+ padding: 5;
27
+ }
28
+ body {
29
+ padding: 30px;
30
+ color: #ff0000;
31
+ }
32
+ .scope-mix { width: 8; }
@@ -0,0 +1,28 @@
1
+ .mixin { border: 1px solid black; }
2
+ .mixout { border-color: orange; }
3
+ .borders { border-style: dashed; }
4
+ #namespace .borders { border-style: dotted; }
5
+ #namespace .biohazard { content: "death"; }
6
+ #namespace .biohazard .man { color: transparent; }
7
+ #theme > .mixin { background-color: grey; }
8
+ #container {
9
+ color: black;
10
+ border: 1px solid black;
11
+ border-color: orange;
12
+ background-color: grey;
13
+ }
14
+ #header .milk {
15
+ color: white;
16
+ border: 1px solid black;
17
+ background-color: grey;
18
+ }
19
+ #header #cookie { border-style: dashed; }
20
+ #header #cookie .chips { border-style: dotted; }
21
+ #header #cookie .chips .calories {
22
+ color: black;
23
+ border: 1px solid black;
24
+ border-color: orange;
25
+ background-color: grey;
26
+ }
27
+ .secure-zone { color: transparent; }
28
+ .direct { border-style: dotted; }
@@ -0,0 +1,28 @@
1
+ #operations {
2
+ color: #111111;
3
+ height: 9px;
4
+ width: 3em;
5
+ }
6
+ #operations .spacing {
7
+ height: 9px;
8
+ width: 3em;
9
+ }
10
+ .with-variables {
11
+ height: 16em;
12
+ width: 24em;
13
+ size: 1cm;
14
+ }
15
+ .negative {
16
+ height: 0px;
17
+ width: 4px;
18
+ }
19
+ .shorthands { padding: -1px 2px 0 -4px; }
20
+ .colors {
21
+ color: #112233;
22
+ border-color: #334455;
23
+ background-color: #000000;
24
+ }
25
+ .colors .other {
26
+ color: #222222;
27
+ border-color: #222222;
28
+ }
@@ -0,0 +1,20 @@
1
+ .parens {
2
+ border: 2px solid black;
3
+ margin: 1px 3px 16 3;
4
+ width: 36;
5
+ padding: 2px 36px;
6
+ }
7
+ .more-parens {
8
+ padding: 8 4 4 4px;
9
+ width: 96;
10
+ height: 113;
11
+ margin: 12;
12
+ }
13
+ .nested-parens {
14
+ width: 71;
15
+ height: 6;
16
+ }
17
+ .mixed-units {
18
+ margin: 2px 4em 1 5pc;
19
+ padding: 6px 1em 2px 2;
20
+ }
@@ -0,0 +1,17 @@
1
+ #first > .one { font-size: 2em; }
2
+ #first > .one > #second .two > #deux { width: 50%; }
3
+ #first > .one > #second .two > #deux #third { height: 100%; }
4
+ #first > .one > #second .two > #deux #third:focus { color: black; }
5
+ #first > .one > #second .two > #deux #third:focus #fifth > #sixth .seventh #eighth + #ninth { color: purple; }
6
+ #first > .one > #second .two > #deux #fourth { color: #110000; }
7
+ #first > .one > #second .two > #deux #fourth .seven { border: 1px solid black; }
8
+ #first > .one > #second .two > #deux #fourth .eight > #nine { border: 1px solid black; }
9
+ #first > .one > #second .two > #deux #fourth #ten { color: red; }
10
+ #first > .one > #second .two > #deux #five { color: #110000; }
11
+ #first > .one > #second .two > #deux #five .seven { border: 1px solid black; }
12
+ #first > .one > #second .two > #deux #five .eight > #nine { border: 1px solid black; }
13
+ #first > .one > #second .two > #deux #five #ten { color: red; }
14
+ #first > .one > #second .two > #deux #six { color: #110000; }
15
+ #first > .one > #second .two > #deux #six .seven { border: 1px solid black; }
16
+ #first > .one > #second .two > #deux #six .eight > #nine { border: 1px solid black; }
17
+ #first > .one > #second .two > #deux #six #ten { color: red; }
@@ -0,0 +1,11 @@
1
+ .tiny-scope { color: #998899; }
2
+ .scope1 {
3
+ color: blue;
4
+ border-color: black;
5
+ }
6
+ .scope1 .scope2 { color: blue; }
7
+ .scope1 .scope2 .scope3 {
8
+ color: red;
9
+ border-color: black;
10
+ background-color: white;
11
+ }
@@ -0,0 +1,13 @@
1
+ h1 a:hover { color: red; }
2
+ h1 p:hover { color: red; }
3
+ h2 a:hover { color: red; }
4
+ h2 p:hover { color: red; }
5
+ h3 a:hover { color: red; }
6
+ h3 p:hover { color: red; }
7
+ #all, #the, #same { color: blue; }
8
+ ul, li, div, q, blockquote, textarea { margin: 0; }
9
+ td {
10
+ margin: 0;
11
+ padding: 0;
12
+ }
13
+ td, input { line-height: 1em; }
@@ -0,0 +1,12 @@
1
+ #strings {
2
+ background-image: url("http://son-of-a-banana.com");
3
+ quotes: "~" "~";
4
+ content: "#*%:&^,)!.(~*})";
5
+ empty: "";
6
+ }
7
+ #comments { content: "/* hello */ // not-so-secret"; }
8
+ #single-quote {
9
+ quotes: "'" "'";
10
+ content: '""#!&""';
11
+ empty: '';
12
+ }
@@ -0,0 +1,8 @@
1
+ .variables { width: 14cm; }
2
+ .variables {
3
+ height: 24px;
4
+ color: #888888;
5
+ font-family: "Trebuchet MS", Verdana, sans-serif;
6
+ quotes: "~" "~";
7
+ }
8
+ .alpha { filter: alpha(opacity=95); }
@@ -0,0 +1,7 @@
1
+ .whitespace, .white, .space, .mania, .no-semi-column { color: white; }
2
+ .no-semi-column {
3
+ color: white;
4
+ white-space: pre;
5
+ }
6
+ .no-semi-column { border: 2px solid white; }
7
+ .newlines { border: 2px solid black; }
data/spec/engine_spec.rb CHANGED
@@ -1,8 +1,16 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
1
+ require 'spec/spec_helper'
2
2
 
3
3
  module LessEngineSpecHelper
4
- def lessify(string)
5
- return Less::Engine.new(string).to_css(:desc)
4
+ def lessify arg
5
+ if arg.is_a? String or arg.is_a? File
6
+ return Less::Engine.new(arg).to_css
7
+ else
8
+ lessify File.new("spec/less/#{arg.to_s.gsub('_', '-')}.less")
9
+ end
10
+ end
11
+
12
+ def css file
13
+ File.read("spec/css/#{file.to_s.gsub('_', '-')}.css")
6
14
  end
7
15
  end
8
16
 
@@ -10,25 +18,109 @@ describe Less::Engine do
10
18
  include LessEngineSpecHelper
11
19
 
12
20
  describe "to_css" do
13
- it "should return p {} for p {}" do
14
- lessify('p {}').should == 'p { }'
21
+ it "should parse css" do
22
+ lessify(:css).should == css(:css)
15
23
  end
16
-
17
- it "should return css with variable usage" do
18
- lessify("@brand_color: #4D926F;\n #header { color: @brand_color; }").should == "#header { color: #4D926F; }"
24
+
25
+ it "should group selectors when it can" do
26
+ lessify(:selectors).should == css(:selectors)
19
27
  end
20
-
21
- it "should return css as shown on home page" do
22
- lessify("#header { \n color: red;\n a {\n font-weight: bold;\n text-decoration: none;\n }\n}").should == "#header a { font-weight: bold; text-decoration: none; }\n#header { color: red; }"
28
+
29
+ it "should parse css 3" do
30
+ lessify(:css_3).should == css(:css_3)
31
+ end
32
+
33
+ it "should handle properties prefixed with a dash" do
34
+ lessify(:dash_prefix).should == css(:dash_prefix)
35
+ end
36
+
37
+ it "should parse comments" do
38
+ lessify(:comments).should == css(:comments)
39
+ end
40
+
41
+ it "should deal with whitespace" do
42
+ lessify(:whitespace).should == css(:whitespace)
43
+ end
44
+
45
+ it "should parse nested rules" do
46
+ lessify(:rulesets).should == css(:rulesets)
47
+ end
48
+
49
+ it "should parse variables" do
50
+ lessify(:variables).should == css(:variables)
51
+ end
52
+
53
+ it "should parse operations" do
54
+ lessify(:operations).should == css(:operations)
55
+ end
56
+
57
+ it "should manage scope" do
58
+ lessify(:scope).should == css(:scope)
59
+ end
60
+
61
+ it "should parse parens" do
62
+ lessify(:parens).should == css(:parens)
63
+ end
64
+
65
+ it "should parse strings" do
66
+ lessify(:strings).should == css(:strings)
67
+ end
68
+
69
+ it "should parse accessors" do
70
+ lessify(:accessors).should == css(:accessors)
71
+ end
72
+
73
+ it "should parse colors in hex" do
74
+ lessify(:colors).should == css(:colors)
75
+ end
76
+
77
+ it "should parse mixins" do
78
+ lessify(:mixins).should == css(:mixins)
79
+ end
80
+
81
+ it "should parse mixins with arguments" do
82
+ lessify(:mixins_args).should == css(:mixins_args)
83
+ end
84
+
85
+ it "should evaluate variables lazily" do
86
+ lessify(:lazy_eval).should == css(:lazy_eval)
23
87
  end
24
88
 
25
- it "should handle :hover" do
26
- lessify("a:hover {\n color: red; }").should == "a:hover { color: red; }"
89
+ it "should handle custom functions" do
90
+ module Less::Functions
91
+ def color args
92
+ arg = args.first
93
+ Less::Node::Color.new("99", "99", "99") if arg == "evil red"
94
+ end
95
+
96
+ def increment a
97
+ Less::Node::Number.new(a.evaluate.to_i + 1)
98
+ end
99
+
100
+ def add a, b
101
+ Less::Node::Number.new(a.evaluate + b.evaluate)
102
+ end
103
+ end
104
+ lessify(:functions).should == css(:functions)
105
+ end
106
+
107
+ it "should work with import" do
108
+ lessify(:import).should == css(:import)
27
109
  end
28
110
 
29
- it "should handle instances of double-quotes" do
30
- lessify("blockquote:before, blockquote:after, q:before, q:after {\n content: \"\"; }").should == "blockquote:before, blockquote:after, q:before, q:after { content: ''; }"
111
+ it "should work tih import using extra paths" do
112
+ lambda {
113
+ lessify(:import_with_extra_paths).should == css(:import_with_extra_paths)
114
+ }.should raise_error(Less::ImportError)
115
+ # finding a partial in another location
116
+ $LESS_LOAD_PATH = ["spec/less/extra_import_path"]
117
+ lessify(:import_with_extra_paths).should == css(:import_with_extra_paths)
118
+ # overriding a partial in another location so this takes priority over the same named partial in the same directory
119
+ lessify(:import).should == css(:import_with_partial_in_extra_path)
31
120
  end
121
+
122
+ it "should parse a big file"
123
+ it "should handle complex color operations"
32
124
  end
33
125
  end
34
126
 
@@ -0,0 +1,20 @@
1
+ .magic-box {
2
+ @trim: orange;
3
+ content: "gold";
4
+ width: 60cm;
5
+ height: 40cm;
6
+ #lock {
7
+ color: silver;
8
+ }
9
+ }
10
+
11
+ #accessors {
12
+ content: .magic-box['content']; // "gold"
13
+ width: .magic-box['width']; // 60cm
14
+ }
15
+
16
+ .unlock {
17
+ .magic-box;
18
+ color: #lock['color']; // silver
19
+ border-color: .magic-box[@trim]; // orange
20
+ }