stac 0.2.0 → 0.3.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +10 -0
  4. data/GETTING_STARTED.md +384 -0
  5. data/Gemfile.lock +48 -37
  6. data/README.md +12 -59
  7. data/Rakefile +62 -4
  8. data/Steepfile +2 -0
  9. data/lib/stac/asset.rb +3 -1
  10. data/lib/stac/catalog.rb +78 -8
  11. data/lib/stac/collection.rb +43 -9
  12. data/lib/stac/common_metadata.rb +1 -1
  13. data/lib/stac/errors.rb +2 -5
  14. data/lib/stac/extension.rb +34 -0
  15. data/lib/stac/extensions/electro_optical.rb +67 -0
  16. data/lib/stac/extensions/projection.rb +42 -0
  17. data/lib/stac/extensions/scientific_citation.rb +84 -0
  18. data/lib/stac/extensions/view_geometry.rb +38 -0
  19. data/lib/stac/extent.rb +39 -31
  20. data/lib/stac/file_writer.rb +31 -0
  21. data/lib/stac/hash_like.rb +74 -0
  22. data/lib/stac/item.rb +56 -22
  23. data/lib/stac/link.rb +51 -9
  24. data/lib/stac/object_resolver.rb +4 -4
  25. data/lib/stac/properties.rb +3 -1
  26. data/lib/stac/provider.rb +5 -1
  27. data/lib/stac/simple_http_client.rb +3 -0
  28. data/lib/stac/stac_object.rb +138 -36
  29. data/lib/stac/version.rb +1 -1
  30. data/lib/stac.rb +12 -1
  31. data/sig/stac/asset.rbs +1 -3
  32. data/sig/stac/catalog.rbs +28 -5
  33. data/sig/stac/collection.rbs +13 -5
  34. data/sig/stac/common_metadata.rbs +2 -2
  35. data/sig/stac/errors.rbs +1 -4
  36. data/sig/stac/extension.rbs +12 -0
  37. data/sig/stac/extensions/electro_optical.rbs +40 -0
  38. data/sig/stac/extensions/projection.rbs +32 -0
  39. data/sig/stac/extensions/scientific_citation.rbs +38 -0
  40. data/sig/stac/extensions/view_geometry.rbs +22 -0
  41. data/sig/stac/extent.rbs +13 -16
  42. data/sig/stac/file_writer.rbs +13 -0
  43. data/sig/stac/hash_like.rbs +13 -0
  44. data/sig/stac/item.rbs +16 -7
  45. data/sig/stac/link.rbs +20 -12
  46. data/sig/stac/object_resolver.rbs +2 -2
  47. data/sig/stac/properties.rbs +1 -3
  48. data/sig/stac/provider.rbs +2 -3
  49. data/sig/stac/simple_http_client.rbs +3 -0
  50. data/sig/stac/stac_object.rbs +33 -10
  51. data/stac.gemspec +1 -1
  52. metadata +18 -3
data/Rakefile CHANGED
@@ -1,19 +1,77 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/gem_tasks'
4
-
5
4
  require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+ require 'rdoc/task'
7
+
6
8
  RSpec::Core::RakeTask.new(:spec)
7
9
 
8
- require 'rubocop/rake_task'
9
10
  RuboCop::RakeTask.new
10
11
 
11
12
  task default: %i[spec rubocop]
12
13
 
13
- require 'rdoc/task'
14
14
  RDoc::Task.new do |rdoc|
15
15
  rdoc.rdoc_dir = 'doc'
16
16
  rdoc.title = 'stac-ruby API docs'
17
- rdoc.rdoc_files.include('README.md', 'CHANGELOG.md', 'lib/**/*.rb')
17
+ rdoc.rdoc_files.include('README.md', 'CHANGELOG.md', 'GETTING_STARTED.md', 'lib/**/*.rb')
18
18
  rdoc.main = 'README.md'
19
19
  end
