gribr 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/bin/probe-wukong +7 -0
- data/lib/gribr/degrib.rb +2 -1
- data/lib/gribr/degrib/file.rb +8 -2
- data/lib/gribr/degrib/inventory_record.rb +53 -17
- data/lib/gribr/degrib/message.rb +34 -0
- data/lib/gribr/inventory.rb +25 -14
- data/lib/gribr/wgrib/inventory_record.rb +18 -4
- data/spec/lib/gribr/degrib/file_spec.rb +12 -1
- data/spec/lib/gribr/degrib/inventory_record_spec.rb +4 -0
- data/spec/lib/gribr/degrib/inventory_spec.rb +9 -2
- data/spec/lib/gribr/degrib/message_spec.rb +31 -0
- data/spec/lib/gribr/inventory_spec.rb +8 -4
- data/spec/lib/gribr/wgrib/inventory_record_spec.rb +19 -3
- data/spec/lib/gribr/wgrib/inventory_spec.rb +6 -0
- metadata +10 -7
data/Rakefile
CHANGED
@@ -5,8 +5,8 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "gribr"
|
8
|
-
gem.summary = %Q{
|
9
|
-
gem.description = %Q{Ruby wrapper to read gridded binary (GRIB) files
|
8
|
+
gem.summary = %Q{Read gridded binary (GRIB) files with ruby.}
|
9
|
+
gem.description = %Q{Ruby wrapper to read gridded binary (GRIB) files using degrib.}
|
10
10
|
gem.email = "roman.scherer@burningswell.com"
|
11
11
|
gem.homepage = "http://github.com/r0man/gribr"
|
12
12
|
gem.authors = ["Roman Scherer"]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/bin/probe-wukong
ADDED
data/lib/gribr/degrib.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
require 'gribr/executeable'
|
2
1
|
require 'gribr/degrib/cube'
|
3
2
|
require 'gribr/degrib/file'
|
4
3
|
require 'gribr/degrib/index'
|
5
4
|
require 'gribr/degrib/inventory'
|
6
5
|
require 'gribr/degrib/inventory_record'
|
6
|
+
require 'gribr/degrib/message'
|
7
7
|
require 'gribr/degrib/probe_record'
|
8
|
+
require 'gribr/executeable'
|
8
9
|
|
9
10
|
module Gribr
|
10
11
|
|
data/lib/gribr/degrib/file.rb
CHANGED
@@ -35,7 +35,13 @@ module Gribr
|
|
35
35
|
@inventory ||= Inventory.file(self)
|
36
36
|
end
|
37
37
|
|
38
|
-
#
|
38
|
+
# Returns the messages in the grib file.
|
39
|
+
def messages
|
40
|
+
@messages || inventory.records.map { |record| Message.new(self, record) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Probe the grib file at the given location and return/yield the
|
44
|
+
# records.
|
39
45
|
def probe(latitude, longitude, options = { }, &block)
|
40
46
|
probe_one(latitude, longitude, options, &block)
|
41
47
|
end
|
@@ -69,7 +75,7 @@ module Gribr
|
|
69
75
|
end
|
70
76
|
|
71
77
|
def validate!
|
72
|
-
raise "Sorry, not a grib file: #{path}" unless
|
78
|
+
raise "Sorry, not a grib file: #{path}" unless ::File.gribfile?(self); ensure; rewind
|
73
79
|
end
|
74
80
|
|
75
81
|
end
|
@@ -13,30 +13,66 @@ module Gribr
|
|
13
13
|
REGEXP_LEVEL = Regexp.new('([^,]+)').freeze
|
14
14
|
REGEXP_TIMESTAMP = Regexp.new('((\d{2})/(\d{2})/(\d{4})\s+(\d{2}):(\d{2}))').freeze
|
15
15
|
|
16
|
+
TIME_FORMAT = "%m/%d/%Y %H:%M".freeze
|
17
|
+
|
16
18
|
def end_position_of_previous
|
17
19
|
start_position - 1 if number > 1
|
18
20
|
end
|
19
21
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
record.unit = match_data[8]
|
30
|
-
record.level = match_data[9]
|
31
|
-
record.reference_time = Time.utc(match_data[13].to_i, match_data[11].to_i, match_data[12].to_i, match_data[14].to_i, match_data[15].to_i)
|
32
|
-
record.valid_time = Time.utc(match_data[19].to_i, match_data[17].to_i, match_data[18].to_i, match_data[20].to_i, match_data[21].to_i)
|
33
|
-
record
|
34
|
-
end
|
22
|
+
def to_s
|
23
|
+
[ formatted_number, start_position, version, formatted_element, level, formatted_reference_time, formatted_valid_time, formatted_projection ].join(", ")
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def formatted_element
|
29
|
+
"#{element}=\"#{description}\""
|
30
|
+
end
|
35
31
|
|
32
|
+
def formatted_number
|
33
|
+
sprintf("%.1f", number)
|
36
34
|
end
|
37
35
|
|
38
|
-
def
|
39
|
-
|
36
|
+
def formatted_time(time)
|
37
|
+
time.strftime(TIME_FORMAT)
|
38
|
+
end
|
39
|
+
|
40
|
+
def formatted_projection
|
41
|
+
sprintf("%.2f", (valid_time - reference_time) / 60 / 60)
|
42
|
+
end
|
43
|
+
|
44
|
+
def formatted_reference_time
|
45
|
+
formatted_time(reference_time)
|
46
|
+
end
|
47
|
+
|
48
|
+
def formatted_valid_time
|
49
|
+
formatted_time(valid_time)
|
50
|
+
end
|
51
|
+
|
52
|
+
class << self
|
53
|
+
|
54
|
+
def build(match_data)
|
55
|
+
|
56
|
+
if match_data
|
57
|
+
record = new
|
58
|
+
record.number = match_data[1].to_i
|
59
|
+
record.start_position = match_data[3].to_i
|
60
|
+
record.version = match_data[4].to_i
|
61
|
+
record.element = match_data[6]
|
62
|
+
record.description = match_data[7]
|
63
|
+
record.unit = match_data[8]
|
64
|
+
record.level = match_data[9]
|
65
|
+
record.reference_time = Time.utc(match_data[13].to_i, match_data[11].to_i, match_data[12].to_i, match_data[14].to_i, match_data[15].to_i)
|
66
|
+
record.valid_time = Time.utc(match_data[19].to_i, match_data[17].to_i, match_data[18].to_i, match_data[20].to_i, match_data[21].to_i)
|
67
|
+
record
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def regexp
|
73
|
+
@regexp ||= Regexp.new([REGEXP_FLOAT, REGEXP_INTEGER, REGEXP_INTEGER, REGEXP_ELEMENT, REGEXP_LEVEL, REGEXP_TIMESTAMP, REGEXP_TIMESTAMP].join('\s*,\s*')).freeze
|
74
|
+
end
|
75
|
+
|
40
76
|
end
|
41
77
|
|
42
78
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Gribr
|
2
|
+
module Degrib
|
3
|
+
|
4
|
+
class Message
|
5
|
+
|
6
|
+
attr_reader :file, :inventory_record
|
7
|
+
|
8
|
+
def initialize(file, inventory_record)
|
9
|
+
@file, @inventory_record = file, inventory_record
|
10
|
+
end
|
11
|
+
|
12
|
+
# Probe the grib message at the given location and return/yield
|
13
|
+
# the records.
|
14
|
+
def probe(latitude, longitude, options = { }, &block)
|
15
|
+
|
16
|
+
records = Array.new
|
17
|
+
|
18
|
+
file.probe(latitude, longitude, options) do |record|
|
19
|
+
|
20
|
+
# if record.element.downcase == inventory_record.element.downcase
|
21
|
+
yield(record) if block_given?
|
22
|
+
records << record
|
23
|
+
# end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
records
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/lib/gribr/inventory.rb
CHANGED
@@ -1,31 +1,38 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
1
3
|
module Gribr
|
2
4
|
|
3
5
|
class Inventory
|
4
6
|
|
5
|
-
def initialize(
|
6
|
-
@
|
7
|
-
|
7
|
+
def initialize(records = Array.new)
|
8
|
+
@records = Hash.new
|
9
|
+
records.each { |record| add_record(record) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_record(record)
|
13
|
+
set_end_position_of_previous(record)
|
14
|
+
@records[record.number] = record
|
15
|
+
record
|
8
16
|
end
|
9
17
|
|
10
|
-
def
|
11
|
-
|
12
|
-
@messages[message.number] = message
|
18
|
+
def records
|
19
|
+
@records.values.sort_by(&:number)
|
13
20
|
end
|
14
21
|
|
15
|
-
def
|
16
|
-
|
22
|
+
def to_s
|
23
|
+
records.join("\n")
|
17
24
|
end
|
18
25
|
|
19
26
|
protected
|
20
27
|
|
21
|
-
def set_end_position_of_previous(
|
22
|
-
@
|
28
|
+
def set_end_position_of_previous(record)
|
29
|
+
@records[record.number - 1].end_position = record.end_position_of_previous if @records[record.number - 1]
|
23
30
|
end
|
24
31
|
|
25
32
|
class << self
|
26
33
|
|
27
34
|
def file(file)
|
28
|
-
|
35
|
+
::File.gribfile?(file) ? grib_file(file) : inventory_file(file)
|
29
36
|
end
|
30
37
|
|
31
38
|
def io(io)
|
@@ -35,9 +42,9 @@ module Gribr
|
|
35
42
|
io.each_with_index do |line, index|
|
36
43
|
|
37
44
|
if index > 0
|
38
|
-
|
39
|
-
inventory.
|
40
|
-
yield(
|
45
|
+
record = parse_record(line)
|
46
|
+
inventory.add_record(record)
|
47
|
+
yield(record) if block_given?
|
41
48
|
end
|
42
49
|
|
43
50
|
end
|
@@ -46,6 +53,10 @@ module Gribr
|
|
46
53
|
|
47
54
|
end
|
48
55
|
|
56
|
+
def url(url)
|
57
|
+
open(url) { |io| io(io) }
|
58
|
+
end
|
59
|
+
|
49
60
|
protected
|
50
61
|
|
51
62
|
def grib_file(file)
|
@@ -3,7 +3,7 @@ require 'gribr/utils'
|
|
3
3
|
module Gribr
|
4
4
|
module Wgrib
|
5
5
|
|
6
|
-
class InventoryRecord < Struct.new(:element, :end_position, :number, :start_position, :reference_time, :valid_time)
|
6
|
+
class InventoryRecord < Struct.new(:average, :element, :end_position, :level, :number, :start_position, :projection, :reference_time, :valid_time)
|
7
7
|
|
8
8
|
include Gribr::RegexpParser
|
9
9
|
|
@@ -16,6 +16,17 @@ module Gribr
|
|
16
16
|
class ShortInventoryRecord < InventoryRecord
|
17
17
|
|
18
18
|
REGEX_TIMESTAMP = Regexp.new("(d=(\\d{2,4})(\\d{2})(\\d{2})(\\d{2}))").freeze
|
19
|
+
TIME_FORMAT = "%Y%m%d%H".freeze
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
[number, start_position, formatted_reference_time, element, level, projection, average].join(":")
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def formatted_reference_time
|
28
|
+
"d=" + reference_time.strftime(TIME_FORMAT)
|
29
|
+
end
|
19
30
|
|
20
31
|
def self.build(match_data)
|
21
32
|
|
@@ -25,13 +36,16 @@ module Gribr
|
|
25
36
|
record.number = match_data[1].to_i
|
26
37
|
record.start_position = match_data[2].to_i
|
27
38
|
record.element = match_data[8]
|
39
|
+
record.level = match_data[9]
|
28
40
|
|
29
41
|
year = (match_data[4].size == 4 ? match_data[4] : Time.now.utc.year.to_s.gsub(/\d{2}$/, match_data[4])).to_i
|
30
|
-
record.
|
42
|
+
record.reference_time = Time.utc(year, match_data[5].to_i, match_data[6].to_i, match_data[7].to_i)
|
31
43
|
|
32
|
-
# Calculte reference time
|
33
44
|
offset = match_data[10].split.first.to_i * 60 * 60
|
34
|
-
record.
|
45
|
+
record.valid_time = record.reference_time + offset
|
46
|
+
|
47
|
+
record.projection = match_data[10]
|
48
|
+
record.average = match_data[11]
|
35
49
|
|
36
50
|
record
|
37
51
|
|
@@ -50,6 +50,14 @@ module Gribr::Degrib
|
|
50
50
|
@file.inventory.should be_kind_of(Inventory)
|
51
51
|
end
|
52
52
|
|
53
|
+
it "should return the messages as an array" do
|
54
|
+
@file.messages.should be_kind_of(Array)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return the messages as an array of Gribr::Degrib::Message objects" do
|
58
|
+
@file.messages.each { |message| message.should be_kind_of(Message) }
|
59
|
+
end
|
60
|
+
|
53
61
|
it "should probe at the given position and return the records in an array" do
|
54
62
|
@file.probe(@latitude, @longitude).should be_kind_of(Array)
|
55
63
|
end
|
@@ -61,9 +69,12 @@ module Gribr::Degrib
|
|
61
69
|
it "should probe at the given position and yield the records" do
|
62
70
|
@file.index!
|
63
71
|
@file.probe(@latitude, @longitude) { |record| record.should be_kind_of(ProbeRecord) }
|
64
|
-
# @file.probe(@latitude, @longitude) { |record| puts record }
|
65
72
|
end
|
66
73
|
|
74
|
+
# it "should probe at the given position and yield the records" do
|
75
|
+
# @file.probe(@latitude, @longitude) { |record| puts record }
|
76
|
+
# end
|
77
|
+
|
67
78
|
end
|
68
79
|
|
69
80
|
end
|
@@ -7,11 +7,18 @@ module Gribr::Degrib
|
|
7
7
|
describe "A degrib inventory" do
|
8
8
|
|
9
9
|
before(:each) do
|
10
|
-
@
|
10
|
+
@gribfilename = File.expand_path(File.dirname(__FILE__) + '/../../../fixtures/wind.grib')
|
11
|
+
@inventory = Inventory.file(@gribfilename)
|
11
12
|
end
|
12
13
|
|
13
14
|
it_should_behave_like "An inventory"
|
14
15
|
|
16
|
+
it "should return the string representation" do
|
17
|
+
expected = (`degrib #{@gribfilename} -I`).split("\n")
|
18
|
+
expected = expected[1..(expected.size - 1)].join("\n")
|
19
|
+
@inventory.to_s.should == expected
|
20
|
+
end
|
21
|
+
|
15
22
|
end
|
16
23
|
|
17
24
|
describe Inventory do
|
@@ -34,7 +41,7 @@ module Gribr::Degrib
|
|
34
41
|
Inventory.file(clazz.new(@gribfile)).should be_kind_of(Inventory)
|
35
42
|
end
|
36
43
|
|
37
|
-
it "should parse the inventory from the
|
44
|
+
it "should parse the inventory from the given inventory file" do
|
38
45
|
Tempfile.open("inventory") do |tempfile|
|
39
46
|
system("degrib #{@gribfile} -I > #{tempfile.path}")
|
40
47
|
Inventory.file(clazz.new(tempfile.path)).should be_kind_of(Inventory)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
|
2
|
+
|
3
|
+
module Gribr::Degrib
|
4
|
+
|
5
|
+
describe Message do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@latitude, @longitude = 0, 0
|
9
|
+
@filename = File.expand_path(File.dirname(__FILE__) + '/../../../fixtures/wind.grib')
|
10
|
+
@message = Gribr::Degrib::File.new(@filename).messages.first
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be kind of Gribr::Degrib::Message" do
|
14
|
+
@message.should be_kind_of(Message)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should probe the records at the given position and return them in an array" do
|
18
|
+
@message.probe(@latitude, @longitude).should be_kind_of(Array)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should probe the records at the given position and yield them to the given block" do
|
22
|
+
@message.probe(@latitude, @longitude) { |record| record.should be_kind_of(ProbeRecord) }
|
23
|
+
end
|
24
|
+
|
25
|
+
# it "should probe at the given position and yield the records" do
|
26
|
+
# @message.probe(@latitude, @longitude) { |record| puts record }
|
27
|
+
# end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -8,12 +8,16 @@ module Gribr
|
|
8
8
|
@inventory.should be_kind_of(Inventory)
|
9
9
|
end
|
10
10
|
|
11
|
-
it "should return the
|
12
|
-
@inventory.
|
11
|
+
it "should return the records as an array" do
|
12
|
+
@inventory.records.should be_kind_of(Array)
|
13
13
|
end
|
14
14
|
|
15
|
-
it "should return the
|
16
|
-
@inventory.
|
15
|
+
it "should return the records sorted by number" do
|
16
|
+
@inventory.records.each_cons(2) { |cons| cons.first.number.should < cons.last.number }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should calculate the end position for each record" do
|
20
|
+
@inventory.records.each_cons(2) { |cons| cons.first.end_position.should == cons.last.start_position - 1 }
|
17
21
|
end
|
18
22
|
|
19
23
|
end
|
@@ -26,12 +26,24 @@ module Gribr::Wgrib
|
|
26
26
|
@record.element.should == 'DIRSW'
|
27
27
|
end
|
28
28
|
|
29
|
-
it 'should assign the
|
30
|
-
@record.
|
29
|
+
it 'should assign the level' do
|
30
|
+
@record.level.should == 'sfc'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should assign the projection' do
|
34
|
+
@record.projection.should == '3hr fcst'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should assign the average value' do
|
38
|
+
@record.average.should == 'NAve=0'
|
31
39
|
end
|
32
40
|
|
33
41
|
it 'should assign the reference time' do
|
34
|
-
@record.reference_time.should ==
|
42
|
+
@record.reference_time.should == Time.utc(2009, 11, 4, 0)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should assign the valid time' do
|
46
|
+
@record.valid_time.should == @record.reference_time + (3 * 60 * 60)
|
35
47
|
end
|
36
48
|
|
37
49
|
end
|
@@ -54,6 +66,10 @@ module Gribr::Wgrib
|
|
54
66
|
|
55
67
|
it_should_behave_like "Parsing a short wgrib record"
|
56
68
|
|
69
|
+
it "should return the wgrib string representation" do
|
70
|
+
@record.to_s.should == "22:1057378:d=2009110400:DIRSW:sfc:3hr fcst:NAve=0"
|
71
|
+
end
|
72
|
+
|
57
73
|
end
|
58
74
|
|
59
75
|
end
|
@@ -12,6 +12,12 @@ module Gribr::Wgrib
|
|
12
12
|
|
13
13
|
it_should_behave_like "An inventory"
|
14
14
|
|
15
|
+
it "should create an inventory from an url" do
|
16
|
+
url = "http://nomad5.ncep.noaa.gov/pub/waves/nww3/nww320091104/nww3.t00z.grib.inv"
|
17
|
+
Inventory.should_receive(:open).with(url).and_yield(StringIO.new(""))
|
18
|
+
Inventory.url(url).should be_kind_of(Inventory)
|
19
|
+
end
|
20
|
+
|
15
21
|
end
|
16
22
|
|
17
23
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gribr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roman Scherer
|
@@ -9,8 +9,8 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
13
|
-
default_executable:
|
12
|
+
date: 2009-11-12 00:00:00 +01:00
|
13
|
+
default_executable: probe-wukong
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: "0"
|
34
34
|
version:
|
35
|
-
description: Ruby wrapper to read gridded binary (GRIB) files
|
35
|
+
description: Ruby wrapper to read gridded binary (GRIB) files using degrib.
|
36
36
|
email: roman.scherer@burningswell.com
|
37
|
-
executables:
|
38
|
-
|
37
|
+
executables:
|
38
|
+
- probe-wukong
|
39
39
|
extensions: []
|
40
40
|
|
41
41
|
extra_rdoc_files:
|
@@ -58,6 +58,7 @@ files:
|
|
58
58
|
- lib/gribr/degrib/index.rb
|
59
59
|
- lib/gribr/degrib/inventory.rb
|
60
60
|
- lib/gribr/degrib/inventory_record.rb
|
61
|
+
- lib/gribr/degrib/message.rb
|
61
62
|
- lib/gribr/degrib/probe_record.rb
|
62
63
|
- lib/gribr/executeable.rb
|
63
64
|
- lib/gribr/inventory.rb
|
@@ -73,6 +74,7 @@ files:
|
|
73
74
|
- spec/lib/gribr/degrib/index_spec.rb
|
74
75
|
- spec/lib/gribr/degrib/inventory_record_spec.rb
|
75
76
|
- spec/lib/gribr/degrib/inventory_spec.rb
|
77
|
+
- spec/lib/gribr/degrib/message_spec.rb
|
76
78
|
- spec/lib/gribr/degrib/probe_record_spec.rb
|
77
79
|
- spec/lib/gribr/degrib_spec.rb
|
78
80
|
- spec/lib/gribr/executeable_spec.rb
|
@@ -108,12 +110,13 @@ rubyforge_project:
|
|
108
110
|
rubygems_version: 1.3.5
|
109
111
|
signing_key:
|
110
112
|
specification_version: 3
|
111
|
-
summary:
|
113
|
+
summary: Read gridded binary (GRIB) files with ruby.
|
112
114
|
test_files:
|
113
115
|
- spec/gribr_spec.rb
|
114
116
|
- spec/lib/gribr/degrib/index_spec.rb
|
115
117
|
- spec/lib/gribr/degrib/cube_spec.rb
|
116
118
|
- spec/lib/gribr/degrib/probe_record_spec.rb
|
119
|
+
- spec/lib/gribr/degrib/message_spec.rb
|
117
120
|
- spec/lib/gribr/degrib/inventory_spec.rb
|
118
121
|
- spec/lib/gribr/degrib/inventory_record_spec.rb
|
119
122
|
- spec/lib/gribr/degrib/file_spec.rb
|