nwn-lib 0.4.6 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
data/spec/gff_spec.rb CHANGED
@@ -1,11 +1,38 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
- WELLFORMED_GFF = IO.read(File.dirname(__FILE__) + "/wellformed_gff.binary").freeze
3
+ describe "Gff.read/write API" do
4
+ it "reads correctly" do
5
+ i = StringIO.new WELLFORMED_GFF
6
+ g = Gff.read(i, :gff)
7
+ end
8
+
9
+ it "writes correctly" do
10
+ i = StringIO.new WELLFORMED_GFF
11
+ gff = Gff.read(i, :gff)
12
+
13
+ out = StringIO.new
14
+ ret = Gff.write(out, :gff, gff)
15
+ ret.should == out.size
16
+ end
17
+
18
+ {
19
+ :gff => %w{utc utd ute uti utm utp uts utt utw git are gic mod ifo fac ssf dlg itp bic},
20
+ :yaml => %w{yml yaml},
21
+ :kivinen => %w{k kivinen},
22
+ :marshal => %w{marshal}
23
+ }.each {|expect, arr|
24
+ arr.each {|ext|
25
+ it "guesses the file format #{expect} for extension #{ext} correctly" do
26
+ Gff.guess_file_format("xxy.#{ext}").should == expect
27
+ end
28
+ }
29
+ }
30
+ end
4
31
 
5
32
  describe "Gff::*" do
6
33
 
7
34
  def wellformed_verify binary
8
- t = Gff::Reader.read(binary)
35
+ t = Gff::Reader.read(StringIO.new binary)
9
36
  end
10
37
 
11
38
  it "reads wellformed GFF data" do
@@ -13,10 +40,26 @@ describe "Gff::*" do
13
40
  end
14
41
 
15
42
  it "reproduces correct GFF binary data" do
16
- t = Gff::Reader.read(WELLFORMED_GFF)
43
+ t = Gff::Reader.read(StringIO.new WELLFORMED_GFF)
17
44
  v = Gff::Writer.dump(t)
18
45
  t2 = wellformed_verify v
19
46
  t2.should == t
20
47
  end
21
48
 
49
+ it "writes to io and returns the number of written bytes" do
50
+ t = Gff::Reader.read(StringIO.new WELLFORMED_GFF)
51
+ out = StringIO.new
52
+ v = Gff::Writer.dump(t, out)
53
+ v.should == out.size
54
+ out.seek(0)
55
+ v = out.read(v)
56
+ t2 = wellformed_verify v
57
+ t2.should == t
58
+ end
59
+
60
+ it "fails on not enough data" do
61
+ proc {wellformed_verify WELLFORMED_GFF[0 .. -2] }.should
62
+ raise_error IOError, "cannot read list_indices"
63
+ end
64
+
22
65
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'rubygems'
2
+ require 'tempfile'
3
+ require 'open3'
2
4
 
3
5
  Thread.abort_on_exception = true
4
6
 
@@ -22,3 +24,175 @@ GffFieldValidations = {
22
24
  :short => [[-0x8000, 0x7fff], [-0x8001, 0x7fff + 1]],
23
25
  :word => [[0, 0xffff], [-1, 0xffff + 1]],
24
26
  }.freeze
