nwn-lib 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -251,3 +251,21 @@ Bernhard Stoeckner <elven@swordcoast.net> (6):
251
251
 
252
252
  Another bugfix and compatibility release. This adds real NWN2 support
253
253
  to gff reading, adds a few new SETTINGS, and adds proper IO reading.
254
+
255
+ === 0.4.9
256
+ Bernhard Stoeckner <elven@swordcoast.net> (10):
257
+ Gff::Reader/YAML: do not taint read objects
258
+ Scripting: satisfy win32 compatibility
259
+ nwn-irb: work on IO object instead of string
260
+ nwn-erf: fix typo in -h: -1 saying ERF 1.0 instead of ERF 1.1
261
+ Scripting: satisfy: close opened fds after loading GFF data
262
+ api.rb: merge into field.rb and struct.rb
263
+ Gff::Struct#by_path: print list index in current_path on error
264
+ Gff::Struct#by_path: / alias, $ and % mods, substruct & locname paths
265
+ TwoDA::Table: fix always printing errors for invalid IDs on table reading
266
+ Update documentation, add HOWTO
267
+ 0.4.9-rel
268
+
269
+ Some medium rare bugfixes, and a overloaded operator for GFF structs,
270
+ which can be used to comfortable walk on trees.
271
+
data/COPYING CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2008 Bernhard Stoeckner <elven@swordcoast.net> and contributors
1
+ Copyright (C) 2008-current Bernhard Stoeckner <elven@swordcoast.net> and contributors
2
2
 
3
3
  This program is free software; you can redistribute it and/or modify
4
4
  it under the terms of the GNU General Public License as published by
