emonti-ffi_dry 0.1.0 → 0.1.1

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/README.rdoc CHANGED
@@ -10,8 +10,9 @@ things and add support for some uncommon ones.
10
10
 
11
11
  == Synopsis
12
12
 
13
+ (samples/ in the package for code)
13
14
 
14
- One major feature is a 'dsl'-like syntax for declaring structure members
15
+ A major feature is a DSL"-like" syntax for declaring structure members
15
16
  in FFI::Struct or FFI::ManagedStruct definitions.
16
17
 
17
18
  require 'rubygems'
@@ -22,27 +23,32 @@ in FFI::Struct or FFI::ManagedStruct definitions.
22
23
  include FFI::DRY::StructHelper
23
24
 
24
25
  # we get a new way of specifying layouts with a 'dsl'-like syntax
25
- # The :desc => ... part is arbitrary and can be used however we like.
26
+ # The hash containing {:desc => ... } can contain arbitrary keys which
27
+ # can be used however we like. dsl_metadata will contain all these
28
+ # in the class and instance.
26
29
  dsl_layout do
27
30
  field :field1, :uint16, :desc => 'this is field 1'
28
31
  field :field2, :uint16, :desc => 'this is field 2'
29
32
  end
30
33
  end
31
34
 
32
-
33
35
  ss0=SomeStruct.new
34
36
 
35
- With the declaration above, we specified :desc hash value, which was stored
36
- in metadata along with the field name and type.
37
+ With the declarations above, we specified :desc hash value in metadata
38
+ Let's check out in our instance.
37
39
 
38
40
  pp ss0.dsl_metadata
39
41
  [{:type=>:uint16, :name=>:field1, :desc=>"this is field 1"},
40
42
  {:type=>:uint16, :name=>:field2, :desc=>"this is field 2"}]
41
43
  # => nil
42
44
 
45
+ Or class.
46
+
47
+ pp SomeStruct.dsl_metadata
48
+ #...
43
49
 
44
- And we get free additional ways of instantiating and declaring values during
45
- initialization. (The FFI standard ways still work too)
50
+ We get some additional ways of instantiating and declaring values for free
51
+ during initialization. (The FFI standard ways still work too)
46
52
 
47
53
  raw_data = "\x00\x00\xff\xff"
48
54
 
@@ -55,10 +61,19 @@ initialization. (The FFI standard ways still work too)
55
61
  ss1,
56
62
  ss2,
57
63
  ss3,
58
- ss4].each_with_index {|x,i| p ["ss#{i}",[x.field1, x.field2]]}
64
+ ss4 ].each_with_index {|x,i| p ["ss#{i}",[x.field1, x.field2]]}
65
+
66
+ # which will produce...
67
+ # ["ss0", [0, 0]]
68
+ # ["ss1", [0, 65535]]
69
+ # ["ss2", [1, 2]]
70
+ # ["ss3", [1, 0]]
71
+ # ["ss4", [1, 65535]]
72
+
59
73
 
60
- Here's an example which utilizes that arbitrary ':desc' parameter in a
61
- "neighborly" way.
74
+ Here's a broader example which utilizes that arbitrary ':desc' parameter in a
75
+ "neighborly" way. This also demonstrates superclasses to add common struct
76
+ features, declaring array fields, as well as nesting other structs.
62
77
 
63
78
  require 'rubygems'
64
79
  require 'ffi'
@@ -68,7 +83,7 @@ Here's an example which utilizes that arbitrary ':desc' parameter in a
68
83
  include ::FFI::DRY::StructHelper
69
84
 
70
85
  def self.describe
71
- print "Struct: #{self.class}"
86
+ print "Struct: #{self.name}"
72
87
  dsl_metadata().each_with_index do |spec, i|
73
88
  print " Field #{i}\n"
74
89
  print " name: #{spec[:name].inspect}\n"
@@ -96,7 +111,8 @@ Here's an example which utilizes that arbitrary ':desc' parameter in a
96
111
  :desc => "a string up to 255 bytes bound by :len"
97
112
  end
98
113
 
99
- # override kind getter method
114
+ # override kind getter method with our own
115
+ # resolves kind to some kind of type array for example...
100
116
  def kind