27
+
28
+ WELLFORMED_GFF_PATH = File.join(File.expand_path(File.dirname(__FILE__)), "wellformed_gff.bic").freeze
29
+ WELLFORMED_GFF = IO.read(WELLFORMED_GFF_PATH).freeze
30
+
31
+ WELLFORMED_ERF = ([
32
+ "HAK", "V1.0",
33
+ locstr_count = 1, locstr_size = 14,
34
+ entry_count = 3,
35
+ offset_to_locstr = 160,
36
+ offset_to_keys = offset_to_locstr + locstr_size,
37
+ offset_to_res = offset_to_locstr + locstr_size + entry_count * (16 + 4 + 2 + 2),
38
+
39
+ 100, 126, # year, dayofyear
40
+ 0xdeadbeef, "" #description strref, 116 bytes 0-padding
41
+ ].pack("A4 A4 VV VV VV VV V a116") + [
42
+ 0, 6, "abcdef" # one locstr
43
+ ].pack("V V a*") + [
44
+ "resref", 0, 10, 0, # keylist: resref.txt, id = 0
45
+ "help", 1, 1, 0, # keylist: help.bmp, id = 1
46
+ "yegods", 2, 4, 0, # keylist: yegods.wav, id = 2
47
+ ].pack("a16 V v v" * entry_count) + [
48
+ offset_to_res + entry_count * 8, 6, # offset, size
49
+ offset_to_res + entry_count * 8 + 6, 4, # offset, size
50
+ offset_to_res + entry_count * 8 + 6 + 4, 6, # offset, size
51
+ ].pack("II" * entry_count) + [
52
+ "resref", "help", "yegods"
53
+ ].pack("a* a* a*")).freeze
54
+
55
+ WELLFORMED_ERF_11 = ([
56
+ "HAK", "V1.1",
57
+ locstr_count = 1, locstr_size = 14,
58
+ entry_count = 3,
59
+ offset_to_locstr = 160,
60
+ offset_to_keys = offset_to_locstr + locstr_size,
61
+ offset_to_res = offset_to_locstr + locstr_size + entry_count * (32 + 4 + 2 + 2),
62
+
63
+ 100, 126, # year, dayofyear
64
+ 0xdeadbeef, "" #description strref, 116 bytes 0-padding
65
+ ].pack("A4 A4 VV VV VV VV V a116") + [
66
+ 0, 6, "abcdef" # one locstr
67
+ ].pack("V V a*") + [
68
+ "resref", 0, 10, 0, # keylist: resref.txt, id = 0
69
+ "help", 1, 1, 0, # keylist: help.bmp, id = 1
70
+ "yegods", 2, 4, 0, # keylist: yegods.wav, id = 2
71
+ ].pack("a32 V v v" * entry_count) + [
72
+ offset_to_res + entry_count * 8, 6, # offset, size
73
+ offset_to_res + entry_count * 8 + 6, 4, # offset, size
74
+ offset_to_res + entry_count * 8 + 6 + 4, 6, # offset, size
75
+ ].pack("II" * entry_count) + [
76
+ "resref", "help", "yegods"
77
+ ].pack("a* a* a*")).freeze
78
+
79
+ WELLFORMED_TLK = ([
80
+ "TLK", "V3.0",
81
+ language_id = 0,
82
+ string_count = 5,
83
+ offset_to_str = 21,
84
+ ].pack("a4 a4 I I I") + [ # string data table
85
+ # flags, soundresref, volvariance, pitchvariance, offset_to_str, sz, soundlen
86
+ 0x1, "", 0, 0, -1 + 40 * string_count, 1, 0.0,
87
+ 0x3, "textsnd", 0, 0, -1 + 40 * string_count + 1, 2, 0.0,
88
+ 0x7, "textsndlen", 0, 0, -1 + 40 * string_count + 3, 3, 2.0,
89
+ 0x1, "", 0, 0, -1 + 40 * string_count + 6, 4, 0.0,
90
+ 0x2, "justsnd", 0, 0, -1 + 40 * string_count + 10, 0, 0.0,
91
+ ].pack("I A16 I I I I f" * string_count) + [
92
+ "1", "22", "333", "4444"
93
+ ].join("")).freeze
94
+
95
+ TWODA_WELLFORMED = <<-EOT
96
+ 2DA V2.0
97
+
98
+ Col1 Col2
99
+ 0 a b
100
+ 1 c d
101
+ EOT
102
+
103
+ TWODA_MISALIGNED = <<-EOT
104
+ 2DA V2.0
105
+
106
+ Col1
107
+ 0 a
108
+ 1 b
109
+ 2 c
110
+ 3 d
111
+ 4 e
112
+ 6 f
113
+ 2 g
114
+ 7 h
115
+ EOT
116
+
117
+ TWODA_WHITESPACE = <<-EOT
118
+ 2DA V2.0
119
+
120
+
121
+ Col1
122
+ 0 4
123
+ EOT
124
+
125
+ TWODA_MISSING_COLUMN = <<-EOT
126
+ 2DA V2.0
127
+
128
+ Col1 Col2 Col3
129
+ 0 a1 b1 c1
130
+ 1 a2 b2
131
+ EOT
132
+
133
+ TWODA_TOO_MANY_CELLS = <<-EOT
134
+ 2DA V2.0
135
+
136
+ Col1
137
+ 0 a1 b1 c1
138
+ 1 a2 b2
139
+ 2 "a2 b2 c1"
140
+ EOT
141
+
142
+
143
+ TWODA_EMPTY_AND_QUOTES = <<-EOT
144
+ 2DA V2.0
145
+
146
+ Col1 Col2
147
+ 0 **** b
148
+ 1 c d
149
+ 2 "" f
150
+ 3 "g g" h
151
+ EOT
152
+
153
+ TWODA_MISSING_ID = <<-EOT
154
+ 2DA V2.0
155
+
156
+ Col1
157
+ a
158
+ 0 b
159
+ 1 c
160
+ 2 d
161
+ EOT
162
+
163
+ describe "bin helper", :shared => true do
164
+ before do
165
+ @tmp = Dir.tmpdir
166
+ end
167
+
168
+ def run_bin *va
169
+ binary = File.join(File.expand_path(File.dirname(__FILE__)), "..", "bin", subject.to_s)
170
+ incl = File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
171
+ old = Dir.pwd
172
+ begin
173
+ Dir.chdir(@tmp)
174
+ Open3.popen3(
175
+ "ruby", "-I#{incl}",
176
+ binary,
177
+ *va
178
+ ) do |i,o,e|
179
+ yield i, o, e
180
+ end
181
+ ensure
182
+ Dir.chdir(old)
183
+ end
184
+ end
185
+
186
+ def run *va
187
+ run_bin *va do |i, o, e|
188
+ e = e.read
189
+ e.should == ""
190
+ end
191
+ end
192
+
193
+ def run_fail *va
194
+ run_bin *va do |i, o, e|
195
+ e.read.size.should > 0
196
+ end
197
+ end
198
+ end
data/spec/struct_spec.rb CHANGED
@@ -58,4 +58,25 @@ describe "Gff::Struct" do
58
58
  end
