bindata 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bindata might be problematic. Click here for more details.

data/ChangeLog CHANGED
@@ -1,5 +1,12 @@
1
1
  = BinData Changelog
2
2
 
3
+ -== Version 0.8.1 (2008-01-14)
4
+
5
+ * Reduced memory consumption.
6
+ * Increased execution speed.
7
+ * Deprecated BinData::Base.parameters
8
+ * Fixed spec syntax (thanks to David Goodlad)
9
+
3
10
  -== Version 0.8.0 (2007-10-14)
4
11
 
5
12
  * Add reserved field names to Struct.
@@ -1,5 +1,5 @@
1
1
  # BinData -- Binary data manipulator.
2
- # Copyright (c) 2007 Dion Mendel.
2
+ # Copyright (c) 2007,2008 Dion Mendel.
3
3
 
4
4
  require 'bindata/array'
5
5
  require 'bindata/choice'
@@ -10,5 +10,5 @@ require 'bindata/stringz'
10
10
  require 'bindata/struct'
11
11
 
12
12
  module BinData
13
- VERSION = "0.8.0"
13
+ VERSION = "0.8.1"
14
14
  end
@@ -40,6 +40,9 @@ module BinData
40
40
  mandatory_parameter :type
41
41
  optional_parameters :initial_length, :read_until
42
42
 
43
+ # An empty hash shared by all instances
44
+ @@empty_hash = Hash.new.freeze
45
+
43
46
  # Creates a new Array
44
47
  def initialize(params = {}, env = nil)
45
48
  super(cleaned_params(params), env)
@@ -51,7 +54,7 @@ module BinData
51
54
 
52
55
  @element_list = nil
53
56
  @element_klass = klass
54
- @element_params = el_params || {}
57
+ @element_params = el_params || @@empty_hash
55
58
  end
56
59
 
57
60
  # Clears the element at position +index+. If +index+ is not given, then
@@ -133,7 +136,7 @@ module BinData
133
136
  # Returns the appended object, or value in the case of single_values.
134
137
  def append(value = nil)
135
138
  append_new_element
136
- self[self.length - 1] = value unless value.nil?
139
+ self[-1] = value unless value.nil?
137
140
  self.last
138
141
  end
139
142
 
@@ -142,9 +145,9 @@ module BinData
142
145
  def [](*index)
143
146
  data = elements[*index]
144
147
  if data.respond_to?(:each)
145
- data.collect { |el| el.single_value? ? el.value : el }
148
+ data.collect { |el| (el && el.single_value?) ? el.value : el }
146
149
  else
147
- data.single_value? ? data.value : data
150
+ (data && data.single_value?) ? data.value : data
148
151
  end
149
152
  end
150
153
  alias_method :slice, :[]
@@ -172,13 +175,9 @@ module BinData
172
175
  # form returns an empty array.
173
176
  def first(n = nil)
174
177
  if n.nil?
175
- self.length.zero? ? nil : self[0]
178
+ self[0]
176
179
  else
177
- array = []
178
- [n, self.length].min.times do |i|
179
- array.push(self[i])
180
- end
181
- array
180
+ self[0, n]
182
181
  end
183
182
  end
184
183
 
@@ -187,14 +186,10 @@ module BinData
187
186
  # form returns an empty array.
188
187
  def last(n = nil)
189
188
  if n.nil?
190
- self.length.zero? ? nil : self[self.length - 1]
189
+ self[-1]
191
190
  else
192
- array = []
193
- start = self.length - [n, self.length].min
194
- start.upto(self.length - 1) do |i|
195
- array.push(self[i])
196
- end
197
- array
191
+ n = length if n > length
192
+ self[-n, n]
198
193
  end
199
194
  end
200
195
 
@@ -65,6 +65,8 @@ module BinData
65
65
 
66
66
  # Returns both the mandatory and optional parameters used by this class.
67
67
  def parameters
68
+ # warn about deprecated method - remove before releasing 1.0
69
+ warn "warning: #parameters is deprecated."
68
70
  (mandatory_parameters + optional_parameters).uniq
