nwn-lib 0.4.6 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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