data/HOWTO ADDED
@@ -0,0 +1,170 @@
1
+ === Writing scripts to do the work for you
2
+
3
+ First, read SCRIPTING. Since an example is more worth than a thousand words,
4
+ here is a quick introduction in the form of a script that handles input
5
+ files from ARGV, does nothing with them, and then saves them back to the same
6
+ file from which they came from.
7
+
8
+ #!/usr/bin/env nwn-dsl
9
+
10
+ ARGV.each_with_index {|file, index|
11
+ # The script will abort hard if file is not an ARE.
12
+ # This looks up the data_type, which are usually the
13
+ # first four bytes of a file.
14
+ gff = need file, :are
15
+
16
+ # This will save gff back to 'file'.
17
+ save gff
18
+
19
+ # This will prefix all lines printed with log with
20
+ # a percentage. It's usage is optional, and the sole
21
+ # reason for using each_with_index instead of each above.
22
+ progress index
23
+ }
24
+
25
+ To run this example, type the following in a directory containing some .are
26
+ files, with script.rb being the name you saved the above script in.
27
+
28
+ nwn-dsl path/to/script.rb *.are
29
+
30
+ The shebang (#!/..) is for unixoid systems and Cygwin, and as such optional.
31
+
32
+ For all available commands to nwn-dsl scripts, see NWN::Gff::Scripting.
33
+
34
+ <b>All code snippets shown here assume that you put <tt>include NWN</tt>
35
+ in your application. It is not needed for nwn-dsl, which imports that
36
+ namespace for you.</b>
37
+
38
+ === Accessing GFF paths
39
+
40
+ You can access GFF paths within structs by using the overloaded division
41
+ operator.
42
+
43
+ #!/usr/bin/env nwn-dsl
44
+
45
+ ARGV.each_with_index {|file, index|
46
+ gff = need file, :are
47
+
48
+ log (gff / 'Name/0')
49
+
50
+ progress index
51
+ }
52
+
53
+ For a full reference of the path syntax, see NWN::Gff::Struct#by_path.
54
+
55
+ You cannot use paths to assign new values to structs - you can only
56
+ modify existing values:
57
+
58
+ (gff / 'Name').v[0] = "New Localized Name with Language ID 0"
59
+
60
+ Wrong, will raise error:
61
+
62
+ (gff / 'Name/0') = "New .."
63
+
64
+ Please note that using the [] method will NOT evaluate paths, just
65
+ access labels in the CURRENT struct (which is actually a hash).
66
+
67
+ === Creating new GFF Structs and Elements
68
+
69
+ You can add new fields to existing structs via NWN::Gff::Struct#add_field:
70
+
71
+ gff.add_field 'LocalVersion', :int, 1
72
+
73
+ # This will print "1"
74
+ log (gff / 'LocalVersion$')
75
+
76
+ You can also the dynamic methods to save some typing:
77
+
78
+ gff.add_int 'LocalVersion', 1
79
+
80
+ You can just as well create whole GFF structures on the fly:
81
+
82
+ Gff::Struct.new do |s|
83
+ s.add_byte 'ImaByte', :int, 1
84
+ list = s.add_list 'ImaList', [] do |l|
85
+ l.add_struct(1) do |ss|
86
+ ss.add_byte 'ImaByteToo', 2
87
+ end
88
+ end
89
+ end
90
+
91
+ Further reading: NWN::Gff::Struct#add_field, NWN::Gff::List#add_struct.
92
+
93
+ === Working with .2da files
94
+
95
+ Working with TwoDA files is easy and painless:
96
+
97
+ #!/usr/bin/env nwn-dsl
98
+
99
+ data = IO.read('path/to/baseitems.2da')
100
+ table = TwoDA::Table.parse(data)
101
+
102
+ # This will print "twobladedsword" with NWN1 1.69
103
+ log table[12].Label
104
+
105
+ # You can re-format (and save) any valid table:
106
+ File.open("/tmp/out", "wb") {|f|
107
+ f.write(table.to_2da)
108
+ # OR
109
+ table.write_to(f)
110
+ }
111
+
112
+ For more documentation, see NWN::TwoDA::Table and
113
+ NWN::TwoDA::Row.
114
+
115
+ You can also set up a default location for 2da files,
116
+ after which you can simply use the following to read
117
+ 2da files:
118
+
119
+ table = TwoDA.get('baseitems')
120
+
121
+ You can set up the TwoDA::Cache by either setting the
122
+ environment variable (recommended, see SETTINGS), or
123
+ like this (see NWN::TwoDA::Cache.setup):
124
+
125
+ TwoDA::Cache.setup("path_a:path_b/blah:path_c")
126
+
127
+ === Accessing .tlk data
128
+
129
+ You can access individual .tlk files, or use a TlkSet,
130
+ which will emulate the way NWN1/2 reads it's .tlk files.
131
+
132
+ Read a simple .tlk file:
133
+
134
+ io = File.open("/path/to/dialog.tlk", "rb")
135
+ tlk = NWN::Tlk::Tlk.new(io)
136
+
137
+ Note that Tlk::Tlk seeks and reads from +io+ as needed,
138
+ so if you close the file handle, any further accesses
139
+ will fail.
140
+
141
+ # Retrieve strref 12
142
+ tlk[12][:text]
143
+
144
+ # Retrieve the attached sound resref, if any:
145
+ tlk[12][:sound]
146
+
147
+ # prints the highest strref used
148
+ log tlk.highest_id
149
+
150
+ # Add a new strrref.
151
+ new_strref = tlk.add 'New text'
152
+
153
+ # And save the new TLK somewhere else.
154
+ File.open("/tmp/new.tlk", "wb") {|another_io|
155
+ tlk.write_to(another_io)
156
+ }
157
+
158
+ Now read-only access with a TlkSet:
159
+
160
+ # The arguments are dialog.tlk, dialogf.tlk,
161
+ # custom.tlk and a customf.tlk each wrapped in
162
+ # a Tlk::Tlk as shown above.
163
+ set = Tlk::TlkSet.new(tlk, tlkf, custom, customf)
164
+
165
+ # Retrieve str_ref 12 as the female variant (dialogf.tlk)
166
+ # if present, :male otherwise.
167
+ log set[12, :female]
168
+
169
+ You cannot use TlkSet to write out .tlk files or modify
170
+ existing entries - it is merely a wrapper.
data/README CHANGED
@@ -50,7 +50,7 @@ And do the following in a script of your own devising:
50
50
  require 'rubygems'
51
51
  require 'nwn/all'
52
52
 
53
- Also, Read BINARIES.
53
+ Also, read BINARIES and HOWTO.
54
54
 
55
55
  For nwn-lib scripts, see SCRIPTING.
56
56
 
data/Rakefile CHANGED
@@ -9,13 +9,13 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "nwn-lib"
12
- VERS = "0.4.8"
12
+ VERS = "0.4.9"
13
13
  CLEAN.include ["**/.*.sw?", "pkg", ".config", "rdoc", "coverage"]
14
14
  RDOC_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', \
15
15
  'nwn-lib: a ruby library for accessing NWN resource files', \
16
16
  '--main', 'README']
