Module NWN::Gff::Scripting

  1. lib/nwn/scripting.rb

This module contains scripting functions and helpers.

Include this if you want to eval nwn-gff-dsl scripts.

Methods

public class

  1. run_script

public instance

  1. ask
  2. log
  3. need
  4. progress
  5. satisfy
  6. save
  7. stop_output
  8. want
  9. will_output?

Public class methods

run_script (code, run_on = nil, arguments = [])

Run a script in a sandboxish environ. Returns true if the code modified run_on in any way.

[show source]
    # 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 (question, match = nil)

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)

[show source]
     # 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 (*args)

Log a friendly message to stderr. Use this instead of puts, since SAFE levels greater than 0 will prevent you from doing logging yourself.

[show source]
     # 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
need (*what)

Same as want, but error out (don’t continue processing).

[show source]
    # 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
progress (position, total_size = nil)

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.

[show source]
     # 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
satisfy (*what)

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.

[show source]
     # 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 (object)

Save the given object if it was loaded via want/need

[show source]
    # 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
stop_output ()

Call this to prevent nwn-gff from emitting output.

[show source]
    # 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
want (*what)

This script only runs for the following conditions (see satisfy).

[show source]
    # 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
will_output? ()
[show source]
    # File lib/nwn/scripting.rb, line 74
74:   def will_output?
75:     !$stop_output
76:   end