59
59
  }
60
60
 
61
+ it "returns proper fields" do
62
+ t = Gff::Reader.read(StringIO.new WELLFORMED_GFF)
63
+ t['Plot'].should respond_to :t
64
+ t['Plot'].should respond_to :l
65
+ t['Plot'].should respond_to :v
66
+ t['Plot'].l.should == "Plot"
67
+ t['Plot'].t.should == :byte
68
+ end
69
+
70
+ it "yields all and correct values in each_by_flat_path" do
71
+ t = Gff::Reader.read(StringIO.new WELLFORMED_GFF)
72
+ t.each_by_flat_path do |k,v|
73
+ k.class.should == String
74
+ k.should =~ %r{^/}
75
+ end
76
+ end
77
+
78
+ it "responds_to to_gff" do
79
+ t = Gff::Reader.read(StringIO.new WELLFORMED_GFF)
80
+ Gff::Reader.read(StringIO.new t.to_gff).should == t
81
+ end
61
82
  end
data/spec/tlk_spec.rb CHANGED
@@ -1,22 +1,5 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
- WELLFORMED_TLK = ([
4
- "TLK", "V3.0",
5
- language_id = 0,
6
- string_count = 5,
7
- offset_to_str = 21,
8
- ].pack("a4 a4 I I I") + [ # string data table
9
- # flags, soundresref, volvariance, pitchvariance, offset_to_str, sz, soundlen
10
- 0x1, "", 0, 0, -1 + 40 * string_count, 1, 0.0,
11
- 0x3, "textsnd", 0, 0, -1 + 40 * string_count + 1, 2, 0.0,
12
- 0x7, "textsndlen", 0, 0, -1 + 40 * string_count + 3, 3, 2.0,
13
- 0x1, "", 0, 0, -1 + 40 * string_count + 6, 4, 0.0,
14
- 0x2, "justsnd", 0, 0, -1 + 40 * string_count + 10, 0, 0.0,
15
- ].pack("I A16 I I I I f" * string_count) + [
16
- "1", "22", "333", "4444"
17
- ].join("")).freeze
18
-
19
-
20
3
  describe "Tlk::Tlk" do
21
4
 
22
5
  def wellformed_verify binary
data/spec/twoda_spec.rb CHANGED
@@ -1,73 +1,5 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
- TWODA_WELLFORMED = <<-EOT
4
- 2DA V2.0
5
-
6
- Col1 Col2
7
- 0 a b
8
- 1 c d
9
- EOT
10
-
11
- TWODA_MISALIGNED = <<-EOT
12
- 2DA V2.0
13
-
14
- Col1
15
- 0 a
16
- 1 b
17
- 2 c
18
- 3 d
19
- 4 e
20
- 6 f
21
- 2 g
22
- 7 h
23
- EOT
24
-
25
- TWODA_WHITESPACE = <<-EOT
26
- 2DA V2.0
27
-
28
-
29
- Col1
30
- 0 4
31
- EOT
32
-
33
- TWODA_MISSING_COLUMN = <<-EOT
34
- 2DA V2.0
35
-
36
- Col1 Col2 Col3
37
- 0 a1 b1 c1
38
- 1 a2 b2
39
- EOT
40
-
41
- TWODA_TOO_MANY_CELLS = <<-EOT
42
- 2DA V2.0
43
-
44
- Col1
45
- 0 a1 b1 c1
46
- 1 a2 b2
47
- 2 "a2 b2 c1"
48
- EOT
49
-
50
-
51
- TWODA_EMPTY_AND_QUOTES = <<-EOT
52
- 2DA V2.0
53
-
54
- Col1 Col2
55
- 0 **** b
56
- 1 c d
57
- 2 "" f
58
- 3 "g g" h
59
- EOT
60
-
61
- TWODA_MISSING_ID = <<-EOT
62
- 2DA V2.0
63
-
64
- Col1
65
- a
66
- 0 b
67
- 1 c
68
- 2 d
69
- EOT
70
-
71
3
  describe TwoDA::Table do
