jsanders-bitfields 0.2.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/README +0 -0
  2. data/Rakefile +38 -0
  3. data/demo.rb +46 -0
  4. data/lib/bitfields.rb +127 -0
  5. data/lib/bits.rb +60 -0
  6. metadata +57 -0
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ begin
2
+ require 'rubygems'
3
+ rescue Exception
4
+ puts 'RubyGems is not installed. See http://www.rubygems.org/read/chapter/3 for instructions.'
5
+ end
6
+
7
+ begin
8
+ require 'spec/rake/spectask'
9
+
10
+ Spec::Rake::SpecTask.new do |t|
11
+ t.spec_opts = ['-c']
12
+ t.libs << 'lib'
13
+ t.spec_files = FileList['spec/**/*_spec.rb']
14
+ t.rcov = true
15
+ end
16
+ rescue Exception
17
+ puts 'RSpec not available. Install it with: sudo gem install rspec'
18
+ end
19
+
20
+ begin
21
+ require 'jeweler'
22
+ Jeweler::Tasks.new do |s|
23
+ s.name = "bitfields"
24
+ s.summary = "Simple named bit fields"
25
+ s.description = "A very simple library for building binary data by declaring named bit fields"
26
+ s.email = 'sanderjd@gmail.com'
27
+ s.homepage = 'http://github.com/jsanders/bitfields'
28
+ s.authors = ['James Sanders']
29
+ s.has_rdoc = true
30
+ s.files = ["README",
31
+ "Rakefile",
32
+ "demo.rb",
33
+ "lib/bitfields.rb",
34
+ "lib/bits.rb"]
35
+ end
36
+ rescue LoadError
37
+ puts 'Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com'
38
+ end
data/demo.rb ADDED
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/lib/bitfields'
2
+
3
+ # Make a template
4
+ BitFields.template :demo do |m|
5
+ m.bits :beginning, :length => 10, :value => 0b1010101010
6
+ m.bits :middle, :length => 5
7
+ m.bits :end, :length => 10, :value => 1
8
+ end
9
+
10
+ # Create an object with that template
11
+ message = BitFields.create(:demo)
12
+
13
+ # 1010101010000000000000001
14
+ puts message.bit_string
15
+
16
+ # Create an object with that template and give it parameters
17
+ message = BitFields.create(:demo, :middle => 0b11111)
18
+
19
+ # 1010101010111110000000001
20
+ puts message.bit_string
21
+ # 1557c01
22
+ puts message.hex_string
23
+ # 125276001
24
+ puts message.oct_string
25
+ # 22379521
26
+ puts message.integer
27
+
28
+ # Compose another message using this object as one of its fields
29
+ new_message = BitFields.compose do |m|
30
+ m.bits :before, :length => 1, :value => 1
31
+ m.add :demo__message, message
32
+ m.bits :after, :length => 1, :value => 0
33
+ end
34
+
35
+ # 110101010101111100000000010
36
+ puts new_message.bit_string
37
+
38
+ # Compose another message without creating the original message
39
+ newer_message = BitFields.compose do |m|
40
+ m.bits :before, :length => 1, :value => 1
41
+ m.bring :demo, :middle => 0
42
+ m.bits :after, :length => 1, :value => 0
43
+ end
44
+
45
+ # 110101010100000000000000010
46
+ puts newer_message.bit_string
data/lib/bitfields.rb ADDED
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__) + '/bits'
2
+
3
+ class BitFields
4
+
5
+ # Class methods
6
+
7
+ def self.template(template_name, &block)
8
+ template_name = symbol_if_string(template_name)
9
+ templates[template_name] = block
10
+ nil
11
+ end
12
+
13
+ def self.create(template_name, params = {})
14
+ template_name = symbol_if_string(template_name)
15
+ if templates[template_name]
16
+ instance = self.new
17
+ templates[template_name].call(instance)
18
+ params.each_pair { | field_name, value | instance[field_name] = value }
19
+ instance
20
+ else
21
+ warn "BitFields: No template named #{template_name}"
22
+ nil
23
+ end
24
+ end
25
+
26
+ def self.decode(template_name, value)
27
+ template_name = symbol_if_string(template_name)
28
+ if templates[template_name]
29
+ instance = self.new
30
+ templates[template_name].call(instance)
31
+ bit_string = Bits.new(value, instance.total_length).bit_string
32
+ current_index = 0
33
+ instance.field_names.each_with_index do |field_name, index|
34
+ length = instance.field_lengths[index]
35
+ instance[field_name] = bit_string[current_index, length].to_i(2)
36
+ current_index += length
37
+ end
38
+ instance
39
+ else
40
+ warn "BitFields: No template named #{template_name}"
41
+ nil
42
+ end
43
+ end
44
+
45
+ def self.compose(&block)
46
+ composition = self.new
47
+ yield composition
48
+ composition
49
+ end
50
+
51
+ # Object methods
52
+
53
+ def integer; get_bits.integer end
54
+ def bit_string; get_bits.bit_string end
55
+ def hex_string; get_bits.hex_string end
56
+ def oct_string; get_bits.oct_string end
57
+
58
+ def total_length
59
+ field_lengths.inject { |total, length| total + length }
60
+ end
61
+
62
+ def add(field_name, instance)
63
+ field_name = BitFields.symbol_if_string(field_name)
64
+ if instance
65
+ field_names << field_name
66
+ field_values << instance.get_bits
67
+ end
68
+ end
69
+
70
+ def bring(template_name, params = {})
71
+ template_name = BitFields.symbol_if_string(template_name)
72
+ instance = BitFields.create(template_name, params)
73
+ if instance
74
+ field_names << template_name
75
+ field_values << instance.get_bits
76
+ end
77
+ end
78
+
79
+ def bits(field_name, params = {})
80
+ field_name = BitFields.symbol_if_string(field_name)
81
+ value = params.key?(:value) ? params[:value] : 0
82
+ length = params.key?(:length) ? params[:length] : 0
83
+ field_names << field_name
84
+ field_values << Bits.new(value, length)
85
+ field_lengths << length
86
+ end
87
+
88
+ def get_bits
89
+ field_values.inject(nil) do |final, value|
90
+ final ? final + value : value
91
+ end
92
+ end
93
+
94
+ def [](field_name)
95
+ field_name = BitFields.symbol_if_string(field_name)
96
+ field_values[field_names.index(field_name)] if field_names.index(field_name)
97
+ end
98
+
99
+ def []=(field_name, value)
100
+ self[field_name].set(value) if self[field_name]
101
+ end
102
+
103
+ def field_names
104
+ @field_names ||= Array.new
105
+ end
106
+
107
+ def field_values
108
+ @field_values ||= Array.new
109
+ end
110
+
111
+ def field_lengths
112
+ @field_lengths ||= Array.new
113
+ end
114
+
115
+ private
116
+
117
+ def self.templates
118
+ @@templates ||= Hash.new
119
+ end
120
+
121
+ # Helpers
122
+
123
+ def self.symbol_if_string(name)
124
+ name.kind_of?(String) ? name.to_sym : name
125
+ end
126
+ end
127
+
data/lib/bits.rb ADDED
@@ -0,0 +1,60 @@
1
+ # Bits provides an easy way to store and access sequences of bits,
2
+ # allowing input and output in multiple formats
3
+
4
+ class Bits
5
+
6
+ # +bits+:: The bit field to store
7
+ # +length+:: Length of the bit field - default to calculated length, 0-pad on
8
+ # MSB
9
+
10
+ def initialize(bits, length = 0)
11
+ @length = length
12
+ @bits = bit_string_from_input(bits, length)
13
+ end
14
+
15
+ def +(bits)
16
+ Bits.new("0b#{@bits}" + bit_string_from_input(bits))
17
+ end
18
+
19
+ def bit_string
20
+ @bits
21
+ end
22
+
23
+ def hex_string
24
+ @bits.to_i(2).to_s(16)
25
+ end
26
+
27
+ def oct_string
28
+ @bits.to_i(2).to_s(8)
29
+ end
30
+
31
+ def integer
32
+ @bits.to_i(2)
33
+ end
34
+
35
+ def set(bits)
36
+ @bits = bit_string_from_input(bits, @length)
37
+ end
38
+
39
+ protected
40
+
41
+ attr_reader :bits
42
+
43
+ private
44
+
45
+ def bit_string_from_input(bits, length = 0)
46
+ case bits
47
+ when Integer, Fixnum, Bignum
48
+ "%0#{length}b" % bits
49
+ when String
50
+ "%0#{length}b" % Integer(bits)
51
+ when Bits
52
+ bits.bits
53
+ when BitFields
54
+ bits.get_bits.bits
55
+ else
56
+ warn "Unsupported data #{bits} (#{bits.class}) - defaulting to #{length} length zero field"
57
+ "%0#{length}b" % 0
58
+ end
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsanders-bitfields
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.4
5
+ platform: ruby
6
+ authors:
7
+ - James Sanders
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-23 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A very simple library for building binary data by declaring named bit fields
17
+ email: sanderjd@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README
26
+ - Rakefile
27
+ - demo.rb
28
+ - lib/bitfields.rb
29
+ - lib/bits.rb
30
+ has_rdoc: true
31
+ homepage: http://github.com/jsanders/bitfields
32
+ post_install_message:
33
+ rdoc_options: []
34
+
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: "0"
42
+ version:
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.2.0
53
+ signing_key:
54
+ specification_version: 2
55
+ summary: Simple named bit fields
56
+ test_files: []
57
+