ffi_dry 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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