gribr 0.2.0 → 0.3.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/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{Ruby wrapper to read gridded binary (GRIB) files with degrib.}
9
- gem.description = %Q{Ruby wrapper to read gridded binary (GRIB) files with degrib.}
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.2.0
1
+ 0.3.0
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
3
+ require 'gribr'
4
+ require 'gribr/degrib/probe_mapper'
5
+ require 'gribr/degrib/probe_reducer'
6
+ Wukong::Script.new(Gribr::Degrib::ProbeMapper, Gribr::Degrib::ProbeReducer).run
7
+
@@ -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
 
@@ -35,7 +35,13 @@ module Gribr
35
35
  @inventory ||= Inventory.file(self)
36
36
  end
37
37
 
38
- # Probe the grib file at the given location and return/yield the records.
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 self.class.gribfile?(self); ensure; rewind
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 self.build(match_data)
21
-
22
- if match_data
23
- record = new
24
- record.number = match_data[1].to_i
25
- record.start_position = match_data[3].to_i
26
- record.version = match_data[4].to_i
27
- record.element = match_data[6]
28
- record.description = match_data[7]
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 self.regexp
39
- @regexp ||= Regexp.new([REGEXP_FLOAT, REGEXP_INTEGER, REGEXP_INTEGER, REGEXP_ELEMENT, REGEXP_LEVEL, REGEXP_TIMESTAMP, REGEXP_TIMESTAMP].join('\s*,\s*')).freeze
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
@@ -1,31 +1,38 @@
1
+ require 'open-uri'
2
+
1
3
  module Gribr
2
4
 
3
5
  class Inventory
4
6
 
5
- def initialize(messages = Array.new)
6
- @messages = Hash.new
7
- messages.each { |message| add_message(message) }
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 add_message(message)
11
- set_end_position_of_previous(message)
12
- @messages[message.number] = message
18
+ def records
19
+ @records.values.sort_by(&:number)
13
20
  end
14
21
 
15
- def messages
16
- @messages.values.sort_by(&:number)
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(message)
22
- @messages[message.number - 1].end_position = message.end_position_of_previous if @messages[message.number - 1]
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
- Gribr::Degrib::File.gribfile?(file) ? grib_file(file) : inventory_file(file)
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
- message = parse_record(line)
39
- inventory.add_message(message)
40
- yield(message) if block_given?
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.valid_time = Time.utc(year, match_data[5].to_i, match_data[6].to_i, match_data[7].to_i)
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.reference_time = record.valid_time + offset
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
@@ -113,6 +113,10 @@ module Gribr::Degrib
113
113
  @record.valid_time.should == Time.utc(2009, 9, 18, 0)
114
114
  end
115
115
 
116
+ it "should have the same string representation as the raw record" do
117
+ @record.to_s.should == @raw
118
+ end
119
+
116
120
  end
117
121
 
118
122
  end
@@ -7,11 +7,18 @@ module Gribr::Degrib
7
7
  describe "A degrib inventory" do
8
8
 
9
9
  before(:each) do
10
- @inventory = Inventory.file(File.expand_path(File.dirname(__FILE__) + '/../../../fixtures/wind.grib'))
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 content of the given file" do
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 messages as an array" do
12
- @inventory.messages.should be_kind_of(Array)
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 messages sorted by number" do
16
- @inventory.messages.each_cons(2) { |cons| cons.first.number.should < cons.last.number }
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 valid time' do
30
- @record.valid_time.should == Time.utc(2009, 11, 4, 0)
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 == @record.valid_time + (3 * 60 * 60)
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.2.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-04 00:00:00 +01:00
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 with degrib.
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: Ruby wrapper to read gridded binary (GRIB) files with degrib.
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