69
71
  end
70
72
 
@@ -112,6 +114,10 @@ module BinData
112
114
  # reference callable objects (methods or procs). +env+ is the
113
115
  # environment that these callable objects are evaluated in.
114
116
  def initialize(params = {}, env = nil)
117
+ # all known parameters
118
+ mandatory = self.class.mandatory_parameters
119
+ optional = self.class.optional_parameters
120
+
115
121
  # default :readwrite param to true if unspecified
116
122
  if not params.has_key?(:readwrite)
117
123
  params = params.dup
@@ -119,22 +125,20 @@ module BinData
119
125
  end
120
126
 
121
127
  # ensure mandatory parameters exist
122
- self.class.mandatory_parameters.each do |prm|
128
+ mandatory.each do |prm|
123
129
  if not params.has_key?(prm)
124
130
  raise ArgumentError, "parameter ':#{prm}' must be specified " +
125
131
  "in #{self}"
126
132
  end
127
133
  end
128
134
 
129
- known_params = self.class.parameters
130
-
131
135
  # partition parameters into known and extra parameters
132
136
  @params = {}
133
137
  extra = {}
134
138
  params.each do |k,v|
135
139
  k = k.to_sym
136
140
  raise ArgumentError, "parameter :#{k} is nil in #{self}" if v.nil?
137
- if known_params.include?(k)
141
+ if mandatory.include?(k) or optional.include?(k)
138
142
  @params[k] = v.freeze
139
143
  else
140
144
  extra[k] = v.freeze
@@ -149,18 +153,22 @@ module BinData
149
153
 
150
154
  # Returns the class matching a previously registered +name+.
151
155
  def klass_lookup(name)
152
- klass = self.class.lookup(name)
153
- if klass.nil? and @env.parent_data_object != nil
154
- # lookup failed so retry in the context of the parent data object
155
- klass = @env.parent_data_object.klass_lookup(name)
156
+ @cache ||= {}
157
+ klass = @cache[name]
158
+ if klass.nil?
159
+ klass = self.class.lookup(name)
160
+ if klass.nil? and @env.parent_data_object != nil
161
+ # lookup failed so retry in the context of the parent data object
162
+ klass = @env.parent_data_object.klass_lookup(name)
163
+ end
164
+ @cache[name] = klass
156
165
  end
157
166
  klass
158
167
  end
159
168
 
160
- # Returns a list of parameters that *weren't* provided to this object.
161
- def unsupplied_parameters
162
- supplied = @params.keys + @env.params.keys
163
- self.class.parameters - supplied
169
+ # Returns a list of parameters that are accepted by this object
170
+ def accepted_parameters
171
+ (self.class.mandatory_parameters + self.class.optional_parameters).uniq
164
172
  end
165
173
 
166
174
  # Reads data into this bin object by calling #do_read then #done_read.
@@ -218,7 +226,7 @@ module BinData
218
226
  # parameter from the +params+ hash used when creating the data object.
219
227
  # +values+ contains data that may be accessed when evaluating +key+.
220
228
  # Returns nil if +key+ does not refer to any parameter.
221
- def eval_param(key, values = {})
229
+ def eval_param(key, values = nil)
222
230
  @env.lazy_eval(@params[key], values)
223
231
  end
224
232
 
@@ -97,9 +97,9 @@ module BinData
97
97
  super || the_choice.respond_to?(symbol, include_private)
98
98
  end
99
99
 
100
- def method_missing(symbol, *args)
100
+ def method_missing(symbol, *args, &block)
101
101
  if the_choice.respond_to?(symbol)
102
- the_choice.__send__(symbol, *args)
102
+ the_choice.__send__(symbol, *args, &block)
103
103
  else
104
104
  super
105
105
  end
@@ -13,23 +13,35 @@ module BinData
13
13
  # parent data object. This makes the lambda easier to read as we just write
14
14
  # <tt>field</tt> instead of <tt>obj.field</tt>.
15
15
  class LazyEvalEnv
