knmi 0.1.4 → 0.2.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.
@@ -0,0 +1,181 @@
1
+ ---
2
+ - parameter: YYYYMMDD
3
+ category:
4
+ description: Time Stamp
5
+ validate:
6
+ conversion: |-
7
+ Time.utc(
8
+ year = n.to_s[(0..3)],
9
+ month = n.to_s[(4..5)],
10
+ day = n.to_s[(6..7)]
11
+ )
12
+ units: Time
13
+ period: hourly
14
+ - parameter: HH
15
+ category:
16
+ description: Hour
17
+ validate: (1..24).include?(n)
18
+ conversion:
19
+ units: hour
20
+ period: hourly
21
+ - parameter: DD
22
+ category: WIND
23
+ description: Mean Wind Direction During the 10-Minute Period Preceding the Time of Observation
24
+ validate: (0..360).to_a.push(990).include?(n)
25
+ conversion:
26
+ units: Polar Coordinates (360=north, 90=east, 180=south, 270=west,0=calm, 990=variable)
27
+ period: hourly
28
+ - parameter: FH
29
+ category: WIND
30
+ description: Hourly Mean Wind Speed
31
+ validate: n.integer?
32
+ conversion: n / 10
33
+ units: m/s
34
+ period: hourly
35
+ - parameter: FF
36
+ category: WIND
37
+ description: Mean Wind Speed
38
+ validate: n.integer?
39
+ conversion: n / 10
40
+ units: m/s
41
+ period: hourly
42
+ - parameter: FX
43
+ category: WIND
44
+ description: Maximum Wind Gust
45
+ validate: n.integer?
46
+ conversion: n / 10
47
+ units: m/s
48
+ period: hourly
49
+ - parameter: T
50
+ category: TEMP
51
+ description: Air Temperature at 1.5 m
52
+ validate: n.integer?
53
+ conversion: n / 10
54
+ units: C
55
+ period: hourly
56
+ - parameter: T10N
57
+ category: TEMP
58
+ description: Minimum Air Temperature at 10 cm in the Preceding 6 Hours
59
+ validate: n.integer?
60
+ conversion: n / 10
61
+ units: C
62
+ period: hourly
63
+ - parameter: TD
64
+ category: TEMP
65
+ description: Dew Point Temperature
66
+ validate: n.integer?
67
+ conversion: n / 10
68
+ units: C
69
+ period: hourly
70
+ - parameter: SQ
71
+ category: RDTN
72
+ description: Sunshine Duration
73
+ validate: (-1..240).include?(n)
74
+ conversion: "n == -1 ? 0.05 : (n / 10) * 60"
75
+ units: minutes
76
+ period: hourly
77
+ - parameter: Q
78
+ category: RDTN
79
+ description: Golbal Radiation
80
+ validate: n.integer?
81
+ conversion:
82
+ units: J/cm^2
83
+ period: hourly
84
+ - parameter: DR
85
+ category: PRCP
86
+ description: Precipitation Duration
87
+ validate: (0..240).include?(n)
88
+ conversion: (n / 10) * 60
89
+ units: minutes
90
+ period: hourly
91
+ - parameter: RH
92
+ category: PRCP
93
+ description: Precipitation
94
+ validate: n.integer?
95
+ conversion: n / 10
96
+ units: mm
97
+ period: hourly
98
+ - parameter: P
99
+ category: ATMS
100
+ description: Air Pressure
101
+ validate: n.integer?
102
+ conversion: n / 10
103
+ units: hPa
104
+ period: hourly
105
+ - parameter: VV
106
+ category: VISB
107
+ description: Visibility
108
+ validate:
109
+ conversion: |-
110
+ if n == 0
111
+ '< 100 meters'
112
+ elsif (1..49).include?(n)
113
+ (n * 100).to_s + '-' + ((n+1) * 100).to_s + ' meters'
114
+ elsif n == 50
115
+ '5-6 kilometers'
116
+ elsif (56..79).include?(n)
117
+ (n - 50).to_s + '-' + (n - 49).to_s + ' kilometers'
118
+ elsif (80..88).include?(n)
119
+ (n - 50).to_s + '-' + (n - 45).to_s + ' kilometers'
120
+ elsif n == 89
121
+ '> 70 kilometers'
122
+ end
123
+ units:
124
+ period: hourly
125
+ - parameter: N
126
+ category: VISB
127
+ description: Cloud Cover
128
+ validate: (0..9).include?(n)
129
+ conversion:
130
+ units:
131
+ period: hourly
132
+ - parameter: U
133
+ category: ATMS
134
+ description: Relative Humidity
135
+ validate: (0..100).include?(n)
136
+ conversion:
137
+ units: %
138
+ period: hourly
139
+ - parameter: M
140
+ category: WTHR
141
+ description: Fog
142
+ validate: (0..1).include?(n)
143
+ conversion:
144
+ units: boolean
145
+ period: hourly
146
+ - parameter: R
147
+ category: WTHR
148
+ description: Rainfall
149
+ validate: (0..1).include?(n)
150
+ conversion:
151
+ units: boolean
152
+ period: hourly
153
+ - parameter: S
154
+ category: WTHR
155
+ description: Snow
156
+ validate: (0..1).include?(n)
157
+ conversion:
158
+ units: boolean
159
+ period: hourly
160
+ - parameter: O
161
+ category: WTHR
162
+ description: Thunder
163
+ validate: (0..1).include?(n)
164
+ conversion:
165
+ units: boolean
166
+ period: hourly
167
+ - parameter: Y
168
+ category: WTHR
169
+ description: Ice
170
+ validate: (0..1).include?(n)
171
+ conversion:
172
+ units: boolean
173
+ period: hourly
174
+ - parameter: WW
175
+ category: WTHR
176
+ description: Weather Code
177
+ validate: (0..99).include?(n)
178
+ conversion:
179
+ units: code
180
+ period: hourly
181
+
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{knmi}
8
- s.version = "0.1.4"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["bullfight"]
12
- s.date = %q{2011-05-02}
12
+ s.date = %q{2011-05-17}
13
13
  s.description = %q{A set of methods to query the KNMI HTTP get form for daily climate data and select a variety of measured parameters, from available stations, in a json style array of hashes, and if necessary convert to csv.}
