module YPetri::Place::Guarded

Support of places' marking guards.

Public Instance Methods

common_guard_closure() click to toggle source

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
guard(*args, &block) click to toggle source

Expects a guard assertion in natural language, and a guard block. Guard block is a unary block that validates marking. A validation fails when:

  1. The block returns false.

  2. 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
guard!() click to toggle source

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

add_default_guards!( reference_marking ) click to toggle source

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