17
17
 
18
- DOCS = ["README", "BINARIES", "SCRIPTING", "SETTINGS", "CHEATSHEET", "CHANGELOG", "COPYING"]
18
+ DOCS = ["README", "BINARIES", "HOWTO", "SCRIPTING", "SETTINGS", "CHEATSHEET", "CHANGELOG", "COPYING"]
19
19
 
20
20
  Rake::RDocTask.new do |rdoc|
21
21
  rdoc.rdoc_dir = "rdoc"
@@ -66,7 +66,7 @@ begin OptionParser.new do |o|
66
66
  o.on "-0", "Create (only -c) V1.0 ERF, 16 byte resrefs. (NWN1, default)" do
67
67
  $version = "V1.0"
68
68
  end
69
- o.on "-1", "Create (only -c) V1.0 ERF, 32 byte resrefs. (NWN2)." do
69
+ o.on "-1", "Create (only -c) V1.1 ERF, 32 byte resrefs. (NWN2)." do
70
70
  $version = "V1.1"
71
71
  end
72
72
 
@@ -29,7 +29,7 @@ def read file
29
29
  file = File.expand_path(file || $file)
30
30
  $stderr.puts "Reading `#{file}' .."
31
31
  fmt = NWN::Gff.guess_file_format(file)
32
- $gff = NWN::Gff.read(IO.read(file), fmt)
32
+ $gff = NWN::Gff.read(File.open(file, "rb"), fmt)
33
33
 
34
34
  $stderr.puts "Your GFF file is in `$gff' (data_type: #{$gff.data_type.inspect})."
35
35
  $stderr.puts "Type `save' to save to the filename it came from (make a backup!), `exit' (or Ctrl+D) to exit (without saving)."
@@ -116,4 +116,3 @@ require 'nwn/gff/list'
116
116
  require 'nwn/gff/cexolocstr'
117
117
  require 'nwn/gff/reader'
118
118
  require 'nwn/gff/writer'
119
- require 'nwn/gff/api'
@@ -158,4 +158,36 @@ module NWN::Gff::Field
158
158
  false
159
159
  end
160
160
  end
161
+
162
+ #:stopdoc:
163
+ # Used by NWN::Gff::Struct#by_flat_path
164
+ def each_by_flat_path &block
165
+ case field_type
166
+ when :cexolocstr
167
+ yield("", self)
168
+ field_value.sort.each {|lid, str|
169
+ yield("/" + lid.to_s, str)
170
+ }
171
+
172
+ when :struct
173
+ yield("", self)
174
+ field_value.each_by_flat_path {|v, x|
175
+ yield(v, x)
176
+ }
177
+
178
+ when :list
179
+ yield("", self)
180
+ field_value.each_with_index {|item, index|
181
+ yield("[" + index.to_s + "]", item)
182
+ item.each_by_flat_path("/") {|v, x|
183
+ yield("[" + index.to_s + "]" + v, x)
184
+ }
185
+ }
186
+
187
+ else
188
+ yield("", self)
189
+ end
190
+ end
191
+ #:startdoc:
192
+
161
193
  end
