natour 0.1.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a465921bd4e696f168be735851b576e1ec95eca0396eb52581801a16d9c75e1
4
- data.tar.gz: 5c0fd93836e21d57752a185842c17787894b8c56d1850564240a6f88b514dcb5
3
+ metadata.gz: b125a5ba293c91fa5efcb56ee32bc6e5ed52c1b8daf82439bcbec6c7b279a29d
4
+ data.tar.gz: bda03749fc2db89b56adadbb8bfb1522b8e116d294be244f918f9a6142005d07
5
5
  SHA512:
6
- metadata.gz: d39f3f80ab7bc2ee632d3458d623e8f7bb517c19b2f8c3d3fcc110c15ff8c09c646e52fb59623ca3be7c7f08877e527991c5f2774c41f1f17f4752d8b7a636ff
7
- data.tar.gz: d20556324500e26c3d428c6925f0e5ceefad9dfd790f78083e25d38fe28e27756653f5eecb5f9545b978a36a28a761dd9d257fafa8ca1ff0c75b62d9d0670308
6
+ metadata.gz: c3ddac7902534aec8e14fb546287a45d6fd589c3b4c445b1291bef15d209b7eb9c43484f169ee7e3b9dcac44939b57f4d19d6fae07a261edf6d12499af11d16a
7
+ data.tar.gz: e1eebd6fa2c8704e25afe48c2120a146d0513f17a55df883d68aad05bbedd08e04173455119abe06ab8ef15894358b650a5590be74435ffd166f27e698c6aef6
data/CHANGELOG.adoc CHANGED
@@ -6,6 +6,62 @@ The format is based on https://keepachangelog.com/en/1.0.0/[Keep a Changelog^],
6
6
 
7
7
  == Unreleased
8
8
 
9
+ == 0.5.0 - 2021-08-16
10
+
11
+ === Added
12
+
13
+ - Reflect the date of the last update in the revision date
14
+ - Add captions to species lists in the AsciiDoc output
15
+ - Group species lists by taxonomic groups in the AsciiDoc output
16
+
17
+ === Fixed
18
+
19
+ - Support species lists of Flora Helvetica exported from Favoriten
20
+ - Consider botanical names with the authority name preceding the subspecies
21
+
22
+ == 0.4.0 - 2021-05-02
23
+
24
+ === Added
25
+
26
+ - Show date/time of images in draft output
27
+ - Support preferred conversion backend for draft output
28
+
29
+ === Changed
30
+
31
+ - Remove redundant method `Image.portrait?`
32
+
33
+ == 0.3.0 - 2021-03-07
34
+
35
+ === Changed
36
+
37
+ - Sort the reports according to their GPS track
38
+ - Bump minimum required Ruby version to 2.5
39
+ - Change font in PDF output to support ♀ and ♂ symbols
40
+
41
+ === Fixed
42
+
43
+ - Make source code compatible with Ruby version 2.5
44
+
45
+ == 0.2.0 - 2021-01-24
46
+
47
+ === Added
48
+
49
+ - Add this gem's name to the footer of the PDF output
50
+ - Support species lists from https://www.ornitho.ch/[ornitho.ch^] (KML format only)
51
+ - Classify species lists by taxonomic groups (i.e. `SpeciesList.group`)
52
+
53
+ === Changed
54
+
55
+ - Change `SpeciesList.name` to `SpeciesList.title`
56
+ - Return an empty array from `SpeciesList.load_file` if the format is unknown
57
+ - Change the format of the start time in the AsciiDoc output from _12:30_ to _12:30 Uhr_
58
+ - Change the format of the duration in the AsciiDoc output from _1h30_ to _1:30 h_
59
+
60
+ === Fixed
61
+
62
+ - Get the date from images even if the orientation tag is missing
63
+ - Fix typo in help message
64
+
9
65
  == 0.1.0 - 2020-12-04
10
66
 
11
67
  === Added
data/README.adoc CHANGED
@@ -45,7 +45,7 @@ sudo apt install build-essential patch ruby-dev zlib1g-dev liblzma-dev
45
45
  +
46
46
  [source,shell]
47
47
  ----
48
- sudo apt install libvips42
48
+ sudo apt install libvips
49
49
  ----
