avataaars 0.0.1
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 +7 -0
- data/lib/avataaars.rb +41 -0
- data/lib/avataaars/errors.rb +18 -0
- data/lib/avataaars/js/processor.js +48 -0
- data/lib/avataaars/processor.rb +103 -0
- data/lib/avataaars/utils.rb +46 -0
- data/lib/avataaars/version.rb +5 -0
- metadata +64 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 60f039285cc32f5d8f61332fed8ac81c0781d85ffcfe59c7edc6b7865ee2e8fe
|
4
|
+
data.tar.gz: 7d157732e340a421768bf61f944933ffc087af5e7095478cb3facd7e58f8e1ae
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0a6456a02ff4752045f1888a6909df104152302957c5bc2103ffc4af36e2786fe9d134eda272be444ecb40f4ee8a7b7243f6a12a8c5e8fc7810292cdc87a5628
|
7
|
+
data.tar.gz: faf7e0f2d982558eece42d6023cacb8c871fc98d866a91c8bfc34b6ba4bd270e81ef0c556b80da90913a79d7cf32aad964a4304669dfe57721525eb40c79bf86
|
data/lib/avataaars.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'avataaars/version'
|
4
|
+
|
5
|
+
require 'avataaars/errors'
|
6
|
+
require 'avataaars/processor'
|
7
|
+
require 'avataaars/utils'
|
8
|
+
|
9
|
+
#
|
10
|
+
# Avataaars interface for creating avatar SVGs from feature traits
|
11
|
+
#
|
12
|
+
class Avataaars
|
13
|
+
#
|
14
|
+
# @param [Hash] options Optional parameters to pass to avatar processor
|
15
|
+
# see https://github.com/fangpenlin/avataaars
|
16
|
+
#
|
17
|
+
def initialize(options = {})
|
18
|
+
@root_path = options.delete :root_path
|
19
|
+
@options = options
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Call to avatar creation processor and return rendered SVG
|
24
|
+
#
|
25
|
+
# @return [String] The resulting SVG data
|
26
|
+
#
|
27
|
+
def create_avatar
|
28
|
+
normalised_options = Utils.normalize_object(@options)
|
29
|
+
processor.create_avatar normalised_options
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def root_path
|
35
|
+
@root_path ||= Dir.pwd
|
36
|
+
end
|
37
|
+
|
38
|
+
def processor
|
39
|
+
Processor.new(root_path)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Avataaars
|
4
|
+
#
|
5
|
+
# Error classes for calling out to Avataaars NodeJS library
|
6
|
+
#
|
7
|
+
# Heavily based on the Schmooze library https://github.com/Shopify/schmooze
|
8
|
+
#
|
9
|
+
Error = Class.new(StandardError)
|
10
|
+
DependencyError = Class.new(Error)
|
11
|
+
module JavaScript # rubocop:disable Style/Documentation
|
12
|
+
Error = Class.new(::Avataaars::Error)
|
13
|
+
UnknownError = Class.new(Error)
|
14
|
+
def self.const_missing(name)
|
15
|
+
const_set name, Class.new(Error)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
// Setup imports
|
2
|
+
try {
|
3
|
+
const Module = require('module');
|
4
|
+
// resolve libraries from the CWD instead of where this script is located
|
5
|
+
const libraryPaths = Module._nodeModulePaths(process.cwd());
|
6
|
+
var React = require(require.resolve('react', { paths: libraryPaths }));
|
7
|
+
var ReactDOMServer = require(require.resolve('react-dom/server', { paths: libraryPaths }));
|
8
|
+
var Avatar = require(require.resolve('avataaars', { paths: libraryPaths })).default;
|
9
|
+
} catch (e) {
|
10
|
+
process.stdout.write(JSON.stringify(['err', e.toString()]));
|
11
|
+
process.stdout.write("\n");
|
12
|
+
process.exit(1);
|
13
|
+
}
|
14
|
+
process.stdout.write("[\"ok\"]\n");
|
15
|
+
|
16
|
+
const _createAvatar = (async (options) => {
|
17
|
+
return ReactDOMServer.renderToString(
|
18
|
+
React.createElement(Avatar, options)
|
19
|
+
);
|
20
|
+
});
|
21
|
+
|
22
|
+
function _handleError(error) {
|
23
|
+
if (error instanceof Error) {
|
24
|
+
process.stdout.write(
|
25
|
+
JSON.stringify(['err', error.toString().replace(new RegExp('^' + error.name + ': '), ''), error.name])
|
26
|
+
);
|
27
|
+
} else {
|
28
|
+
process.stdout.write(JSON.stringify(['err', error.toString()]));
|
29
|
+
}
|
30
|
+
process.stdout.write("\n");
|
31
|
+
}
|
32
|
+
|
33
|
+
// Interface for communicating between Ruby processor and Node processor
|
34
|
+
require('readline').createInterface({
|
35
|
+
input: process.stdin,
|
36
|
+
terminal: false,
|
37
|
+
}).on('line', function(line) {
|
38
|
+
try {
|
39
|
+
Promise.resolve(_createAvatar.apply(null, JSON.parse(line)))
|
40
|
+
.then(function (result) {
|
41
|
+
process.stdout.write(JSON.stringify(['ok', result]));
|
42
|
+
process.stdout.write("\n");
|
43
|
+
})
|
44
|
+
.catch(_handleError);
|
45
|
+
} catch(error) {
|
46
|
+
_handleError(error);
|
47
|
+
}
|
48
|
+
});
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'open3'
|
5
|
+
|
6
|
+
class Avataaars
|
7
|
+
#
|
8
|
+
# Processor helper class for calling out to Avataaars NodeJS library
|
9
|
+
#
|
10
|
+
# Heavily based on the Schmooze library https://github.com/Shopify/schmooze
|
11
|
+
#
|
12
|
+
class Processor
|
13
|
+
def initialize(app_root)
|
14
|
+
@app_root = app_root
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_avatar(options)
|
18
|
+
puts "O: #{options}"
|
19
|
+
|
20
|
+
spawn_process
|
21
|
+
ensure_packages_are_initiated
|
22
|
+
call_js_method options
|
23
|
+
ensure
|
24
|
+
cleanup_process if stdin
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :app_root, :stdin, :stdout, :stderr, :wait_thr
|
30
|
+
|
31
|
+
def spawn_process
|
32
|
+
@stdin, @stdout, @stderr, @wait_thr = Open3.popen3(
|
33
|
+
'node',
|
34
|
+
File.expand_path(File.join(__dir__, 'js/processor.js')),
|
35
|
+
chdir: app_root
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def ensure_packages_are_initiated
|
40
|
+
input = stdout.gets
|
41
|
+
raise Avataaars::Error, "Failed to instantiate worker process:\n#{stderr.read}" if input.nil?
|
42
|
+
|
43
|
+
result = JSON.parse(input)
|
44
|
+
return if result[0] == 'ok'
|
45
|
+
|
46
|
+
cleanup_process
|
47
|
+
parse_package_error result[1]
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_package_error(error_message) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
51
|
+
package_name = error_message[/^Error: Cannot find module '(.*)'$/, 1]
|
52
|
+
raise Avataaars::Error, error_message unless package_name
|
53
|
+
|
54
|
+
begin
|
55
|
+
%w[dependencies devDependencies].each do |key|
|
56
|
+
next unless package_json.key?(key) && package_json[key].key?(package_name)
|
57
|
+
|
58
|
+
raise Avataaars::DependencyError, Utils.squish(<<~ERROR)
|
59
|
+
Cannot find module '#{package_name}'.
|
60
|
+
The module was found in '#{package_json_path}' however, please run 'npm install' from '#{app_root}'
|
61
|
+
ERROR
|
62
|
+
end
|
63
|
+
rescue Errno::ENOENT # rubocop:disable Lint/SuppressedException
|
64
|
+
end
|
65
|
+
raise Avataaars::DependencyError, Utils.squish(<<~ERROR)
|
66
|
+
Cannot find module '#{package_name}'. You need to add it to '#{package_json_path}' and run 'npm install'
|
67
|
+
ERROR
|
68
|
+
end
|
69
|
+
|
70
|
+
def package_json_path
|
71
|
+
@package_json_path ||= File.join(app_root, 'package.json')
|
72
|
+
end
|
73
|
+
|
74
|
+
def package_json
|
75
|
+
@package_json ||= JSON.parse(File.read(package_json_path))
|
76
|
+
end
|
77
|
+
|
78
|
+
def call_js_method(options) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
79
|
+
stdin.puts JSON.dump([options])
|
80
|
+
input = stdout.gets
|
81
|
+
raise Errno::EPIPE, "Can't read from worker" if input.nil?
|
82
|
+
|
83
|
+
status, message, error_class = JSON.parse(input)
|
84
|
+
|
85
|
+
if status == 'ok'
|
86
|
+
message
|
87
|
+
elsif error_class.nil?
|
88
|
+
raise Avataaars::JavaScript::UnknownError, message
|
89
|
+
else
|
90
|
+
raise Avataaars::JavaScript.const_get(error_class, false), message
|
91
|
+
end
|
92
|
+
rescue Errno::EPIPE, IOError
|
93
|
+
raise Avataaars::Error, "Worker process failed:\n#{stderr.read}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def cleanup_process
|
97
|
+
stdin.close
|
98
|
+
stdout.close
|
99
|
+
stderr.close
|
100
|
+
wait_thr.join
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Avataaars
|
4
|
+
#
|
5
|
+
# Utility class for Avataaars helper methods
|
6
|
+
#
|
7
|
+
class Utils
|
8
|
+
#
|
9
|
+
# Deep transform the keys in an object (Hash/Array)
|
10
|
+
#
|
11
|
+
# Copied from active support
|
12
|
+
# @see active_support/core_ext/hash/keys.rb
|
13
|
+
#
|
14
|
+
def self.deep_transform_keys_in_object(object, &block)
|
15
|
+
case object
|
16
|
+
when Hash
|
17
|
+
object.each_with_object({}) do |(key, value), result|
|
18
|
+
result[yield(key)] = deep_transform_keys_in_object(value, &block)
|
19
|
+
end
|
20
|
+
when Array
|
21
|
+
object.map { |e| deep_transform_keys_in_object(e, &block) }
|
22
|
+
else
|
23
|
+
object
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Recursively normalizes hash objects with camelized string keys
|
29
|
+
#
|
30
|
+
def self.normalize_object(object)
|
31
|
+
deep_transform_keys_in_object(object) { |k| normalize_key(k) }
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Normalizes hash keys into camelized strings
|
36
|
+
#
|
37
|
+
# Regex sourced from ActiveSupport camelize
|
38
|
+
#
|
39
|
+
def self.normalize_key(key)
|
40
|
+
key.to_s.downcase.gsub(%r{(?:_|(/))([a-z\d]*)}) do
|
41
|
+
"#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
private_class_method :normalize_key
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: avataaars
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Bromwich
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rubocop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.86'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.86'
|
27
|
+
description: Ruby wrapper library to call to avataaars React component using NodeJS
|
28
|
+
email:
|
29
|
+
- abromwich@studiosity.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/avataaars.rb
|
35
|
+
- lib/avataaars/errors.rb
|
36
|
+
- lib/avataaars/js/processor.js
|
37
|
+
- lib/avataaars/processor.rb
|
38
|
+
- lib/avataaars/utils.rb
|
39
|
+
- lib/avataaars/version.rb
|
40
|
+
homepage: https://github.com/Studiosity/avataaars-rb
|
41
|
+
licenses:
|
42
|
+
- MIT
|
43
|
+
metadata: {}
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubygems_version: 3.0.6
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: A Ruby gem to transform attributes into avatar SVGs using the React avataaars
|
63
|
+
library through NodeJS
|
64
|
+
test_files: []
|