diff --git a/lib/oga/parser.y b/lib/oga/parser.y index e0ccd0e..8d77ca1 100644 --- a/lib/oga/parser.y +++ b/lib/oga/parser.y @@ -5,6 +5,7 @@ token T_STRING T_TEXT token T_DOCTYPE_START T_DOCTYPE_END T_DOCTYPE_TYPE token T_CDATA_START T_CDATA_END token T_COMMENT_START T_COMMENT_END +token T_ELEM_OPEN T_ELEM_NAME T_ELEM_NS T_ELEM_CLOSE T_ATTR options no_result_var @@ -23,6 +24,8 @@ rule : doctype | cdata | comment + | element + | text ; # Doctypes @@ -70,6 +73,66 @@ rule | T_COMMENT_START T_TEXT T_COMMENT_END { s(:comment, val[1]) } ; + # Elements + + element + #

+ : element_open T_ELEM_CLOSE { s(:element, val[0]) } + + #

+ | element_open attributes T_ELEM_CLOSE + { + s(:element, val[0], val[1]) + } + + #

foo

+ | element_open text T_ELEM_CLOSE + { + s(:element, val[0], nil, val[1]) + } + + #

Bar

+ | element_open attributes text T_ELEM_CLOSE + { + s(:element, val[0], val[1], val[2]) + } + ; + + element_open + #

+ : T_ELEM_OPEN T_ELEM_NAME { [nil, val[1]] } + + # + | T_ELEM_OPEN T_ELEM_NS T_ELEM_NAME { [val[1], val[2]] } + ; + + # Attributes + + attributes + : attributes_ { s(:attributes, val[0]) } + ; + + attributes_ + : attributes_ attribute { val } + | attribute { val } + ; + + attribute + # foo + : T_ATTR { s(:attribute, val[0]) } + + # foo="bar" + | T_ATTR T_STRING { s(:attribute, val[0], val[1]) } + ; + + # Plain text + + text + : T_TEXT { s(:text, val[0]) } + ; + + # Whitespace + whitespaces : whitespaces whitespace | whitespace diff --git a/spec/oga/parser/elements_spec.rb b/spec/oga/parser/elements_spec.rb new file mode 100644 index 0000000..fb5b25f --- /dev/null +++ b/spec/oga/parser/elements_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe Oga::Parser do + context 'elements' do + example 'parse an empty element' do + parse_html('

').should == s(:document, s(:element, nil, 'p')) + end + + example 'parse an element with text' do + parse_html('

foo

').should == s( + :document, + s(:element, nil, 'p', nil, s(:text, 'foo')) + ) + end + + example 'parse an element with a single attribute' do + parse_html('

').should == s( + :document, + s(:element, nil, 'p', s(:attributes, s(:attribute, 'foo'))) + ) + end + + example 'parse an element with a single attribute with a value' do + parse_html('

').should == s( + :document, + s(:element, nil, 'p', s(:attributes, s(:attribute, 'foo', 'bar'))) + ) + end + + example 'parse an element with multiple attributes' do + parse_html('

').should == s( + :document, + s( + :element, + nil, + 'p', + s( + :attributes, + s(:attribute, 'foo', 'bar'), + s(:attribute, 'baz', 'bad') + ) + ) + ) + end + + example 'parse an element with text and attributes' do + parse_html('

Bar

').should == s( + :document, + s( + :element, + nil, + 'p', + s(:attributes, s(:attribute, 'class', 'foo')), + s(:text, 'Bar') + ) + ) + end + + example 'parse an element with a namespace' do + parse_html('

').should == s( + :document, + s(:element, 'foo', 'p') + ) + end + + example 'parse an element with a namespace and an attribute' do + parse_html('

').should == s( + :document, + s(:element, 'foo', 'p', s(:attributes, s(:attribute, 'class', 'bar'))) + ) + end + end +end