ffi_dry 0.1.3 → 0.1.4

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.
Files changed (6) hide show
  1. data/History.txt +5 -0
  2. data/Rakefile +3 -2
  3. data/VERSION +1 -1
  4. data/ffi_dry.gemspec +8 -4
  5. data/lib/ffi/dry.rb +116 -24
  6. metadata +15 -4
data/History.txt ADDED
@@ -0,0 +1,5 @@
1
+ === 0.1.4 / 2010-1-1
2
+ * Support for FFI 0.5.0 final and up.
3
+ * Added NetStructHelper with accessors to provide automatic network byte
4
+ order conversion on network packet structures.
5
+
data/Rakefile CHANGED
@@ -7,11 +7,11 @@ begin
7
7
  Jeweler::Tasks.new do |gem|
8
8
  gem.name = "ffi_dry"
9
9
  gem.summary = %Q{Syntactic sugar and helper utilities for FFI}
10
- gem.description = %Q{Provides a some useful modules, classes, and methods as well as a DSL-like syntax for FFI::Struct layouts}
10
+ gem.description = %Q{Provides some useful modules, classes, and methods for FFI bindings as well as a DSL-like syntax for FFI::Struct layouts}
11
11
  gem.email = "emonti@matasano.com"
12
12
  gem.homepage = "http://github.com/emonti/ffi_dry"
13
13
  gem.authors = ["Eric Monti"]
14
- # gem.add_dependency "ffi", ">= 0.5.0"
14
+ gem.add_dependency "ffi", ">= 0.5.0"
15
15
  gem.add_development_dependency "rspec"
16
16
  gem.add_development_dependency "yard"
17
17
  end
@@ -55,6 +55,7 @@ Rake::RDocTask.new do |rdoc|
55
55
  rdoc.rdoc_dir = 'rdoc'
56
56
  rdoc.title = "ffi_dry #{version}"
57
57
  rdoc.rdoc_files.include('README*')
58
+ rdoc.rdoc_files.include('History.txt')
58
59
  rdoc.rdoc_files.include('lib/**/*.rb')
59
60
  end
