nwn-lib 0.4.12 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -21,7 +21,7 @@ module NWN::Gff::Scripting
21
21
  catch(:exit) {
22
22
  begin
23
23
  run_on.instance_eval $code
24
- rescue => e
24
+ rescue
25
25
  raise
26
26
  end
27
27
  }
@@ -1,5 +1,3 @@
1
- require 'iconv'
2
-
3
1
  module NWN
4
2
  SETTING_DEFAULT_VALUES = {
5
3
  'NWN_LIB_IN_ENCODING' => 'ISO-8859-1',
@@ -51,20 +49,12 @@ module NWN
51
49
 
52
50
  # Converts text from native format (such as json) to Gff (required by NWN).
53
51
  def self.iconv_native_to_gff text
54
- if IconvState[:in] != NWN.setting(:in_encoding) ||
55
- IconvState[:out] != NWN.setting(:out_encoding)
56
- IconvState[:in_i] = Iconv.new(NWN.setting(:in_encoding), NWN.setting(:out_encoding))
57
- end
58
- IconvState[:in_i].iconv(text)
52
+ text.encode(NWN.setting(:out_encoding))
59
53
  end
60
54
 
61
55
  # Converts text from Gff format to native/external, such as json (usually UTF-8).
62
56
  def self.iconv_gff_to_native text
63
- if IconvState[:in] != NWN.setting(:in_encoding) ||
64
- IconvState[:out] != NWN.setting(:out_encoding)
65
- IconvState[:out_i] = Iconv.new(NWN.setting(:out_encoding), NWN.setting(:in_encoding))
66
- end
67
- IconvState[:out_i].iconv(text)
57
+ text.encode('UTF-8')
68
58
  end
69
59
  end
70
60
 
@@ -1,5 +1,3 @@
1
- require 'shellwords'
2
-
3
1
  class Integer
4
2
  # Returns the level that this amount experience resolves to.
5
3
  # Depends on a set-up TwoDA::Cache, and reads from <tt>exptable</tt>.
@@ -41,8 +39,17 @@ module NWN
41
39
  end
42
40
 
43
41
  def method_missing meth, *args
44
- if idx = @table.columns.index(meth.to_s.downcase) || idx = @table.columns.index(meth.to_s)
45
- if meth.to_s =~ /=$/
42
+ col = meth.to_s
43
+ assignment = if col =~ /(.+?)=$/
44
+ col = $1
45
+ true
46
+ else
47
+ false
48
+ end
49
+
50
+ if idx = @table.columns.index(col.downcase) ||
51
+ idx = @table.columns.index(col)
52
+ if assignment
46
53
  self[idx] = args.shift or raise ArgumentError,
47
54
  "Need a paramenter for assignments .."
48
55
  else
@@ -120,9 +127,9 @@ module NWN
120
127
 
121
128
  header = data.shift
122
129
 
123
- header = Shellwords.shellwords(header.strip)
130
+ header = colsplit(header.strip)
124
131
  data.map! {|line|
125
- Shellwords.shellwords(line.strip)
132
+ colsplit(line.strip)
126
133
  }
127
134
 
128
135
  new_row_data = []
@@ -277,6 +284,7 @@ module NWN
277
284
  row.each_with_index {|cell, column_idx|
278
285
  cell = "****" if cell == ""
279
286
  cell = '"%s"' % cell if cell =~ /\s/
287
+ cell = cell.to_s
280
288
  rv << cell + " " * (max_cell_size_by_column[column_idx] - cell.size)
281
289
  }
282
290
  ret << rv.join("").rstrip
@@ -296,6 +304,35 @@ module NWN
296
304
  @newline
297
305
  end)
298
306
  end
