avataaars 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avataaars
4
+ VERSION = '0.0.1'
5
+ 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: []