20
+
21
+ namespace :fixture do
22
+ desc 'Setup spec/fixtures'
23
+ task setup: %w[
24
+ spec/fixtures/stac-spec
25
+ spec/fixtures/eo/item.json
26
+ spec/fixtures/projection/item.json
27
+ spec/fixtures/scientific/item.json
28
+ spec/fixtures/scientific/collection.json
29
+ spec/fixtures/scientific/collection-assets.json
30
+ spec/fixtures/view/item.json
31
+ ]
32
+
33
+ desc 'Remove spec/fixtures'
34
+ task :clean do
35
+ rm_r 'spec/fixtures'
36
+ end
37
+
38
+ directory 'spec/fixtures/stac-spec'
39
+
40
+ file 'spec/fixtures/stac-spec' do |t|
41
+ cp_r 'stac-spec/examples/.', t.name
42
+ end
43
+
44
+ directory 'spec/fixtures/eo'
45
+
46
+ file 'spec/fixtures/eo/item.json' => 'spec/fixtures/eo' do |t|
47
+ sh "curl https://raw.githubusercontent.com/stac-extensions/eo/v1.0.0/examples/item.json -o #{t.name} -sS"
48
+ end
49
+
50
+ directory 'spec/fixtures/projection'
51
+
52
+ file 'spec/fixtures/projection/item.json' => 'spec/fixtures/projection' do |t|
53
+ sh "curl https://raw.githubusercontent.com/stac-extensions/projection/v1.0.0/examples/item.json -o #{t.name} -sS"
54
+ end
55
+
56
+ directory 'spec/fixtures/scientific'
57
+
58
+ file 'spec/fixtures/scientific/item.json' => 'spec/fixtures/scientific' do |t|
59
+ sh "curl https://raw.githubusercontent.com/stac-extensions/scientific/v1.0.0/examples/item.json -o #{t.name} -sS"
60
+ end
61
+
62
+ file 'spec/fixtures/scientific/collection.json' => 'spec/fixtures/scientific' do |t|
63
+ sh 'curl https://raw.githubusercontent.com/stac-extensions/scientific/v1.0.0/examples/collection.json ' \
64
+ "-o #{t.name} -sS"
65
+ end
66
+
67
+ file 'spec/fixtures/scientific/collection-assets.json' => 'spec/fixtures/scientific' do |t|
68
+ sh 'curl https://raw.githubusercontent.com/stac-extensions/scientific/v1.0.0/examples/collection-assets.json ' \
69
+ "-o #{t.name} -sS"
70
+ end
71
+
72
+ directory 'spec/fixtures/view'
73
+
74
+ file 'spec/fixtures/view/item.json' => 'spec/fixtures/view' do |t|
75
+ sh "curl https://raw.githubusercontent.com/stac-extensions/view/v1.0.0/examples/item.json -o #{t.name} -sS"
76
+ end
77
+ end
data/Steepfile CHANGED
@@ -15,6 +15,8 @@ target :lib do
15
15
  hash[D::Ruby::InsufficientKeywordArguments] = :hint
16
16
  hash[D::Ruby::MethodBodyTypeMismatch] = :information
17
17
  hash[D::Ruby::MethodDefinitionMissing] = nil # To supress noisy VS Code extension message.
18
+ hash[D::Ruby::NoMethod] = :information
19
+ hash[D::Ruby::UnknownConstant] = :information
18
20
  hash[D::Ruby::UnsupportedSyntax] = :hint
19
21
  end
20
22
  end
data/lib/stac/asset.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'common_metadata'
4
+ require_relative 'hash_like'
4
5
 
5
6
  module STAC
6
7
  # Represents \STAC asset object, which contains a link to data associated with an Item or Collection that can be
7
8
  # downloaded or streamed.
8
9
  class Asset
10
+ include HashLike
9
11
  include CommonMetadata
10
12
 
11
13
  class << self
@@ -23,7 +25,7 @@ module STAC
23
25
  @description = description
24
26
  @type = type
25
27
  @roles = roles
26
- self.extra = extra.transform_keys(&:to_s)
28
+ @extra = extra.transform_keys(&:to_s)
27
29
  end
28
30
 
29
31
  # Serializes self to a Hash.
data/lib/stac/catalog.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'pathname'
3
4
  require_relative 'errors'
4
5
  require_relative 'stac_object'
5
6
 
@@ -8,15 +9,26 @@ module STAC
8
9
  #
9
10
  # \STAC \Catalog Specification: https://github.com/radiantearth/stac-spec/tree/master/catalog-spec
10
11
  class Catalog < STAC::STACObject