@@ -67,7 +67,7 @@ class NWN::Gff::Reader
67
67
 
68
68
  # This iterates through a struct and reads all fields into a hash, which it returns.
69
69
  def read_struct index, file_type = nil, file_version = nil
70
- struct = {}.taint
70
+ struct = {}
71
71
  struct.extend(NWN::Gff::Struct)
72
72
 
73
73
  type = @structs[index * 3]
@@ -101,9 +101,7 @@ class NWN::Gff::Reader
101
101
 
102
102
  # Reads the field at +index+ and returns [label_name, Gff::Field]
103
103
  def read_field index, parent_of
104
- gff = {}
105
-
106
- field = {}.taint
104
+ field = {}
107
105
  field.extend(NWN::Gff::Field)
108
106
 
109
107
  index *= 3
@@ -184,7 +182,7 @@ class NWN::Gff::Reader
184
182
  len = total_size + 4
185
183
  # Filter out empty strings.
186
184
  exostr.reject! {|k,v| v.nil? || v.empty?}
187
- exostr.taint
185
+ exostr
188
186
 
189
187
  when :void
190
188
  len = @field_data[data_or_offset, 4].unpack("V")[0]
@@ -215,7 +213,7 @@ class NWN::Gff::Reader
215
213
  list << read_struct(@list_indices[i], field.path, field.parent.data_version)
216
214
  end
217
215
 
218
- list.taint
216
+ list
219
217
 
220
218
  end
221
219
 
@@ -226,7 +224,7 @@ class NWN::Gff::Reader
226
224
  [value].compact.flatten.each {|iv|
227
225
  iv.element = field if iv.respond_to?('element=')
228
226
  }
229
- field['value'] = value.taint
227
+ field['value'] = value
230
228
 
231
229
  # We extend all fields and field_values with matching classes.
232
230
  field.extend_meta_classes
@@ -104,4 +104,100 @@ module NWN::Gff::Struct
104
104
  def to_s
105
105
  "<NWN::Gff::Struct #{self.data_type}/#{self.data_version}, #{self.keys.size} fields>"
106
106
  end
