diff --git a/lib/oga.rb b/lib/oga.rb index 9a5b786..5bc0e6a 100644 --- a/lib/oga.rb +++ b/lib/oga.rb @@ -23,6 +23,7 @@ require_relative 'oga/xml/text' require_relative 'oga/xml/comment' require_relative 'oga/xml/cdata' require_relative 'oga/xml/xml_declaration' +require_relative 'oga/xml/processing_instruction' require_relative 'oga/xml/doctype' require_relative 'oga/xml/attribute' require_relative 'oga/xml/namespace' diff --git a/lib/oga/xml/parser.y b/lib/oga/xml/parser.y index 0f11f1f..a0327f1 100644 --- a/lib/oga/xml/parser.y +++ b/lib/oga/xml/parser.y @@ -15,6 +15,7 @@ token T_DOCTYPE_INLINE token T_CDATA T_COMMENT token T_ELEM_START T_ELEM_NAME T_ELEM_NS T_ELEM_END T_ATTR T_ATTR_NS token T_XML_DECL_START T_XML_DECL_END +token T_PROC_INS_START T_PROC_INS_NAME T_PROC_INS_END options no_result_var @@ -40,6 +41,7 @@ rule | element | text | xmldecl + | proc_ins ; # Doctypes @@ -95,6 +97,20 @@ rule : T_COMMENT { on_comment(val[0]) } ; + # Processing Instructions + + proc_ins + # + : T_PROC_INS_START T_PROC_INS_NAME T_PROC_INS_END + { + on_proc_ins(val[1]) + } + | T_PROC_INS_START T_PROC_INS_NAME T_TEXT T_PROC_INS_END + { + on_proc_ins(val[1], val[2]) + } + ; + # Elements element_open @@ -155,6 +171,7 @@ rule ; # XML declarations + xmldecl : T_XML_DECL_START attributes T_XML_DECL_END { on_xml_decl(val[1]) } ; @@ -307,6 +324,15 @@ Unexpected #{name} with value #{value.inspect} on line #{@line}: return Comment.new(:text => text) end + ## + # @param [String] name + # @param [String] text + # @return [Oga::XML::ProcessingInstruction] + # + def on_proc_ins(name, text = nil) + return ProcessingInstruction.new(:name => name, :text => text) + end + ## # @param [Array] attributes # @return [Oga::XML::XmlDeclaration] diff --git a/lib/oga/xml/processing_instruction.rb b/lib/oga/xml/processing_instruction.rb new file mode 100644 index 0000000..c0c2dbd --- /dev/null +++ b/lib/oga/xml/processing_instruction.rb @@ -0,0 +1,39 @@ +module Oga + module XML + ## + # Class used for storing information about a single processing instruction. + # + # @!attribute [rw] name + # @return [String] + # + class ProcessingInstruction < CharacterNode + attr_accessor :name + + ## + # @param [Hash] options + # + # @option options [String] :name The name of the instruction. + # @see [Oga::XML::CharacterNode#initialize] + # + def initialize(options = {}) + super + + @name = options[:name] + end + + ## + # @return [String] + # + def to_xml + return "" + end + + ## + # @return [String] + # + def inspect + return "ProcessingInstruction(name: #{name.inspect} text: #{text.inspect})" + end + end # ProcessingInstruction + end # XML +end # Oga diff --git a/lib/oga/xml/pull_parser.rb b/lib/oga/xml/pull_parser.rb index bff29c6..0bc632b 100644 --- a/lib/oga/xml/pull_parser.rb +++ b/lib/oga/xml/pull_parser.rb @@ -46,7 +46,8 @@ module Oga BLOCK_CALLBACKS = [ :on_cdata, :on_comment, - :on_text + :on_text, + :on_proc_ins ] ## diff --git a/spec/oga/xml/parser/processing_instruction_spec.rb b/spec/oga/xml/parser/processing_instruction_spec.rb new file mode 100644 index 0000000..5af06e2 --- /dev/null +++ b/spec/oga/xml/parser/processing_instruction_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Oga::XML::Parser do + context 'empty processing instructions' do + before :all do + @node = parse('').children[0] + end + + example 'return a ProcessingInstruction instance' do + @node.is_a?(Oga::XML::ProcessingInstruction).should == true + end + + example 'set the name of the instruction' do + @node.name.should == 'foo' + end + end + + context 'processing instructions with text' do + before :all do + @node = parse('').children[0] + end + + example 'return a ProcessingInstruction instance' do + @node.is_a?(Oga::XML::ProcessingInstruction).should == true + end + + example 'set the name of the instruction' do + @node.name.should == 'foo' + end + + example 'set the text of the instruction' do + @node.text.should == ' bar ' + end + end +end diff --git a/spec/oga/xml/processing_instruction_spec.rb b/spec/oga/xml/processing_instruction_spec.rb new file mode 100644 index 0000000..51c8073 --- /dev/null +++ b/spec/oga/xml/processing_instruction_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe Oga::XML::ProcessingInstruction do + context '#initialize' do + example 'set the name of the node' do + described_class.new(:name => 'foo').name.should == 'foo' + end + + example 'set the text of the node' do + described_class.new(:text => 'foo').text.should == 'foo' + end + end + + context '#to_xml' do + example 'conver the node into XML' do + node = described_class.new(:name => 'foo', :text => ' bar ') + + node.to_xml.should == '' + end + end + + context '#inspect' do + example 'return the inspect value of the node' do + node = described_class.new(:name => 'foo', :text => ' bar ') + + node.inspect.should == 'ProcessingInstruction(name: "foo" text: " bar ")' + end + end +end diff --git a/spec/oga/xml/pull_parser/processing_instruction_spec.rb b/spec/oga/xml/pull_parser/processing_instruction_spec.rb new file mode 100644 index 0000000..19f6d5e --- /dev/null +++ b/spec/oga/xml/pull_parser/processing_instruction_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe Oga::XML::PullParser do + context 'processing instructions' do + before :all do + @parser = described_class.new('') + + @node = nil + + @parser.parse { |node| @node = node } + end + + example 'return a ProcessingInstruction node' do + @node.is_a?(Oga::XML::ProcessingInstruction).should == true + end + + example 'set the name of the node' do + @node.name.should == 'foo' + end + + example 'set the text of the node' do + @node.text.should == ' bar ' + end + end +end