11
- self.type = 'Catalog'
12
+ @type = 'Catalog'
13
+
14
+ class << self
15
+ def root(id:, description:, href:, links: [], title: nil, stac_extensions: [], **extra)
16
+ catalog = new(
17
+ id: id, description: description, links: links, title: title, stac_extensions: stac_extensions, **extra,
18
+ )
19
+ catalog.self_href = href
20
+ catalog.root = catalog
21
+ catalog
22
+ end
23
+ end
12
24
 
13
25
  attr_accessor :id, :description, :title
14
26
 
15
- def initialize(id:, description:, links:, title: nil, stac_extensions: nil, **extra)
16
- super(links: links, stac_extensions: stac_extensions, **extra)
27
+ def initialize(id:, description:, links: [], title: nil, stac_extensions: [], **extra)
17
28
  @id = id
18
29
  @description = description
19
30
  @title = title
31
+ super(links: links, stac_extensions: stac_extensions, **extra)
20
32
  end
21
33
 
22
34
  # Serializes self to a Hash.
@@ -32,7 +44,11 @@ module STAC
32
44
 
33
45
  # Returns catalog/collection objects from rel="child" links of this catalog.
34
46
  def children
35
- links.select { |link| link.rel == 'child' }.lazy.map(&:target)
47
+ child_links.lazy.map(&:target)
48
+ end
49
+
50
+ def all_children # :nodoc:
51
+ children.chain(children.flat_map(&:all_children)).lazy
36
52
  end
37
53
 
38
54
  # Filters only collections from #children.
@@ -40,17 +56,24 @@ module STAC
40
56
  children.select { |child| child.type == 'Collection' }
41
57
  end
42
58
 
59
+ # Returns all collections from this catalog and its child catalogs/collections recursively.
60
+ def all_collections
61
+ # The last `.lazy` is not necessary with Ruby 3.1.
62
+ # But with Ruby 3.0, it is necessary because Enumerator::Lazy#chain returns Enumerator::Chain
63
+ # and RBS type check fails.
64
+ collections.chain(children.flat_map(&:all_collections)).lazy
65
+ end
66
+
43
67
  # Returns the child catalog/collection with the given ID if it exists.
44
68
  #
45
69
  # With option `recusive: true`, it will traverse all child catalogs/collections recursively.
46
70
  def find_child(id, recursive: false)
47
- targets = recursive ? children.chain(children.flat_map(&:children)) : children
48
- targets.find { |child| child.id == id }
71
+ (recursive ? all_children : children).find { |child| child.id == id }
49
72
  end
50
73
 
51
74
  # Returns item objects from rel="item" links of this catalog.
52
75
  def items
53
- links.select { |link| link.rel == 'item' }.lazy.map(&:target)
76
+ item_links.lazy.map(&:target)
54
77
  end
55
78
 
56
79
  # Returns all items from this catalog and its child catalogs/collections recursively.
@@ -58,7 +81,7 @@ module STAC
58
81
  # The last `.lazy` is not necessary with Ruby 3.1.
59
82
  # But with Ruby 3.0, it is necessary because Enumerator::Lazy#chain returns Enumerator::Chain
60
83
  # and RBS type check fails.
61
- items.chain(children.flat_map(&:items)).lazy
84
+ items.chain(children.flat_map(&:all_items)).lazy
62
85
  end
63
86
 
64
87
  # Returns the item with the given ID if it exists.
@@ -67,5 +90,52 @@ module STAC
67
90
  def find_item(id, recursive: false)
68
91
  (recursive ? all_items : items).find { |item| item.id == id }
69
92
  end
