stac 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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