This module contains scripting functions and helpers.
Include this if you want to eval nwn-gff-dsl scripts.
Methods
public class
public instance
Public class methods
Run a script in a sandboxish environ. Returns true if the code modified run_on in any way.
# File lib/nwn/scripting.rb, line 13 13: def self.run_script code, run_on = nil, arguments = [] 14: $code = code 15: $argv = arguments 16: $standalone = run_on.nil? 17: $satisfy_loaded = {} 18: run_on ||= Sandbox.new 19: 20: $script_obj_hash = run_on.hash 21: catch(:exit) { 22: begin 23: run_on.instance_eval $code 24: rescue => e 25: raise 26: end 27: } 28: $script_obj_hash != run_on.hash 29: end
Public instance methods
Ask the user for something. question the Question to ask match a selection of answers to choose from (eg, a hash, the user would choose the key)
# File lib/nwn/scripting.rb, line 175 175: def ask question, match = nil 176: object = case match 177: when Array 178: i = 0 ; Hash[match.map {|x| [i+=1, x]}] 179: 180: when Hash, Regexp, Fixnum, Float 181: match 182: 183: else 184: raise NWN::Gff::GffError, "Do not know how to " + 185: "validate against #{match.class}" 186: end 187: 188: ret = nil 189: while true 190: y object 191: $stderr.print File.basename($SCRIPT) + ": " + question + " " 192: ret = $stdin.gets 193: ret = ret.rstrip 194: 195: break if object.nil? || case object 196: when Hash 197: if object.keys.index(ret) || (ret != "" && object.keys.index(ret.to_i)) 198: ret = object[ret] || (ret != "" && object[ret.to_i]) 199: else 200: nil 201: end 202: when Regexp 203: ret =~ match 204: when Fixnum 205: ret =~ /^\d+$/ 206: when Float 207: ret =~ /^\d+(.\d+)?$/ 208: end 209: end 210: 211: case match 212: when Float; ret.to_f 213: when Fixnum; ret.to_i 214: else; ret 215: end 216: end
Log a friendly message to stderr. Use this instead of puts, since SAFE levels greater than 0 will prevent you from doing logging yourself.
# File lib/nwn/scripting.rb, line 162 162: def log *args 163: perc = $PERCENTAGE_DONE.nil? ? "" : " (%d%%)" % [ $PERCENTAGE_DONE.to_i ] 164: if $options 165: $stderr.puts [$SCRIPT, perc, " on ", $options[:infile], ": ", *args].join("") 166: else 167: $stderr.puts [$SCRIPT, perc, ": ", *args].join("") 168: end 169: end
Same as want, but error out (don’t continue processing).
# File lib/nwn/scripting.rb, line 60 60: def need *what 61: satisfy(*what) or raise ArgumentError, "Needs #{what.inspect}, cannot satisfy - aborting." 62: end
You can call this to provide a progress indicator, if your script is long-running. the calculated percentage will be prefixed before each log message.
position The number of items in the work queue finished. total_size The total size of the work queue, defaults to ARGV.size.
# File lib/nwn/scripting.rb, line 154 154: def progress position, total_size = nil 155: total_size ||= ARGV.size 156: $PERCENTAGE_DONE = position.to_f / total_size.to_f * 100 157: end
This checks if the currently-operating field or struct satisfies one of the given conditions.
When you’re running in standalone mode, the first argument is expected to be a file or IO stream that needs to satisfy the given conditions.
Example:
need ARGV.shift, :bic, :utc, :uti
will require the user to supply a filename as the first argument to the standalone script, which needs to resolve to a bic, utc, or uti data_type.
Conditions can be:
- A symbol describing the data_type, eg :utc
- A symbol describing the field_type, eg :int
- A module or class name
Returns the object that satisfies the asked-for conditions, or nil if none can be given.
If only a filename/string is given and no further arguments, the read object will be returned as-is.
# File lib/nwn/scripting.rb, line 101 101: def satisfy *what 102: close_me = false 103: if $standalone 104: fn = what.shift 105: io = case fn 106: when String 107: close_me = true 108: File.new(fn, "rb") 109: when IO 110: fn 111: else 112: return nil 113: #raise ArgumentError, "When running in standalone mode, " + 114: # "`need', `want' and `satisfy' need a filename or a IO " + 115: # "object to read from (usually the first script argument)." 116: end 117: 118: obj = begin 119: NWN::Gff.read(io, NWN::Gff.guess_file_format(fn)) 120: ensure 121: io.close if close_me 122: end 123: log "satisfied #{fn} -> #{obj.to_s}" 124: $satisfy_loaded[obj.object_id] = [fn, obj.hash] 125: 126: return obj if what.size == 1 127: else 128: obj = self 129: end 130: 131: what.each {|w| 132: case w 133: when Class, Module 134: return obj if obj.is_a?(w) 135: 136: when Symbol 137: case obj 138: when NWN::Gff::Struct 139: return obj if obj.data_type.downcase == w.to_s.downcase 140: when NWN::Gff::Field 141: return obj if obj.field_type.to_sdowncase == w.to_s.downcase 142: end 143: end 144: } 145: 146: return nil 147: end
Save the given object if it was loaded via want/need
# File lib/nwn/scripting.rb, line 32 32: def save object 33: fn, hash = $satisfy_loaded[object.object_id] 34: if fn 35: if hash != object.hash 36: File.open(fn, "wb") {|f| 37: NWN::Gff.write(f, NWN::Gff.guess_file_format(fn), object) 38: } 39: log "saved #{object.to_s} -> #{fn}" 40: else 41: log "not saving #{fn}: not modified" 42: end 43: else 44: raise ArgumentError, 45: "#save: object #{object.to_s} was not loaded via want/need/satisfy, cannot save" 46: end 47: end
Call this to prevent nwn-gff from emitting output.
# File lib/nwn/scripting.rb, line 65 65: def stop_output 66: if $standalone 67: log "warn: no need to stop_output on standalone scripts" 68: else 69: log "#{$SCRIPT}: not emitting any data." 70: end 71: $stop_output = true 72: end
This script only runs for the following conditions (see satisfy).
# File lib/nwn/scripting.rb, line 50 50: def want *what 51: obj = satisfy(*what) 52: unless obj 53: log "Wants #{what.inspect}, cannot satisfy - continuing." 54: throw(:exit) 55: end 56: obj 57: end
# File lib/nwn/scripting.rb, line 74 74: def will_output? 75: !$stop_output 76: end