charta 0.2.2 → 0.4.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 (39) hide show
  1. checksums.yaml +5 -5
  2. data/charta.gemspec +21 -20
  3. data/lib/charta/bounding_box.rb +5 -1
  4. data/lib/charta/coordinates.rb +65 -0
  5. data/lib/charta/ewkt_serializer.rb +101 -0
  6. data/lib/charta/factory/ewkt_feature_builder.rb +17 -0
  7. data/lib/charta/factory/feature_factory_base.rb +15 -0
  8. data/lib/charta/factory/simple_feature_factory.rb +50 -0
  9. data/lib/charta/factory/simple_geometry_factory.rb +46 -0
  10. data/lib/charta/factory/srid_provider.rb +36 -0
  11. data/lib/charta/factory/transformers/ewkt_passthrough.rb +20 -0
  12. data/lib/charta/factory/transformers/ewkt_transformer.rb +20 -0
  13. data/lib/charta/factory/transformers/ewkt_transformer_chain.rb +42 -0
  14. data/lib/charta/factory/transformers/from_geo_json_transformer.rb +20 -0
  15. data/lib/charta/factory/transformers/from_gml_transformer.rb +20 -0
  16. data/lib/charta/factory/transformers/from_kml_transformer.rb +20 -0
  17. data/lib/charta/factory/transformers/from_wkb_transformer.rb +24 -0
  18. data/lib/charta/factory/transformers/transformation_error.rb +10 -0
  19. data/lib/charta/geo_json.rb +12 -124
  20. data/lib/charta/geometry.rb +70 -16
  21. data/lib/charta/geometry_collection.rb +6 -4
  22. data/lib/charta/gml.rb +18 -2
  23. data/lib/charta/gml_import.rb +24 -24
  24. data/lib/charta/kml.rb +21 -3
  25. data/lib/charta/multi_polygon.rb +1 -1
  26. data/lib/charta/point.rb +6 -0
  27. data/lib/charta/polygon.rb +5 -0
  28. data/lib/charta/version.rb +1 -1
  29. data/lib/charta.rb +39 -87
  30. data/lib/rgeo/svg.rb +44 -44
  31. metadata +78 -44
  32. data/.gitignore +0 -11
  33. data/.gitlab-ci.yml +0 -14
  34. data/.travis.yml +0 -7
  35. data/CODE_OF_CONDUCT.md +0 -74
  36. data/Gemfile +0 -4
  37. data/LICENSE.txt +0 -21
  38. data/README.md +0 -44
  39. data/Rakefile +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5cef2f555beb27d13a0cbc3bbc24f64f9143d2cb
4
- data.tar.gz: 64f46d959388ca952edbb53e8deb4a887335bc9f
2
+ SHA256:
3
+ metadata.gz: 96bee13636a087302272ef4bc271ca0200e46aece932f932a2c9ff6b989254a8
4
+ data.tar.gz: 4d139f4c3d628b178862b6879edc2ba92e11f82e96f43d748def1ac063c89562
5
5
  SHA512:
