wasserstand 0.0.4 → 0.0.5
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/lib/wasserstand.rb +7 -3
- data/lib/wasserstand/level.rb +28 -5
- data/lib/wasserstand/provider/level_mapper.rb +41 -0
- data/lib/wasserstand/provider/pegel-online.rb +65 -7
- data/lib/wasserstand/provider/waterway_mapper.rb +34 -0
- data/lib/wasserstand/version.rb +1 -1
- data/lib/wasserstand/waterway.rb +25 -2
- data/test/helper.rb +9 -0
- data/test/unit/test_level.rb +37 -0
- data/test/unit/test_measurement.rb +11 -0
- data/test/unit/test_waterway.rb +21 -0
- metadata +10 -5
- data/lib/wasserstand/mapper.rb +0 -43
- data/test/unit/test_wasserstand.rb +0 -31
data/lib/wasserstand.rb
CHANGED
@@ -7,10 +7,14 @@ require_rel 'wasserstand'
|
|
7
7
|
|
8
8
|
module Wasserstand
|
9
9
|
class << self
|
10
|
-
attr_writer :
|
10
|
+
attr_writer :waterway_provider, :level_provider
|
11
11
|
|
12
|
-
def
|
13
|
-
@
|
12
|
+
def waterway_provider
|
13
|
+
@waterway_provider ||= PegelOnline::WaterwayProvider.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def level_provider
|
17
|
+
@level_provider ||= PegelOnline::LevelProvider.new
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
data/lib/wasserstand/level.rb
CHANGED
@@ -3,16 +3,39 @@ module Wasserstand
|
|
3
3
|
# see http://www.pegelonline.wsv.de/gast/hilfe#hilfe_pegelparameter
|
4
4
|
#
|
5
5
|
class Level # Pegel
|
6
|
-
|
7
|
-
|
6
|
+
class << self
|
7
|
+
def [](name)
|
8
|
+
Wasserstand.level_provider[name]
|
9
|
+
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
+
def all
|
12
|
+
Wasserstand.level_provider.all
|
13
|
+
end
|
14
|
+
|
15
|
+
def find_by_name(regex)
|
16
|
+
Wasserstand.level_provider.find_by_name(regex)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :name
|
21
|
+
attr_accessor :level_id, :km, :measurements
|
22
|
+
attr_writer :waterway
|
23
|
+
|
24
|
+
def initialize(name)
|
25
|
+
@name = name
|
11
26
|
@measurements = []
|
12
27
|
end
|
13
28
|
|
29
|
+
def waterway
|
30
|
+
if @waterway.respond_to?(:name)
|
31
|
+
@waterway
|
32
|
+
else
|
33
|
+
@waterway = Waterway[@waterway]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
14
37
|
def to_s
|
15
|
-
|
38
|
+
name
|
16
39
|
end
|
17
40
|
end
|
18
41
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Wasserstand
|
2
|
+
module PegelOnline
|
3
|
+
=begin
|
4
|
+
<item>
|
5
|
+
<no>8</no>
|
6
|
+
<psmgr>320</psmgr>
|
7
|
+
<pegelname>KONSTANZ</pegelname>
|
8
|
+
<messwert>380,7</messwert>
|
9
|
+
<km>0</km>
|
10
|
+
<pnp>391,89</pnp>
|
11
|
+
<tendenz>Gleich</tendenz>
|
12
|
+
<datum>13.09.2012</datum>
|
13
|
+
<uhrzeit>20:00:00</uhrzeit>
|
14
|
+
<pegelnummer>0906</pegelnummer>
|
15
|
+
</item>
|
16
|
+
=end
|
17
|
+
class LevelMapper
|
18
|
+
class << self
|
19
|
+
def map(item)
|
20
|
+
level_name = item.xpath('pegelname').text
|
21
|
+
|
22
|
+
Level.new(level_name).tap do |pegel|
|
23
|
+
# The level class will resolve the name to a real object if required
|
24
|
+
pegel.waterway = item.xpath('../name').text
|
25
|
+
|
26
|
+
pegel.level_id = item.xpath('pegelnummer').text
|
27
|
+
pegel.km = item.xpath('km').text.sub(',', '.').to_f
|
28
|
+
datum = item.xpath('datum').text
|
29
|
+
uhrzeit = item.xpath('uhrzeit').text
|
30
|
+
|
31
|
+
messdatum = TZInfo::Timezone.get('Europe/Berlin').local_to_utc(Time.parse("#{datum} #{uhrzeit}"))
|
32
|
+
wert = item.xpath('messwert').text.sub(',', '.').to_f
|
33
|
+
tendenz = item.xpath('tendenz').text.downcase.to_sym
|
34
|
+
|
35
|
+
pegel.measurements << Measurement.new(messdatum, wert, tendenz)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,23 +1,81 @@
|
|
1
1
|
module Wasserstand
|
2
|
-
module
|
3
|
-
class
|
2
|
+
module PegelOnline
|
3
|
+
class Provider
|
4
4
|
def initialize(url = 'http://www.pegelonline.wsv.de/svgz/pegelstaende_neu.xml')
|
5
5
|
@url = url
|
6
6
|
end
|
7
7
|
|
8
8
|
def [](name)
|
9
|
-
doc = Nokogiri::HTML(
|
10
|
-
results = doc.xpath(
|
9
|
+
doc = Nokogiri::HTML(fetch(@url), nil, 'ISO-8859-1')
|
10
|
+
results = doc.xpath(xpath_lookup(name))
|
11
11
|
|
12
12
|
case results.size
|
13
13
|
when 0
|
14
|
-
return
|
14
|
+
return nil # loookup returns nil if not found. This is a lookup, not find_all.
|
15
15
|
when 1
|
16
|
-
return
|
16
|
+
return mapper.map(results.first)
|
17
17
|
else
|
18
|
-
raise "Found #{results.size} results for #{name}."
|
18
|
+
raise "Name is not unique. Found #{results.size} results for #{name}."
|
19
19
|
end
|
20
20
|
end
|
21
|
+
|
22
|
+
def all
|
23
|
+
Nokogiri::HTML(fetch(@url), nil, 'ISO-8859-1').xpath(xpath_all).map{|o| mapper.map(o)}
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_by_name(name_expression)
|
27
|
+
# Not the best performing way, but it gives us the ability to use the XPath 2.0 'matches' function
|
28
|
+
# which isn't supported in Nokogiri (yet).
|
29
|
+
Nokogiri::HTML(fetch(@url), nil, 'ISO-8859-1').xpath(xpath_finder(name_expression), Class.new{
|
30
|
+
def matches(node_set, regex)
|
31
|
+
node_set.find_all do |node|
|
32
|
+
node.to_s.match(%r{#{regex}})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
}.new).map{|o| mapper.map(o)}
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def xpath_lookup(name)
|
41
|
+
"#{xpath_all}[#{name_attribute}/text() = '#{name.upcase}']"
|
42
|
+
end
|
43
|
+
|
44
|
+
def xpath_finder(regex)
|
45
|
+
"#{xpath_all}[matches(#{name_attribute}/text(), '#{regex}')]"
|
46
|
+
end
|
47
|
+
|
48
|
+
def fetch(url)
|
49
|
+
open(url).read
|
50
|
+
end
|
51
|
+
|
52
|
+
def name_attribute
|
53
|
+
'name'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class WaterwayProvider < Provider
|
58
|
+
def xpath_all
|
59
|
+
"//data/table/gewaesser"
|
60
|
+
end
|
61
|
+
|
62
|
+
def mapper
|
63
|
+
Wasserstand::PegelOnline::WaterwayMapper
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class LevelProvider < Provider
|
68
|
+
def xpath_all
|
69
|
+
"//data/table/gewaesser/item"
|
70
|
+
end
|
71
|
+
|
72
|
+
def mapper
|
73
|
+
Wasserstand::PegelOnline::LevelMapper
|
74
|
+
end
|
75
|
+
|
76
|
+
def name_attribute
|
77
|
+
'pegelname'
|
78
|
+
end
|
21
79
|
end
|
22
80
|
end
|
23
81
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Wasserstand
|
2
|
+
module PegelOnline
|
3
|
+
=begin
|
4
|
+
<gewaesser>
|
5
|
+
<name>BODENSEE</name>
|
6
|
+
<item>
|
7
|
+
<no>8</no>
|
8
|
+
<psmgr>320</psmgr>
|
9
|
+
<pegelname>KONSTANZ</pegelname>
|
10
|
+
<messwert>380,7</messwert>
|
11
|
+
<km>0</km>
|
12
|
+
<pnp>391,89</pnp>
|
13
|
+
<tendenz>Gleich</tendenz>
|
14
|
+
<datum>13.09.2012</datum>
|
15
|
+
<uhrzeit>20:00:00</uhrzeit>
|
16
|
+
<pegelnummer>0906</pegelnummer>
|
17
|
+
</item>
|
18
|
+
</gewaesser>
|
19
|
+
=end
|
20
|
+
class WaterwayMapper
|
21
|
+
class << self
|
22
|
+
def map(node)
|
23
|
+
Waterway.new(node.xpath('name').text).tap do |ww|
|
24
|
+
node.xpath('item').each do |item|
|
25
|
+
level = LevelMapper.map(item)
|
26
|
+
level.waterway = ww
|
27
|
+
ww.levels[level.name] = level
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/wasserstand/version.rb
CHANGED
data/lib/wasserstand/waterway.rb
CHANGED
@@ -1,8 +1,27 @@
|
|
1
1
|
module Wasserstand
|
2
|
+
# http://stackoverflow.com/questions/2030336/how-do-i-create-a-hash-in-ruby-that-compares-strings-ignoring-case
|
3
|
+
class HashClod < Hash
|
4
|
+
def [](key)
|
5
|
+
key.respond_to?(:upcase) ? super(key.upcase) : super(key)
|
6
|
+
end
|
7
|
+
|
8
|
+
def []=(key, value)
|
9
|
+
key.respond_to?(:upcase) ? super(key.encode.upcase, value) : super(key, value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
2
13
|
class Waterway
|
3
14
|
class << self
|
4
15
|
def [](name)
|
5
|
-
Wasserstand.
|
16
|
+
Wasserstand.waterway_provider[name]
|
17
|
+
end
|
18
|
+
|
19
|
+
def all
|
20
|
+
Wasserstand.waterway_provider.all
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_by_name(regex)
|
24
|
+
Wasserstand.waterway_provider.find_by_name(regex)
|
6
25
|
end
|
7
26
|
end
|
8
27
|
|
@@ -10,7 +29,11 @@ module Wasserstand
|
|
10
29
|
|
11
30
|
def initialize(name)
|
12
31
|
@name = name
|
13
|
-
@levels =
|
32
|
+
@levels = HashClod.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
name
|
14
37
|
end
|
15
38
|
end
|
16
39
|
end
|
data/test/helper.rb
CHANGED
@@ -1,2 +1,11 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require 'wasserstand'
|
3
|
+
|
4
|
+
class WasserstandTestCase < MiniTest::Unit::TestCase
|
5
|
+
include Wasserstand
|
6
|
+
|
7
|
+
def setup
|
8
|
+
url = File.join(File.dirname(__FILE__), 'fixtures', 'pegelstaende_neu.xml')
|
9
|
+
Wasserstand.waterway_provider = PegelOnline::WaterwayProvider.new(url)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestLevel < WasserstandTestCase
|
4
|
+
def test_size
|
5
|
+
assert_equal(534, Level.all.size)
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_kms
|
9
|
+
elbe_levels = Waterway['ELBE'].levels
|
10
|
+
assert_equal(60, elbe_levels.size)
|
11
|
+
|
12
|
+
assert_level({:name => 'PIRNA', :km => 34.67, :measurements_size => 1}, elbe_levels['PIRNA'])
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_finder
|
16
|
+
assert_equal(['HEIDELBERG UW', 'HAVELBERG EP', 'HAVELBERG STADT', 'HAVELBERG UP'], Level.find_by_name('ELBERG').map{|w| w.name})
|
17
|
+
assert_equal(21, Level.find_by_name('^E').size)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_lookup
|
21
|
+
pirna = Level['Pirna']
|
22
|
+
assert(pirna)
|
23
|
+
assert(pirna.waterway)
|
24
|
+
assert_equal('ELBE', pirna.waterway.name)
|
25
|
+
|
26
|
+
assert(Level['GENTHIN'])
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def assert_level(values, level)
|
32
|
+
assert(level)
|
33
|
+
assert_equal(values[:name], level.name)
|
34
|
+
assert_equal(values[:km], level.km)
|
35
|
+
assert_equal(values[:measurements_size], level.measurements.size)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestMeasurement < WasserstandTestCase
|
4
|
+
def test_single
|
5
|
+
konstanz_measurements = Waterway['BODENSEE'].levels['KONSTANZ'].measurements
|
6
|
+
|
7
|
+
assert_equal(Time.parse('2012-09-13 18:00:00 UTC'), konstanz_measurements.last.date)
|
8
|
+
assert_equal(380.7, konstanz_measurements.last.value)
|
9
|
+
assert_equal(:gleich, konstanz_measurements.last.trend)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestWaterway < WasserstandTestCase
|
4
|
+
def test_finder
|
5
|
+
assert_equal(['ELBE', 'ELBE-HAVEL-KANAL', 'ELBESEITENKANAL'], Waterway.find_by_name('ELB.*').map{|w| w.name})
|
6
|
+
assert_equal(7, Waterway.find_by_name('^E').size)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_size
|
10
|
+
assert_equal(77, Waterway.all.size)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_levels
|
14
|
+
assert_equal(1, Waterway['BODENSEE'].levels.size)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_lookup
|
18
|
+
assert(Waterway['Elbe'].levels['Pirna'])
|
19
|
+
assert(Waterway['ELBE-HAVEL-KANAL'].levels['GENTHIN'])
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wasserstand
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: require_all
|
@@ -108,14 +108,17 @@ files:
|
|
108
108
|
- bin/wasserstand
|
109
109
|
- lib/wasserstand.rb
|
110
110
|
- lib/wasserstand/level.rb
|
111
|
-
- lib/wasserstand/mapper.rb
|
112
111
|
- lib/wasserstand/measurement.rb
|
112
|
+
- lib/wasserstand/provider/level_mapper.rb
|
113
113
|
- lib/wasserstand/provider/pegel-online.rb
|
114
|
+
- lib/wasserstand/provider/waterway_mapper.rb
|
114
115
|
- lib/wasserstand/version.rb
|
115
116
|
- lib/wasserstand/waterway.rb
|
116
117
|
- test/fixtures/pegelstaende_neu.xml
|
117
118
|
- test/helper.rb
|
118
|
-
- test/unit/
|
119
|
+
- test/unit/test_level.rb
|
120
|
+
- test/unit/test_measurement.rb
|
121
|
+
- test/unit/test_waterway.rb
|
119
122
|
- wasserstand.gemspec
|
120
123
|
homepage: http://github.com/nerab/wasserstand
|
121
124
|
licenses: []
|
@@ -144,4 +147,6 @@ summary: Wasserstand auf deutschen Flüssen
|
|
144
147
|
test_files:
|
145
148
|
- test/fixtures/pegelstaende_neu.xml
|
146
149
|
- test/helper.rb
|
147
|
-
- test/unit/
|
150
|
+
- test/unit/test_level.rb
|
151
|
+
- test/unit/test_measurement.rb
|
152
|
+
- test/unit/test_waterway.rb
|
data/lib/wasserstand/mapper.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
module Wasserstand
|
2
|
-
=begin
|
3
|
-
<gewaesser>
|
4
|
-
<name>BODENSEE</name>
|
5
|
-
<item>
|
6
|
-
<no>8</no>
|
7
|
-
<psmgr>320</psmgr>
|
8
|
-
<pegelname>KONSTANZ</pegelname>
|
9
|
-
<messwert>380,7</messwert>
|
10
|
-
<km>0</km>
|
11
|
-
<pnp>391,89</pnp>
|
12
|
-
<tendenz>Gleich</tendenz>
|
13
|
-
<datum>13.09.2012</datum>
|
14
|
-
<uhrzeit>20:00:00</uhrzeit>
|
15
|
-
<pegelnummer>0906</pegelnummer>
|
16
|
-
</item>
|
17
|
-
</gewaesser>
|
18
|
-
=end
|
19
|
-
class Mapper
|
20
|
-
class << self
|
21
|
-
def map(node)
|
22
|
-
Waterway.new(node.xpath('name').text) .tap do |ww|
|
23
|
-
node.xpath('item').each do |item|
|
24
|
-
pegel_name = item.xpath('pegelname').text
|
25
|
-
ww.levels[pegel_name] = Level.new(item.xpath('pegelnummer').text).tap do |pegel|
|
26
|
-
pegel.name = pegel_name
|
27
|
-
pegel.km = item.xpath('km').text
|
28
|
-
|
29
|
-
datum = item.xpath('datum').text
|
30
|
-
uhrzeit = item.xpath('uhrzeit').text
|
31
|
-
|
32
|
-
messdatum = TZInfo::Timezone.get('Europe/Berlin').local_to_utc(Time.parse("#{datum} #{uhrzeit}"))
|
33
|
-
wert = item.xpath('messwert').text.sub(',', '.').to_f
|
34
|
-
tendenz = item.xpath('tendenz').text.downcase.to_sym
|
35
|
-
|
36
|
-
pegel.measurements << Measurement.new(messdatum, wert, tendenz)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
class TestWasserstand < MiniTest::Unit::TestCase
|
4
|
-
include Wasserstand
|
5
|
-
|
6
|
-
def setup
|
7
|
-
url = File.join(File.dirname(__FILE__), '..', 'fixtures', 'pegelstaende_neu.xml')
|
8
|
-
Wasserstand.provider = Provider::PegelOnline.new(url)
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_plain
|
12
|
-
assert Waterway['BODENSEE']
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_levels
|
16
|
-
assert_equal(1, Waterway['BODENSEE'].levels.size)
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_level_lookup
|
20
|
-
assert(Waterway['BODENSEE'].levels['KONSTANZ'])
|
21
|
-
assert(Waterway['ELBE-HAVEL-KANAL'].levels['GENTHIN'])
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_single_measurement
|
25
|
-
konstanz_measurements = Waterway['BODENSEE'].levels['KONSTANZ'].measurements
|
26
|
-
|
27
|
-
assert_equal(Time.parse('2012-09-13 18:00:00 UTC'), konstanz_measurements.last.date)
|
28
|
-
assert_equal(380.7, konstanz_measurements.last.value)
|
29
|
-
assert_equal(:gleich, konstanz_measurements.last.trend)
|
30
|
-
end
|
31
|
-
end
|