101
117
  [:default, :bar, :baz][ self[:kind] ]
102
118
  end
@@ -105,16 +121,78 @@ Here's an example which utilizes that arbitrary ':desc' parameter in a
105
121
  s1=TestStruct.new
106
122
  s2=SomeStruct.new
107
123
 
124
+ # check out that 'kind' override:
125
+ s2.kind
126
+ # => :default
127
+
128
+ # oh and the regular FFI way is always intact
129
+ s2[:kind]
130
+ # => 0
131
+
132
+ s2[:kind]=1
133
+ s2.kind
134
+ # => :bar
135
+
136
+ s2.kind=3
137
+ s2.kind
138
+ # => :baz
139
+
108
140
  puts "*"*70
109
141
  s1.describe
110
- # we get a dump of metadata
142
+ ## we get a dump of metadata
143
+ # **********************************************************************
144
+ # Struct: TestStruct
145
+ # Field 0
146
+ # name: :field1
147
+ # type: :uint8
148
+ # desc: test field 1
149
+ #
150
+ # Field 1
151
+ # name: :field2
152
+ # type: :uint8
153
+ # desc: test field 2
154
+
111
155
  puts "*"*70
112
156
  s2.describe
113
- # we get a dump of metadata
157
+ ## we get a dump of metadata
158
+ # Struct: SomeStruct Field 0
159
+ # name: :kind
160
+ # type: :uint8
161
+ # desc: a type identifier
162
+ #
163
+ # Field 1
164
+ # name: :tst
165
+ # type: TestStruct
166
+ # desc: a nested TestStruct
167
+ #
168
+ # Field 2
169
+ # name: :len
170
+ # type: :uint8
171
+ # desc: 8-bit size value (>= self.size+2)
172
+ #
173
+ # Field 3
174
+ # name: :str
175
+ # type: [:char, 255]
176
+ # desc: a string up to 255 bytes bound by :len
114
177
 
178
+ puts "*"*70
179
+ s2.tst.describe
180
+ ## same as s1.describe
181
+ # **********************************************************************
182
+ # Struct: TestStruct
183
+ # Field 0
184
+ # name: :field1
185
+ # type: :uint8
186
+ # desc: test field 1
187
+ #
188
+ # Field 1
189
+ # name: :field2
190
+ # type: :uint8
191
+ # desc: test field 2
115
192
 
116
193
  There's also some helpers for collecting lookup maps for constants, a common
117
- and handy thing when porting various libraries.
194
+ and handy thing when porting various libraries. We use Socket here just for
195
+ example purposes, you can 'slurp' constants form any namespace this way.
118
196
 
119
197
  require 'ffi/dry'
120
198
  require 'socket'
@@ -122,29 +200,34 @@ and handy thing when porting various libraries.
122
200
  module AddressFamily
123
201
  include FFI::DRY::ConstMap
124
202
  slurp_constants ::Socket, "AF_"
125
- def list ; @@list ||= super() ; end
203
+ def list ; @@list ||= super() ; end # only generate the hash once
126
204
  end
127
205
 
128
- AddressFamily now has all the constants it found for Socket::AF_*
206
+ AddressFamily now has all the constants it found for Socket::AF_* minus the
207
+ prefix.
129
208
 
130
209
  AddressFamily::INET
131
210
  AddressFamily::LINK
132
211
  AddressFamily::INET6
212
+
133
213
  etc...
134
214
 
135
- We can do type and value lookups using []
215
+ We can do type or value lookups using []
216
+
136
217
  AddressFamily[2] # => "INET"
137
218
  AddressFamily["INET"] # => 2
138
219
 
139
- We can get a hash of all key-value pairs with .list
220
+ We can get a hash of all constant->value pairs with .list
221
+
140
222
  AddressFamily.list
141
223
  # => {"NATM"=>31, "DLI"=>13, "UNIX"=>1, "NETBIOS"=>33, ...}
142
224
 
143
- ... which can be inverted for a reverse mapping
225
+ ... and invert for a reverse mapping
226
+
144
227
  AddressFamily.list.invert