6
- metadata.gz: 99614ef99edfdbd74e8d107279a1e8533b887cc3e4e503ba7355c60f964a4aeb95e5778debd35dc3fd4c385c61c3a199f412ac1252691accf0b079e60530b99d
7
- data.tar.gz: 4abce4b81dd5ccab25fcb6778b896615c627d389aec8cd465301595ff9e171f1af7c64bb1f1b7f3947d4d9b73ca5a16cc23c508303796e254f57a92ac0f7a56d
6
+ metadata.gz: 04b4a7e56bc7a412114f4f2713725d1304bc4c859911a2079a847b88511d80c5f20057df7a19f79c6b022b107ff9b1328b064084f0ebdf1e5335622afbff7f27
7
+ data.tar.gz: 3f8cec56a64a686abcfd14264df20b593c396fb0296b779b48c2697a630ad9bed6d16de61a86c12995fec6f74e5a1cf4ac1f65655e244a840393ea5448fd00ed
data/charta.gemspec CHANGED
@@ -1,30 +1,31 @@
1
- lib = File.expand_path('../lib', __FILE__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'charta/version'
1
+ require_relative 'lib/charta/version'
4
2
 
5
3
  Gem::Specification.new do |spec|
6
- spec.name = 'charta'
7
- spec.version = Charta::VERSION
8
- spec.authors = ['Brice TEXIER']
9
- spec.email = ['brice@ekylibre.com']
4
+ spec.name = 'charta'
5
+ spec.version = Charta::VERSION
6
+ spec.authors = ['Ekylibre developers']
7
+ spec.email = ['dev@ekylibre.com']
10
8
 
11
- spec.summary = 'Simple tool over geos and co'
12
- spec.homepage = 'https://github.com/ekylibre/charta'
13
- spec.license = 'MIT'
9
+ spec.summary = 'Simple tool over geos and co'
10
+ spec.required_ruby_version = '>= 2.6.0'
11
+ spec.homepage = 'https://gitlab.com/ekylibre'
12
+ spec.license = 'AGPL-3.0-only'
13
+
14
+ spec.files = Dir.glob(%w[lib/**/*.rb *.gemspec])
14
15
 
15
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
- f.match(%r{^(test|spec|features)/})
17
- end
18
16
  spec.require_paths = ['lib']
19
17
 
20
- spec.add_dependency 'nokogiri', '>= 1.7.0'
21
- spec.add_dependency 'rgeo', '~> 1.0'
22
- spec.add_dependency 'json', '>= 1.8.0'
23
- spec.add_dependency 'rgeo-geojson', '~> 1.0'
24
- spec.add_dependency 'rgeo-proj4', '~> 1.0'
25
18
  spec.add_dependency 'activesupport', '~> 5.0'
19
+ spec.add_dependency 'json', '>= 1.8.0'
20
+ spec.add_dependency 'nokogiri', '>= 1.7.0'
21
+ spec.add_dependency 'rgeo', '~> 2.0'
22
+ spec.add_dependency 'rgeo-geojson', '~> 2.0'
23
+ spec.add_dependency 'rgeo-proj4', '~> 2.0'
24
+ spec.add_dependency 'victor', '~> 0.3.3'
25
+ spec.add_dependency 'zeitwerk', '~> 2.4.0'
26
+
26
27
  spec.add_development_dependency 'bundler', '~> 2.0'
27
- spec.add_development_dependency 'rake', '~> 10.0'
28
28
  spec.add_development_dependency 'minitest', '~> 5.0'
29
- spec.add_development_dependency 'byebug'
29
+ spec.add_development_dependency 'rake', '~> 12.0'
30
+ spec.add_development_dependency 'rubocop', '1.3.1'
30
31
  end
@@ -18,11 +18,15 @@ module Charta
18
18
  end
19
19
 
20
20
  def svg_view_box
21
- [x_min, -y_max, width, height]
21
+ [x_min, y_min, width, height]
22
22
  end
23
23
 
24
24
  def to_a
25
25
  [[@y_min, @x_min], [@y_max, @x_max]]
26
26
  end
27
+
28
+ def to_bbox_string
29
+ "#{@x_min}, #{@y_min}, #{x_max}, #{y_max}"
30
+ end
27
31
  end
28
32
  end
@@ -0,0 +1,65 @@
1
+ module Charta
2
+ module Coordinates
3
+ class << self
4
+
5
+ # Force coordinates to 2D
6
+ def flatten(hash)
7
+ map_coordinates(hash) { |position| position[0..1] }
8
+ end
9
+
10
+ def map_coordinates(hash, &block)
11
+ case hash['type']
12
+ when 'FeatureCollection'
13
+ map_feature_collection_coordinates hash, &block
14
+ when 'Feature'
15
+ map_feature_coordinates hash, &block
16
+ else
17
+ map_geometry_coordinates hash, &block
18
+ end
19
+ end
20
+
21
+ def normalize_4326_geometry(json)
22
+ map_coordinates json do |(x, y)|
23
+ [((x + 180.to_d) % 360.to_d) - 180.to_d, ((y + 90.to_d) % 180.to_d) - 90.to_d]
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def map_feature_collection_coordinates(hash, &block)
30
+ hash.merge 'features' => hash['features'].map { |feature| map_feature_coordinates feature, &block }
31
+ end
32
+
33
+ def map_feature_coordinates(hash, &block)
34
+ hash.merge 'geometry' => map_geometry_coordinates(hash['geometry'], &block)
35
+ end
36
+
37
+ def map_geometry_coordinates(hash, &block)
38
+ if hash['type'] == 'GeometryCollection'
39
+ map_geometry_collection_coordinates hash, &block
40
+ else
41
+ coordinates = hash['coordinates']
42
+ mapped =
43
+ case hash['type']
44
+ when 'Point'
45
+ block.call coordinates
46
+ when 'MultiPoint', 'LineString'
47
+ coordinates.map(&block)
48
+ when 'MultiLineString', 'Polygon'
49
+ coordinates.map { |line| line.map(&block) }
50
+ when 'MultiPolygon'
51
+ coordinates.map { |poly| poly.map { |line| line.map(&block) } }
52
+ else
53
+ raise StandardError.new("Cannot handle: #{hash['type'].inspect}. In #{hash.inspect}")
54
+ end
55
+
56
+ hash.merge 'coordinates' => mapped
57
+ end
58
+ end
59
+
60
+ def map_geometry_collection_coordinates(hash, &block)
61
+ hash.merge 'geometries' => hash['geometries'].map { |geometry| map_geometry_coordinates(geometry, &block) }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,101 @@
1
+ module Charta
2
+ module EwktSerializer
3
+
4
+ class << self
5
+ def object_to_ewkt(hash)
6
+ type = hash[:type] || hash['type']
7
+ send("#{type.gsub(/(.)([A-Z])/, '\1_\2').downcase}_to_ewkt", hash)
8
+ end
9
+
10
+ private
11
+
12
+ def feature_collection_to_ewkt(hash)
13
+ return 'GEOMETRYCOLLECTION EMPTY' if hash['features'].nil?
14
+
15
+ 'GEOMETRYCOLLECTION(' + hash['features'].collect do |feature|
16
+ object_to_ewkt(feature)
17
+ end.join(', ') + ')'
18
+ end
19
+
20
+ def geometry_collection_to_ewkt(hash)
21
+ return 'GEOMETRYCOLLECTION EMPTY' if hash['geometries'].nil?
22
+
23
+ 'GEOMETRYCOLLECTION(' + hash['geometries'].collect do |feature|
24
+ object_to_ewkt(feature)
25
+ end.join(', ') + ')'
26
+ end
27
+
28
+ def feature_to_ewkt(hash)
29
+ object_to_ewkt(hash['geometry'])
30
+ end
31
+
32
+ def point_to_ewkt(hash)
33
+ return 'POINT EMPTY' if hash['coordinates'].nil?
34
+
35
+ 'POINT(' + hash['coordinates'].join(' ') + ')'
36
+ end
37
+
38
+ def line_string_to_ewkt(hash)
39
+ return 'LINESTRING EMPTY' if hash['coordinates'].nil?
40
+
41
+ 'LINESTRING(' + hash['coordinates'].collect do |point|
42
+ point.join(' ')
43
+ end.join(', ') + ')'
44
+ end
45
+
46
+ def polygon_to_ewkt(hash)
47
+ return 'POLYGON EMPTY' if hash['coordinates'].nil?
48
+
49
+ 'POLYGON(' + hash['coordinates'].collect do |hole|
50
+ '(' + hole.collect do |point|
51
+ point.join(' ')
52
+ end.join(', ') + ')'
53
+ end.join(', ') + ')'
54
+ end
55
+
56
+ def multi_point_to_ewkt(hash)
57
+ return 'MULTIPOINT EMPTY' if hash['coordinates'].nil?
58
+
59
+ 'MULTIPOINT(' + hash['coordinates'].collect do |point|
60
+ '(' + point.join(' ') + ')'
61
+ end.join(', ') + ')'
62
+ end
63
+
64
+ def multi_line_string_to_ewkt(hash)
65
+ return 'MULTILINESTRING EMPTY' if hash['coordinates'].nil?
66
+
67
+ 'MULTILINESTRING(' + hash['coordinates'].collect do |line|
68
+ '(' + line.collect do |point|
69
+ point.join(' ')
70
+ end.join(', ') + ')'
71
+ end.join(', ') + ')'
72
+ end
73
+
74
+ def multipolygon_to_ewkt(hash)
75
+ return 'MULTIPOLYGON EMPTY' if hash['coordinates'].nil?
76
+
77
+ 'MULTIPOLYGON(' + hash['coordinates'].collect do |polygon|
78
+ '(' + polygon.collect do |hole|
79
+ '(' + hole.collect do |point|
80
+ point.join(' ')
81
+ end.join(', ') + ')'
82
+ end.join(', ') + ')'
83
+ end.join(', ') + ')'
84
+ end
85
+
86
+ # for PostGIS ST_ASGeoJSON compatibility
87
+ def multi_polygon_to_ewkt(hash)
88
+ return 'MULTIPOLYGON EMPTY' if hash['coordinates'].nil?
89
+
90
+ 'MULTIPOLYGON(' + hash['coordinates'].collect do |polygon|
91
+ '(' + polygon.collect do |hole|
92
+ '(' + hole.collect do |point|
93
+ point.join(' ')
94
+ end.join(', ') + ')'
95
+ end.join(', ') + ')'
96
+ end.join(', ') + ')'
97
+ end
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class EwktFeatureBuilder
6
+ # @param [String] ewkt EWKT representation of a feature
7
+ # @return [RGeo::Feature::Instance]
8
+ def from_ewkt(ewkt)
9
+ if ewkt.to_s =~ /\A[[:space:]]*\z/
10
+ raise ArgumentError.new("Invalid data: #{ewkt.inspect}")
11
+ end
12
+
13
+ Geometry.feature(ewkt)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class FeatureFactoryBase
6
+ def new_feature(coordinates, srs: nil, format: nil)
7
+ raise StandardError.new('Not implemented')
8
+ end
9
+
10
+ def empty_feature(srs = :WGS84)
11
+ new_feature('GEOMETRYCOLLECTION EMPTY', srs: srs)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class SimpleFeatureFactory < FeatureFactoryBase
6
+ class << self
7
+ def build
8
+ new(
9
+ ewkt_builder: EwktFeatureBuilder.new,
10
+ srid_provider: SridProvider.build,
11
+ transformer: Transformers::EwktTransformerChain.build
12
+ )
13
+ end
14
+ end
15
+
16
+ # @return [EwktFeatureBuilder]
17
+ attr_reader :ewkt_builder
18
+ # @return [SridProvider]
19
+ attr_reader :srid_provider
20
+ # @return [Transformers::EwktTransformer]
21
+ attr_reader :transformer
22
+
23
+ def initialize(ewkt_builder:, srid_provider:, transformer:)
24
+ @ewkt_builder = ewkt_builder
25
+ @srid_provider = srid_provider
26
+ @transformer = transformer
27
+ end
28
+
29
+ def new_feature(coordinates, srs: nil, format: nil)
30
+ if coordinates.is_a?(Charta::Geometry)
31
+ coordinates
32
+ elsif coordinates.is_a?(RGeo::Feature::Instance)
33
+ Geometry.feature(coordinates)
34
+ elsif coordinates.to_s =~ /\A[[:space:]]*\z/
35
+ empty_feature(srs)
36
+ else
37
+ convert_feature(coordinates, srs: srs, format: format)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def convert_feature(coordinates, srs: nil, format: nil)
44
+ srid = srs.nil? ? nil : srid_provider.find(srs)
45
+
46
+ ewkt_builder.from_ewkt(transformer.transform(coordinates, srid: srid, format: format))
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class SimpleGeometryFactory
6
+ # @return [SimpleFeatureFactory]
7
+ attr_reader :feature_factory
8
+
9
+ # @param [SimpleFeatureFactory] feature_factory
10
+ def initialize(feature_factory:)
11
+ @feature_factory = feature_factory
12
+ end
13
+
14
+ def new_geometry(coordinates, srs: nil, format: nil)
15
+ if coordinates.is_a?(::Charta::Geometry)
16
+ coordinates
17
+ else
18
+ wrap(feature_factory.new_feature(coordinates, srs: srs, format: format))
19
+ end
20
+ end
21
+
22
+ def empty_geometry(srs)
23
+ wrap(feature_factory.empty_feature(srs))
24
+ end
25
+
26
+ protected
27
+
28
+ def wrap(feature)
29
+ case feature.geometry_type
30
+ when RGeo::Feature::Point
31
+ Point.new(feature)
32
+ when RGeo::Feature::LineString
33
+ LineString.new(feature)
34
+ when RGeo::Feature::Polygon
35
+ Polygon.new(feature)
36
+ when RGeo::Feature::MultiPolygon
37
+ MultiPolygon.new(feature)
38
+ when RGeo::Feature::GeometryCollection
39
+ GeometryCollection.new(feature)
40
+ else
41
+ Geometry.new(feature)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class SridProvider
6
+ SRS = {
7
+ WGS84: 4326,
8
+ CRS84: 4326,
9
+ RGF93: 2143
10
+ }.freeze
11
+
12
+ class << self
13
+ def build
14
+ new(SRS)
15
+ end
16
+ end
17
+
18
+ def initialize(srs)
19
+ @srs = srs
20
+ end
21
+
22
+ def find(srname_or_srid)
23
+ if srname_or_srid.to_s =~ /\Aurn:ogc:def:crs:.*\z/
24
+ x = srname_or_srid.split(':').last.upcase.to_sym
25
+ @srs[x] || x
26
+ elsif srname_or_srid.to_s =~ /\AEPSG::?(\d{4,5})\z/
27
+ srname_or_srid.split(':').last
28
+ elsif srname_or_srid.to_s =~ /\A\d+\z/
29
+ srname_or_srid.to_i
30
+ else
31
+ @srs[srname_or_srid] || srname_or_srid
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class EwktPassthrough < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(String) && format.nil?
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ value
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ false
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ raise StandardError.new('Not implemented')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class EwktTransformerChain < EwktTransformer
7
+ class << self
8
+ def build
9
+ new(
10
+ Transformers::FromGeoJsonTransformer.new,
11
+ Transformers::FromWkbTransformer.new,
12
+ Transformers::FromGmlTransformer.new,
13
+ Transformers::FromKmlTransformer.new,
14
+ Transformers::EwktPassthrough.new
15
+ )
16
+ end
17
+ end
18
+
19
+ # @return [Array<EwktTransformer>]
20
+ attr_reader :transformers
21
+
22
+ def initialize(*transformers)
23
+ @transformers = transformers
24
+ end
25
+
26
+ # @return [Boolean]
27
+ def handles?(value, format:)
28
+ transformers.any? { |t| t.handles?(value, format: format) }
29
+ end
30
+
31
+ # @param [String, Hash] value
32
+ # @return [String] ewkt representation of value
33
+ def transform(value, srid: nil, format: nil)
34
+ transformer = transformers.detect { |t| t.handles?(value, format: format) }
35
+ raise TransformationError.new('Not handled') if transformer.nil?
36
+
37
+ transformer.transform(value, srid: srid, format: format)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class FromGeoJsonTransformer < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(Hash) || (value.is_a?(String) && Charta::GeoJSON.valid?(value)) # GeoJSON
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ Charta::GeoJSON.new(value, srid).to_ewkt
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class FromGmlTransformer < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(String) && format == 'gml' && Charta::GML.valid?(value)
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ Charta::GML.new(value, srid).to_ewkt
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class FromKmlTransformer < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(String) && format == 'kml' && Charta::KML.valid?(value)
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ Charta::KML.new(value, srid).to_ewkt
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class FromWkbTransformer < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(String) && !!(value =~ /\A[A-F0-9]+\z/)
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ if srid.nil?
16
+ Geometry.factory.parse_wkb(value)
17
+ else
18
+ RGeo::Geos.factory(srid: srid).parse_wkb(value)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class TransformationError < StandardError
7
+ end
8
+ end
9
+ end
10
+ end