50
50
 
51
51
  . Install https://www.google.com/chrome/[Google Chrome-Webbroser^]
data/bin/natour CHANGED
@@ -17,6 +17,7 @@ config = Natour::Config.load_file(
17
17
  'adoc-author' => nil,
18
18
  'backend' => 'pdf',
19
19
  'draft' => false,
20
+ 'draft-backend' => nil,
20
21
  'image-maxdim' => 1800
21
22
  }
22
23
  )
@@ -27,9 +28,9 @@ option_parser = OptionParser.new do |opts|
27
28
  opts.separator(WordWrap.ww(
28
29
  'If PATH refers to a directory, one or more reports are created in ' \
29
30
  'AsciiDoc format. GPS tracks, images and species lists (Kosmos ' \
30
- 'Vogelführer, Flora Helvetica, Info Flora Online-Feldbuch) are ' \
31
- 'included. Images of the map section covered by the GPS tracks are also ' \
32
- 'created and included. If PATH refers to an AsciiDoc file, it is ' \
31
+ 'Vogelführer, ornitho.ch, Flora Helvetica, Info Flora Online-Feldbuch) ' \
32
+ 'are included. Images of the map section covered by the GPS tracks are ' \
33
+ 'also created and included. If PATH refers to an AsciiDoc file, it is ' \
33
34
  'converted to PDF (or any other supported format).'
34
35
  ))
35
36
  opts.separator('')
@@ -49,7 +50,7 @@ option_parser = OptionParser.new do |opts|
49
50
  end
50
51
  opts.separator('')
51
52
  opts.separator('Creation:')
52
- opts.on('--track-formats FORMATS', Array, 'GPS track formats (gpx, fit') do |value|
53
+ opts.on('--track-formats FORMATS', Array, 'GPS track formats (gpx, fit)') do |value|
53
54
  config['track-formats'] = value.map(&:to_sym)
54
55
  end
55
56
  opts.on('--[no-]map', 'Create map images') do |value|
@@ -69,6 +70,9 @@ option_parser = OptionParser.new do |opts|
69
70
  opts.on('--[no-]draft', 'Show additional information (e.g. image paths)') do |value|
70
71
  config['draft'] = value
71
72
  end
73
+ opts.on('--draft-backend BACKEND', 'Preferred conversion backend for draft (pdf, html5 ...)') do |value|
74
+ config['draft-backend'] = value
75
+ end
72
76
  opts.on('--image-maxdim DIM', 'Shrink oversized images (PDF only)') do |value|
73
77
  config['image-maxdim'] = value.to_i
74
78
  end
@@ -106,6 +110,7 @@ else
106
110
  overwrite: config['overwrite'],
107
111
  backend: config['backend'],
108
112
  draft: config['draft'],
113
+ draft_backend: config['draft-backend'],
109
114
  image_maxdim: config['image-maxdim']
110
115
  )
111
116
  end
data/lib/natour.rb CHANGED
@@ -1,7 +1,8 @@
1
- require 'natour/cli/convert'
2
- require 'natour/cli/create'
3
- require 'natour/helpers/date_parser'
4
- require 'natour/helpers/suppress_output'
1
+ require 'natour/utils/botanical_name_utils'
2
+ require 'natour/utils/date_utils'
3
+ require 'natour/utils/stdout_utils'
4
+ require 'natour/convert'
5
+ require 'natour/create'
5
6
  require 'natour/asciinurse'
6
7
  require 'natour/config'
7
8
  require 'natour/gps_track'
@@ -30,9 +30,10 @@ module Natour
30
30
  doc << "= #{title}"
31
31
  if author
32
32
  doc << author
33
- doc << Date.today.strftime('%d.%m.%Y')
33
+ doc << ':revdate: {docdate}'
34
34
  end
35
35
  doc << ':figure-caption!:'
36
+ doc << ':table-caption!:'
36
37
  doc << ':pdf-page-mode: none'
37
38
  doc << ':title-page:'
38
39
  if title_image
@@ -51,8 +52,8 @@ module Natour
51
52
  doc << '[cols="h,3"]'
52
53
  doc << '|==='
53
54
  doc << "|Datum |#{gps_track&.date&.strftime('%d.%m.%Y')}"