145
228
  # => {16=>"APPLETALK", 5=>"CHAOS", 27=>"NDRV", 0=>"UNSPEC", ...}
146
229
 
147
230
 
148
- == Copyright
231
+ == License
149
232
 
150
233
  Copyright (c) 2009 Eric Monti. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
data/lib/ffi/dry.rb CHANGED
@@ -217,6 +217,7 @@ module FFI::DRY
217
217
  #
218
218
  # struct field_name, RubyClass, { ... metadata ... }
219
219
  #
220
+ # :offset is a special key in metadata, specifies the offset of the field.
220
221
  def struct(name, klass, o={})
221
222
  unless klass.kind_of?(Class) and klass < ::FFI::Struct
222
223
  raise(::ArgumentError, "klass must be a struct")
@@ -236,6 +237,7 @@ module FFI::DRY
236
237
  #
237
238
  # array field_name, [ctype, N], { ... metadata ... }
238
239
  #
240
+ # :offset is a special key in metadata, specifies the offset of the field.
239
241
  def array(name, type, o={})
240
242
  unless type.kind_of?(::Array)
241
243
  raise(::ArgumentError, "type must be an array")
@@ -256,6 +258,7 @@ module FFI::DRY
256
258
  #
257
259
  # field field_name, ctype, { ... metadata ... }
258
260
  #
261
+ # :offset is a special key in metadata, specifies the offset of the field.
259
262
  def field(name, type, o={})
260
263
  opts = o.merge(:name => name, :type => type)
261
264
  offset = opts[:offset]
@@ -275,8 +278,7 @@ module FFI::DRY
275
278
 
276
279
  end
277
280
 
278
- # Used for creating various value <=> constant mapping modules such as
279
- # Ip::Hdr::Proto for IP protocols.
281
+ # Used for creating various value <=> constant mapping namespace modules.
280
282
  module ConstMap
281
283
 
282
284
  def self.included(klass)
@@ -333,8 +335,8 @@ module FFI::DRY
333
335
  end
334
336
 
335
337
  # A flexible lookup. Takes 'arg' as a Symbol or String as a name to lookup
336
- # a value, or an Integer to lookup a corresponding names for the flags
337
- # present in it.
338
+ # a bit-flag value, or an Integer to lookup a corresponding names for the
339
+ # flags present in it.
338
340
  def [](arg)
339
341
  if arg.is_a? Integer
340
342
  ret = []
