rosetta-stone 0.1.0 → 0.2.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: e3cf674dc5b340ddd9571dd573754c8053b9bb979b53cb29724c0614f3a97ca5
4
- data.tar.gz: 9ffb03bc8efa51760fa3f9ca970fc9dd99c5041360dae61dd1ad35382bc903f9
3
+ metadata.gz: 6f49ad30a0b19d92be9bca2d6b43eca56f1843fe9b594d9c46c1401113304c15
4
+ data.tar.gz: 5989f92c630e155ea5da9a5191c6a06e5e41ac2f8854d347372f611b814a0b68
5
5
  SHA512:
6
- metadata.gz: 0c9d3c191c137f481b690e91803b8e8ea80a2a47c298c66c3f0f184de06f5e91c5c9e1d9731dfd25e9e129e7c7caa40ceb25202260e0d6992ebcbbcf2d17c633
7
- data.tar.gz: e474a60fe27c7c91e78282b4598d6de4e739f267e64799b92f2a50118385c3d06b01decfcbe5a143164062f901e2a791b7fed9833cf548fe32f04b3fb30b7ca0
6
+ metadata.gz: ef07a8fbf976977caff7b8de46ff30df4ff500df9784bda69fb81e146d03123f7208434f5eddf8cacb57663d0113f5a352cd3ded94664ac09cd5f36eee4a8914
7
+ data.tar.gz: 12c85f29aebe211372dc362c221bc6f82e0ff8f64524060c2fb679e9ac7185893b0b2e9421e4f4a9dae7331b1095d71c2b5b8809d574d1ffd8531aa059475d74
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rosetta-stone (0.1.0)
4
+ rosetta-stone (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -7,7 +7,7 @@ A lightweight format-to-format translator.
7
7
  Add this line to your application's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'rosetta'
10
+ gem 'rosetta-stone'
11
11
  ```
12
12
 
13
13
  And then execute:
@@ -16,7 +16,7 @@ And then execute:
16
16
 
17
17
  Or install it yourself as:
18
18
 
19
- $ gem install rosetta
19
+ $ gem install rosetta-stone
20
20
 
21
21
  ## Usage
22
22
 
@@ -64,7 +64,7 @@ Rosetta::Translation.new(deserializer, serializer).call("olleh") # => HELLO
64
64
  When given `Symbol`s instead, they will try to lookup the registered serializers
65
65
  and deserializers to find a match to use with the input.
66
66
  By default, the only ones supplied with the gem are a JSON deserializer and a
67
- CSV serializer.
67
+ CSV serializer. (`Rosetta::Deserializers::JSON` and `Rosetta::Serializers::CSV`).
68
68
  See *Registering a Serializer / Deserializer* for more info on how to add your own.
69
69
 
70
70
  You can also register `Translator`s, which are pipes connecting to specific
@@ -76,7 +76,7 @@ See *Registering a Translator* for more info on how to use them.
76
76
  You can register a new serializer or deserializer by calling the `register`
77
77
  methods of respectively `Rosetta::Serializers` or `Rosetta::Deserializers`.
78
78
  The method takes the Symbol that's going to be used as shorthand for it as first
79
- parameter and the callable object you want to use as second.
79
+ parameter and either a callable object or a block for the serializer/deserializer.
80
80
 
81
81
  Example:
82
82
  ```ruby
@@ -87,6 +87,11 @@ Rosetta::Deserializers.register(:mirror, deserializer)
87
87
  Rosetta::Serializers.register(:BIG, serializer)
88
88
 
89
89
  Rosetta.translate(from: :mirror, to: :big, "em ti si") # => "IS IT ME"
90
+
91
+ # Alternative
92
+
93
+ Rosetta::Deserializers.register(:BIG) { |input| input.upcase }
94
+ Rosetta::Deserializers.register(:mirror) { |input| input.reverse }
90
95
  ```
91
96
 
92
97
  Whatever the Deserializer returns will be fed to the Serializer when
@@ -1,54 +1,23 @@
1
1
  require 'rosetta/exceptions'
2
2
 
3
3
  module Rosetta
4
- class Deserializers
4
+ module Deserializers
5
5
  @registered = {}
6
6
 
7
- def self.[](key)
8
- @registered[key]
9
- end
10
-
11
- def self.register(name, deserializer)
12
- raise ExistingDeserializerError, <<-ERROR.strip if @registered.key? name
13
- Deserializer #{name} is already registered.
14
- ERROR
15
- @registered[name] = deserializer
16
- end
17
-
18
- class Base
19
- attr_reader :input
20
-
21
- class << self
22
- def inherited(new_serializer)
23
- key = new_serializer.name.match(/^(.*?)(Deserializer)?$/)[1]
24
- key = key.split("::").last
25
- #NOTE: Similar to Rails's #underscore
26
- #TODO: Extract in refinement?
27
- key = key.scan(/[A-Z]+[a-z]*/).join('_').downcase.to_sym
28
- Deserializers.register(key, new_serializer)
29
- end
7
+ class << self
8
+ attr_reader :registered
30
9
 
31
- def call(input)
32
- new(input).call
33
- end
34
- alias_method :deserialize, :call
35
-
36
- def to_proc
37
- proc { |*args, &block| self.call(*args, &block) }
38
- end
39
- end
40
-
41
- def initialize(input)
42
- @input = input.dup.freeze
10
+ def [](key)
11
+ registered[key]
43
12
  end
44
13
 
45
- def call
46
- raise NotImplementedError
47
- end
48
- alias_method :deserialize, :call
14
+ def register(name, deserializer, &block)
15
+ raise ExistingDeserializerError, <<-ERROR.strip if @registered.key? name
16
+ Deserializer #{name} is already registered.
17
+ ERROR
49
18
 
50
- def to_proc
51
- proc { |*args, &block| self.call(*args, &block) }
19
+ raise ArgumentError, "Can't take both deserializer object and block." if deserializer && block
20
+ @registered[name] = deserializer
52
21
  end
53
22
  end
54
23
  end
@@ -0,0 +1,43 @@
1
+ require 'rosetta/deserializers'
2
+ require 'rosetta/exceptions'
3
+
4
+ module Rosetta
5
+ module Deserializers
6
+ class Base
7
+ attr_reader :input
8
+
9
+ class << self
10
+ def inherited(new_serializer)
11
+ key = new_serializer.name.match(/^(.*?)(Deserializer)?$/)[1]
12
+ key = key.split("::").last
13
+ #NOTE: Similar to Rails's #underscore
14
+ #TODO: Extract in refinement?
15
+ key = key.scan(/[A-Z]+[a-z]*/).join('_').downcase.to_sym
16
+ Deserializers.register(key, new_serializer)
17
+ end
18
+
19
+ def call(input)
20
+ new(input).call
21
+ end
22
+ alias_method :deserialize, :call
23
+
24
+ def to_proc
25
+ proc { |*args, &block| self.call(*args, &block) }
26
+ end
27
+ end
28
+
29
+ def initialize(input)
30
+ @input = input.dup.freeze
31
+ end
32
+
33
+ def call
34
+ raise NotImplementedError
35
+ end
36
+ alias_method :deserialize, :call
37
+
38
+ def to_proc
39
+ proc { |*args, &block| self.call(*args, &block) }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ require 'json'
2
+
3
+ require 'rosetta/element'
4
+ require 'rosetta/exceptions'
5
+ require 'rosetta/deserializers/base'
6
+
7
+ module Rosetta
8
+ module Deserializers
9
+ class JSON < Base
10
+ def call
11
+ validate_input!
12
+ input.map { |obj| Element.new(obj) }
13
+ end
14
+
15
+ private
16
+
17
+ def validate_input!
18
+ raise DeserializationError, <<-ERROR.strip unless parsed_input = valid_json(@input)
19
+ JSON input is invalid
20
+ ERROR
21
+ raise DeserializationError, <<-ERROR.strip unless parsed_input.is_a? Array
22
+ JSON input must be an array
23
+ ERROR
24
+ raise DeserializationError, <<-ERROR.strip unless parsed_input.all? { |o| o.is_a? Hash }
25
+ JSON input must contain objects
26
+ ERROR
27
+
28
+ @input = parsed_input.freeze
29
+ end
30
+
31
+ #HACK: Feels dirty but there's no JSON soft-parsing in ruby's json lib
32
+ def valid_json(json)
33
+ JSON(json)
34
+ #NOTE: Rescuing TypeError too in case json is not a String
35
+ rescue ::JSON::ParserError, TypeError
36
+ nil
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,55 +1,23 @@
1
1
  require 'rosetta/exceptions'
2
2
 
3
3
  module Rosetta
4
- class Serializers
4
+ module Serializers
5
5
  @registered = {}
6
6
 
7
- def self.[](key)
8
- @registered[key]
9
- end
10
-
11
- def self.register(name, serializer)
12
- raise ExistingSerializerError, <<-ERROR.strip if @registered.key? name
13
- Serializer #{name} is already registered.
14
- ERROR
15
- @registered[name] = serializer
16
- end
17
-
18
- class Base
19
- attr_reader :elements
20
-
21
- class << self
22
- def inherited(new_serializer)
23
- key = new_serializer.name.match(/^(.*?)(Serializer)?$/)[1]
24
- key = key.split("::").last
25
- #NOTE: Similar to Rails's #underscore
26
- #TODO: Extract in refinement?
27
- key = key.scan(/[A-Z]+[a-z]*/).join('_').downcase.to_sym
28
- Serializers.register(key, new_serializer)
29
- end
7
+ class << self
8
+ attr_reader :registered
30
9
 
31
- def call(elements)
32
- new(elements).call
33
- end
34
- alias_method :serialize, :call
35
-
36
- def to_proc
37
- proc { |*args, &block| self.call(*args, &block) }
38
- end
39
- end
40
-
41
- def initialize(elements)
42
- @elements = elements.dup.freeze
43
- validate_input!
10
+ def [](key)
11
+ @registered[key]
44
12
  end
45
13
 
46
- def call
47
- raise NotImplementedError
48
- end
49
- alias_method :serialize, :call
14
+ def register(name, serializer, &block)
15
+ raise ExistingSerializerError, <<-ERROR.strip if @registered.key? name
16
+ Serializer #{name} is already registered.
17
+ ERROR
50
18
 
51
- def to_proc
52
- proc { |*args, &block| self.call(*args, &block) }
19
+ raise ArgumentError, "Can't take both serializer object and block." if serializer && block
20
+ @registered[name] = serializer
53
21
  end
54
22
  end
55
23
  end
@@ -0,0 +1,44 @@
1
+ require 'rosetta/serializers'
2
+ require 'rosetta/exceptions'
3
+
4
+ module Rosetta
5
+ module Serializers
6
+ class Base
7
+ attr_reader :elements
8
+
9
+ class << self
10
+ def inherited(new_serializer)
11
+ key = new_serializer.name.match(/^(.*?)(Serializer)?$/)[1]
12
+ key = key.split("::").last
13
+ #NOTE: Similar to Rails's #underscore
14
+ #TODO: Extract in refinement?
15
+ key = key.scan(/[A-Z]+[a-z]*/).join('_').downcase.to_sym
16
+ Serializers.register(key, new_serializer)
17
+ end
18
+
19
+ def call(elements)
20
+ new(elements).call
21
+ end
22
+ alias_method :serialize, :call
23
+
24
+ def to_proc
25
+ proc { |*args, &block| self.call(*args, &block) }
26
+ end
27
+ end
28
+
29
+ def initialize(elements)
30
+ @elements = elements.dup.freeze
31
+ validate_input!
32
+ end
33
+
34
+ def call
35
+ raise NotImplementedError
36
+ end
37
+ alias_method :serialize, :call
38
+
39
+ def to_proc
40
+ proc { |*args, &block| self.call(*args, &block) }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ require 'csv'
2
+
3
+ require 'rosetta/exceptions'
4
+ require 'rosetta/serializers/base'
5
+
6
+ module Rosetta
7
+ module Serializers
8
+ class CSV < Base
9
+ def call
10
+ ::CSV.generate do |csv|
11
+ csv << headers
12
+ elements.each do |element|
13
+ csv << headers.map { |header| serialize_value(element[header]) }
14
+ end
15
+ end
16
+ end
17
+
18
+ def headers
19
+ head, *_ = elements.map(&:properties).uniq
20
+ head
21
+ end
22
+
23
+ def validate_input!
24
+ _, *others = elements.map(&:properties).uniq
25
+
26
+ raise SerializationError, <<-ERROR.strip unless others.none?
27
+ All objects need to share their structure to be serialized to CSV.
28
+ ERROR
29
+ end
30
+
31
+ private
32
+
33
+ def serialize_value(value)
34
+ case value
35
+ when Array
36
+ value.join(',')
37
+ else
38
+ value
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -3,21 +3,24 @@ require 'rosetta/exceptions'
3
3
  module Rosetta
4
4
  class Translation
5
5
  @registered = {}
6
-
7
6
  attr_reader :serializer, :deserializer, :translator
8
7
  alias_method :translator?, :translator
9
8
 
10
- def self.register(source, destination, callable = nil, &block)
11
- raise ExistingTranslatorError, <<-ERROR.strip if @registered.key? name
12
- There already is a translator from #{source} to #{destination}.
13
- ERROR
9
+ class << self
10
+ attr_reader :registered
14
11
 
15
- raise ArgumentError, "Can't take both callabel object and block." if callable && block
16
- @registered[source => destination] = callable || block
17
- end
12
+ def [](key)
13
+ @registered[key]
14
+ end
18
15
 
19
- def self.[](key)
20
- @registered[key]
16
+ def register(source, destination, callable = nil, &block)
17
+ raise ExistingTranslatorError, <<-ERROR.strip if @registered.key? name
18
+ There already is a translator from #{source} to #{destination}.
19
+ ERROR
20
+
21
+ raise ArgumentError, "Can't take both callable object and block." if callable && block
22
+ @registered[source => destination] = callable || block
23
+ end
21
24
  end
22
25
 
23
26
  def initialize(deserializer, serializer)
@@ -1,3 +1,3 @@
1
1
  module Rosetta
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rosetta-stone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jérémie Bonal
@@ -85,12 +85,14 @@ files:
85
85
  - bin/console
86
86
  - bin/setup
87
87
  - lib/rosetta.rb
88
- - lib/rosetta/csv_serializer.rb
89
88
  - lib/rosetta/deserializers.rb
89
+ - lib/rosetta/deserializers/base.rb
90
+ - lib/rosetta/deserializers/json.rb
90
91
  - lib/rosetta/element.rb
91
92
  - lib/rosetta/exceptions.rb
92
- - lib/rosetta/json_deserializer.rb
93
93
  - lib/rosetta/serializers.rb
94
+ - lib/rosetta/serializers/base.rb
95
+ - lib/rosetta/serializers/csv.rb
94
96
  - lib/rosetta/translation.rb
95
97
  - lib/rosetta/version.rb
96
98
  - rosetta.gemspec
@@ -1,41 +0,0 @@
1
- require 'csv'
2
-
3
- require 'rosetta/exceptions'
4
- require 'rosetta/serializers'
5
-
6
- module Rosetta
7
- class CSVSerializer < Serializers::Base
8
- def call
9
- CSV.generate do |csv|
10
- csv << headers
11
- elements.each do |element|
12
- csv << headers.map { |header| serialize_value(element[header]) }
13
- end
14
- end
15
- end
16
-
17
- def headers
18
- head, *_ = elements.map(&:properties).uniq
19
- head
20
- end
21
-
22
- def validate_input!
23
- _, *others = elements.map(&:properties).uniq
24
-
25
- raise SerializationError, <<-ERROR.strip unless others.none?
26
- All objects need to share their structure to be serialized to CSV.
27
- ERROR
28
- end
29
-
30
- private
31
-
32
- def serialize_value(value)
33
- case value
34
- when Array
35
- value.join(',')
36
- else
37
- value
38
- end
39
- end
40
- end
41
- end
@@ -1,38 +0,0 @@
1
- require 'json'
2
-
3
- require 'rosetta/element'
4
- require 'rosetta/exceptions'
5
- require 'rosetta/deserializers'
6
-
7
- module Rosetta
8
- class JSONDeserializer < Deserializers::Base
9
- def call
10
- validate_input!
11
- input.map { |obj| Element.new(obj) }
12
- end
13
-
14
- private
15
-
16
- def validate_input!
17
- raise DeserializationError, <<-ERROR.strip unless parsed_input = valid_json(@input)
18
- JSON input is invalid
19
- ERROR
20
- raise DeserializationError, <<-ERROR.strip unless parsed_input.is_a? Array
21
- JSON input must be an array
22
- ERROR
23
- raise DeserializationError, <<-ERROR.strip unless parsed_input.all? { |o| o.is_a? Hash }
24
- JSON input must contain objects
25
- ERROR
26
-
27
- @input = parsed_input.freeze
28
- end
29
-
30
- #HACK: Feels dirty but there's no JSON soft-parsing in ruby's json lib
31
- def valid_json(json)
32
- JSON(json)
33
- #NOTE: Rescuing TypeError too in case json is not a String
34
- rescue JSON::ParserError, TypeError
35
- nil
36
- end
37
- end
38
- end