rosetta-stone 0.1.0 → 0.2.0

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