data/samples/basic.rb CHANGED
@@ -1,35 +1,55 @@
1
- require 'rubygems'
2
- require 'ffi'
3
- require 'ffi/dry'
4
-
5
- class SomeStruct < FFI::Struct
6
- include FFI::DRY::StructHelper
7
-
8
- # we get a new way of specifying layouts with a 'dsl'-like syntax
9
- dsl_layout do
10
- field :field1, :uint16, :desc => 'this is field 1'
11
- field :field2, :uint16, :desc => 'this is field 2'
12
- end
13
- end
14
-
15
-
16
- ss0=SomeStruct.new
17
-
18
- p ss0.dsl_metadata # we can look at definition metadata
19
-
20
- # And we have additional ways of instantiating and declaring values
21
- # during initialization. (The FFI standard ways still work too)
22
-
23
- raw_data = "\x00\x00\xff\xff"
24
-
25
- ss1=SomeStruct.new :raw => raw_data
26
- ss2=SomeStruct.new :raw => raw_data, :field1 => 1, :field2 => 2
27
- ss3=SomeStruct.new {|x| x.field1=1 }
28
- ss4=SomeStruct.new(:raw => raw_data) {|x| x.field1=1 }
29
-
30
- [ ss0,
31
- ss1,
32
- ss2,
33
- ss3,
34
- ss4].each_with_index {|x,i| p ["ss#{i}",[x.field1, x.field2]]}
1
+ #!/usr/bin/env ruby
2
+ # One major feature is a dsl"-like" syntax for declaring structure members
3
+ # in FFI::Struct or FFI::ManagedStruct definitions.
4
+
5
+ require 'rubygems'
6
+ require 'ffi'
7
+ require 'ffi/dry'
8
+
9
+ class SomeStruct < FFI::Struct
10
+ include FFI::DRY::StructHelper
11
+
12
+ # we get a new way of specifying layouts with a 'dsl'-like syntax
13
+ # The hash containing {:desc => ... } can contain arbitrary keys which
14
+ # can be used however we like. dsl_metadata will contain all these
15
+ # in the class and instance.
16
+ dsl_layout do
17
+ field :field1, :uint16, :desc => 'this is field 1'
18
+ field :field2, :uint16, :desc => 'this is field 2'
19
+ end
20
+ end
21
+
22
+ ss0=SomeStruct.new
23
+
24
+ # With the declaration above, we specified :desc hash value, which was stored
25
+ # in metadata along with the field name and type.
26
+
27
+ pp ss0.dsl_metadata
28
+ [{:type=>:uint16, :name=>:field1, :desc=>"this is field 1"},
29
+ {:type=>:uint16, :name=>:field2, :desc=>"this is field 2"}]
30
+ # => nil
31
+
32
+
33
+ # We get some free additional ways of instantiating and declaring values during
34
+ # initialization. (The FFI standard ways still work too)
35
+
36
+ raw_data = "\x00\x00\xff\xff"
37
+
38
+ ss1=SomeStruct.new :raw => raw_data
39
+ ss2=SomeStruct.new :raw => raw_data, :field1 => 1, :field2 => 2
40
+ ss3=SomeStruct.new {|x| x.field1=1 }
41
+ ss4=SomeStruct.new(:raw => raw_data) {|x| x.field1=1 }
42
+
43
+ [ ss0,
44
+ ss1,
45
+ ss2,
46
+ ss3,
47
+ ss4 ].each_with_index {|x,i| p ["ss#{i}",[x.field1, x.field2]]}
48
+
49
+ # which should produce...
50
+ # ["ss0", [0, 0]]
51
+ # ["ss1", [0, 65535]]
52
+ # ["ss2", [1, 2]]
53
+ # ["ss3", [1, 0]]
54
+ # ["ss4", [1, 65535]]
35
55
 
data/samples/describer.rb CHANGED
@@ -1,48 +1,119 @@
1
- require 'rubygems'
2
- require 'ffi'
3
- require 'ffi/dry'
4
-
5
- class NeighborlyStruct < ::FFI::Struct
6
- include ::FFI::DRY::StructHelper
7
-
8
- def self.describe
9
- print "Struct: #{self.class}"
10
- dsl_metadata().each_with_index do |spec, i|
11
- print " Field #{i}\n"+
12
- " name: #{spec[:name].inspect}\n"+
13
- " type: #{spec[:type].inspect}\n"+
14
- " desc: #{spec[:desc]}\n\n"
1
+ # Here's a broader example which utilizes that arbitrary ':desc' parameter in a
2
+ # "neighborly" way. This also demonstrates superclasses to add common struct
3
+ # features, declaring array fields, as well as nesting other structs.
4
+
5
+ require 'rubygems'
6
+ require 'ffi'
7
+ require 'ffi/dry'
8
+
9
+ class NeighborlyStruct < ::FFI::Struct
10
+ include ::FFI::DRY::StructHelper
11
+
12
+ def self.describe
13
+ print "Struct: #{self.name}"
14
+ dsl_metadata().each_with_index do |spec, i|
15
+ print " Field #{i}\n"
16
+ print " name: #{spec[:name].inspect}\n"
17
+ print " type: #{spec[:type].inspect}\n"
18
+ print " desc: #{spec[:desc]}\n\n"
19
+ end
20
+ print "\n"
21
+ end
22
+ def describe; self.class.describe; end
23
+ end
24
+
25
+ class TestStruct < NeighborlyStruct
26
+ dsl_layout do
27
+ field :field1, :uint8, :desc => "test field 1"
28
+ field :field2, :uint8, :desc => "test field 2"
29
+ end
15
30
  end