54
- doc << "|Startzeit |#{gps_track&.start_point&.time&.strftime('%H:%M')}"
55
- doc << "|Dauer |#{gps_track&.duration&.strftime('%thh%M')}"
55
+ doc << "|Startzeit |#{gps_track&.start_point&.time&.strftime('%H:%M Uhr')}"
56
+ doc << "|Dauer |#{gps_track&.duration&.strftime('%th:%M h')}"
56
57
  doc << "|Strecke |#{distance.call(gps_track)}"
57
58
  doc << "|Aufstieg |#{ascent.call(gps_track)}"
58
59
  doc << "|Abstieg |#{descent.call(gps_track)}"
@@ -77,10 +78,10 @@ module Natour
77
78
  doc << '== Bilder'
78
79
  doc << ''
79
80
  images.each do |image|
80
- width = if image.portrait?
81
- '40%'
82
- else
81
+ width = if image.landscape?
83
82
  '80%'
83
+ else
84
+ '40%'
84
85
  end
85
86
  doc << '.Abbildung {counter:image}'
86
87
  doc << "image::#{Pathname(doc_root).join(image.path)}[width=#{width}]"
@@ -88,36 +89,45 @@ module Natour
88
89
  end
89
90
  end
90
91
  unless species_lists.empty?
91
- birds_info = OpenStruct.new(
92
- title: 'Vogelarten',
93
- headers: %w[Deutscher\ Name Wissenschaftlicher\ Name],
94
- columns: %i[name_de name]
95
- )
96
- plants_info = OpenStruct.new(
97
- title: 'Pflanzenarten',
98
- headers: %w[Wissenschaftlicher\ Name Deutscher\ Name],
99
- columns: %i[name name_de]
100
- )
101
92
  doc << '<<<'
102
93
  doc << ''
103
94
  doc << '== Artenlisten'
104
95
  doc << ''
105
- species_lists.each.with_index(1) do |species_list, index|
106
- info = {
107
- kosmos_vogelfuehrer: birds_info,
108
- flora_helvetica: plants_info,
109
- info_flora: plants_info
110
- }[species_list.type]
96
+ index = 1
97
+ groups = species_lists.group_by(&:group)
98
+ [
99
+ OpenStruct.new(
100
+ group: :plants,
101
+ title: 'Pflanzenarten',
102
+ headers: %w[Wissenschaftlicher\ Name Deutscher\ Name],
103
+ columns: %i[name name_de]
104
+ ),
105
+ OpenStruct.new(
106
+ group: :birds,
107
+ title: 'Vogelarten',
108
+ headers: %w[Deutscher\ Name Wissenschaftlicher\ Name],
109
+ columns: %i[name_de name]
110
+ )
111
+ ].each do |info|
112
+ group = groups.fetch(info.group, [])
113
+ next if group.empty?
114
+
111
115
  doc << "=== #{info.title}"
112
116
  doc << ''
113
- doc << '[cols="1,5,5",options=header]'
114
- doc << '|==='
115
- doc << "|Nr.|#{info.headers.join('|')}"
116
- species_list.each do |species|
117
- doc << "|{counter:species_list#{index}}|#{info.columns.map { |method| species.send(method) }.join('|')}"
117
+ group.each do |species_list|
118
+ caption = '.Tabelle {counter:species_lists}'
119
+ caption << ": #{species_list.description}" if species_list.description
120
+ doc << caption
121
+ doc << '[cols="1,5,5",options=header]'
122
+ doc << '|==='
123
+ doc << "|Nr.|#{info.headers.join('|')}"
124
+ species_list.each do |species|
125
+ doc << "|{counter:species_list#{index}}|#{info.columns.map { |method| species.send(method) }.join('|')}"
126
+ end
127
+ doc << '|==='
128
+ doc << ''
129
+ index += 1
118
130
  end
119
- doc << '|==='
120
- doc << ''
121
131
  end
122
132
  end
123
133
  doc.join("\n")
data/lib/natour/config.rb CHANGED
@@ -5,14 +5,12 @@ module Natour
5
5
  class Config
6
6
  def self.load_file(filename, default: {}, dirs: [Dir.home, Dir.pwd])
