Skip to content

Commit def804d

Browse files
committed
Implements common css parser rules
1 parent d12fa5f commit def804d

File tree

4 files changed

+144
-0
lines changed

4 files changed

+144
-0
lines changed

lib/csscss.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@
1111
require "csscss/redundancy_analyzer"
1212
require "csscss/reporter"
1313
require "csscss/json_reporter"
14+
15+
require "csscss/parser/common"

lib/csscss/parser/common.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module Csscss
2+
module Parser
3+
module Common
4+
include Parslet
5+
6+
rule(:spaces) { match["\s"].repeat }
7+
rule(:number) { match["0-9"] }
8+
rule(:numbers) { number.repeat(1) }
9+
rule(:percent) { numbers >> (str(".") >> numbers).maybe >> symbol("%") }
10+
rule(:inherit) { stri("inherit") }
11+
12+
def stri(str)
13+
key_chars = str.split(//)
14+
key_chars.
15+
collect! { |char|
16+
if char.upcase == char.downcase
17+
str(char)
18+
else
19+
match["#{char.upcase}#{char.downcase}"]
20+
end
21+
}.reduce(:>>)
22+
end
23+
24+
def symbol(s, label = nil)
25+
if label
26+
stri(s).as(label) >> spaces
27+
else
28+
stri(s) >> spaces
29+
end
30+
end
31+
32+
def between(left, right)
33+
raise "block not given" unless block_given?
34+
symbol(left) >> yield >> symbol(right)
35+
end
36+
37+
def parens(&block)
38+
between("(", ")", &block)
39+
end
40+
end
41+
end
42+
end

test/csscss/parser/common_test.rb

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
require "test_helper"
2+
3+
module Csscss::Parser
4+
describe Common do
5+
class CommonTest
6+
include Common
7+
end
8+
9+
before { @parser = CommonTest.new }
10+
11+
describe "#stri" do
12+
it "parses case insensitive strings" do
13+
@parser.stri("a").must_parse "a"
14+
@parser.stri("A").must_parse "a"
15+
@parser.stri("A").must_not_parse "b"
16+
17+
@parser.stri("This too shall pass").must_parse "this TOO shall PASS"
18+
@parser.stri("[").must_parse "["
19+
end
20+
end
21+
22+
describe "#spaces" do
23+
it "parses series of spaces" do
24+
@parser.spaces.must_parse ""
25+
@parser.spaces.must_parse " "
26+
@parser.spaces.must_parse " "
27+
@parser.spaces.must_not_parse " a"
28+
end
29+
end
30+
31+
describe "#symbol" do
32+
it "parses case insensitive characters followed by spaces" do
33+
@parser.symbol("foo").must_parse "foo"
34+
@parser.symbol("foo").must_parse "foo "
35+
@parser.symbol("foo").must_parse "Foo "
36+
@parser.symbol("foo").must_not_parse " Foo "
37+
end
38+
39+
it "optionally captures input" do
40+
parsed = @parser.symbol("foo", :foo).parse("Foo ")
41+
parsed[:foo].must_equal "Foo"
42+
end
43+
end
44+
45+
describe "parens and between" do
46+
it "parses input surrounded by parens" do
47+
@parser.parens { @parser.symbol("foo") }.must_parse "(foo)"
48+
@parser.parens { @parser.symbol("foo") }.must_parse "(FOo) "
49+
@parser.parens { @parser.symbol("foo") }.must_parse "(FOo ) "
50+
@parser.parens { @parser.symbol("food") }.must_not_parse "(FOo"
51+
end
52+
53+
it "parses characters surrounded" do
54+
@parser.between("[", "]") { @parser.symbol("foo") }.must_parse "[foo]"
55+
end
56+
end
57+
58+
describe "number and numbers" do
59+
it "parses single numbers" do
60+
@parser.number.must_parse "1"
61+
@parser.number.must_not_parse "12"
62+
@parser.number.must_not_parse "a"
63+
@parser.number.must_not_parse "1 "
64+
end
65+
66+
it "parses multiple numbers" do
67+
@parser.numbers.must_parse "1"
68+
@parser.numbers.must_parse "12"
69+
@parser.numbers.must_not_parse "12 "
70+
@parser.numbers.must_not_parse "1223a"
71+
end
72+
73+
it "parses percentages" do
74+
@parser.percent.must_parse "100%"
75+
@parser.percent.must_parse "100% "
76+
@parser.percent.must_parse "100.344%"
77+
@parser.percent.must_not_parse "100 %"
78+
end
79+
end
80+
end
81+
end

test/test_helper.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,24 @@ def cmatch(selectors, decs)
2121
end
2222
end
2323

24+
module MiniTest::Assertions
25+
def assert_parse(parser, string)
26+
assert parser.parse(string)
27+
rescue Parslet::ParseFailed => ex
28+
assert false, ex.cause.ascii_tree
29+
end
30+
31+
def assert_not_parse(parser, string)
32+
parser.parse(string)
33+
assert false, "expected #{parser} to not successfully parse \"#{string}\" and it did"
34+
rescue Parslet::ParseFailed => ex
35+
assert ex
36+
end
37+
end
38+
39+
Parslet::Atoms::DSL.infect_an_assertion :assert_parse, :must_parse, :do_not_flip
40+
Parslet::Atoms::DSL.infect_an_assertion :assert_not_parse, :must_not_parse, :do_not_flip
41+
2442
Debugger.settings[:autoeval] = true
2543
Debugger.settings[:autolist] = 1
44+

0 commit comments

Comments
 (0)