107
+
108
+
109
+ # Iterates this struct, yielding flat, absolute
110
+ # paths and the Gff::Field for each element found.
111
+
112
+ # Example:
113
+ # "/AddCost" => {"type"=>:dword, ..}
114
+ def each_by_flat_path prefix = "/", &block
115
+ sort.each {|label, field|
116
+ field.each_by_flat_path do |ll, lv|
117
+ yield(prefix + label + ll, lv)
118
+ end
119
+ }
120
+ end
121
+
122
+ # Retrieve an object from within the given tree.
123
+ # Path is a slash-separated destination, given as
124
+ # a string
125
+ #
126
+ # Prefixed/postfixed slashes are optional.
127
+ #
128
+ # You can retrieve CExoLocString values by giving the
129
+ # language ID as the last label:
130
+ # /FirstName/0
131
+ #
132
+ # You can retrieve list values by specifying the index
133
+ # in square brackets:
134
+ # /SkillList[0]
135
+ # /SkillList[0]/Rank => {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}
136
+ #
137
+ # You can directly retrieve field values and types
138
+ # instead of the field itself:
139
+ # /SkillList[0]/Rank$ => 0
140
+ # /SkillList[0]/Rank? => :byte
141
+ #
142
+ # This will raise an error for non-field paths, naturally:
143
+ # SkillList[0]$ => undefined method `field_value' for {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}:Hash
144
+ # SkillList[0]? => undefined method `field_type' for {"Rank"=>{"label"=>"Rank", "value"=>0, "type"=>:byte}}:Hash
145
+ #
146
+ # For CExoLocStrings, you can retrieve the str_ref:
147
+ # FirstName% => 4294967295
148
+ # This will return DEFAULT_STR_REF (0xffffffff) if the given path does not have
149
+ # a str_ref.
150
+ def by_path path
151
+ struct = self
152
+ current_path = ""
153
+ path = path.split('/').map {|v| v.strip }.reject {|v| v.empty?}.join('/')
154
+
155
+ path, mod = $1, $2 if path =~ /^(.+?)([\$\?%])?$/
156
+
157
+ path.split('/').each_with_index {|v, path_index|
158
+ if struct.is_a?(NWN::Gff::Field) && struct.field_type == :cexolocstr &&
159
+ v =~ /^\d+$/ && path_index == path.split('/').size - 1
160
+ struct = struct.field_value[v.to_i]
161
+ break
162
+ end
163
+
164
+ v, index = $1, $2 if v =~ /^(.+?)\[(\d+)\]$/
165
+
166
+ struct = struct.v if struct.is_a?(NWN::Gff::Field) &&
167
+ struct.field_type == :struct
168
+
169
+ struct = struct[v]
170
+ if index
171
+ struct.field_type == :list or raise NWN::Gff::GffPathInvalidError,
172
+ "Specified a list offset for a non-list item: #{v}[#{index}]."
173
+
174
+ struct = struct.field_value[index.to_i]
175
+ end
176
+
177
+
178
+ raise NWN::Gff::GffPathInvalidError,
179
+ "Cannot find a path to /#{path} (at: #{current_path})." unless struct
180
+
181
+ current_path += "/" + v
182
+ current_path += "[#{index}]" if index
183
+ }
184
+
185
+ case mod
186
+ when "$"
187
+ struct.field_value
188
+ when "?"
189
+ struct.field_type
190
+ when "%"
191
+ struct.has_str_ref? ? struct.str_ref :
192
+ NWN::Gff::Cexolocstr::DEFAULT_STR_REF
193
+ else
194
+ struct
195
+ end
196
+ end
197
+
198
+ # An alias for +by_path+.
199
+ def / path
200
+ by_path(path)
201
+ end
202
+
107
203
  end
@@ -3,7 +3,7 @@
3
3
  # Include this if you want to eval nwn-gff-dsl scripts.
4
4
  module NWN::Gff::Scripting
5
5
 
6
- class Sandbox
6
+ class Sandbox #:nodoc:
7
7
  include NWN
8
8
  include NWN::Gff::Scripting
9
9
  end
@@ -99,11 +99,13 @@ module NWN::Gff::Scripting
99
99
  # If only a filename/string is given and no further arguments,
100
100
  # the read object will be returned as-is.
101
101
  def satisfy *what
102
+ close_me = false
102
103
  if $standalone
103
104
  fn = what.shift
104
105
  io = case fn
105
106
  when String
106
- File.new(fn, "r")
107
+ close_me = true
108
+ File.new(fn, "rb")
107
109
  when IO
108
110
  fn
109
111
  else
@@ -112,7 +114,12 @@ module NWN::Gff::Scripting
112
114
  # "`need', `want' and `satisfy' need a filename or a IO " +
113
115
  # "object to read from (usually the first script argument)."
114
116
  end
115
- obj = NWN::Gff.read(io, NWN::Gff.guess_file_format(fn))
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
116
123
  log "satisfied #{fn} -> #{obj.to_s}"
117
124
  $satisfy_loaded[obj.object_id] = [fn, obj.hash]
118
125
 