7
7
  dirs.map do |dir|
8
- begin
9
- YAML.safe_load(
10
- File.read(Pathname(dir).join(filename)),
11
- permitted_classes: [Symbol]
12
- )
13
- rescue Errno::ENOENT
14
- {}
15
- end
8
+ YAML.safe_load(
9
+ File.read(Pathname(dir).join(filename)),
10
+ [Symbol]
11
+ )
12
+ rescue Errno::ENOENT
13
+ {}
16
14
  end.reduce(default, &:merge)
17
15
  end
18
16
  end
@@ -3,17 +3,29 @@ require 'pathname'
3
3
  require 'asciidoctor'
4
4
  require 'asciidoctor-pdf'
5
5
  require 'vips'
6
+ require 'time'
6
7
 
7
8
  module Natour
8
9
  module_function
9
10
 
10
11
  def convert(filename, out_dir: nil, out_file: nil, overwrite: false,
11
- backend: 'pdf', draft: false, image_maxdim: 16000)
12
+ backend: 'pdf', draft: false, draft_backend: nil, image_maxdim: 16000)
13
+ backend = if draft
14
+ draft_backend || backend
15
+ else
16
+ backend
17
+ end
18
+
12
19
  doc = Asciidoctor.load_file(
13
20
  filename,
14
21
  backend: backend,
15
22
  safe: :unsafe,
16
- standalone: true
23
+ standalone: true,
24
+ attributes: {
25
+ 'pdf-theme' => 'natour',
26
+ 'pdf-themesdir' => "#{__dir__}/data/themes",
27
+ 'pdf-fontsdir' => "#{__dir__}/data/fonts"
28
+ }
17
29
  )
18
30
 
19
31
  dir = Pathname(filename).dirname
@@ -24,7 +36,28 @@ module Natour
24
36
 
25
37
  if draft
26
38
  doc.find_by(context: :image).each do |node|
27
- node.title = "#{node.title} [#{node.attr('target')}]"
39
+ target = node.attr('target')
40
+ image = Image.load_file(dir.join(target).to_s)
41
+ node.title = "#{node.title} [#{[target, image.date_time].compact.join('|')}]"
42
+ end
43
+ end
44
+
45
+ %w[
46
+ revdate
47
+ docdate
48
+ doctime
49
+ docdatetime
50
+ localdate
51
+ localtime
52
+ localdatetime
53
+ ].each do |attr_name|
54
+ date_time = Time.parse(doc.attr(attr_name))
55
+ if attr_name.end_with?('datetime')
56
+ doc.set_attr(attr_name, date_time.strftime('%d.%m.%Y %H:%M:%S'))
57
+ elsif attr_name.end_with?('date')
58
+ doc.set_attr(attr_name, date_time.strftime('%d.%m.%Y'))
59
+ elsif attr_name.end_with?('time')
60
+ doc.set_attr(attr_name, date_time.strftime('%H:%M:%S'))
28
61
  end
29
62
  end
30
63
 
@@ -35,25 +68,17 @@ module Natour
35
68
  title_logo_image = doc.attr('title-logo-image')
36
69
  if title_logo_image
37
70
  target = title_logo_image[/^image:{1,2}(.*?)\[(.*?)\]$/, 1]
38
- options = {}
39
- options[:autorotate] = true if target =~ /\.jpe?g$/i
40
- image = Vips::Image.new_from_file(dir.join(target).to_s, options)
41
- scale = image_maxdim / image.size.max.to_f
42
- image = image.resize(scale) if scale < 1.0
71
+ image = Image.load_file(dir.join(target).to_s).autorotate.shrink_to(image_maxdim)
43
72
  new_target = tmp_dir.join("title_logo_image_#{Pathname(target).basename}").to_s
44
- suppress_output { image.write_to_file(new_target) }
73
+ image.save_as(new_target)
45
74
  doc.set_attr('title-logo-image', title_logo_image.gsub(target, new_target))
46
75
  end
47
76
 
48
77
  doc.find_by(context: :image).each.with_index do |node, index|
49
78
  target = node.attr('target')
