module YPetri::Place::Guarded
Support of places' marking guards.
Public Instance Methods
Returns a closure combining all the guards defined for the place so far, which passes if, and only if, all the included guards pass. The common closure, if it passes, returns the tested marking value.
# File lib/y_petri/place/guarded.rb, line 40 def common_guard_closure place_name, lineup = name.to_s, guards.dup -> marking { lineup.each { |g| g.validate marking }; marking } end
Expects a guard assertion in natural language, and a guard block. Guard
block is a unary block that validates marking. A validation fails when:
-
The block returns false.
-
The block raises
YPetri::GuardError
.
In all other cases, including when the block returns nil (beware!), the marking is considered valid! Inside the block, #fail
keyword is redefined so that it can (and must) be called without arguments, and it raises an appropriately worded GuardError
. (Other exceptions can still be raised using #raise
keyword.) Practical example:
guard "should be a number" do |m| fail unless m.is_a? Numeric end
Then guard! :foobar
raises GuardError
with a message “Marking foobar:Symbol should be a number!”
Finally, this method is overloaded in such way, that if no block is given to it, it acts as an alias of #common_guard_closure
method.
# File lib/y_petri/place/guarded.rb, line 26 def guard *args, &block if block then @guards << YPetri::Place::Guard.new( *args, place: self, &block ) elsif args.size == 1 then common_guard_closure.( args[0] ) elsif args.empty? then common_guard_closure end end
Applies the guards defined for the place on the current marking (contents of +@marking+ instance variable).
# File lib/y_petri/place/guarded.rb, line 48 def guard! guard.( marking ) end
Private Instance Methods
If no guards were specified by the user, this method can construct standard guards based on the data type of places' marking
and/or default_marking
. (For most data types, default guards enfore type compliance. Numeric descendants, however, are considered interchangeable, except for Complex class.)
# File lib/y_petri/place/guarded.rb, line 60 def add_default_guards!( reference_marking ) case reference_marking when Complex then # 1 guard marking "should be Numeric" do |m| m.is_a? Numeric end when Numeric then # 3 guards marking "should be Numeric" do |m| m.is_a? Numeric end marking "should not be complex" do |m| fail if m.is_a? Complex end marking( "should not be negative" ) { |m| m >= 0 } if reference_marking >= 0 when nil then # no guards when true, false then # 1 guard marking "should be Boolean" do |m| m == !!m end else # 1 guard reference_marking.class.tap do |klass| marking "should be a #{klass}" do |m| m.is_a? klass end end end return nil end