14
14
  s.email = %q{p.schmitz@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
17
17
  "README.rdoc"
18
18
  ]
19
19
  s.files = [
20
+ ".DS_Store",
20
21
  ".document",
21
22
  "Gemfile",
22
23
  "Gemfile.lock",
@@ -24,10 +25,21 @@ Gem::Specification.new do |s|
24
25
  "README.rdoc",
25
26
  "Rakefile",
26
27
  "VERSION",
28
+ "data/current_stations.yml",
29
+ "data/daily_data_key.yml",
30
+ "data/data_key.yml",
31
+ "data/hourly_data_key.yml",
27
32
  "knmi.gemspec",
33
+ "lib/.DS_Store",
28
34
  "lib/knmi.rb",
35
+ "lib/knmi/httpservice.rb",
36
+ "lib/knmi/parameters.rb",
37
+ "lib/knmi/station.rb",
29
38
  "test/helper.rb",
30
- "test/test_knmi.rb"
39
+ "test/test_httpservice.rb",
40
+ "test/test_knmi.rb",
41
+ "test/test_parameters.rb",
42
+ "test/test_station.rb"
31
43
  ]
32
44
  s.homepage = %q{http://github.com/bullfight/knmi}
33
45
  s.licenses = ["MIT"]
@@ -36,30 +48,45 @@ Gem::Specification.new do |s|
36
48
  s.summary = %q{Ruby API to access daily climate data from the Royal Netherlands Meteorological Institute}
37
49
  s.test_files = [
38
50
  "test/helper.rb",
39
- "test/test_knmi.rb"
51
+ "test/test_httpservice.rb",
52
+ "test/test_knmi.rb",
53
+ "test/test_parameters.rb",
54
+ "test/test_station.rb"
40
55
  ]
41
56
 
42
57
  if s.respond_to? :specification_version then
43
58
  s.specification_version = 3
44
59
 
45
60
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
- s.add_development_dependency(%q<shoulda>, [">= 0"])
61
+ s.add_runtime_dependency(%q<httparty>, ["~> 0.7.7"])
62
+ s.add_runtime_dependency(%q<geokit>, ["~> 1.5.0"])
63
+ s.add_development_dependency(%q<shoulda>, ["~> 2.11.3"])
64
+ s.add_development_dependency(%q<shoulda-context>, ["~> 1.0.0.beta1"])
47
65
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
48
66
  s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
49
67
  s.add_development_dependency(%q<rcov>, [">= 0"])
68
+ s.add_development_dependency(%q<pry>, ["~> 0.8.3"])
50
69
  s.add_runtime_dependency(%q<httparty>, [">= 0.7.4"])
51
70
  else
52
- s.add_dependency(%q<shoulda>, [">= 0"])
71
+ s.add_dependency(%q<httparty>, ["~> 0.7.7"])
72
+ s.add_dependency(%q<geokit>, ["~> 1.5.0"])
73
+ s.add_dependency(%q<shoulda>, ["~> 2.11.3"])
74
+ s.add_dependency(%q<shoulda-context>, ["~> 1.0.0.beta1"])
53
75
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
54
76
  s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
55
77
  s.add_dependency(%q<rcov>, [">= 0"])
78
+ s.add_dependency(%q<pry>, ["~> 0.8.3"])
56
79
  s.add_dependency(%q<httparty>, [">= 0.7.4"])
57
80
  end
58
81
  else
59
- s.add_dependency(%q<shoulda>, [">= 0"])
82
+ s.add_dependency(%q<httparty>, ["~> 0.7.7"])
83
+ s.add_dependency(%q<geokit>, ["~> 1.5.0"])
84
+ s.add_dependency(%q<shoulda>, ["~> 2.11.3"])
85
+ s.add_dependency(%q<shoulda-context>, ["~> 1.0.0.beta1"])
60
86
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
61
87
  s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
62
88
  s.add_dependency(%q<rcov>, [">= 0"])
89
+ s.add_dependency(%q<pry>, ["~> 0.8.3"])
63
90
  s.add_dependency(%q<httparty>, [">= 0.7.4"])
64
91
  end
65
92
  end
Binary file
@@ -1,202 +1,83 @@
1
- require 'httparty'
2
- require 'csv'
1
+ begin
2
+ require 'httparty'
3
+ require 'geokit'
4
+ require 'csv'
5
+ rescue LoadError => e
6
+ if require 'rubygems' then retry
7
+ else raise(e)
8
+ end
9
+ end
10
+
11
+ %w(station parameters httpservice).each { |file| require File.join(File.dirname(__FILE__), 'knmi', file) }
12
+
13
+ module KNMI
3
14
 
4
- class KNMI
5
- include HTTParty
6
- base_uri 'http://www.knmi.nl/climatology/daily_data/getdata_day.cgi'
7
-
8
15
  class << self
9
- private :new
10
16
 
11
- # station1:station2:station15 requires station or list of stations NO DEFAULT
12
- def station(station_number)
13
- if station_number.nil? == true
14
- raise "Station Number Required" # doesn't work look into this
15
- elsif station_number.kind_of?(Array)
16
- "stns=#{station_number * ":"}"
17
- else
18
- "stns=#{station_number}"
19
- end
17
+ #
18
+ # Get nearest station by lat lng
19
+ # KNMI.station_by_location(52.165, 4.419) #=> #<KNMI::Station:0x0000010134e7f0>
20
+ def station_by_location(lat, lng)
21
+ Station.closest_to(lat, lng)
20
22
  end
21
23
 
22
- def check_stations
23
- # stubbed out complete later
24
+ #
25
+ # Get station object by station ID
26
+ # KNMI.station_by_id(210) #=> #<KNMI::Station:0x000001016b9b38>
27
+ def station_by_id(station_id)
28
+ Station.find(station_id)
24
29
  end
25
30
 
26
- # YYYYMMDD Default is first day of current month
27
- def start_date(_start)
28
- "start=#{_start}"
29
- end
31
+ #
32
+ # Generate array of unique daily or hourly parameter objects
33
+ # All details in daily_data_key.yml and hourly_data_key.yml
34
+ # inputs
35
+ # period = "daily" or "hourly"
36
+ # params =
37
+ # categories =
30
38
 
31
- # YYYYMMDD Default is current or last recorded day
32
- def end_date(_end)
33
- "end=#{_end}"
34
- end
35
-
36
- def variables(vars)
37
-
38
- if vars.empty? == true
39
- "vars=ALL"
40
- else
41
- vars, nvars = check_variables(vars)
42
- "vars=#{vars * ":"}"
43
- end
39
+ def parameters(period, params = "", categories = "")
40
+ if params.blank? and categories.blank?
41
+ list = Parameters.all(period)
42
+ else
43
+ list = []
44
+
45
+ # Parameters by category
46
+ list << Parameters.category(period, categories)
47
+ list.flatten!
48
+
49
+ # Parameters by name
50
+ params = unique_params(params, list) #ensure params are unique to list
51
+ list << Parameters.find(period, params)
52
+ list.flatten!
53
+ list.compact!
54
+ end
55
+ return list
44
56
  end
45
-
46
- # Delete Invalid Variables and keep those valid, if none are valid replace with all
47
- def check_variables(vars)
48
-
49
- if vars.kind_of?(Array) == false
50
- vars = [vars]
57
+
58
+ #
59
+ # Input a station object from KNMI.station_by_id or KNMI.station_by_location
60
+ # and a parameter hash of objects from # KNMI.Parameters
61
+ # return
62
+ def get_data(station_object, parameter_object, start_at = nil, end_at = nil, seasonal = false)
63
+ if parameter_object[0].period == "daily"
64
+ HttpService.get_daily(station_object, parameter_object, start_at, end_at, seasonal)
65
+ elsif parameter_object[0].period == "hourly"
66
+ HttpService.get_hourly(station_object, parameter_object, start_at, end_at, seasonal)
51
67
  end
52
-
53
- # Collections of variables and all Possible Variables
54
- varOpts = {
55
- "WIND" => ["DDVEC", "FG", "FHX", "FHX", "FX"],
56
- "TEMP" => ["TG", "TN", "TX", "T10N"],
57
- "SUNR" => ["SQ", "SP", "Q"],
58
- "PRCP" => ["DR", "RH", "EV24"],
59
- "PRES" => ["PG", "PGX", "PGN"],
60
- "VICL" => ["VVN", "VVX", "NG"],
61
- "MSTR" => ["VVN", "VVX", "NG"],
62
- "ALL" => ["DDVEC", "FHVEC", "FG", "FHX",
63
- "FHXH", "FHN", "FHNH", "FXX", "FXXH", "TG", "TN",
64
- "TNH", "TX", "TXH", "T10N", "T10NH", "SQ", "SP",
65
- "Q", "DR", "RH", "RHX", "RHXH", "EV24", "PG", "PX",
66
- "PXH", "PN", "PNH", "VVN", "VVNH", "VVX", "VVXH",
67
- "NG", "UG", "UX", "UXH", "UN", "UNH"]
68
- }
69
-
70
- # Drop in invalid vars
71
- vars = ( vars & varOpts.to_a.flatten )
72
-
73
- # Only Allow Variable to be selected once, All, or TEMP, not ALL & TEMP
74
- # And count the number of selected variables
75
- if vars.include?("ALL") == true or vars.empty? == true
76
- vars = "ALL"
77
- nvars = varOpts["ALL"].count
78
- elsif (vars & varOpts.keys) # check if contains keys
79
-
80
- x = []
81
- (vars & varOpts.keys).each do |k|
82
- x << varOpts.values_at(k)
83
- end
84
- vars = (vars - x.flatten)
85
-
86
- nvars = 0
87
- ( vars & varOpts.keys ).each do |v|
88
- nvars += varOpts[v].count
89
- end
90
-
91
- ( vars - varOpts.keys ).each do |v|
92
- nvars += 1
93
- end
94
- end
95
-
96
- return vars, nvars
97
68
  end
98
-
99
- # Parse Response into hashed arrays
100
- #Other elements
101
- #varlist = res[(7+nstn)..(6 + nstn + nvars)]
102
- #colheader = res[(8 + nstn + nvars)]
103
- #header = res[0..(9 + nstn + nvars)]
104
- def parse(response, station_number, vars)
105
- # Line Index Numbers
106
- nstn = [station_number].flatten.length
107
- vars, nvars = check_variables(vars)
108
-
109
- # Split lines into array
110
- response = response.split(/\n/)
111
-
112
- # Get Station Details
113
- stations = response[5..(4+nstn)]
114
- stations = stations.join.tr("\t", "\s")
115
- stations = stations.tr("#", "")
116
- stations = stations.tr(":", "")
117
- stations = CSV.parse( stations, {:col_sep => "\s"} )
118
- stations = stations.map {|row| row.map {|cell| cell.to_s } }
119
- st_header = [:station_code, :lng, :lat, :elev, :name]
120
- stations = stations.map {|row| Hash[*st_header.zip(row).flatten] }
121
69
 
122
- # Get Variable Details
123
- varlist = response[(7+nstn)..(6 + nstn + nvars)]
124
- varlist = varlist.join
125
- varlist = varlist.gsub(/# /, "")
126
- varlist = varlist.gsub(/\s{2,}/, "")
127
- varlist = varlist.gsub(/;/, "\r")
128
- varlist = CSV.parse( varlist, {:col_sep => "= "} )
129
- vr_header = [:var, :description]
130
- varlist = varlist.map {|row| Hash[*vr_header.zip(row).flatten] }
131
-
132
- # Get and clean data
133
- response = response[(8 + nstn + nvars)..response.length]
134
- response = response.join.tr("\s+", "")
135
- response = response.tr("#", "")
136
-
137
- # Parse into array and then hash with var name
138
- response = CSV.parse(response, {:skip_blanks => true})
139
- header = response.shift.map {|i| i.to_s.intern }
140
- string_data = response.map {|row| row.map {|cell| cell.to_s } }
141
- data = string_data.map {|row| Hash[*header.zip(row).flatten] }
142
-
143
- return {:stations => stations, :variables => varlist, :data => data}
144
- end
145
- end # End Private
146
-
147
- # gets variables from station or list of stations
148
- # with all variables if vars is empty or selected variables passed as an array
149
- # data is from begining of current month to current day
150
- # Example
151
- # station_number = [210, 212]
152
- # vars = "TG"
153
- # res = KNMIdaily.get_station( station_number, vars )
154
- # output {:stations => {:}}
155
- def self.get_station(station_number, vars = "")
156
- query = station(station_number) + "&" + variables(vars)
157
- puts query
158
- res = get("", { :query => query } )
159
- res = parse(res, station_number, vars)
160
- end
161
-
162
- # gets variables from station or list of stations
163
- # with all variables if vars is empty or selected variables passed as an array
164
- # data is from start date to current
165
- def self.get_station_start_to_current(station_number, start, vars = "")
166
- query = station(station_number) + "&" + start_date(start) + "&" + variables(vars)
167
- puts query
168
- res = get("", { :query => query } )
169
- res = parse(res, station_number, vars)
170
- end
171
-
172
- # gets variables from station or list of stations
173
- # with all variables if vars is empty or selected variables passed as an array
174
- # data is from start date to end date
175
- def self.get_station_range(station_number, _start, _end, vars = "")
176
- query = station(station_number) + "&" + start_date(_start) + "&" + end_date(_end) + "&" + variables(vars)
177
- puts query
178
- res = get("", { :query => query } )
179
- res = parse(res, station_number, vars)
180
- end
181
-
182
- # gets variables from station or list of stations
183
- # with all variables if vars is empty or selected variables passed as an array
184
- # seasonal data is from start date to end date
185
- # by selected month and day within each year
186
- def self.get_seasonal(station_number, _start, _end, vars = "")
187
- query = station(station_number) + "&" + "inseason=true" + "&" + start_date(_start) + "&" + end_date(_end) + "&" + variables(vars)
188
- puts query
189
- get("", { :query => query } )
190
- end
191
-
192
- def self.to_csv(filename, response)
193
- CSV.open(filename, "wb") do |csv|
194
- response[:data]
195
- csv << response[0].keys
196
- response[(1..(response.length - 1))].each do |line|
197
- csv << line.values
70
+
71
+ private
72
+
73
+ # Identify and eliminate overlap between params and categories
74
+ def unique_params(params, list)
75
+ list.each do |e|
76
+ params = [params].flatten
77
+ params.delete_if {|p| p == e.parameter }
198
78
  end
79
+ return params
199
80
  end
81
+
200
82
  end
201
-
202
83
  end