50
- options = {}
51
- options[:autorotate] = true if target =~ /\.jpe?g$/i
52
- image = Vips::Image.new_from_file(dir.join(target).to_s, options)
53
- scale = image_maxdim / image.size.max.to_f
54
- image = image.resize(scale) if scale < 1.0
79
+ image = Image.load_file(dir.join(target).to_s).autorotate.shrink_to(image_maxdim)
55
80
  new_target = tmp_dir.join("image#{index}_#{Pathname(target).basename}").to_s
56
- suppress_output { image.write_to_file(new_target) }
81
+ image.save_as(new_target)
57
82
  node.set_attr('target', new_target)
58
83
  end
59
84
 
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,22 @@
1
+ ---
2
+ extends: default
3
+ font:
4
+ catalog:
5
+ DejaVu Serif Condensed:
6
+ normal: dejavuserifcondensed-normal.ttf
7
+ italic: dejavuserifcondensed-italic.ttf
8
+ bold: dejavuserifcondensed-bold.ttf
9
+ bold_italic: dejavuserifcondensed-bold_italic.ttf
10
+ base:
11
+ font-family: DejaVu Serif Condensed
12
+ footer:
13
+ recto:
14
+ left:
15
+ content: 'by natour'
16
+ right:
17
+ content: '{page-number}'
18
+ verso:
19
+ left:
20
+ content: $footer_recto_right_content
21
+ right:
22
+ content: $footer_recto_left_content
data/lib/natour/image.rb CHANGED
@@ -1,33 +1,57 @@
1
1
  require 'vips'
2
2
  require 'timeliness'
3
+ require 'fileutils'
4
+ require 'pathname'
3
5
 
4
6
  module Natour
5
7
  class Image
6
8
  attr_reader :path
7
9
  attr_reader :date_time
8
10
 
9
- def initialize(path)
11
+ def initialize(path, image)
10
12
  @path = path
