From 07b52fb48a598642987f0bdf0c958ca3b1a49579 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 5 Aug 2015 09:43:07 +0200 Subject: [PATCH] Added Ruby::Node#not This is a shortcut for "!foo". Using this method one doesn't have to worry about how the "!" operator binds. For example, this: !foo.or(bar) would be parsed/evaluated as this: !(foo.or(bar)) when instead we want it to be this: (!foo).or(bar) Using explicit parenthesis leads to ugly code, so now we can do this instead: foo.not.or(bar) --- lib/oga/ruby/node.rb | 11 +++++++++++ lib/oga/xpath/compiler.rb | 4 ++-- spec/oga/ruby/node_spec.rb | 10 ++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/oga/ruby/node.rb b/lib/oga/ruby/node.rb index bf11e0e..f0fefef 100644 --- a/lib/oga/ruby/node.rb +++ b/lib/oga/ruby/node.rb @@ -84,6 +84,17 @@ module Oga Node.new(:or, [self, other]) end + ## + # Returns a node that evaluates to its inverse. + # + # For example, a variable `foo` would be turned into `!foo`. + # + # @return [Oga::Ruby::Node] + # + def not + !self + end + ## # Returns a node for Ruby's "is_a?" method. # diff --git a/lib/oga/xpath/compiler.rb b/lib/oga/xpath/compiler.rb index ae70edd..880cbde 100644 --- a/lib/oga/xpath/compiler.rb +++ b/lib/oga/xpath/compiler.rb @@ -302,7 +302,7 @@ module Oga .followed_by(throw_message(:skip_children)) end - next_check = (!check).or(parent != doc_node.parent).if_true do + next_check = check.not.or(parent != doc_node.parent).if_true do send_message(:next) end @@ -343,7 +343,7 @@ module Oga .followed_by(throw_message(:skip_children)) end - next_check = (!check).if_true { send_message(:next) } + next_check = check.not.if_true { send_message(:next) } match_node = backup_variable(node, doc_node) do process(ast, node, &block).if_true do diff --git a/spec/oga/ruby/node_spec.rb b/spec/oga/ruby/node_spec.rb index c13dd20..586ecc5 100644 --- a/spec/oga/ruby/node_spec.rb +++ b/spec/oga/ruby/node_spec.rb @@ -61,6 +61,16 @@ describe Oga::Ruby::Node do end end + describe '#not' do + it 'returns a send Node' do + node = described_class.new(:lit, %w{foo}) + inverted = node.not + + inverted.type.should == :send + inverted.to_a.should == [node, '!'] + end + end + describe '#is_a?' do it 'returns a is_a? call Node' do left = described_class.new(:lit, %w{number})