72
4
 
73
5
  it "parses wellformed files" do
File without changes
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.6
4
+ version: 0.4.7
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-05-18 00:00:00 +02:00
12
+ date: 2009-05-26 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -39,9 +39,9 @@ files:
39
39
  - bin/nwn-gff
40
40
  - bin/nwn-irb
41
41
  - bin/nwn-erf
42
+ - spec/wellformed_gff.bic
42
43
  - spec/gff_spec.rb
43
44
  - spec/res_spec.rb
44
- - spec/wellformed_gff.binary
45
45
  - spec/spec.opts
46
46
  - spec/erf_spec.rb
47
47
  - spec/field_spec.rb
@@ -49,7 +49,10 @@ files:
49
49
  - spec/struct_spec.rb
50
50
  - spec/spec_helper.rb
51
51
  - spec/tlk_spec.rb
52
+ - spec/bin_dsl_spec.rb
53
+ - spec/bin_gff_spec.rb
52
54
  - spec/rcov.opts
55
+ - spec/bin_erf_spec.rb
53
56
  - spec/twoda_spec.rb
54
57
  - lib/nwn
55
58
  - lib/nwn/scripting.rb
@@ -62,7 +65,6 @@ files:
62
65
  - lib/nwn/res.rb
63
66
  - lib/nwn/kivinen.rb
64
67
  - lib/nwn/all.rb
65
- - lib/nwn/helpers.rb
66
68
  - lib/nwn/gff
67
69
  - lib/nwn/gff/field.rb
68
70
  - lib/nwn/gff/reader.rb