93
+
94
+ # Adds a rel="child" link to self and adds "self", "root", and "parent" links to the child catalog.
95
+ def add_child(catalog, href: "#{catalog.id}/#{catalog.type.downcase}.json", title: catalog.title)
96
+ if (base = self_href)
97
+ catalog.self_href = Pathname(base).dirname.join(href).to_s
98
+ end
99
+ catalog.root = root
100
+ catalog.parent = self
101
+ add_link(catalog, rel: 'child', type: 'application/json', title: title)
102
+ end
103
+
104
+ # Adds a rel="item" link to self and adds "self", "root", and "parent" links to the given item.
105
+ def add_item(item, href: "#{item.id}.json", title: item.properties.title)
106
+ if (base = self_href)
107
+ item.self_href = Pathname(base).dirname.join(href).to_s
108
+ end
109
+ item.root = root
110
+ item.parent = self
111
+ add_link(item, rel: 'item', type: 'application/geo+json', title: title)
112
+ end
113
+
114
+ # Exports this catalog and all its children and items to the specified dir or each self href.
115
+ def export(dest_dir = nil, writer: FileWriter.new)
116
+ dest_pathname = Pathname(dest_dir) if dest_dir
117
+ self_dest = dest_pathname.join(File.basename(self_href!)).to_s if dest_pathname
118
+ save(self_dest, writer: writer)
119
+
120
+ item_links.select(&:resolved?).each do |item_link|
121
+ item_dest = dest_pathname.join(item_link.relative_href!).to_s if dest_pathname
122
+ item_link.target.save(item_dest, writer: writer)
123
+ end
124
+
125
+ child_links.select(&:resolved?).each do |child_link|
126
+ child_dest_dir = dest_pathname.join(child_link.relative_href!).dirname.to_s if dest_pathname
127
+ child_link.target.export(child_dest_dir, writer: writer)
128
+ end
129
+ end
130
+
131
+ private
132
+
133
+ def child_links
134
+ links.select { |link| link.rel == 'child' }
135
+ end
136
+
137
+ def item_links
138
+ links.select { |link| link.rel == 'item' }
139
+ end
70
140
  end
71
141
  end
@@ -10,43 +10,46 @@ module STAC
10
10
  #
11
11
  # \STAC \Collection Specification: https://github.com/radiantearth/stac-spec/tree/master/collection-spec
12
12
  class Collection < Catalog
13
- self.type = 'Collection'
13
+ @type = 'Collection'
14
14
 
15
15
  class << self
16
16
  def from_hash(hash)
17
- h = hash.dup
18
- h['extent'] = Extent.from_hash(h.fetch('extent'))
19
- h['providers'] = h['providers']&.map { |provider| Provider.from_hash(provider) }
20
- h['assets'] = h['assets']&.transform_values { |v| Asset.from_hash(v) }
17
+ h = hash.transform_keys(&:to_sym)
18
+ h[:extent] = Extent.from_hash(h.fetch(:extent))
19
+ h[:providers] = h[:providers]&.map { |provider| Provider.from_hash(provider) }
20
+ h[:summaries] = h[:summaries]&.transform_keys(&:to_s)
21
+ h[:assets] = h[:assets]&.to_h { |k, v| [k.to_s, Asset.from_hash(v)] }
21
22
  super(h)
22
23
  rescue KeyError => e
23
24
  raise ArgumentError, "required field not found: #{e.key}"
24
25
  end
25
26
  end
26
27
 
27
- attr_accessor :license, :extent, :keywords, :providers, :summaries, :assets
28
+ attr_accessor :license, :extent, :keywords, :providers, :summaries
29
+
30
+ attr_reader :assets
28
31
 
29
32
  def initialize(
30
33
  id:,
31
34
  description:,
32
- links:,
33
35
  license:,
34
36
  extent:,
37
+ links: [],
35
38
  title: nil,
36
39
  keywords: nil,
37
40
  providers: nil,
38
41
  summaries: nil,
39
42
  assets: nil,
40
- stac_extensions: nil,
43
+ stac_extensions: [],
41
44
  **extra
42
45
  )
43
- super(id: id, description: description, links: links, title: title, stac_extensions: stac_extensions, **extra)
44
46
  @license = license
45
47
  @extent = extent
46
48
  @keywords = keywords
47
49
  @providers = providers
48
50
  @summaries = summaries
49
51
  @assets = assets
52
+ super(id: id, description: description, links: links, title: title, stac_extensions: stac_extensions, **extra)
50
53
  end
51
54
 
52
55
  # Serializes self to a Hash.
@@ -62,5 +65,36 @@ module STAC
62
65
  }.compact,
63
66
  )
64
67
  end