16
+ # An empty hash shared by all instances
17
+ @@empty_hash = Hash.new.freeze
18
+
16
19
  # Creates a new environment. +parent+ is the environment of the
17
20
  # parent data object.
18
21
  def initialize(parent = nil)
19
22
  @parent = parent
20
- @variables = {}
21
- @overrides = {}
23
+ @variables = @@empty_hash
24
+ @overrides = @@empty_hash
25
+ @params = @@empty_hash
22
26
  end
23
- attr_reader :parent
24
- attr_accessor :data_object, :params
27
+ attr_reader :parent, :params
28
+ attr_accessor :data_object
25
29
 
26
30
  # only accessible by another LazyEvalEnv
27
31
  protected :data_object
28
32
 
33
+ # Set the parameters for this environment.
34
+ def params=(p)
35
+ @params = (p.nil? or p.empty?) ? @@empty_hash : p
36
+ end
37
+
29
38
  # Add a variable with a pre-assigned value to this environment. +sym+
30
39
  # will be accessible as a variable for any lambda evaluated
31
40
  # with #lazy_eval.
32
41
  def add_variable(sym, value)
42
+ if @variables.equal?(@@empty_hash)
43
+ @variables = {}
44
+ end
33
45
  @variables[sym.to_sym] = value
34
46
  end
35
47
 
@@ -47,15 +59,16 @@ module BinData
47
59
 
48
60
  # Evaluates +obj+ in the context of this environment. Evaluation
49
61
  # recurses until it yields a value that is not a symbol or lambda.
50
- def lazy_eval(obj, overrides = {})
51
- @overrides = overrides
62
+ # +overrides+ is an optional +params+ like hash
63
+ def lazy_eval(obj, overrides = nil)
64
+ @overrides = overrides if overrides
52
65
  if obj.is_a? Symbol
53
66
  # treat :foo as lambda { foo }
54
67
  obj = __send__(obj)
55
68
  elsif obj.respond_to? :arity
56
69
  obj = instance_eval(&obj)
57
70
  end
58
- @overrides = {}
71
+ @overrides = @@empty_hash
59
72
  obj
60
73
  end
61
74
 
@@ -26,8 +26,8 @@ module BinData
26
26
  # class PascalString < BinData::Struct
27
27
  # delegate :data
28
28
  #
29
- # int32le :len, :value => lambda { data.length }
30
- # string :data, :read_length => :len
29
+ # uint8 :len, :value => lambda { data.length }
30
+ # string :data, :read_length => :len
31
31
  # end
32
32
  #
33
33
  # str = PascalString.new
@@ -176,35 +176,46 @@ module BinData
176
176
  all_reserved_methods = delegate.methods + delegate.field_names -
177
177
  all_methods
178
178
 
179
- # move unsupplied params from this object to the delegate object
180
- delegate.unsupplied_parameters.each do |p|
181
- if (v = @env.params.delete(p))
179
+ # move accepted params from this object to the delegate object
180
+ env_params = @env.params.dup
181
+ delegate.accepted_parameters.each do |p|
182
+ if (v = env_params.delete(p))
182
183
  delegate_params[p] = v
183
184
  end
184
185
  end
186
+ @env.params = env_params
185
187
  else
186
188
  # no delegate so all instance methods of Hash are reserved
187
189
  all_reserved_methods = Hash.instance_methods - all_methods
188
190
  end
189
191
 
192
+ # check if field names conflict with any reserved names
193
+ field_names = param(:fields).collect { |f| f[1] }
194
+ field_names_okay = (all_methods & field_names).empty? &&
195
+ (all_reserved_methods & field_names).empty?
196
+
190
197
  # create instances of the fields
191
198
  @fields = param(:fields).collect do |type, name, params|
192
199
  klass = klass_lookup(type)
193
200
  raise TypeError, "unknown type '#{type}' for #{self}" if klass.nil?