307
+
308
+ private
309
+
310
+ def colsplit(line)
311
+ line = String.new(line) rescue
312
+ raise(ArgumentError, "Argument must be a string")
313
+ line.lstrip!
314
+ words = []
315
+ until line.empty?
316
+ field = ''
317
+ loop do
318
+ if line.sub!(/\A"(([^"\\]|\\.)*)"/, '') then
319
+ snippet = $1.gsub(/\\(.)/, '\1')
320
+ elsif line =~ /\A"/ then
321
+ raise ArgumentError, "Unmatched double quote: #{line}"
322
+ elsif line.sub!(/\A\\(.)?/, '') then
323
+ snippet = $1 || '\\'
324
+ elsif line.sub!(/\A([^\s\\"]+)/, '') then
325
+ snippet = $1
326
+ else
327
+ line.lstrip!
328
+ break
329
+ end
330
+ field.concat(snippet)
331
+ end
332
+ words.push(field)
333
+ end
334
+ words
335
+ end
299
336
  end
300
337
 
301
338
  # An alias for TwoDA::Cache.get
@@ -312,7 +349,8 @@ module NWN
312
349
  # Call this on application startup.
313
350
  # path spec is a colon-separated list of paths, just like $PATH.
314
351
  def self.setup root_directories
315
- @_roots = root_directories.split(':').compact.reject {|x| "" == x.strip }
352
+ @_roots = root_directories.split(File::PATH_SEPARATOR).
353
+ compact.reject {|x| "" == x.strip }
316
354
  end
317
355
 
318
356
  # Get the 2da file with the given name. +name+ is without extension.
@@ -327,7 +365,7 @@ module NWN
327
365
 
328
366
  def self.read_2da name # :nodoc:
329
367
  @_roots.each {|root|
330
- file = root + '/' + name + '.2da'
368
+ file = root + File::SEPARATOR + name + '.2da'
331
369
  next unless FileTest.exists?(file)
332
370
  return Table.parse(IO.read(file))
333
371
  }
@@ -0,0 +1,3 @@
1
+ module NWN
2
+ VERSION = "0.5.0"
3
+ end
@@ -17,7 +17,7 @@ private
17
17
  struct.data_version != NWN::Gff::Struct::DEFAULT_DATA_VERSION
18
18
  end
19
19
 
20
- struct.sort.each {|(k,v)|
20
+ struct.sort.each {|(*,v)|
21
21
  s << field_to_xml(v)
22
22
  }
23
23
  s
@@ -33,12 +33,12 @@ private
33
33
  e['name'] = field.field_label
34
34
  e['type'] = case @format
35
35
  when :modpacker
36
- NWN::Gff::Types.index(field.field_type).to_s
36
+ NWN::Gff::Types.key(field.field_type).to_s
37
37
  when :nxml
38
38
  field.field_type.to_s
39
39
  end
40
40
 
41
- vv = case field.field_type
41
+ case field.field_type
42
42
  when :cexolocstr
43
43
  case @format
44
44
  when :modpacker
@@ -1,5 +1,6 @@
1
1
  # This file contains all YAML-specific loading and dumping code.
2
2
  require 'yaml'
3
+ Psych::ENGINE.yamler = 'syck'
3
4
 
4
5
  module NWN::Gff::Handler::YAML
5
6
  # These field types can never be inlined in YAML.
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/nwn/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Bernhard Stoeckner"]
6
+ gem.email = ["n@e-ix.net"]
7
+ gem.description = %q{Neverwinter Nights 1/2 file formats ruby library}
8
+ gem.summary = gem.description
9
+ gem.homepage = "https://github.com/niv/nwn-lib"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "nwn-lib"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = NWN::VERSION
17
+ gem.required_ruby_version = '>= 1.9.1'
18
+ end
@@ -1,9 +1,14 @@
1
1
  #!/usr/bin/env nwn-dsl
2
2
  # vim: ft=ruby
3
3
 
4
- ARGV.each {|f|
5
- log "Working on #{f} .."
6
- t = TwoDA::Table.parse(IO.read(f))
7
- File.open(f, "wb") {|n| n.puts t.to_2da }
8
- log "done."
9
- }
4
+ if ARGV.size == 0
5
+ t = TwoDA::Table.parse($stdin.read)
6
+ $stdout.puts t.to_2da
7
+ else
8
+ ARGV.each {|f|
9
+ log "Working on #{f} .."
10
+ t = TwoDA::Table.parse(IO.read(f))
11
+ File.open(f, "wb") {|n| n.puts t.to_2da }
12
+ log "done."
13
+ }
14
+ end
@@ -1,16 +1,16 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
3
  describe "nwn-dsl" do
4
- it_should_behave_like "bin helper"
4
+ include BinHelper
5
5
 
6
6
  it "runs empty scripts" do
7
- t = Tempfile.new(@tmp)
7
+ t = Tempfile.new(["nwn-lib", "dsl"])
8
8
  t.close
9
9
  run(t.path)
10
10
  end
11
11
 
12
12
  it "runs want/need scripts" do
13
- t = Tempfile.new(@tmp)
13
+ t = Tempfile.new(["nwn-lib", "dsl"])
14
14
  t.write("need ARGV.shift, :bic")
15
15
  t.close
16
16
  run_bin(t.path, WELLFORMED_GFF_PATH) do |i,o,e|
@@ -22,7 +22,7 @@ describe "nwn-dsl" do
22
22
  end
23
23
 
24
24
  it "logs to stderr" do
25
- t = Tempfile.new(@tmp)
25
+ t = Tempfile.new(["nwn-lib", "dsl"])
26
26
  t.write("log 'hey'")
27
27
  t.close
28
28
  run_bin(t.path, WELLFORMED_GFF_PATH) do |i,o,e|
@@ -1,38 +1,33 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
3
  describe "nwn-erf" do
4
- it_should_behave_like "bin helper"
5
-
4
+ include BinHelper
6
5
  # Create temporary testcase files.
7
6
  before do
8
- @target = File.join(@tmp, "nwn-lib-spec-target.erf")
7
+ @tmpdir = Dir.mktmpdir
8
+
9
+ @target = File.join(@tmpdir, "nwn-lib-spec-target.erf")
9
10
 
10
11
  @tmp0s = []
11
12
  @tmp1s = []
12
13
  for x in %w{aaa.tga bbbb.erf ccc.bmp 44.txt} do
13
- File.open(File.join(@tmp, x), "w") do |fn|
14
+ File.open(File.join(@tmpdir, x), "w") do |fn|
14
15
  fn.write(x)
15
16
  end
16
- @tmp0s << File.join(@tmp, x)
17
+ @tmp0s << File.join(@tmpdir, x)
17
18
  end
18
19
  for x in %w{bbbbbbbbbbbbbbbbbbbb.bmp} do
19
- File.open(File.join(@tmp, x), "w") do |fn|
20
+ File.open(File.join(@tmpdir, x), "w") do |fn|
20
21
  fn.write(x)
21
22
  end
22
- @tmp1s << File.join(@tmp, x)
23
+ @tmp1s << File.join(@tmpdir, x)
23
24
  end
24
25
  @tmp0s.sort!
25
26
  @tmp1s.sort!
26
27
  end
27
28
 
28
29
  after do
29
- @tmp0s.each {|f|
30
- File.unlink(f.path) rescue nil
31
- }
32
- @tmp1s.each {|f|
33
- File.unlink(f.path) rescue nil
34
- }
35
- File.unlink(@target) rescue nil
30
+ FileUtils.rm_r @tmpdir
36
31
  end
37
32
 
38
33
  it "packs -0" do
@@ -66,35 +61,35 @@ describe "nwn-erf" do
66
61
  it "extracts -0" do
67
62
  run("-c", "-f", @target, *@tmp0s)
68
63
  @tmp0s.each {|f| File.unlink(f) }
69
- run("-v", "-x", "-f", @target)
64
+ run("-x", "-f", @target)
70
65
  @tmp0s.each {|f| FileTest.exists?(f).should == true }
71
- @tmp0s.each {|f| IO.read(f).should == File.basename(f) }
66
+ @tmp0s.each {|f| IO.read(f, :encoding => "BINARY").should == File.basename(f) }
72
67
  end
73
68
 
74
69
  it "extracts -1" do
75
70
  workon = @tmp0s + @tmp1s
76
71
  run("-1", "-c", "-f", @target, *workon)
77
72
  workon.each {|f| File.unlink(f) }
78
- run("-v", "-x", "-f", @target)
73
+ run("-x", "-f", @target)
79
74
  workon.each {|f| FileTest.exists?(f).should == true }
80
- workon.each {|f| IO.read(f).should == File.basename(f) }
75
+ workon.each {|f| IO.read(f, :encoding => "BINARY").should == File.basename(f) }
81
76
  end
82
77
 
83
78
  it "creates haks" do
84
79
  run("-H", "-c", "-f", @target, *@tmp0s)
85
- IO.read(@target).should =~ /^HAK/
80
+ IO.read(@target, :encoding => "BINARY").should =~ /^HAK/
86
81
  end
87
82
 
88
83
  it "creates mods" do
89
84
  run("-M", "-c", "-f", @target, *@tmp0s)
90
- IO.read(@target).should =~ /^MOD/
85
+ IO.read(@target, :encoding => "BINARY").should =~ /^MOD/
91
86
  end
92
87
 
93
88
  it "creates erfs (by default)" do
94
89
  run("-E", "-c", "-f", @target, *@tmp0s)
95
- IO.read(@target).should =~ /^ERF/
90
+ IO.read(@target, :encoding => "BINARY").should =~ /^ERF/
96
91
  run("-c", "-f", @target, *@tmp0s)
97
- IO.read(@target).should =~ /^ERF/
92
+ IO.read(@target, :encoding => "BINARY").should =~ /^ERF/
98
93
  end
99
94
 
100
95
  it "adds files from existing archives" do
@@ -1,7 +1,15 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
3
  describe "nwn-gff" do
4
- it_should_behave_like "bin helper"
4
+ include BinHelper
5
+
6
+ before do
7
+ @tmpdir = Dir.mktmpdir
8
+ end
9
+
10
+ after do
11
+ FileUtils.rm_r(@tmpdir)
12
+ end
5
13
 
6
14
  NWN::Gff::InputFormats.each do |in_format, handler|
7
15
  inf = in_format.to_s
@@ -11,7 +19,7 @@ describe "nwn-gff" do
11
19
 
12
20
  it "converts #{inf} to #{otf}" do
13
21
  # prepare the temp file
14
- t = Tempfile.new(@tmp)
22
+ t = Tempfile.new('nwn-gff', @tmpdir)
15
23
  t.close
16
24
 
17
25
  run("-lg", "-i", WELLFORMED_GFF_PATH, "-k", inf, "-o", t.path)
@@ -22,7 +30,7 @@ describe "nwn-gff" do
22
30
  end
23
31
 
24
32
  it "supports none GNU-style backup" do
25
- t = Tempfile.new(@tmp)
33
+ t = Tempfile.new('nwn-gff', @tmpdir)
26
34
  t.close
27
35
  run("-b", "none", "-lg", "-i", WELLFORMED_GFF_PATH, "-kg", "-o", t.path)
28
36
  FileTest.exists?(t.path).should == true
@@ -30,7 +38,7 @@ describe "nwn-gff" do
30
38
  end
31
39
 
32
40
  it "supports numbered GNU-style backup" do
33
- t = Tempfile.new(@tmp)
41
+ t = Tempfile.new('nwn-gff', @tmpdir)
34
42
  t.close
35
43
 
36
44
  run("-b", "numbered", "-lg", "-i", WELLFORMED_GFF_PATH, "-kg", "-o", t.path)
@@ -49,7 +57,7 @@ describe "nwn-gff" do
49
57
  end
50
58
 
51
59
  it "supports existing with no numbered backups GNU-style backup" do
52
- t = Tempfile.new(@tmp)
60
+ t = Tempfile.new('nwn-gff', @tmpdir)
53
61
  t.close
54
62
 
55
63
  FileTest.exists?(t.path + "~").should == false
@@ -74,7 +82,7 @@ describe "nwn-gff" do
74
82
 
75
83
 
76
84
  it "supports simple GNU-style backup" do
77
- t = Tempfile.new(@tmp)
85
+ t = Tempfile.new('nwn-gff', @tmpdir)
78
86
  t.close
79
87
 
80
88
  FileTest.exists?(t.path + "~").should == false
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
- describe "Erf::Erf", :shared => true do
3
+ shared_examples_for "Erf::Erf" do
4
4
  def wellformed_verify binary, expect_locstr = true
5
5
  t = Erf::Erf.new(StringIO.new binary)
6
6
 
@@ -40,6 +40,7 @@ describe "Erf::Erf", :shared => true do
40
40
  it "reproduces correct ERF binary data" do
41
41
  t = Erf::Erf.new(StringIO.new @erf)
42
42
  io = StringIO.new
43
+ io.set_encoding 'BINARY'
43
44
  t.write_to(io)
44
45
  io.seek(0)
45
46
  n = io.read
@@ -20,4 +20,13 @@ describe "Gff::Field" do
20
20
  NWN.setting(:resref16, nil)
21
21
  end
22
22
  end
23
+
24
+ describe ":void" do
25
+ it "stores data in binary" do
26
+ gff = Gff::Struct.new do |root|
27
+ root.add_void 'Test', "\xde\xad\xbe\xef"
28
+ end.to_gff
29
+ gff.index("\xde\xad\xbe\xef").should_not be_nil
30
+ end
31
+ end
23
32
  end
@@ -20,8 +20,7 @@ describe "Gff.read/write API" do
20
20
  :yaml => %w{yml yaml},
21
21
  :json => %w{json},
22
22
  :nxml => %w{nxml},
23
- :kivinen => %w{k kivinen},
24
- :marshal => %w{marshal}
23
+ :kivinen => %w{k kivinen}
25
24
  }.each {|expect, arr|
26
25
  arr.each {|ext|
27
26
  it "guesses the file format #{expect} for extension #{ext} correctly" do
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
- describe "Key::Key", :shared => true do
3
+ shared_examples_for "Key::Key" do
4
4
  def wellformed_verify binary
5
5
  t = Key::Key.new(StringIO.new(binary), Dir.tmpdir)
6
6
 
@@ -13,7 +13,7 @@ describe "Kivinen Support" do
13
13
  label.should == w[0]
14
14
  case entry
15
15
  when Float
16
- entry.should be_close(w[1], 0.001)
16
+ entry.should be_within(0.001).of(w[1])
17
17
  else
18
18
  entry.should == w[1]
19
19
  end