68
+
69
+ # Adds an asset with the given key.
70
+ #
71
+ # When the item has extendable stac_extensions, make the asset extend the extension modules.
72
+ def add_asset(key:, href:, title: nil, description: nil, type: nil, roles: nil, **extra)
73
+ asset = Asset.new(href: href, title: title, description: description, type: type, roles: roles, **extra)
74
+ extensions.each do |extension|
75
+ asset.extend(extension::Asset) if extension.const_defined?(:Asset)
76
+ end
77
+ if assets
78
+ assets[key] = asset
79
+ else
80
+ @assets = { key => asset }
81
+ end
82
+ self
83
+ end
84
+
85
+ # Adds a rel="item" link to self and adds "self", "root", "parent", and "collection" links to the given item.
86
+ def add_item(item, href: "#{item.id}.json", title: item.properties.title)
87
+ super
88
+ item.collection = self
89
+ self
90
+ end
91
+
92
+ private
93
+
94
+ def apply_extension!(extension)
95
+ super
96
+ extend(extension::Collection) if extension.const_defined?(:Collection)
97
+ assets&.each_value { |asset| asset.extend(extension::Asset) } if extension.const_defined?(:Asset)
98
+ end
65
99
  end
66
100
  end
@@ -10,7 +10,7 @@ module STAC
10
10
  #
11
11
  # Specification: https://github.com/radiantearth/stac-spec/blob/master/item-spec/common-metadata.md
12
12
  module CommonMetadata
13
- attr_accessor :extra
13
+ attr_reader :extra
14
14
 
15
15
  def title
16
16
  extra['title']
data/lib/stac/errors.rb CHANGED
@@ -7,9 +7,6 @@ module STAC
7
7
  # Raised when unexpected "type" field was given.
8
8
  class TypeError < Error; end
9
9
 
