natour 0.1.0 → 0.5.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.
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