60
61
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.4
data/ffi_dry.gemspec CHANGED
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ffi_dry}
8
- s.version = "0.1.3"
8
+ s.version = "0.1.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Eric Monti"]
12
- s.date = %q{2009-09-16}
13
- s.description = %q{Provides a some useful modules, classes, and methods as well as a DSL-like syntax for FFI::Struct layouts}
12
+ s.date = %q{2010-01-02}
13
+ s.description = %q{Provides some useful modules, classes, and methods for FFI bindings as well as a DSL-like syntax for FFI::Struct layouts}
14
14
  s.email = %q{emonti@matasano.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.files = [
20
20
  ".document",
21
21
  ".gitignore",
22
+ "History.txt",
22
23
  "LICENSE",
23
24
  "README.rdoc",
24
25
  "Rakefile",
@@ -35,7 +36,7 @@ Gem::Specification.new do |s|
35
36
  s.homepage = %q{http://github.com/emonti/ffi_dry}
36
37
  s.rdoc_options = ["--charset=UTF-8"]
37
38
  s.require_paths = ["lib"]
38
- s.rubygems_version = %q{1.3.4}
39
+ s.rubygems_version = %q{1.3.5}
39
40
  s.summary = %q{Syntactic sugar and helper utilities for FFI}
40
41
  s.test_files = [
41
42
  "spec/ffi_dry_spec.rb",
@@ -47,13 +48,16 @@ Gem::Specification.new do |s|
47
48
  s.specification_version = 3
48
49
 
49
50
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<ffi>, [">= 0.5.0"])
50
52
  s.add_development_dependency(%q<rspec>, [">= 0"])
51
53
  s.add_development_dependency(%q<yard>, [">= 0"])
52
54
  else
55
+ s.add_dependency(%q<ffi>, [">= 0.5.0"])
53
56
  s.add_dependency(%q<rspec>, [">= 0"])
54
57
  s.add_dependency(%q<yard>, [">= 0"])
55
58
  end
56
59
  else
60
+ s.add_dependency(%q<ffi>, [">= 0.5.0"])
57
61
  s.add_dependency(%q<rspec>, [">= 0"])
58
62
  s.add_dependency(%q<yard>, [">= 0"])
59
63
  end
data/lib/ffi/dry.rb CHANGED
@@ -5,7 +5,7 @@ require 'ffi'
5
5
  module FFI::DRY
6
6
 
7
7
  # A module to add syntactic sugar and some nice automatic getter/setter
8
- # logic to FFI::Struct, FFI::ManagedStruct, etc.
8
+ # methods to FFI::Struct, FFI::ManagedStruct, etc.
9
9
  #
10
10
  # For example:
11
11
  # require 'rubygems'
@@ -54,16 +54,20 @@ module FFI::DRY
54
54
  # # ["ss3", [1, 0]]
55
55
  # # ["ss4", [1, 65535]]
56
56
  #
57
- module StructHelper #< ::FFI::Struct
57
+ module StructHelper
58
58
 
59
59
  attr_reader :dsl_metadata
60
60
 
61
- # Adds field setting on initialization to ::FFI::Struct.new as well as
62
- # a "yield(self) if block_given?" at the end.
61
+ # Allows setting structure fields on initialization to ::FFI::Struct.new
62
+ # as well as a "yield(self) if block_given?" at the end.
63
63
  #
64
- # The field initialization kicks in if there is only one argument, and it
65
- # is a Hash.
64
+ # Field initialization happens if there is only one argument and it is
65
+ # a Hash.
66
66
  #
67
+ # The params hash is taken as a set of values for fields where the hash
68
+ # keys specify the field names to set.
69
+ #
70
+ # @param [Hash] params
67
71
  # Note:
68
72
  # The :raw parameter is a special tag in the hash. The value is taken as a
69
73
  # string and initialized into a new FFI::MemoryPointer which this Struct
@@ -148,15 +152,13 @@ module FFI::DRY
148
152
 
149
153
  private
150
154
 
151
- # This passes a block to an instance of DSL_StructLayoutBuilder, allowing
152
- # for a more declarative syntax.
155
+ # This passes a block to an instance of DSLStructLayoutBuilder, allowing
156
+ # for a more declarative syntax with extra metadata.
153
157
  #
154
158
  # It is a replacement to layout() and stores the dsl_metadata gathered
155
159
  # about structure members locally.
156
- #
157
- #
158
160
  def dsl_layout &block
159
- builder = DSL_StructLayoutBuilder.new(self)
161
+ builder = DSLStructLayoutBuilder.new(self)
160
162
  builder.instance_eval(&block)
161
163
  @layout = builder.build
162
164
  @size = @layout.size
@@ -197,7 +199,7 @@ module FFI::DRY
197
199
  #
198
200
  # See the individual method descriptions for more info.
199
201
  #
200
- class DSL_StructLayoutBuilder
202
+ class DSLStructLayoutBuilder
201
203
  attr_reader :builder, :metadata
202
204
 
203
205
  # Initializes the builder with a reference to the structure using it
@@ -277,25 +279,39 @@ module FFI::DRY
277
279
  return ret
278
280
  end
279
281
 
282
+ # This is a support method used similarly as in the actual builder.
283
+ # XXX Note, as of 0.5.0-final, this became a protected method in the
284
+ # FFI builder. We probably need to figure out another, *supported*, way to
285
+ # do this without meddling into back-end FFI implementations.
280
286
  def find_type(*args)
281
- @pbind.find_type(*args)
287
+ @pbind.instance_eval { find_type(*args) }
282
288
  end
283
289
 
290
+ # This is a support method used similarly as in the actual builder.
291
+ # XXX Note, as of 0.5.0-final, this became a protected method in the
292
+ # FFI builder. We probably need to figure out another, *supported*, way to
293
+ # do this without meddling into back-end FFI implementations.
284
294
  def enclosing_module(*args)
285
- @pbind.enclosing_module(*args)
295
+ @pbind.instance_eval { enclosing_module(*args) }
286
296
  end
287
297
 
288
298
  end
289
299
 
290
- # Used for creating various value <=> constant mapping namespace modules.
300
+ # ConstMap can be used to organize and lookup value to constant mappings and
301
+ # vice versa. Constants can be imported from a namespace based on a regular
302
+ # expression or other means.
291
303
  module ConstMap
292
304
 
293
305
  def self.included(klass)
294
306
  klass.extend(ConstMap)
295
307
  end
296
308
 
297
- # A flexible lookup. Takes 'arg' as a Symbol or String as a name to lookup
298
- # a value, or an Integer to lookup a corresponding name.
309
+ # A flexible name to value lookup.
310
+ #
311
+ # @param [String, Symbol, Integer] arg
312
+ # Use a Symbol or String as a name to lookup its value. Use an
313
+ # Integer to lookup the corresponding name.
314
+ #
299
315
  def [](arg)
300
316
  if arg.is_a? Integer
301
317
  list.invert[arg]
@@ -305,9 +321,10 @@ module FFI::DRY
305
321
  end
306
322
 
307
323
  # Generates a hash of all the constant names mapped to value. Usually,
308
- # it's a good idea to override this like so in derived modules:
324
+ # it's a good idea to override this like so to cache results in
325
+ # derived modules:
309
326
  #
310
- # def list; @@list = super() ; end
327
+ # def list; @@list ||= super() ; end
311
328
  #
312
329
  def list
313
330
  constants.inject({}){|h,c| h.merge! c => const_get(c) }
@@ -333,8 +350,8 @@ module FFI::DRY
333
350
  end
334
351
  end
335
352
 
336
- # Behaves just like ConstFlags, except that the [nnn] returns a list
337
- # of names for the flags set on nnn. Name string lookups work same way as
353
+ # Behaves just like ConstFlags, except that it returns a list
354
+ # of names for the flags. Name string lookups work same way as
338
355
  # ConstFlags.
339
356
  module ConstFlagsMap
340
357
  include ConstMap
@@ -343,9 +360,11 @@ module FFI::DRY
343
360
  klass.extend(ConstFlagsMap)
344
361
  end
345
362
 
346
- # A flexible lookup. Takes 'arg' as a Symbol or String as a name to lookup
347
- # a bit-flag value, or an Integer to lookup a corresponding names for the
348
- # flags present in it.
363
+ # A flexible lookup method for name to bit-flag mappings.
364
+ #
365
+ # @param [String, Symbol, Integer] arg
366
+ # Symbol or String as a name to lookup a bit-flag value, or an
367
+ # Integer to lookup a corresponding names for the flags present in it.
349
368
  def [](arg)
350
369
  if arg.is_a? Integer
351
370
  ret = []
@@ -361,6 +380,79 @@ module FFI::DRY
361
380
  end
362
381
  end
363
382
  end
383
+
384
+
385
+ module NetEndian
386
+ extend ::FFI::Library
387
+
388
+ attach_function :htons, [:uint16], :uint16
389
+ attach_function :ntohs, [:uint16], :uint16
390
+ attach_function :htonl, [:uint32], :uint32
391
+ attach_function :ntohl, [:uint32], :uint32
392
+
393
+ I16_convert = [method(:ntohs), method(:htons)]
394
+ I32_convert = [method(:ntohl), method(:htonl)]
395
+
396
+ ENDIAN_METHS = {
397
+ ::FFI.find_type(:int16) => I16_convert,
398
+ ::FFI.find_type(:uint16) => I16_convert,
399
+ ::FFI.find_type(:int32) => I32_convert,
400
+ ::FFI.find_type(:uint32) => I32_convert,
401
+ }
402
+ end
403
+
404
+
405
+ # A special helper for network packet structures that use big-endian or
406
+ # "network" byte-order. This helper generates read/write accessors that
407
+ # automatically call the appropriate byte conversion function, ntohs/ntohl
408
+ # for 'reading' a 16/32 bit field, and htons/htonl for writing to one.
409
+ #
410
+ # NOTE this helper does not currently do anything special for 64-bit or
411
+ # higher values.
412
+ #
413
+ module NetStructHelper
414
+ def self.included(base)
415
+ base.instance_eval { include StructHelper }
416
+ base.extend(ClassMethods)
417
+ end
418
+
419
+ module ClassMethods
420
+
421
+ private
422
+
423
+ def _class_meths_from_dsl_metadata(meta)
424
+ (@dsl_metadata = meta).each do |spec|
425
+ name = spec[:name]
426
+ type = spec[:type]
427
+
428
+ # Create endian swapper accessors methods for each applicable
429
+ # field
430
+ if( type.kind_of?(Symbol) and
431
+ cnv=NetEndian::ENDIAN_METHS[ ::FFI.find_type(type) ] )
432
+
433
+ unless instance_methods.include?(:"#{name}")
434
+ define_method(:"#{name}"){ cnv[0].call(self[name]) }
435
+ end
436
+ unless instance_methods.include?(:"#{name}=")
437
+ define_method(:"#{name}="){|val| self[name] = cnv[1].call(val) }
438
+ end
439
+
440
+ else
441
+
442
+ unless instance_methods.include?(:"#{name}")
443
+ define_method(:"#{name}"){ self[name] }
444
+ end
445
+ unless instance_methods.include?(:"#{name}=")
446
+ define_method(:"#{name}="){|val| self[name]=val }
447
+ end
448
+
449
+ end
450
+
451
+ end
452
+ end
453
+ end
454
+ end
455
+
364
456
  end
365
457
 
366
458
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi_dry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Monti
@@ -9,9 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-16 00:00:00 -04:00
12
+ date: 2010-01-02 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ffi
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.5.0
24
+ version:
15
25
  - !ruby/object:Gem::Dependency
16
26
  name: rspec
17
27
  type: :development
@@ -32,7 +42,7 @@ dependencies:
32
42
  - !ruby/object:Gem::Version
33
43
  version: "0"
34
44
  version:
35
- description: Provides a some useful modules, classes, and methods as well as a DSL-like syntax for FFI::Struct layouts
45
+ description: Provides some useful modules, classes, and methods for FFI bindings as well as a DSL-like syntax for FFI::Struct layouts
36
46
  email: emonti@matasano.com
37
47
  executables: []
38
48
 
@@ -44,6 +54,7 @@ extra_rdoc_files:
44
54
  files:
45
55
  - .document
46
56
  - .gitignore
57
+ - History.txt
47
58
  - LICENSE
48
59
  - README.rdoc
49
60
  - Rakefile
@@ -80,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
91
  requirements: []
81
92
 
82
93
  rubyforge_project:
83
- rubygems_version: 1.3.4
94
+ rubygems_version: 1.3.5
84
95
  signing_key:
85
96
  specification_version: 3
86
97
  summary: Syntactic sugar and helper utilities for FFI