stac 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/CHANGELOG.md +18 -0
  4. data/GETTING_STARTED.md +384 -0
  5. data/Gemfile.lock +48 -37
  6. data/README.md +16 -57
  7. data/Rakefile +62 -4
  8. data/Steepfile +2 -0
  9. data/lib/stac/asset.rb +7 -1
  10. data/lib/stac/catalog.rb +81 -9
  11. data/lib/stac/collection.rb +43 -9
  12. data/lib/stac/common_metadata.rb +162 -0
  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 +58 -22
  23. data/lib/stac/link.rb +50 -14
  24. data/lib/stac/object_resolver.rb +14 -20
  25. data/lib/stac/properties.rb +6 -1
  26. data/lib/stac/provider.rb +5 -1
  27. data/lib/stac/{default_http_client.rb → simple_http_client.rb} +9 -4
  28. data/lib/stac/stac_object.rb +142 -31
  29. data/lib/stac/version.rb +1 -1
  30. data/lib/stac.rb +18 -2
  31. data/sig/stac/asset.rbs +3 -3
  32. data/sig/stac/catalog.rbs +29 -5
  33. data/sig/stac/collection.rbs +13 -5
  34. data/sig/stac/common_metadata.rbs +34 -0
  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 +17 -7
  45. data/sig/stac/link.rbs +21 -12
  46. data/sig/stac/object_resolver.rbs +5 -9
  47. data/sig/stac/properties.rbs +3 -3
  48. data/sig/stac/provider.rbs +2 -3
  49. data/sig/stac/{default_http_client.rbs → simple_http_client.rbs} +5 -2
  50. data/sig/stac/stac_object.rbs +34 -11
  51. data/sig/stac.rbs +7 -1
  52. data/stac.gemspec +1 -1
  53. metadata +26 -9
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,9 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'common_metadata'
4
+ require_relative 'hash_like'
5
+
3
6
  module STAC
4
7
  # Represents \STAC asset object, which contains a link to data associated with an Item or Collection that can be
5
8
  # downloaded or streamed.
6
9
  class Asset
10
+ include HashLike
11
+ include CommonMetadata
12
+
7
13
  class << self
8
14
  # Deserializes an Asset from a Hash.
9
15
  def from_hash(hash)
@@ -11,7 +17,7 @@ module STAC
11
17
  end
12
18
  end
13
19
 
14
- attr_accessor :href, :title, :description, :type, :roles, :extra
20
+ attr_accessor :href, :title, :description, :type, :roles
15
21
 
16
22
  def initialize(href:, title: nil, description: nil, type: nil, roles: nil, **extra)
17
23
  @href = href
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,20 +9,33 @@ 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'
12
13
 
13
- attr_accessor :description, :title
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
24
+
25
+ attr_accessor :id, :description, :title
14
26
 
15
- def initialize(id:, description:, links:, title: nil, stac_extensions: nil, **extra)
16
- super(id: id, links: links, stac_extensions: stac_extensions, **extra)
27
+ def initialize(id:, description:, links: [], title: nil, stac_extensions: [], **extra)
28
+ @id = id
17
29
  @description = description
18
30
  @title = title
31
+ super(links: links, stac_extensions: stac_extensions, **extra)
19
32
  end
20
33
 
21
34
  # Serializes self to a Hash.
22
35
  def to_h