@@ -132,7 +132,7 @@ module NWN
132
132
  data.each_with_index {|row, idx|
133
133
  id = row.shift
134
134
 
135
- NWN.log_debug "Warning: invalid ID in line #{idx}: #{id.inspect}" if $id !~ /^\d+$/
135
+ NWN.log_debug "Warning: invalid ID in line #{idx}: #{id.inspect}" if id !~ /^\d+$/
136
136
 
137
137
  id = id.to_i + id_offset
138
138
 
@@ -310,7 +310,7 @@ module NWN
310
310
 
311
311
  # Set the file system path spec where all 2da files reside.
312
312
  # Call this on application startup.
313
- # path spec is a colon-separated list of pathes, just like $PATH.
313
+ # path spec is a colon-separated list of paths, just like $PATH.
314
314
  def self.setup root_directories
315
315
  @_roots = root_directories.split(':').compact.reject {|x| "" == x.strip }
316
316
  end
@@ -74,7 +74,7 @@ end
74
74
 
75
75
  # This parses the struct and extends all fields with their proper type.
76
76
  YAML.add_domain_type(NWN::YAML_DOMAIN,'struct') {|t,hash|
77
- struct = {}.taint
77
+ struct = {}
78
78
  struct.extend(NWN::Gff::Struct)
79
79
 
80
80
  # The metadata
@@ -96,7 +96,7 @@ YAML.add_domain_type(NWN::YAML_DOMAIN,'struct') {|t,hash|
96
96
  element.extend_meta_classes
97
97
  element.validate
98
98
 
99
- struct[label] = element.taint
99
+ struct[label] = element
100
100
  }
101
101
 
102
102
  struct
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nwn-lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: 0.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernhard Stoeckner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-30 00:00:00 +02:00
12
+ date: 2009-07-19 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -25,6 +25,7 @@ extensions: []
25
25
  extra_rdoc_files:
26
26
  - README
27
27
  - BINARIES
28
+ - HOWTO
28
29
  - SCRIPTING
29
30
  - SETTINGS
30
31
  - CHEATSHEET
@@ -35,51 +36,51 @@ files:
35
36
  - CHANGELOG
36
37
  - README
37
38
  - Rakefile
38
- - bin/nwn-gff
39
39
  - bin/nwn-dsl
40
- - bin/nwn-erf
40
+ - bin/nwn-gff
41
41
  - bin/nwn-irb
42
- - spec/bin_dsl_spec.rb
42
+ - bin/nwn-erf
43
+ - spec/wellformed_gff.bic
43
44
  - spec/gff_spec.rb
44
- - spec/bin_gff_spec.rb
45
- - spec/bin_erf_spec.rb
45
+ - spec/res_spec.rb
46
+ - spec/spec.opts
47
+ - spec/erf_spec.rb
46
48
  - spec/field_spec.rb
47
49
  - spec/cexolocstr_spec.rb
48
- - spec/erf_spec.rb
49
50
  - spec/struct_spec.rb
50
- - spec/spec.opts
51
- - spec/res_spec.rb
51
+ - spec/spec_helper.rb
52
52
  - spec/tlk_spec.rb
53
+ - spec/bin_dsl_spec.rb
54
+ - spec/bin_gff_spec.rb
53
55
  - spec/rcov.opts
56
+ - spec/bin_erf_spec.rb
54
57
  - spec/twoda_spec.rb
55
- - spec/spec_helper.rb
56
- - spec/wellformed_gff.bic
57
- - lib/nwn/erf.rb
58
- - lib/nwn/io.rb
59
- - lib/nwn/settings.rb
58
+ - lib/nwn/scripting.rb
60
59
  - lib/nwn/yaml.rb
61
- - lib/nwn/all.rb
62
- - lib/nwn/res.rb
63
60
  - lib/nwn/twoda.rb
64
- - lib/nwn/tlk.rb
61
+ - lib/nwn/erf.rb
62
+ - lib/nwn/settings.rb
65
63
  - lib/nwn/gff.rb
64
+ - lib/nwn/tlk.rb
65
+ - lib/nwn/io.rb
66
+ - lib/nwn/res.rb
66
67
  - lib/nwn/kivinen.rb
67
- - lib/nwn/scripting.rb
68
- - lib/nwn/gff/api.rb
69
- - lib/nwn/gff/writer.rb
70
- - lib/nwn/gff/struct.rb
71
- - lib/nwn/gff/list.rb
68
+ - lib/nwn/all.rb
69
+ - lib/nwn/gff/field.rb
72
70
  - lib/nwn/gff/reader.rb
73
71
  - lib/nwn/gff/cexolocstr.rb
74
- - lib/nwn/gff/field.rb
72
+ - lib/nwn/gff/struct.rb
73
+ - lib/nwn/gff/list.rb
74
+ - lib/nwn/gff/writer.rb
75
75
  - tools/verify.sh
76
76
  - tools/migrate_03x_to_04x.sh
77
77
  - scripts/truncate_floats.rb
78
+ - scripts/reformat_2da
78
79
  - scripts/clean_locstrs.rb
79
- - scripts/debug_check_objid.rb
80
80
  - scripts/extract_all_items.rb
81
- - scripts/reformat_2da
81
+ - scripts/debug_check_objid.rb
82
82
  - BINARIES
83
+ - HOWTO
83
84
  - SCRIPTING
84
85
  - SETTINGS
85
86
  - CHEATSHEET
@@ -1,88 +0,0 @@
1
-
2
- module NWN::Gff::Field
3
- #:stopdoc:
4
- # Used by NWN::Gff::Struct#by_flat_path
5
- def each_by_flat_path &block
6
- case field_type
7
- when :cexolocstr
8
- yield("", self)
9
- field_value.sort.each {|lid, str|
10
- yield("/" + lid.to_s, str)
11
- }
12
-
13
- when :struct
14
- yield("", self)
15
- field_value.each_by_flat_path {|v, x|
16
- yield(v, x)
17
- }
18
-
19
- when :list
20
- yield("", self)
21
- field_value.each_with_index {|item, index|
22
- yield("[" + index.to_s + "]", item)
23
- item.each_by_flat_path("/") {|v, x|
24
- yield("[" + index.to_s + "]" + v, x)
25
- }
26
- }
27
-
28
- else
29
- yield("", self)
30
- end
31
- end
32
- #:startdoc:
33
- end
34
-
35
- module NWN::Gff::Struct
36
-
37
- # Iterates this struct, yielding flat, absolute
38
- # pathes and the Gff::Field for each element found.
39
-
40
- # Example:
41
- # "/AddCost" => {"type"=>:dword, ..}
42
- def each_by_flat_path prefix = "/", &block
43
- sort.each {|label, field|
44
- field.each_by_flat_path do |ll, lv|
45
- yield(prefix + label + ll, lv)
46
- end
47
- }
48
- end
49
-
50
- # Retrieve an object from within the given tree.
51
- # Path is a slash-separated destination, given as
52
- # a string
53
- #
54
- # Prefixed/postfixed slashes are optional.
55
- #
56
- # Examples:
57
- # /
58
- # /AddCost
59
- # /PropertiesList/
60
- # /PropertiesList[0]/CostValue
61
- def by_path path
62
- struct = self
63
- current_path = ""
64
- path = path.split('/').map {|v| v.strip }.reject {|v| v.empty?}.join('/')
65
-
66
- path.split('/').each {|v|
67
- if v =~ /^(.+?)\[(\d+)\]$/
68
- v, index = $1, $2
69
- end
70
-
71
- struct = struct[v]
72
- if index
73
- struct.field_type == :list or raise NWN::Gff::GffPathInvalidError,
74
- "Specified a list offset for a non-list item: #{v}[#{index}]."
75
-
76
- struct = struct.field_value[index.to_i]
77
- end
78
-
79
- raise NWN::Gff::GffPathInvalidError,
80
- "Cannot find a path to /#{path} (at: /#{current_path})." unless struct
81
-
82
- current_path += v
83
- }
84
-
85
- struct
86
- end
87
-
88
- end