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 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