23
36
  super.merge(
24
37
  {
38
+ 'id' => id,
25
39
  'title' => title,
26
40
  'description' => description,
27
41
  }.compact,
@@ -30,7 +44,11 @@ module STAC
30
44
 
31
45
  # Returns catalog/collection objects from rel="child" links of this catalog.
32
46
  def children
33
- 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
34
52
  end
35
53
 
36
54
  # Filters only collections from #children.
@@ -38,17 +56,24 @@ module STAC
38
56
  children.select { |child| child.type == 'Collection' }
39
57
  end
40
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
+
41
67
  # Returns the child catalog/collection with the given ID if it exists.
42
68
  #
43
69
  # With option `recusive: true`, it will traverse all child catalogs/collections recursively.
44
70
  def find_child(id, recursive: false)
45
- targets = recursive ? children.chain(children.flat_map(&:children)) : children
46
- targets.find { |child| child.id == id }
71
+ (recursive ? all_children : children).find { |child| child.id == id }
47
72
  end
48
73
 
49
74
  # Returns item objects from rel="item" links of this catalog.
50
75
  def items
51
- links.select { |link| link.rel == 'item' }.lazy.map(&:target)
76
+ item_links.lazy.map(&:target)
52
77
  end
53
78
 
54
79
  # Returns all items from this catalog and its child catalogs/collections recursively.
@@ -56,7 +81,7 @@ module STAC
56
81
  # The last `.lazy` is not necessary with Ruby 3.1.
57
82
  # But with Ruby 3.0, it is necessary because Enumerator::Lazy#chain returns Enumerator::Chain
58
83
  # and RBS type check fails.
59
- items.chain(children.flat_map(&:items)).lazy
84
+ items.chain(children.flat_map(&:all_items)).lazy
60
85
  end
61
86
 
62
87
  # Returns the item with the given ID if it exists.
@@ -65,5 +90,52 @@ module STAC
65
90
  def find_item(id, recursive: false)
66
91
  (recursive ? all_items : items).find { |item| item.id == id }
67
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
68
140
  end
69
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
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module STAC
6
+ # Provides read/write methods for \STAC Common Metadata.
7
+ #
8
+ # These methods are shorthand accessors of #extra Hash.
9
+ # Asset and \Item Properties include this module.
10
+ #
11
+ # Specification: https://github.com/radiantearth/stac-spec/blob/master/item-spec/common-metadata.md
12
+ module CommonMetadata
13
+ attr_reader :extra
14
+
15
+ def title
16
+ extra['title']
17
+ end
18
+
19
+ def title=(str)
20
+ extra['title'] = str
21
+ end
22
+
23
+ def description
24
+ extra['description']
25
+ end
26
+
27
+ def description=(str)
28
+ extra['description'] = str
29
+ end
30
+
31
+ def created
32
+ if (str = extra['created'])
33
+ Time.iso8601(str)
34
+ end
35
+ end
36
+
37
+ def created=(time)
38
+ extra['created'] = case time
39
+ when Time
40
+ time.iso8601
41
+ else
42
+ time
43
+ end
44
+ end
45
+
46
+ def updated
47
+ if (str = extra['updated'])
48
+ Time.iso8601(str)
49
+ end
50
+ end
51
+
52
+ def updated=(time)
53
+ extra['updated'] = case time
54
+ when Time
55
+ time.iso8601
56
+ else
57
+ time
58
+ end
59
+ end
60
+
61
+ def start_datetime
62
+ if (str = extra['start_datetime'])
63
+ Time.iso8601(str)
64
+ end
65
+ end
66
+
67
+ def start_datetime=(time)
68
+ extra['start_datetime'] = case time
69
+ when Time
70
+ time.iso8601
71
+ else
72
+ time
73
+ end
74
+ end
75
+
76
+ def end_datetime
77
+ if (str = extra['end_datetime'])
78
+ Time.iso8601(str)
79
+ end
80
+ end
81
+
82
+ def end_datetime=(time)
83
+ extra['end_datetime'] = case time
84
+ when Time
85
+ time.iso8601
86
+ else
87
+ time
88
+ end
89
+ end
90
+
91
+ # Returns a range from #start_datetime to #end_datetime.
92
+ def datetime_range
93
+ if (start = start_datetime) && (last = end_datetime)
94
+ start..last
95
+ end
96
+ end
97
+
98
+ # Sets #start_datetime and #end_datetime by the given range.
99
+ def datetime_range=(time_range)
100
+ self.start_datetime = time_range.begin
101
+ self.end_datetime = time_range.end
102
+ end
103
+
104
+ def license
105
+ extra['license']
106
+ end
107
+
108
+ def license=(str)
109
+ extra['license'] = str
110
+ end
111
+
112
+ def providers
113
+ extra.fetch('providers', []).map do |provider_hash|
114
+ Provider.from_hash(provider_hash)
115
+ end
116
+ end
117
+
118
+ def providers=(arr)
119
+ extra['providers'] = arr.map(&:to_h)
120
+ end
121
+
122
+ def platform
123
+ extra['platform']
124
+ end
125
+
126
+ def platform=(str)
127
+ extra['platform'] = str
128
+ end
129
+
130
+ def instruments
131
+ extra['instruments']
132
+ end
133
+
134
+ def instruments=(arr)
135
+ extra['instruments'] = arr
136
+ end
137
+
138
+ def constellation
139
+ extra['constellation']
140
+ end
141
+
142
+ def constellation=(str)
143
+ extra['constellation'] = str
144
+ end
145
+
146
+ def mission
147
+ extra['mission']
148
+ end
149
+
150
+ def mission=(str)
151
+ extra['mission'] = str
152
+ end
153
+
154
+ def gsd
155
+ extra['gsd']
156
+ end
157
+
158
+ def gsd=(num)
159
+ extra['gsd'] = num
160
+ end
161
+ end
162
+ end
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