data/lib/nwn/helpers.rb DELETED
@@ -1,153 +0,0 @@
1
- require 'nwn/gff'
2
- require 'nwn/twoda'
3
-
4
- module NWN
5
- module Gff
6
-
7
- module Helpers
8
- # This sets up the IPRP cache. Used internally; no need to call this yourself.
9
- def self._ip_cache_setup #:nodoc:
10
- return if defined? @costtables
11
- @costtables = {}
12
- @paramtables = {}
13
- @costtable_index = NWN::TwoDA::Cache.get('iprp_costtable')
14
- @paramtable_index = NWN::TwoDA::Cache.get('iprp_paramtable')
15
- @costtable_index.by_col('Name').each_with_index {|p,idx|
16
- next if @costtables[p.downcase]
17
- @costtables[p.downcase] = @costtables[idx] = NWN::TwoDA::Cache.get(p.downcase)
18
- }
19
- @paramtable_index.by_col('TableResRef').each_with_index {|p,idx|
20
- next if @paramtables[p.downcase]
21
- @paramtables[p.downcase] = @paramtables[idx] = NWN::TwoDA::Cache.get(p.downcase)
22
- }
23
- @properties = NWN::TwoDA::Cache.get('itemprops')
24
- @propdef = NWN::TwoDA::Cache.get('itempropdef')
25
- @subtypes = []
26
- @propdef.by_col('SubTypeResRef').each_with_index {|st, idx|
27
- @subtypes[idx] = NWN::TwoDA::Cache.get(st.downcase) if st != "****"
28
- }
29
- @prop_id_to_costtable = []
30
- @propdef.by_col('CostTableResRef').each_with_index {|st, idx|
31
- @prop_id_to_costtable[idx] = st.to_i if st != "****"
32
- }
33
- @prop_id_to_param1 = []
34
- @propdef.by_col('Param1ResRef').each_with_index {|st, idx|
35
- @prop_id_to_param1[idx] = st.to_i if st != "****"
36
- }
37
- end
38
-
39
- def self.resolve_or_match_partial name_spec, list #:nodoc:
40
- name_spec = name_spec.downcase
41
-
42
- raise ArgumentError, "?-expand: #{list.inspect}" if name_spec == '?'
43
-
44
- list.each {|l|
45
- return l if l.downcase == name_spec
46
- }
47
-
48
- substrings = list.select {|l| l.downcase.index(name_spec) }
49
- if substrings.size == 1
50
- return substrings[0]
51
- elsif substrings.size > 1
52
- raise ArgumentError, "Cannot resolve #{name_spec}. Partial matches: #{substrings.inspect}."
53
- end
54
-
55
- raise ArgumentError, "Cannot resolve #{name_spec}."
56
- end
57
-
58
- # This creates a NWN::Gff::Struct describing the item property in question.
59
- #
60
- # [+name+] The iprp name to resolve, for example <tt>Damage_Bonus_vs_Racial_Group</tt>
61
- # [+subtype+] The iprp subtype, for example <tt>Elf</tt>
62
- # [+value+] The iprp value, for example <tt>2d12</tt>
63
- # [+param+] The iprp param1, for example <tt>Acid</tt>
64
- # [+chance+] The iprp appearance chance (whats this?)
65
- #
66
- # Depends on the 2da cache set up correctly.
67
- #
68
- # Note that the given arguments can be resolved with partial matches as well, as long
69
- # as they are unique. (<tt>Fir -> Fire</tt>)
70
- #
71
- # Arguments are case-insensitive.
72
- def self.item_property name, subtype = nil, value = nil, param1 = nil, chance_appear = 100
73
- self._ip_cache_setup
74
-
75
- struct = NWN::Gff::Struct.new
76
-
77
- name = resolve_or_match_partial name, @properties.by_col('Label')
78
- index = @properties.by_col('Label').index(name)
79
- raise ArgumentError, "Cannot find property #{name}" unless index
80
-
81
- raise ArgumentError, "Property #{name} needs subtype of type #{NWN::TwoDA::Cache.get('itempropdef').by_col('SubTypeResRef', index)}, but none given." if
82
- @subtypes[index] && !subtype
83
- raise ArgumentError, "Property #{name} does not need subtype, but subtype given." if
84
- !@subtypes[index] && subtype
85
-
86
- subindex = 255
87
-
88
- if subtype
89
- subtype = resolve_or_match_partial subtype, @subtypes[index].by_col('Label')
90
-
91
- subindex = @subtypes[index].by_col('Label').index(subtype)
92
- raise ArgumentError, "Cannot find subtype #{subtype} for property #{name}" unless
93
- subindex
94
-
95
- raise ArgumentError, "Property #{name} requires a cost value of type #{@costtable_index.by_row(@prop_id_to_costtable[index], 'Name')}, but none given" if
96
- !value && @prop_id_to_costtable[index]
97
- raise ArgumentError, "Property #{name} does not require a cost value, but value given" if
98
- value && !@prop_id_to_costtable[index]
99
- end
100
-
101
- _cost = 255
102
- _cost_value = 0
103
-
104
- if value
105
- ct = @prop_id_to_costtable[index]
106
- value = resolve_or_match_partial value, @costtables[ct.to_i].by_col('Label')
107
-
108
- costvalue = @costtables[ct.to_i].by_col('Label').index(value)
109
- raise ArgumentError, "Cannot find CostValue for #{value}" unless costvalue
110
- _cost = ct
111
- _cost_value = costvalue
112
- end
113
- struct.merge!({
114
- 'CostTable' => Element.new('CostTable', :byte, _cost),
115
- 'CostValue' => Element.new('CostValue', :word, _cost_value)
116
- })
117
-
118
-
119
- raise ArgumentError, "Property #{name} requires a param1 value of type #{@paramtable_index.by_row(@prop_id_to_param1[index], 'TableResRef')}, but none given" if
120
- !param1 && @prop_id_to_param1[index]
121
- raise ArgumentError, "Property #{name} does not require a param1 value, but value given" if
122
- param1 && !@prop_id_to_param1[index]
123
-
124
- _param1 = 255
125
- _param1_value = 0
126
-
127
- if param1
128
- pt = @prop_id_to_param1[index]
129
- param1 = resolve_or_match_partial param1, @paramtables[pt.to_i].by_col('Label')
130
-
131
- param1value = @paramtables[pt.to_i].by_col('Label').index(param1)
132
- raise ArgumentError, "Cannot find Param1 for #{param1}" unless param1value
133
- _param1 = pt
134
- _param1_value = param1value
135
- end
136
- struct.merge!({
137
- 'Param1' => Element.new('Param1', :byte, _param1),
138
- 'Param1Value' => Element.new('Param1Value', :byte, _param1_value)
139
- })
140
-
141
- struct.merge!({
142
- 'PropertyName' => Element.new('PropertyName', :word, index),
143
- 'Subtype' => Element.new('Subtype', :word, subindex),
144
- 'ChanceAppear' => Element.new('ChanceAppear', :byte, chance_appear)
145
- })
146
-
147
- struct.struct_id = 0
148
- struct
149
- end
150
-
151
- end
152
- end
153
- end