[PATCH 1/5] Add boolean operators to AST

6 views
Skip to first unread message

Brice Figureau

unread,
Sep 27, 2008, 5:21:14 AM9/27/08
to puppe...@googlegroups.com

Signed-off-by: Brice Figureau <brice-...@daysofwonder.com>
---
lib/puppet/parser/ast.rb | 1 +
lib/puppet/parser/ast/boolean_operator.rb | 48 ++++++++++++++++++++++++++
spec/unit/parser/ast/boolean_operator.rb | 52 +++++++++++++++++++++++++++++
3 files changed, 101 insertions(+), 0 deletions(-)
create mode 100644 lib/puppet/parser/ast/boolean_operator.rb
create mode 100755 spec/unit/parser/ast/boolean_operator.rb

diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb
index c9bd7c9..6674452 100644
--- a/lib/puppet/parser/ast.rb
+++ b/lib/puppet/parser/ast.rb
@@ -76,6 +76,7 @@ end
# And include all of the AST subclasses.
require 'puppet/parser/ast/astarray'
require 'puppet/parser/ast/branch'
+require 'puppet/parser/ast/boolean_operator'
require 'puppet/parser/ast/caseopt'
require 'puppet/parser/ast/casestatement'
require 'puppet/parser/ast/collection'
diff --git a/lib/puppet/parser/ast/boolean_operator.rb b/lib/puppet/parser/ast/boolean_operator.rb
new file mode 100644
index 0000000..c3b5c7d
--- /dev/null
+++ b/lib/puppet/parser/ast/boolean_operator.rb
@@ -0,0 +1,48 @@
+require 'puppet'
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+ class BooleanOperator < AST::Branch
+
+ attr_accessor :operator, :lval, :rval
+
+ # Iterate across all of our children.
+ def each
+ [@lval,@rval,@operator].each { |child| yield child }
+ end
+
+ # Returns a boolean which is the result of the boolean operation
+ # of lval and rval operands
+ def evaluate(scope)
+ # evaluate the first operand, should return a boolean value
+ lval = @lval.safeevaluate(scope)
+
+ # return result
+ # lazy evaluate right operand
+ case @operator
+ when "and";
+ if Puppet::Parser::Scope.true?(lval)
+ rval = @rval.safeevaluate(scope)
+ Puppet::Parser::Scope.true?(rval)
+ else # false and false == false
+ false
+ end
+ when "or";
+ if Puppet::Parser::Scope.true?(lval)
+ true
+ else
+ rval = @rval.safeevaluate(scope)
+ Puppet::Parser::Scope.true?(rval)
+ end
+ end
+ end
+
+ def initialize(hash)
+ super
+
+ unless %w{and or}.include?(@operator)
+ raise ArgumentError, "Invalid boolean operator %s" % @operator
+ end
+ end
+ end
+end
diff --git a/spec/unit/parser/ast/boolean_operator.rb b/spec/unit/parser/ast/boolean_operator.rb
new file mode 100755
index 0000000..e7fb683
--- /dev/null
+++ b/spec/unit/parser/ast/boolean_operator.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe Puppet::Parser::AST::BooleanOperator do
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ @true_ast = Puppet::Parser::AST::Boolean.new( :value => true)
+ @false_ast = Puppet::Parser::AST::Boolean.new( :value => false)
+ end
+
+ it "should evaluate left operand inconditionally" do
+ lval = stub "lval"
+ lval.expects(:safeevaluate).with(@scope).returns("true")
+ rval = stub "rval", :safeevaluate => false
+
+ operator = Puppet::Parser::AST::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval
+ operator.evaluate(@scope)
+ end
+
+ it "should evaluate right 'and' operand only if left operand is true" do
+ lval = stub "lval", :safeevaluate => true
+ rval = stub "rval", :safeevaluate => false
+ rval.expects(:safeevaluate).with(@scope).returns(false)
+ operator = Puppet::Parser::AST::BooleanOperator.new :rval => rval, :operator => "and", :lval => lval
+ operator.evaluate(@scope)
+ end
+
+ it "should evaluate right 'or' operand only if left operand is false" do
+ lval = stub "lval", :safeevaluate => false
+ rval = stub "rval", :safeevaluate => false
+ rval.expects(:safeevaluate).with(@scope).returns(false)
+ operator = Puppet::Parser::AST::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval
+ operator.evaluate(@scope)
+ end
+
+ it "should return true for false OR true" do
+ operator = Puppet::Parser::AST::BooleanOperator.new :rval => @true_ast, :operator => "or", :lval => @false_ast
+ operator.evaluate(@scope).should == true
+ end
+
+ it "should return false for true AND false" do
+ operator = Puppet::Parser::AST::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @false_ast )
+ operator.evaluate(@scope).should == false
+ end
+
+ it "should return true for true AND true" do
+ operator = Puppet::Parser::AST::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @true_ast )
+ operator.evaluate(@scope).should == true
+ end
+
+end
--
1.6.0.2

Luke Kanies

unread,
Sep 29, 2008, 1:55:26 PM9/29/08
to puppe...@googlegroups.com
On Sep 27, 2008, at 4:21 AM, Brice Figureau wrote:
> +
> + it "should evaluate left operand inconditionally" do
> + lval = stub "lval"
> + lval.expects(:safeevaluate).with(@scope).returns("true")
> + rval = stub "rval", :safeevaluate => false
> +
> + operator = Puppet::Parser::AST::BooleanOperator.new :rval
> => rval, :operator => "or", :lval => lval
> + operator.evaluate(@scope)
> + end

Here I might do something like 'rval.expects(:evaluate).never', to
make the assertion clear.

I can't actually quite tell if you are asserting here that the rval
shouldn't be evaluated.

It's nitpicky, but these can be done as oneliners:

Puppet::Parser::AST::BooleanOperator.new(:rval => @true_ast, :operator

=> "or", :lval => @false_ast).evaluate(@scope).should be_true

(Note RSpec has builtin be_true, be_false, and be_nil matchers.)

This is stylistic, so it doesn't matter much to me. I use a wide
editor window, as you probably know by now, so that works well for me.

--
I do not feel obliged to believe that the same God who has endowed us
with sense, reason, and intellect has intended us to forgo their use.
-- Galileo Galilei
---------------------------------------------------------------------
Luke Kanies | http://reductivelabs.com | http://madstop.com

Reply all
Reply to author
Forward
0 new messages