11
- image = Vips::Image.new_from_file(path)
12
- width, height = image.size
13
- @portrait = width < height
14
- orientation = image.get('exif-ifd0-Orientation')
15
- @portrait = orientation[/^(\d) \(/, 1].to_i.between?(5, 8)
16
- date_time = image.get('exif-ifd0-DateTime')
17
- @date_time = Timeliness.parse(
18
- date_time[/^(.*?) \(/, 1],
19
- format: 'yyyy:mm:dd hh:nn:ss'
20
- )
21
- rescue Vips::Error => e
22
- raise unless e.to_s =~ /exif-ifd0-(Orientation|DateTime)/
13
+ @image = image
14
+ orientation = get_field('exif-ifd0-Orientation')
15
+ @landscape = if orientation
16
+ orientation[/^(\d) \(/, 1].to_i.between?(1, 4)
17
+ else
18
+ image.width >= image.height
19
+ end
20
+ date_time = get_field('exif-ifd0-DateTime')
21
+ @date_time = Timeliness.parse(date_time[/^(.*?) \(/, 1], format: 'yyyy:mm:dd hh:nn:ss') if date_time
23
22
  end
24
23
 
25
- def portrait?
26
- @portrait
24
+ def self.load_file(filename)
25
+ Image.new(filename, Vips::Image.new_from_file(filename))
27
26
  end
28
27
 
29
28
  def landscape?
30
- !portrait?
29
+ @landscape
30
+ end
31
+
32
+ def autorotate
33
+ Image.new(@path, @image.autorot)
34
+ end
35
+
36
+ def shrink_to(maxdim)
37
+ scale = maxdim / @image.size.max.to_f
38
+ image = if scale < 1.0
39
+ @image.resize(scale)
40
+ else
41
+ @image.copy
42
+ end
43
+ Image.new(@path, image)
44
+ end
45
+
46
+ def save_as(filename)
47
+ FileUtils.mkdir_p(Pathname(filename).dirname)
48
+ StdoutUtils.suppress_output { @image.write_to_file(filename) }
49
+ end
50
+
51
+ private
52
+
53
+ def get_field(name)
54
+ @image.get(name) if @image.get_fields.include?(name)
31
55
  end
32
56
  end
33
57
  end
@@ -9,7 +9,7 @@ module Natour
9
9
  class MapGeoAdmin
10
10
  def initialize(port: 0)
11
11
  @doc_root = Dir.mktmpdir
12
- FileUtils.cp_r("#{__dir__}/js", @doc_root)
12
+ FileUtils.cp_r("#{__dir__}/data/js", @doc_root)
13
13
  event = Concurrent::Event.new
14
14
  @server = WEBrick::HTTPServer.new(
15
15
  StartCallback: -> { event.set },
data/lib/natour/report.rb CHANGED
@@ -35,10 +35,10 @@ module Natour
35
35
  title = Pathname.pwd.basename.to_s.encode('utf-8')
36
36
  .gsub(/^\d{4}-\d{2}-\d{2}( |_|-)?/, '')
37
37
  images = Pathname.glob('**/*.{jpg,jpeg}', File::FNM_CASEFOLD)
38
- .map { |filename| Image.new(filename.to_s) }
38
+ .map { |filename| Image.load_file(filename.to_s) }
39
39
  .sort_by { |image| [image.date_time ? 0 : 1, image.date_time, image.path] }
40
40
  species_lists =
41
- Pathname.glob('**/*.csv', File::FNM_CASEFOLD)
41
+ Pathname.glob('**/*.{csv,kml}', File::FNM_CASEFOLD)
42
42
  .map { |filename| SpeciesList.load_file(filename.to_s) }
43
43
  .flatten
44
44
  .sort_by { |species_list| [species_list.type, species_list.date ? 0 : 1, species_list.date] }
@@ -47,6 +47,7 @@ module Natour
47
47
  else
48
48
  Pathname.glob("**/*.{#{track_formats.join(',')}}", File::FNM_CASEFOLD)
49
49
  .map { |filename| GPSTrack.load_file(filename.to_s) }
50
+ .sort_by { |gps_track| [gps_track.date, gps_track.path] }
50
51
  end
51
52
 
52
53
  if create_map
@@ -57,7 +58,7 @@ module Natour
57
58
  gps_track.save_gpx(track, overwrite: true)
58
59
  filename = Pathname(gps_track.path).sub_ext('.jpg')
59
60
  map.save_image(filename, tracks: [track], layers: map_layers)
60
- Image.new(filename.to_s)
61
+ Image.load_file(filename.to_s)
61
62
  end
62
63
  end
63
64
  end
@@ -1,4 +1,5 @@
1
1
  require 'csv'
2
+ require 'nokogiri'
2
3
  require 'pathname'
3
4
 
4
5
  module Natour
@@ -6,51 +7,64 @@ module Natour
6
7
  attr_reader :path
7
8
  attr_reader :date
8
9
  attr_reader :type
9
- attr_reader :name
10
+ attr_reader :group
11
+ attr_reader :title
10
12
  attr_reader :description
11
13
 
12
- def initialize(path, date, type, name, description, items)
14
+ def initialize(path, date, type, group, title, description, items)
13
15
  @path = path
14
16
  @date = date
15
17
  @type = type
16
- @name = name
18
+ @group = group
19
+ @title = title
17
20
  @description = description
18
21
  @items = items
19
22
  end
20
23
 
21
24
  def self.load_file(filename)
22
- block = IO.binread(filename, 32)
25
+ block = IO.binread(filename, 128)
23
26
  header = if block.unpack('CC') == [0xff, 0xfe]
24
27
  block[2..-1].force_encoding('utf-16le').encode('utf-8')
25
28
  elsif block.unpack('CCC') == [0xef, 0xbb, 0xbf]
26
29
  block[3..-1].force_encoding('utf-8')
27
30
  else
28
- block.force_encoding('utf-8')
31
+ block
29
32
  end
30
33
 
31
34
  case header
32
35
  when /^Primary/
33
36
  CSV.open(filename, 'r:windows-1252:utf-8', headers: true, liberal_parsing: true) do |csv|
34
- date = DateParser.parse(Pathname(filename).basename).compact.first
37
+ date = DateUtils.parse(Pathname(filename).basename).compact.first
35
38
  items = csv.map { |row| Species.new(row[1], row[0]) }
36
39
  .sort_by(&:name_de).uniq
37
- [SpeciesList.new(filename, date, :kosmos_vogelfuehrer, nil, nil, items)]
40
+ [SpeciesList.new(filename, date, :kosmos_vogelfuehrer, :birds, nil, nil, items)]
38
41
  end
39
- when /^Favoriten/
42
+ when /^<\?xml.*?www\.ornitho\.ch/m
43
+ date = DateUtils.parse(Pathname(filename).basename).compact.first
44
+ doc = Nokogiri.XML(File.read(filename, mode: 'r:utf-8'))
45
+ folder = doc.at('/xmlns:kml/xmlns:Document/xmlns:Folder/xmlns:Folder/xmlns:Folder')
46
+ name = folder.at('./xmlns:name').text
47
+ items = folder.xpath('./xmlns:Placemark/xmlns:description')
48
+ .map(&:text)
49
+ .map { |description| Species.new(*description.scan(/&gt;([^&(]+)&lt;/).flatten.reverse) }
50
+ .sort_by(&:name_de).uniq
51
+ [SpeciesList.new(filename, date, :ornitho_ch, :birds, name, nil, items)]
52
+ when /^(Favoriten|NUMMER_FLORA)/
40
53
  CSV.open(filename, 'r:bom|utf-8', col_sep: ';', skip_blanks: true) do |csv|
41
- chunks = csv.reject { |row| row.count == 1 && row[0] != 'Favoriten' }
42
- .reject { |row| row.count == 4 && row[0] == 'NUMMER_FLORA' }
54
+ chunks = csv.reject { |row| row.count == 1 }
55
+ .map { |row| row[0] == 'NUMMER_FLORA' ? ['Favoriten'] : row }
43
56
  .slice_before { |row| row.count == 1 || row.count == 3 }
44
57
  .reject { |rows| rows.count == 1 }
45
58
  chunks.map do |rows|
46
59
  name, description = rows.shift
47
- date = DateParser.parse(name, Pathname(filename).basename).compact.first
48
- items = rows.map { |row| Species.new(row[1][/^(([^ ]+ [^ ]+)(( aggr\.)|( subsp\. [^ ]+))?)/, 1], row[2]) }
60
+ date = DateUtils.parse(name, Pathname(filename).basename).compact.first
61
+ items = rows.map { |row| Species.new(BotanicalNameUtils.parse(row[1]), row[2]) }
49
62
  .sort_by(&:name).uniq
50
63
  SpeciesList.new(
51
64
  filename,
52
65
  date,
53
66
  :flora_helvetica,
67
+ :plants,
54
68
  name&.gsub(/^(\d{4}-)?\d{2}-\d{2}( |_|-)?/, ''),
55
69
  description,
56
70
  items
@@ -59,12 +73,14 @@ module Natour
59
73
  end
60
74
  when /^obs_id/
61
75
  CSV.open(filename, 'r:bom|utf-16le:utf-8', col_sep: "\t", headers: true) do |csv|
62
- date = DateParser.parse(Pathname(filename).basename).compact.first
76
+ date = DateUtils.parse(Pathname(filename).basename).compact.first
63
77
  items = csv.select { |row| row[0] }
64
- .map { |row| Species.new(row[11][/^(([^ ]+ [^ ]+)(( aggr\.)|( subsp\. [^ ]+))?)/, 1], nil) }
78
+ .map { |row| Species.new(BotanicalNameUtils.parse(row[11]), nil) }
65
79
  .sort_by(&:name).uniq
66
- [SpeciesList.new(filename, date, :info_flora, nil, nil, items)]
80
+ [SpeciesList.new(filename, date, :info_flora, :plants, nil, nil, items)]
67
81
  end
82
+ else
83
+ []
68
84
  end
69
85
  end
70
86
 
@@ -0,0 +1,12 @@
1
+ module Natour
2
+ module BotanicalNameUtils
3
+ module_function
4
+
5
+ def parse(name)
6
+ result = name.match(/^([^ ]+ [^ ]+)(( aggr\.)|(.*( subsp\. [^ ]+)))?.*$/)
7
+ return unless result
8
+
9
+ "#{result[1]}#{result[3]}#{result[5]}"
10
+ end
11
+ end
12
+ end
@@ -1,7 +1,7 @@
1
1
  require 'timeliness'
2
2
 
3
3
  module Natour
4
- module DateParser
4
+ module DateUtils
5
5
  module_function
6
6
 
7
7
  def parse(*args)
@@ -0,0 +1,16 @@
1
+ module Natour
2
+ module StdoutUtils
3
+ module_function
4
+
5
+ def suppress_output
6
+ orig_stdout = $stdout.clone
7
+ orig_stderr = $stderr.clone
8
+ $stdout.reopen(File.new(File::NULL, 'w'))
9
+ $stderr.reopen(File.new(File::NULL, 'w'))
10
+ yield
11
+ ensure
12
+ $stdout.reopen(orig_stdout)
13
+ $stderr.reopen(orig_stderr)
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: natour
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Gysi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-04 00:00:00.000000000 Z
11
+ date: 2021-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -70,14 +70,14 @@ dependencies:
70
70
  name: fit4ruby
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - '='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '3.7'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - '='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.7'
83
83
  - !ruby/object:Gem::Dependency
@@ -177,29 +177,37 @@ files:
177
177
  - bin/natour
178
178
  - lib/natour.rb
179
179
  - lib/natour/asciinurse.rb
180
- - lib/natour/cli/convert.rb
181
- - lib/natour/cli/create.rb
182
180
  - lib/natour/config.rb
181
+ - lib/natour/convert.rb
182
+ - lib/natour/create.rb
183
+ - lib/natour/data/fonts/dejavuserifcondensed-bold.ttf
184
+ - lib/natour/data/fonts/dejavuserifcondensed-bold_italic.ttf
185
+ - lib/natour/data/fonts/dejavuserifcondensed-italic.ttf
186
+ - lib/natour/data/fonts/dejavuserifcondensed-normal.ttf
187
+ - lib/natour/data/js/bootstrap.min.js
188
+ - lib/natour/data/js/jquery-3.5.1.slim.min.js
189
+ - lib/natour/data/js/loader.js
190
+ - lib/natour/data/themes/natour-theme.yml
183
191
  - lib/natour/fit_file.rb
184
192
  - lib/natour/gps_track.rb
185
193
  - lib/natour/gps_track_point.rb
186
194
  - lib/natour/gpx_file.rb
187
- - lib/natour/helpers/date_parser.rb
188
- - lib/natour/helpers/suppress_output.rb
189
195
  - lib/natour/image.rb
190
- - lib/natour/js/bootstrap.min.js
191
- - lib/natour/js/jquery-3.5.1.slim.min.js
192
- - lib/natour/js/loader.js
193
196
  - lib/natour/map_geo_admin.rb
194
197
  - lib/natour/public_transport.rb
195
198
  - lib/natour/report.rb
196
199
  - lib/natour/species.rb
197
200
  - lib/natour/species_list.rb
198
201
  - lib/natour/station.rb
202
+ - lib/natour/utils/botanical_name_utils.rb
203
+ - lib/natour/utils/date_utils.rb
204
+ - lib/natour/utils/stdout_utils.rb
199
205
  homepage: https://rubygems.org/gems/natour
200
206
  licenses:
201
207
  - MIT
202
208
  metadata:
209
+ bug_tracker_uri: https://github.com/simongysi/natour/issues
210
+ changelog_uri: https://github.com/simongysi/natour/blob/main/CHANGELOG.adoc
203
211
  source_code_uri: https://github.com/simongysi/natour
204
212
  post_install_message:
205
213
  rdoc_options: []
@@ -209,7 +217,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
209
217
  requirements:
210
218
  - - ">="
211
219
  - !ruby/object:Gem::Version
212
- version: '2.4'
220
+ version: '2.5'
213
221
  required_rubygems_version: !ruby/object:Gem::Requirement
214
222
  requirements:
215
223
  - - ">="
@@ -1,14 +0,0 @@
1
- module Natour
2
- module_function
3
-
4
- def suppress_output
5
- orig_stdout = $stdout.clone
6
- orig_stderr = $stderr.clone
7
- $stdout.reopen(File.new(File::NULL, 'w'))
8
- $stderr.reopen(File.new(File::NULL, 'w'))
9
- yield
10
- ensure
11
- $stdout.reopen(orig_stdout)
12
- $stderr.reopen(orig_stderr)
13
- end
14
- end