194
- if all_methods.include?(name)
195
- raise NameError.new("field '#{name}' shadows an existing method",name)
196
- end
197
- if all_reserved_methods.include?(name)
198
- raise NameError.new("field '#{name}' is a reserved name",name)
201
+ if not field_names_okay
202
+ # at least one field names conflicts so test them all.
203
+ # rationale - #include? is expensive so we avoid it if possible.
204
+ if all_methods.include?(name)
205
+ raise NameError.new("field '#{name}' shadows an existing method",name)
206
+ end
207
+ if all_reserved_methods.include?(name)
208
+ raise NameError.new("field '#{name}' is a reserved name",name)
209
+ end
199
210
  end
200
211
  [name, klass.new(params, create_env)]
201
212
  end
202
213
  end
203
214
 
204
- # Returns a list of parameters that *weren't* provided to this object.
205
- def unsupplied_parameters
215
+ # Returns a list of parameters that are accepted by this object
216
+ def accepted_parameters
206
217
  if delegate_object != nil
207
- delegate_object.unsupplied_parameters
218
+ delegate_object.accepted_parameters
208
219
  else
209
220
  super
210
221
  end
@@ -335,7 +346,7 @@ module BinData
335
346
  delegate_object ? delegate_object.single_value? : false
336
347
  end
337
348
 
338
- def method_missing(symbol, *args)
349
+ def method_missing(symbol, *args, &block)
339
350
  name = symbol.id2name
340
351
 
341
352
  is_writer = (name[-1, 1] == "=")
@@ -352,7 +363,7 @@ module BinData
352
363
  obj
353
364
  end
354
365
  elsif delegate_object.respond_to?(symbol)
355
- delegate_object.__send__(symbol, *args)
366
+ delegate_object.__send__(symbol, *args, &block)
356
367
  else
357
368
  super
358
369
  end
@@ -94,12 +94,12 @@ describe "A data object with parameters" do
94
94
  obj.param(:p3).should respond_to(:arity)
95
95
  end
96
96
 
97
- it "should identify unsupplied parameters" do
97
+ it "should identify accepted parameters" do
98
98
  obj = WithParam.new(:p1 => 1, :p3 => 3, :p4 => 4, :p5 => 5)
99
- obj.unsupplied_parameters.should include(:p2)
100
- obj.unsupplied_parameters.should_not include(:p1)
101
- obj.unsupplied_parameters.should_not include(:p3)
102
- obj.unsupplied_parameters.should_not include(:p4)
99
+ obj.accepted_parameters.should include(:p1)
100
+ obj.accepted_parameters.should include(:p2)
101
+ obj.accepted_parameters.should include(:p3)
102
+ obj.accepted_parameters.should_not include(:p4)
103
103
  end
104
104
  end
105
105
 
@@ -26,7 +26,7 @@ describe "A Struct with hidden fields" do
26
26
  @obj.c = 15
27
27
  @obj.c.should eql(15)
28
28
 
29
- @obj.should respond_to?(:b=)
29
+ @obj.should respond_to(:b=)
30
30
  end
31
31
 
32
32
  it "should not include hidden fields in snapshot" do
@@ -41,7 +41,7 @@ describe "A Struct that delegates" do
41
41
  class DelegateStruct < BinData::Struct
42
42
  delegate :b
43
43
  int8 :a, :initial_value => :num
44
- int8 'b'
44
+ int8 'b', :initial_value => 7
45
45
  int8 :c, :value => :b
46
46
  end
47
47
  END
@@ -50,6 +50,7 @@ describe "A Struct that delegates" do
50
50
 
51
51
  it "should access custom parameters" do
52
52
  @obj.a.should eql(5)
53
+ @obj.b.should eql(7)
53
54
  end
54
55
 
55
56
  it "should have correct num_bytes" do
@@ -66,16 +67,16 @@ describe "A Struct that delegates" do
66
67
  end
67
68
 
68
69
  it "should delegate methods" do
69
- @obj.should respond_to?(:value)
70
- @obj.value = 7
71
- @obj.c.should eql(7)
70
+ @obj.should respond_to(:value)
71
+ @obj.value = 9
72
+ @obj.c.should eql(9)
72
73
  end