16
- print "\n"
17
- end
18
- def describe; self.class.describe; end
19
- end
20
-
21
- class TestStruct < NeighborlyStruct
22
- dsl_layout do
23
- field :field1, :uint8, :desc => "test field 1"
24
- field :field2, :uint8, :desc => "test field 2"
25
- end
26
- end
27
-
28
- class SomeStruct < NeighborlyStruct
29
- dsl_layout do
30
- field :kind, :uint8, :desc => "a type identifier"
31
- struct :tst, TestStruct, :desc => "a nested TestStruct"
32
- field :len, :uint8, :desc => "8-bit size value (>= self.size+2)"
33
- array :str, [:char,255], :desc => "a string up to 255 bytes bound by :len"
34
- end
35
-
36
- # override kind getter method
37
- def kind
38
- [:default, :bar, :baz][ self[:kind] ]
39
- end
40
- end
41
-
42
- s1=TestStruct.new
43
- s2=SomeStruct.new
44
-
45
- puts "*"*70
46
- s1.describe
47
- puts "*"*70
48
- s2.describe
31
+
32
+ class SomeStruct < NeighborlyStruct
33
+ dsl_layout do
34
+ field :kind, :uint8, :desc => "a type identifier"
35
+ struct :tst, TestStruct, :desc => "a nested TestStruct"
36
+ field :len, :uint8, :desc => "8-bit size value (>= self.size+2)"
37
+ array :str, [:char,255],
38
+ :desc => "a string up to 255 bytes bound by :len"
39
+ end
40
+
41
+ # override kind getter method with our own
42
+ # resolves kind to some kind of type array for example...
43
+ def kind
44
+ [:default, :bar, :baz][ self[:kind] ]
45
+ end
46
+ end
47
+
48
+ s1=TestStruct.new
49
+ s2=SomeStruct.new
50
+
51
+ # check out that 'kind' override:
52
+ s2.kind
53
+ # => :default
54
+
55
+ # oh and the regular FFI way is always intact
56
+ s2[:kind]
57
+ # => 0
58
+
59
+ s2[:kind]=1
60
+ s2.kind
61
+ # => :bar
62
+
63
+ s2.kind=3
64
+ s2.kind
65
+ # => :baz
66
+
67
+ puts "*"*70
68
+ s1.describe
69
+ ## we get a dump of metadata
70
+ # **********************************************************************
71
+ # Struct: TestStruct
72
+ # Field 0
73
+ # name: :field1
74
+ # type: :uint8
75
+ # desc: test field 1
76
+ #
77
+ # Field 1
78
+ # name: :field2
79
+ # type: :uint8
80
+ # desc: test field 2
81
+
82
+ puts "*"*70
83
+ s2.describe
84
+ ## we get a dump of metadata
85
+ # Struct: SomeStruct Field 0
86
+ # name: :kind
87
+ # type: :uint8
88
+ # desc: a type identifier
89
+ #
90
+ # Field 1
91
+ # name: :tst
92
+ # type: TestStruct
93
+ # desc: a nested TestStruct
94
+ #
95
+ # Field 2
96
+ # name: :len
97
+ # type: :uint8
98
+ # desc: 8-bit size value (>= self.size+2)
99
+ #
100
+ # Field 3
101
+ # name: :str
102
+ # type: [:char, 255]
103
+ # desc: a string up to 255 bytes bound by :len
104
+
105
+ puts "*"*70
106
+ s2.tst.describe
107
+ ## same as s1.describe
108
+ # **********************************************************************
109
+ # Struct: TestStruct
110
+ # Field 0
111
+ # name: :field1
112
+ # type: :uint8
113
+ # desc: test field 1
114
+ #
115
+ # Field 1
116
+ # name: :field2
117
+ # type: :uint8
118
+ # desc: test field 2
119
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emonti-ffi_dry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Monti
@@ -67,6 +67,7 @@ files:
67
67
  - spec/spec_helper.rb
68
68
  has_rdoc: false
69
69
  homepage: http://github.com/emonti/ffi_dry
70
+ licenses:
70
71
  post_install_message:
71
72
  rdoc_options:
72
73
  - --charset=UTF-8
@@ -87,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
88
  requirements: []
88
89
 
89
90
  rubyforge_project:
90
- rubygems_version: 1.2.0
91
+ rubygems_version: 1.3.5
91
92
  signing_key:
92
93
  specification_version: 3
93
94
  summary: Syntactic sugar and helper utilities for FFI