elia 1.0.0
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/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/bit_fields.rb +232 -0
- data/lib/elia.rb +3 -0
- data/lib/path_operator.rb +15 -0
- data/lib/world_logger.rb +24 -0
- data/spec/lib/bit_fields_spec.rb +59 -0
- data/spec/lib/elia_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +78 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Elia Schito
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= elia
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2009 Elia Schito. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "elia"
|
8
|
+
gem.summary = %Q{Elia Schito's utility belt}
|
9
|
+
gem.description = %Q{useful stuff...}
|
10
|
+
gem.email = "perlelia@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/elia/elia"
|
12
|
+
gem.authors = ["Elia Schito"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.files = FileList["[A-Z]*", "{lib,spec}/**/*"]
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "elia #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/lib/bit_fields.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'world_logger'
|
2
|
+
|
3
|
+
#
|
4
|
+
# BitFields provides a simple way to extract a values from bit fields,
|
5
|
+
# especially if they don't correspond to standard sizes (such as +char+, +int+,
|
6
|
+
# +long+, etc., see <tt>String#unpack</tt> for further informations).
|
7
|
+
#
|
8
|
+
# For example the Primary Header of the Telemetry Frame in the ESA PSS
|
9
|
+
# Standard has this specification:
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# | TRANSFER FRAME PRIMARY HEADER |
|
13
|
+
# ___________|_____________________________________________________________________________________|
|
14
|
+
# |SYNC MARKER| FRAME IDENTIFICATION | MASTER | VIRTUAL | FRAME DATA FIELD STATUS |
|
15
|
+
# | |----------------------| CHANNEL | CHANNEL |------------------------------------------|
|
16
|
+
# | |Ver. |S/C.|Virt.|Op.Co| FRAME | FRAME |2nd head.|Sync|Pkt ord|Seg. |First Header|
|
17
|
+
# | | no. | ID | Chn.| Flag| COUNT | COUNT | flag |flag|flag |len.ID| Pointer |
|
18
|
+
# | |_____|____|_____|_____| | |_________|____|_______|______|____________|
|
19
|
+
# | | 2 | 10 | 3 | 1 | | | 1 | 1 | 1 | 2 | 11 |
|
20
|
+
# |-----------|----------------------|---------|---------|------------------------------------------|
|
21
|
+
# | 32 | 16 | 8 | 8 | 16 |
|
22
|
+
#
|
23
|
+
# Will become:
|
24
|
+
#
|
25
|
+
# class PrimaryHeader
|
26
|
+
# include BitFields
|
27
|
+
# field :frame_identification, 'n' do
|
28
|
+
# bit_field :version, 2
|
29
|
+
# bit_field :spacecraft_id, 10
|
30
|
+
# bit_field :virtual_channel, 3
|
31
|
+
# bit_field :op_control_field_flag, 2
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# field :master_channel_frame_count
|
35
|
+
# field :virtual_channel_frame_count
|
36
|
+
#
|
37
|
+
# field :frame_data_field_status, 'n' do
|
38
|
+
# bit_field :secondary_header_flag, 1
|
39
|
+
# bit_field :sync_flag, 1
|
40
|
+
# bit_field :packet_order_flag, 1
|
41
|
+
# bit_field :segment_length_id, 2
|
42
|
+
# bit_field :first_header_pointer, 11
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# And can be used like:
|
48
|
+
#
|
49
|
+
# packed_ph = [0b10100111_11111111, 11, 23, 0b10100111_11111111].pack('nCCn') # => "\247\377\v\027\247\377"
|
50
|
+
#
|
51
|
+
# ph = PrimaryHeader.new packed_ph
|
52
|
+
#
|
53
|
+
# ph.virtual_channel_frame_count # => 23
|
54
|
+
# ph.secondary_header_flag # => 0b1
|
55
|
+
# ph.sync_flag # => 0b0
|
56
|
+
# ph.first_header_pointer # => 0b111_11111111
|
57
|
+
#
|
58
|
+
# ph[:first_header_pointer] # => 0b111_11111111
|
59
|
+
#
|
60
|
+
#
|
61
|
+
#
|
62
|
+
module BitFields
|
63
|
+
|
64
|
+
# Collects the fields definitions for later parsing
|
65
|
+
attr_reader :fields
|
66
|
+
|
67
|
+
# Collects the bit_fields definitions for later parsing
|
68
|
+
attr_reader :bit_fields
|
69
|
+
|
70
|
+
# Collects the full <tt>String#unpack</tt> directive used to parse the raw value.
|
71
|
+
attr_reader :unpack_recipe
|
72
|
+
|
73
|
+
|
74
|
+
##
|
75
|
+
# Defines a field to be extracted with String#unpack from the raw value
|
76
|
+
#
|
77
|
+
# +name+ :: the name of the field (that will be used to access it)
|
78
|
+
# +unpack_recipe+ :: the <tt>String#unpack</tt> directive corresponding to this field (optional, defaults to char: "C")
|
79
|
+
# +bit_fields_definitions_block+ :: the block in which +bit_fields+ can be defined (optional)
|
80
|
+
#
|
81
|
+
# Also defines the attribute reader method
|
82
|
+
#
|
83
|
+
def field name, unpack_recipe = 'C', &bit_fields_definitions_block
|
84
|
+
include InstanceMethods # when used we include instance methods
|
85
|
+
logger.debug { self.ancestors.inspect }
|
86
|
+
|
87
|
+
# Setup class "instance" vars
|
88
|
+
@fields ||= []
|
89
|
+
@bit_fields ||= {}
|
90
|
+
@unpack_recipe ||= ""
|
91
|
+
|
92
|
+
# Register the field definition
|
93
|
+
@unpack_recipe << unpack_recipe
|
94
|
+
@fields << name
|
95
|
+
|
96
|
+
# Define the attribute reader
|
97
|
+
class_eval "def #{name}; self.attributes[#{name.inspect}]; end;", __FILE__, __LINE__
|
98
|
+
# define_method(name) { self.fields[name] }
|
99
|
+
|
100
|
+
# There's a bit-structure too?
|
101
|
+
if block_given?
|
102
|
+
@_current_bit_fields = []
|
103
|
+
|
104
|
+
bit_fields_definitions_block.call
|
105
|
+
|
106
|
+
@bit_fields[name] = @_current_bit_fields
|
107
|
+
@_current_bit_fields = nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Defines a <em>bit field</em> to be extracted from a +field+
|
113
|
+
#
|
114
|
+
# +name+ :: the name of the bit field (that will be used to access it)
|
115
|
+
# +width+ :: the number of bits from which this value should be extracted
|
116
|
+
#
|
117
|
+
def bit_field name, width
|
118
|
+
raise "'bit_field' can be used only inside a 'field' block." if @_current_bit_fields.nil?
|
119
|
+
|
120
|
+
# Register the bit field definition
|
121
|
+
@_current_bit_fields << [name, width]
|
122
|
+
|
123
|
+
# Define the attribute reader
|
124
|
+
class_eval "def #{name}; self.attributes[#{name.inspect}]; end\n", __FILE__, __LINE__
|
125
|
+
|
126
|
+
if width == 1 or name.to_s =~ /_flag$/
|
127
|
+
# Define a question mark method if the size is 1 bit
|
128
|
+
class_eval "def #{name}?; self.attributes[#{name.inspect}] != 0; end\n", __FILE__, __LINE__
|
129
|
+
|
130
|
+
# returns nil if no substitution happens...
|
131
|
+
if flag_method_name = name.to_s.gsub!(/_flag$/, '?')
|
132
|
+
# Define another question mark method if ends with "_flag"
|
133
|
+
class_eval "alias #{flag_method_name} #{name}?\n", __FILE__, __LINE__
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
logger.debug { @_current_bit_fields.inspect }
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
module InstanceMethods
|
142
|
+
# Contains the raw string
|
143
|
+
attr_reader :raw
|
144
|
+
|
145
|
+
# caches the bit field values
|
146
|
+
attr_reader :attributes
|
147
|
+
|
148
|
+
# caches the bin string unpacked values
|
149
|
+
attr_reader :unpacked
|
150
|
+
|
151
|
+
# Takes the raw binary string and parses it
|
152
|
+
def initialize bit_string
|
153
|
+
parse_bit_fields(bit_string.dup.freeze)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Makes defined fields accessible like a +Hash+
|
157
|
+
def [](name)
|
158
|
+
self.attributes[name]
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def eat_right_bits original_value, bits_number
|
164
|
+
# Filter the original value with the
|
165
|
+
# proper bitmask to get the rightmost bits
|
166
|
+
new_value = original_value & bit_mask(bits_number)
|
167
|
+
|
168
|
+
# Eat those rightmost bits
|
169
|
+
# wich we have just consumed
|
170
|
+
remaning = original_value >> bits_number
|
171
|
+
|
172
|
+
# Return also the remaning bits
|
173
|
+
return new_value, remaning
|
174
|
+
end
|
175
|
+
|
176
|
+
# Parses the raw value extracting the defined bit fields
|
177
|
+
def parse_bit_fields raw
|
178
|
+
@raw = raw
|
179
|
+
|
180
|
+
# Setup
|
181
|
+
unpack_recipe = self.class.unpack_recipe
|
182
|
+
logger.debug "Unpacking #{@raw.inspect} with #{unpack_recipe.inspect}"
|
183
|
+
@unpacked = @raw.unpack(unpack_recipe)
|
184
|
+
@attributes ||= {}
|
185
|
+
|
186
|
+
logger.debug { "Parsing #{@raw.inspect} with fields #{self.class.fields.inspect}" }
|
187
|
+
self.class.fields.each_with_index do |name, position|
|
188
|
+
logger.debug { "Parsing field #{name.inspect}" }
|
189
|
+
|
190
|
+
attributes[name] = @unpacked[position]
|
191
|
+
|
192
|
+
# We must extract bits from end since
|
193
|
+
# ruby doesn't have types (and fixed lengths)
|
194
|
+
if bit_definitions = self.class.bit_fields[name]
|
195
|
+
logger.debug { "Parsing value #{attributes[name]} with bit fields #{bit_definitions.inspect}" }
|
196
|
+
|
197
|
+
bit_value = attributes[name]
|
198
|
+
bit_definitions.reverse.each do |bit_field|
|
199
|
+
logger.debug "Parsing bit field: #{bit_field.inspect} current value: #{bit_value} (#{bit_value.to_s 2})"
|
200
|
+
bit_name, bit_size = *bit_field
|
201
|
+
attributes[bit_name], bit_value = eat_right_bits(bit_value, bit_size)
|
202
|
+
|
203
|
+
logger.debug {
|
204
|
+
"#{bit_name}: #{attributes[bit_name]} 0b#{attributes[bit_name].to_s(2).rjust(16, '0')}"
|
205
|
+
}
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
@parsed = true
|
211
|
+
end
|
212
|
+
|
213
|
+
def bit_mask size
|
214
|
+
2 ** size - 1
|
215
|
+
end
|
216
|
+
|
217
|
+
def to_s
|
218
|
+
raw.to_s
|
219
|
+
end
|
220
|
+
|
221
|
+
def method_missing name, *args
|
222
|
+
if @raw.respond_to? name
|
223
|
+
@raw.send name, *args
|
224
|
+
else
|
225
|
+
super
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
end
|
231
|
+
extend InstanceMethods
|
232
|
+
end
|
data/lib/elia.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module PathOperator
|
2
|
+
def / *others
|
3
|
+
File.join self, *others.map(&:to_s)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
String.class_eval{include PathOperator}
|
8
|
+
Symbol.class_eval{include PathOperator}
|
9
|
+
|
10
|
+
|
11
|
+
class Pathname
|
12
|
+
def / *others
|
13
|
+
join *others.map(&:to_s)
|
14
|
+
end
|
15
|
+
end
|
data/lib/world_logger.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module WorldLogger
|
4
|
+
def self.logger
|
5
|
+
if @logger.nil?
|
6
|
+
@logger ||= Logger.new($stdout)
|
7
|
+
@logger.level = Logger::ERROR
|
8
|
+
end
|
9
|
+
|
10
|
+
@logger
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def logger
|
15
|
+
if self.class.const_defined? :Rails
|
16
|
+
Rails.logger
|
17
|
+
else
|
18
|
+
WorldLogger.logger
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
Object.send :include, WorldLogger
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'bit_fields'
|
3
|
+
|
4
|
+
describe BitFields do
|
5
|
+
before :each do
|
6
|
+
@klass = Class.new
|
7
|
+
|
8
|
+
@klass.class_eval{
|
9
|
+
extend BitFields
|
10
|
+
|
11
|
+
field :char_value
|
12
|
+
|
13
|
+
field :short_value, 'S'
|
14
|
+
|
15
|
+
field :frame_data_field_status, 'S' do
|
16
|
+
bit_field :secondary_header_flag, 1
|
17
|
+
bit_field :sync_flag, 1
|
18
|
+
bit_field :packet_order_flag, 1
|
19
|
+
bit_field :segment_length_id, 2
|
20
|
+
bit_field :first_header_pointer, 11
|
21
|
+
end
|
22
|
+
}
|
23
|
+
@values = [23, 14, 0b10100111_11111111]
|
24
|
+
@bit_string = @values.pack('CSS')
|
25
|
+
@object = @klass.new @bit_string
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should create methods in a class' do
|
29
|
+
@object.char_value.should == 23
|
30
|
+
@object.secondary_header_flag.should == 0b1
|
31
|
+
@object.sync_flag.should == 0b0
|
32
|
+
@object.first_header_pointer.should == 0b111_11111111
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should act as a Hash' do
|
36
|
+
@object.attributes[:char_value].should == 23
|
37
|
+
@object.attributes[:secondary_header_flag].should == 0b1
|
38
|
+
@object.attributes[:sync_flag].should == 0b0
|
39
|
+
@object.attributes[:first_header_pointer].should == 0b111_11111111
|
40
|
+
|
41
|
+
@object[:char_value].should == 23
|
42
|
+
@object[:secondary_header_flag].should == 0b1
|
43
|
+
@object[:sync_flag].should == 0b0
|
44
|
+
@object[:first_header_pointer].should == 0b111_11111111
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should use raw string to respond to "to_s"' do
|
48
|
+
@object.to_s.should == @object.raw.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should define question mark methods for bit fields of length 1' do
|
52
|
+
@object.should respond_to(:sync_flag?)
|
53
|
+
@object.should respond_to(:sync?)
|
54
|
+
@object.sync_flag?.should == false
|
55
|
+
@object.should respond_to(:secondary_header?)
|
56
|
+
@object.secondary_header?.should == true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: elia
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elia Schito
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-26 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
description: useful stuff...
|
26
|
+
email: perlelia@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README.rdoc
|
37
|
+
- Rakefile
|
38
|
+
- VERSION
|
39
|
+
- lib/bit_fields.rb
|
40
|
+
- lib/elia.rb
|
41
|
+
- lib/path_operator.rb
|
42
|
+
- lib/world_logger.rb
|
43
|
+
- spec/lib/bit_fields_spec.rb
|
44
|
+
- spec/lib/elia_spec.rb
|
45
|
+
- spec/spec.opts
|
46
|
+
- spec/spec_helper.rb
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://github.com/elia/elia
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options:
|
53
|
+
- --charset=UTF-8
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.3.5
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Elia Schito's utility belt
|
75
|
+
test_files:
|
76
|
+
- spec/lib/bit_fields_spec.rb
|
77
|
+
- spec/lib/elia_spec.rb
|
78
|
+
- spec/spec_helper.rb
|