73
74
 
74
- it "should identify unsupplied parameters" do
75
- @obj.unsupplied_parameters.should include(:check_value)
76
- @obj.unsupplied_parameters.should include(:initial_value)
77
- @obj.unsupplied_parameters.should include(:value)
78
- @obj.unsupplied_parameters.should_not include(:endian)
75
+ it "should identify accepted parameters" do
76
+ @obj.accepted_parameters.should include(:check_value)
77
+ @obj.accepted_parameters.should include(:initial_value)
78
+ @obj.accepted_parameters.should include(:value)
79
+ @obj.accepted_parameters.should_not include(:endian)
79
80
  end
80
81
 
81
82
  it "should pass params when creating" do
@@ -104,13 +105,14 @@ describe "A Struct with nested delegation" do
104
105
  end
105
106
 
106
107
  it "should forward parameters" do
107
- @obj.should respond_to?(:value)
108
+ @obj.should respond_to(:value)
108
109
  @obj.value.should eql(7)
109
110
  end
110
111
 
111
- it "should identify unsupplied parameters" do
112
- @obj.unsupplied_parameters.should include(:check_value)
113
- @obj.unsupplied_parameters.should include(:value)
112
+ it "should identify accepted parameters" do
113
+ @obj.accepted_parameters.should include(:check_value)
114
+ @obj.accepted_parameters.should include(:initial_value)
115
+ @obj.accepted_parameters.should include(:value)
114
116
  end
115
117
  end
116
118
 
@@ -211,9 +213,9 @@ describe "A Struct with multiple fields" do
211
213
  @obj.num_bytes.should eql(2)
212
214
  end
213
215
 
214
- it "should identify unsupplied parameters" do
215
- @obj.unsupplied_parameters.should include(:delegate)
216
- @obj.unsupplied_parameters.should include(:endian)
216
+ it "should identify accepted parameters" do
217
+ @obj.accepted_parameters.should include(:delegate)
218
+ @obj.accepted_parameters.should include(:endian)
217
219
  end
218
220
 
219
221
  it "should clear" do
metadata CHANGED
@@ -1,33 +1,26 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
3
- specification_version: 1
4
2
  name: bindata
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.8.0
7
- date: 2007-10-14 00:00:00 +08:00
8
- summary: A declarative way to read and write binary file formats
9
- require_paths:
10
- - lib
11
- email: dion@lostrealm.com
12
- homepage: http://bindata.rubyforge.org
13
- rubyforge_project: bindata
14
- description:
15
- autorequire: bindata
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.8.1
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Dion Mendel
8
+ autorequire: bindata
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-01-14 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: dion@lostrealm.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
31
24
  files:
32
25
  - COPYING
33
26
  - GPL
@@ -49,7 +42,6 @@ files:
49
42
  - spec/struct_spec.rb
50
43
  - spec/float_spec.rb
51
44
  - lib/bindata
52
- - lib/bindata.rb
53
45
  - lib/bindata/int.rb
54
46
  - lib/bindata/string.rb
55
47
  - lib/bindata/base.rb
@@ -61,20 +53,35 @@ files:
61
53
  - lib/bindata/lazy.rb
62
54
  - lib/bindata/single.rb
63
55
  - lib/bindata/float.rb
64
- test_files: []
65
-
56
+ - lib/bindata.rb
57
+ has_rdoc: true
58
+ homepage: http://bindata.rubyforge.org
59
+ post_install_message:
66
60
  rdoc_options:
67
61
  - README
68
62
  - lib/bindata
69
63
  - -m
70
64
  - README
71
- extra_rdoc_files: []
72
-
73
- executables: []
74
-
75
- extensions: []
76
-
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
77
79
  requirements: []
78
80
 
79
- dependencies: []
81
+ rubyforge_project: bindata
82
+ rubygems_version: 1.0.1
83
+ signing_key:
84
+ specification_version: 2
85
+ summary: A declarative way to read and write binary file formats
86
+ test_files: []
80
87