10
- # Raised when URL with unsupported scheme was given.
11
- class UnknownURISchemeError < Error; end
12
-
13
- # Raised when a HTTP request failed.
14
- class HTTPError < Error; end
10
+ # Raised when URL with not supported scheme was given.
11
+ class NotSupportedURISchemeError < Error; end
15
12
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors'
4
+
5
+ module STAC
6
+ # Raised when an extension module does have identifier.
7
+ class ExtensionWithoutIdentifierError < Error; end
8
+
9
+ # \Extension modules must extend this module.
10
+ module Extension
11
+ # Returns extension id for `stac_extensions` field.
12
+ #
13
+ # When given an argument, sets the given value as its identifier.
14
+ def identifier(identifier = nil)
15
+ # @type self: Module
16
+ if identifier.nil?
17
+ @identifier or raise ExtensionWithoutIdentifierError, "extension module must be set identifier: #{name}"
18
+ else
19
+ @identifier = identifier
20
+ end
21
+ end
22
+
23
+ # Returns extendable \STAC Object classes.
24
+ #
25
+ # When given arguments, sets the given values as its scope.
26
+ def scope(*scope)
27
+ if scope.empty?
28
+ @scope ||= []
29
+ else
30
+ @scope = scope
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../extension'
4
+ require_relative '../item'
5
+
6
+ module STAC
7
+ module Extensions
8
+ # Utilities for Electro-Optical extension.
9
+ #
10
+ # Electro-Optical \Extension Specification: https://github.com/stac-extensions/eo/
11
+ module ElectroOptical
12
+ extend Extension
13
+
14
+ identifier 'https://stac-extensions.github.io/eo/v1.0.0/schema.json'
15
+ scope STAC::Item
16
+
17
+ module Properties # rubocop:disable Style/Documentation
18
+ attr_reader :extra
19
+
20
+ def eo_bands
21
+ extra.fetch('eo:bands', []).map { |band_hash| Band.new(band_hash) }
22
+ end
23
+
24
+ def eo_bands=(bands)
25
+ extra['eo:bands'] = bands.map(&:to_h)
26
+ end
27
+
28
+ def eo_cloud_cover
29
+ extra['eo:cloud_cover']
30
+ end
31
+
32
+ def eo_cloud_cover=(cloud_cover)
33
+ extra['eo:cloud_cover'] = cloud_cover
34
+ end
35
+ end
36
+
37
+ module Asset
38
+ include Properties
39
+ end
40
+
41
+ # Represents \Band object of Electro-Optical extension.
42
+ class Band
43
+ attr_reader :raw_hash # :nodoc:
44
+
45
+ def initialize(raw_hash)
46
+ @raw_hash = raw_hash
47
+ end
48
+
49
+ def to_h
50
+ raw_hash
51
+ end
52
+
53
+ %i[name common_name description center_wavelength full_width_half_max].each do |field|
54
+ define_method(field) do
55
+ # @type self: Band
56
+ raw_hash[field.to_s]
57
+ end
58
+
59
+ define_method("#{field}=") do |value|
60
+ # @type self: Band
61
+ raw_hash[field.to_s] = value
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../extension'
4
+ require_relative '../item'
5
+
6
+ module STAC
7
+ module Extensions
8
+ # Utilities for \Projection extension.
9
+ #
10
+ # \Projection \Extension Specification: https://github.com/stac-extensions/projection/
11
+ module Projection
12
+ extend Extension
13
+
14
+ identifier 'https://stac-extensions.github.io/projection/v1.0.0/schema.json'
15
+ scope STAC::Item
16
+
17
+ module Properties # rubocop:disable Style/Documentation
18
+ attr_reader :extra
19
+
20
+ %w[
21
+ proj:epsg proj:wkt2 proj:projjson proj:geometry proj:bbox proj:centroid proj:shape proj:transform
22
+ ].each do |field|
23
+ method_name = field.sub(':', '_')
24
+
25
+ define_method(method_name) do
26
+ # @type self: Properties
27
+ extra[field]
28
+ end
29
+
30
+ define_method("#{method_name}=") do |value|
31
+ # @type self: Properties
32
+ extra[field] = value
33
+ end
34
+ end
35
+ end
36
+
37
+ module Asset
38
+ include Properties
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../extension'
4
+ require_relative '../item'
5
+ require_relative '../collection'
6
+
7
+ module STAC
8
+ module Extensions
9
+ # Utilities for Scientific Citation extension.
10
+ #
11
+ # Scientific Citation \Extension Specification: https://github.com/stac-extensions/scientific/
12
+ module ScientificCitation
13
+ extend Extension
14
+
15
+ identifier 'https://stac-extensions.github.io/scientific/v1.0.0/schema.json'
16
+ scope STAC::Item, STAC::Collection
17
+
18
+ module Properties # rubocop:disable Style/Documentation
19
+ attr_reader :extra
20
+
21
+ def sci_doi
22
+ extra['sci:doi']
23
+ end
24
+
25
+ def sci_doi=(doi)
26
+ extra['sci:doi'] = doi
27
+ end
28
+
29
+ def sci_citation
30
+ extra['sci:citation']
31
+ end
32
+
33
+ def sci_citation=(citation)
34
+ extra['sci:citation'] = citation
35
+ end
36
+
37
+ def sci_publications
38
+ extra.fetch('sci:publications', []).map { |hash| Publication.new(hash) }
39
+ end
40
+
41
+ def sci_publications=(publications)
42
+ extra['sci:publications'] = publications.map(&:to_h)
43
+ end
44
+ end
45
+
46
+ module Asset
47
+ include Properties
48
+ end
49
+
50
+ module Collection
51
+ include Properties
52
+ end
53
+
54
+ # Represents \Publication object of Scientific Citation extension.
55
+ class Publication
56
+ attr_reader :raw_hash # :nodoc:
57
+
58
+ def initialize(raw_hash)
59
+ @raw_hash = raw_hash
60
+ end
61
+
62
+ def to_h
63
+ raw_hash
64
+ end
65
+
66
+ def doi
67
+ raw_hash['doi']
68
+ end
69
+
70
+ def doi=(doi)
71
+ raw_hash['doi'] = doi
72
+ end
73
+
74
+ def citation
75
+ raw_hash['citation']
76
+ end
77
+
78
+ def catation=(citation)
79
+ raw_hash['citation'] = citation
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../extension'
4
+ require_relative '../item'
5
+
6
+ module STAC
7
+ module Extensions
8
+ # Utilities for View Geometry extension.
9
+ #
10
+ # View Geometry \Extension Specification: https://github.com/stac-extensions/scientific/
11
+ module ViewGeometry
12
+ extend Extension
13
+
14
+ identifier 'https://stac-extensions.github.io/view/v1.0.0/schema.json'
15
+ scope STAC::Item
16
+
17
+ module Properties # rubocop:disable Style/Documentation
18
+ attr_reader :extra
19
+
20
+ %w[
21
+ view:off_nadir view:incidence_angle view:azimuth view:sun_azimuth view:sun_elevation
22
+ ].each do |field|
23
+ method_name = field.sub(':', '_')
24
+
25
+ define_method(method_name) do
26
+ # @type self: Properties
27
+ extra[field]
28
+ end
29
+
30
+ define_method("#{method_name}=") do |value|
31
+ # @type self: Properties
32
+ extra[field] = value
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end