SFP Parser and Planner for Ruby =============================== - Author: Herry (herry13@gmail.com) - Last update: 20 April 2013 - Version: 1.0.1 - License: [BSD License](https://github.com/herry13/sfp-ruby/blob/master/LICENSE) A Ruby gem that provides a Ruby interface to parse SFP language. It also provides a Ruby interface for a solver to generate a workflow for a planning task written in SFP language. To install ---------- $ gem install sfp Requirements ------------ - Rubygems - antlr3 - json To use as a solver to solve a planning task ------------------------------------------- - parse a SFP file, then print the output in JSON $ sfp -p - solve a planning task, then print the workflow in JSON $ sfp The planning task must be written in [SFP language](https://github.com/herry13/nuri/wiki/SFP-language). To use as Ruby library ---------------------- - include file **main.sfp** in your codes: require 'sfp' - to parse an SFP file, create a Sfp::Parser object, and then pass the content of the file: # Determine the home directory of your SFP file. home_dir = File.expand_path(File.dirname("my_file.sfp")) # Create Sfp::Parser object; pass the home and root directory so the parser # can find the included files. parser = Sfp::Parser.new({:home_dir => home_dir, :root_dir => '/'}) # Parse the file. parser.parse(File.read("my_file.sfp")) # Get the result in Hash data structure result = parser.root - to solve a planning task, create a Sfp::Planner object, and then pass the file's path: # Create Sfp::Planner object. planner = Sfp::Planner.new # Solve a planning task written in "my_file.sfp", then print # the result in JSON. puts planner.solve({:file => "my_file.sfp", :json => true}) Example ------- - Create file **types.sfp** with content: class Service { running is false procedure start { conditions { this.running is false } effects { this.running is true } } procedure stop { conditions { this.running is true } effects { this.running is false } } } class Client { refer isref Service procedure redirect(s isref Service) { conditions { } effects { this.refer is s } } } In this file, we have two classes that model our domain. First, class **Service** with an attribute **running*, procedure **start** that changes **running**'s value from **false** to *true*, and procedure **stop** that changes **running**'s value from **true** to **false**. We also have class **Client** with an attribute **refer**, which is a reference to an instance of **Service**. There is a procedure **redirect** that changes the value of **refer** with any instance if **Service**. - Create file **task.sfp** with content: include "types.sfp" initial state { a isa Service { running is true } b isa Service // with "running" is false pc isa Client { refer is a } } goal constraint { pc.refer is b a.running is false } global constraint { pc.refer.running is true } In this file, we specify a task where in the initial state of our domain, we have two services **a** and **b**, and a client **pc**. **a** is running, **b** is stopped, and **pc** is referring to **a**. We want to generate a workflow that achieves goal: **pc** is referring to **b** and **a** is stopped, and preserves global constraint: **pc** is always referring to a running service. - To generate the workflow, we invoke **sfp** command with argument the path of the task file: $ sfp task.sfp Which will generate a workflow in JSON { "type": "sequential", "workflow": [ { "name": "$.b.start", "parameters": { }, "condition": { "$.b.running": false }, "effect": { "$.b.running": true } }, { "name": "$.pc.redirect", "parameters": { "$.s": "$.b" }, "condition": { }, "effect": { "$.pc.refer": "$.b" } }, { "name": "$.a.stop", "parameters": { }, "condition": { "$.a.running": true }, "effect": { "$.a.running": false } } ], "version": "1", "total": 3 } This workflow is sequential that has 3 procedures. If you executes the workflow in given order, it will achieves the goal state as well as perserves the global constraints during the changes. [Nuri](https://github.com/herry13/nuri) is a configuration tools that binds these procedures with particular shell commands in order to implement the required configuration changes based on the goal and global constraints given by the user.