emonti-ffi_dry 0.1.0 → 0.1.1

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