malachite 1.1.0 → 1.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 +5 -5
- data/.ruby-version +1 -1
- data/Gemfile +2 -0
- data/README.md +4 -12
- data/Rakefile +3 -0
- data/lib/malachite.rb +4 -26
- data/lib/malachite/client.rb +2 -0
- data/lib/malachite/compiler.rb +13 -15
- data/lib/malachite/errors.rb +2 -0
- data/lib/malachite/file_compiler.rb +10 -8
- data/lib/malachite/function.rb +2 -0
- data/lib/malachite/function_cache.rb +5 -2
- data/lib/malachite/railtie.rb +12 -12
- data/lib/malachite/tasks.rb +2 -0
- data/lib/malachite/tasks/malachite.rake +14 -0
- data/lib/malachite/version.rb +3 -1
- data/malachite.gemspec +2 -1
- data/test/client_test.rb +2 -0
- data/test/file_compiler_test.rb +3 -1
- data/test/performance_test.rb +2 -0
- data/test/rails_stub.rb +11 -1
- data/test/test_helper.rb +2 -0
- metadata +19 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d03c3c2f8c6c1f7f95459b33f9b1fc1de9059f9450979220d8078e323c6d7f59
|
4
|
+
data.tar.gz: d5fd7eebc38c4dd8ece734a2e763998e5c8fc110ea839254608b949c3304a53a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da6e655906d4dc4e6460747a2fda0f251f11d8b905a4ce00ad781d25813ce39e82893cc91c2f13ff2103f849ebc87840de13a19f84ef70329554b2055475e6da
|
7
|
+
data.tar.gz: 156e3a2c07a8270cd0cb09343885cc590887b8962a9cc0d107ba1e19c8b5b196d7dbe13983917a43aae0b2b4453bd16748919f509bd5e0426653314467c3ff51
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.3
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Call Go functions directly from Rails.
|
4
4
|
|
5
|
+
|
5
6
|
### Requirements
|
6
7
|
|
7
|
-
Requires Ruby >= 2.0.0, Go 1.5
|
8
|
+
Requires Ruby >= 2.0.0, Go 1.5+.
|
8
9
|
|
9
|
-
Xcode 8.3 is broken, do not use until [this is fixed](https://github.com/golang/go/issues/19734)
|
10
10
|
|
11
11
|
### Installation
|
12
12
|
|
@@ -54,6 +54,7 @@ More examples can be found in [examples](https://github.com/zhubert/malachite/wi
|
|
54
54
|
|
55
55
|
Note: This would actually be slower than doing it in Ruby, due to the JSON serialization.
|
56
56
|
|
57
|
+
|
57
58
|
### Testing
|
58
59
|
|
59
60
|
Check out the wiki on [Testing](https://github.com/zhubert/malachite/wiki/Testing)
|
@@ -62,22 +63,13 @@ Check out the wiki on [Testing](https://github.com/zhubert/malachite/wiki/Testin
|
|
62
63
|
|
63
64
|
Code generation.
|
64
65
|
|
65
|
-
*
|
66
|
+
* On every load in development and one time on boot elsewhere, Malachite will build a shared library from all the Go code in your ```app/go``` folder
|
66
67
|
* It then uses Ruby's Fiddle to call the shared library
|
67
68
|
* Arguments are passed back and forth via JSON
|
68
69
|
|
69
70
|
Because of the JSON step, you'll only see real performance gains on computationally difficult tasks. Ruby's JSON conversion is a large tax.
|
70
71
|
|
71
|
-
Note: You can also request precompilation. This is helpful for production environments. In an initializer:
|
72
|
-
|
73
|
-
```ruby
|
74
|
-
Malachite.precompile
|
75
|
-
```
|
76
72
|
|
77
73
|
### Ruby 2.2.4+
|
78
74
|
|
79
75
|
It's strongly recommended to use the [newest release of Ruby](https://www.ruby-lang.org/en/news/2015/12/16/unsafe-tainted-string-usage-in-fiddle-and-dl-cve-2015-7551/) as there was a security issue with older versions of Fiddle.
|
80
|
-
|
81
|
-
### Production Readiness
|
82
|
-
|
83
|
-
Likely more gotchas with architecture variations and Cgo. Submit a PR if you find something.
|
data/Rakefile
CHANGED
data/lib/malachite.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'malachite/version'
|
2
|
-
|
4
|
+
raise "Malachite #{Malachite::VERSION} does not support Ruby < 2.0.0" if RUBY_VERSION < '2.0.0'
|
3
5
|
|
4
6
|
require 'json'
|
5
7
|
require 'fiddle'
|
@@ -13,26 +15,6 @@ require 'malachite/file_compiler'
|
|
13
15
|
require 'malachite/compiler'
|
14
16
|
|
15
17
|
module Malachite
|
16
|
-
DEFAULTS = {
|
17
|
-
precompile: false
|
18
|
-
}
|
19
|
-
|
20
|
-
def self.options
|
21
|
-
@options ||= DEFAULTS.dup
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.options=(opts)
|
25
|
-
@options = opts
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.precompile?
|
29
|
-
Malachite.options.fetch(:precompile, false)
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.precompile
|
33
|
-
Malachite.options[:precompile] = true
|
34
|
-
end
|
35
|
-
|
36
18
|
def self.method_missing(name, args)
|
37
19
|
Malachite::Client.new(name, args).call
|
38
20
|
end
|
@@ -46,8 +28,4 @@ module Malachite
|
|
46
28
|
end
|
47
29
|
end
|
48
30
|
|
49
|
-
if defined?(
|
50
|
-
require 'malachite/railtie'
|
51
|
-
else
|
52
|
-
fail "Malachite #{Malachite::VERSION} requires Rails"
|
53
|
-
end
|
31
|
+
require 'malachite/railtie' if defined?(Rails)
|
data/lib/malachite/client.rb
CHANGED
data/lib/malachite/compiler.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
require 'open3'
|
5
|
+
|
1
6
|
module Malachite
|
2
7
|
class Compiler
|
3
8
|
def initialize
|
@@ -7,6 +12,7 @@ module Malachite
|
|
7
12
|
|
8
13
|
def compile
|
9
14
|
return @compiled_file if File.exist?(@compiled_file) && File.exist?(@compiled_header)
|
15
|
+
|
10
16
|
compile!
|
11
17
|
end
|
12
18
|
|
@@ -15,21 +21,12 @@ module Malachite
|
|
15
21
|
def compile!
|
16
22
|
modify_source_files_in_tmp
|
17
23
|
|
18
|
-
if modified_go_files == []
|
19
|
-
raise Malachite::BuildError, 'Nothing to build, there are no Go files in tmp'
|
20
|
-
end
|
21
|
-
|
22
|
-
unless system({ 'CGO_ENABLED' => '1' }, 'go', 'build', '-buildmode=c-shared', '-o', @compiled_file, *modified_go_files)
|
23
|
-
raise Malachite::BuildError, 'Unable to Build Shared Library, is Go 1.5+ installed?'
|
24
|
-
end
|
24
|
+
raise Malachite::BuildError, 'Nothing to build, there are no Go files in tmp' if modified_go_files == []
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
unless File.exist?(@compiled_file)
|
31
|
-
raise Malachite::BuildError, 'Unable to Build Shared Object'
|
32
|
-
end
|
26
|
+
stdout, stderr, status = Open3.capture3({ 'CGO_ENABLED' => '1' }, 'go', 'build', '-buildmode=c-shared', '-o', @compiled_file, *modified_go_files)
|
27
|
+
raise Malachite::BuildError, "Unable to Build Shared Library: #{stdout} #{stderr}" unless status.success?
|
28
|
+
raise Malachite::BuildError, 'Unable to Build Header File' unless File.exist?(@compiled_header)
|
29
|
+
raise Malachite::BuildError, 'Unable to Build Shared Object' unless File.exist?(@compiled_file)
|
33
30
|
|
34
31
|
path_to_compiled_file
|
35
32
|
end
|
@@ -38,6 +35,7 @@ module Malachite
|
|
38
35
|
source_files.each do |f|
|
39
36
|
Malachite::FileCompiler.new(f).compile
|
40
37
|
end
|
38
|
+
|
41
39
|
File.open(Rails.root.join('tmp', 'main.go').to_s, 'w') do |file|
|
42
40
|
file.puts main_boilerplate
|
43
41
|
file.close
|
@@ -53,7 +51,7 @@ module Malachite
|
|
53
51
|
end
|
54
52
|
|
55
53
|
def main_boilerplate
|
56
|
-
File.read(File.expand_path('
|
54
|
+
File.read(File.expand_path('main.go.tmpl', __dir__))
|
57
55
|
end
|
58
56
|
|
59
57
|
def path_to_compiled_file
|
data/lib/malachite/errors.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Malachite
|
2
4
|
class FileCompiler
|
3
5
|
def initialize(file)
|
@@ -20,22 +22,22 @@ module Malachite
|
|
20
22
|
private
|
21
23
|
|
22
24
|
def cgo_tmpl
|
23
|
-
cgo = File.read(File.expand_path('
|
24
|
-
|
25
|
+
cgo = File.read(File.expand_path('cgo.tmpl', __dir__))
|
26
|
+
cgo.gsub(/HEADER/, RbConfig::CONFIG['rubyhdrdir']).gsub(/ARCH/, RbConfig::CONFIG['rubyarchhdrdir'])
|
25
27
|
end
|
26
28
|
|
27
|
-
def source_file(
|
28
|
-
File.readlines(
|
29
|
+
def source_file(file)
|
30
|
+
File.readlines(file).drop(1)
|
29
31
|
end
|
30
32
|
|
31
33
|
def exporter_boilerplate(file)
|
32
|
-
exporter = File.read(File.expand_path('
|
34
|
+
exporter = File.read(File.expand_path('exporter.go.tmpl', __dir__))
|
33
35
|
method_name, method_type = extract_method_and_type(file)
|
34
|
-
|
36
|
+
exporter.gsub(/YYYYYY/, "#{method_type}{}").gsub(/XXXXXX/, method_name)
|
35
37
|
end
|
36
38
|
|
37
|
-
def file_has_handle_function?(
|
38
|
-
source = File.read(
|
39
|
+
def file_has_handle_function?(file)
|
40
|
+
source = File.read(file)
|
39
41
|
match = /^func Handle(.*?)\(\w+ (.*?)\)/.match(source)
|
40
42
|
match != nil
|
41
43
|
end
|
data/lib/malachite/function.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Malachite
|
2
4
|
def self.function_cache
|
3
5
|
@function_cache ||= {}
|
@@ -9,7 +11,8 @@ module Malachite
|
|
9
11
|
|
10
12
|
def self.from_function_cache(method_name)
|
11
13
|
existing_function = Malachite.function_cache[method_name]
|
12
|
-
return existing_function
|
14
|
+
return existing_function unless existing_function.nil?
|
15
|
+
|
13
16
|
Malachite.add_to_function_cache(method_name)
|
14
17
|
end
|
15
18
|
|
@@ -37,6 +40,6 @@ module Malachite
|
|
37
40
|
end
|
38
41
|
|
39
42
|
def self.shared_object_path
|
40
|
-
@
|
43
|
+
@shared_object_path ||= Malachite::Compiler.new.compile
|
41
44
|
end
|
42
45
|
end
|
data/lib/malachite/railtie.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Malachite
|
2
|
-
def self.
|
3
|
-
Dir.glob(Rails.root.join('tmp', '*.so')).each do |file|
|
4
|
+
def self.setup!
|
5
|
+
Dir.glob(Rails.root.join('tmp', '*.{so,go,h}')).each do |file|
|
4
6
|
File.delete(file)
|
5
7
|
end
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
Dir.glob(Rails.root.join('tmp', '*.h')).each do |file|
|
10
|
-
File.delete(file)
|
11
|
-
end
|
12
|
-
Malachite::Compiler.new.compile if Malachite.precompile?
|
8
|
+
|
9
|
+
Malachite::Compiler.new.compile
|
13
10
|
end
|
14
|
-
|
11
|
+
|
12
|
+
class Railtie < Rails::Railtie
|
15
13
|
rake_tasks do
|
16
14
|
load 'malachite/tasks/malachite.rake'
|
17
15
|
end
|
18
|
-
|
19
|
-
|
16
|
+
|
17
|
+
# Executed once in production/staging and before each request in development.
|
18
|
+
config.to_prepare do
|
19
|
+
Malachite.setup!
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
data/lib/malachite/tasks.rb
CHANGED
@@ -4,4 +4,18 @@ namespace :malachite do
|
|
4
4
|
test_files = Dir["#{Rails.root.join('app', 'go')}/**/*.go"]
|
5
5
|
system({ 'CGO_ENABLED' => '1' }, 'go', 'test', *test_files)
|
6
6
|
end
|
7
|
+
|
8
|
+
desc 'deletes any existing shared library and re-compiles'
|
9
|
+
task :compile do
|
10
|
+
Dir.glob(Rails.root.join('tmp', '*.so')).each do |file|
|
11
|
+
File.delete(file)
|
12
|
+
end
|
13
|
+
Dir.glob(Rails.root.join('tmp', '*.go')).each do |file|
|
14
|
+
File.delete(file)
|
15
|
+
end
|
16
|
+
Dir.glob(Rails.root.join('tmp', '*.h')).each do |file|
|
17
|
+
File.delete(file)
|
18
|
+
end
|
19
|
+
Malachite::Compiler.new.compile
|
20
|
+
end
|
7
21
|
end
|
data/lib/malachite/version.rb
CHANGED
data/malachite.gemspec
CHANGED
@@ -16,7 +16,8 @@ Gem::Specification.new do |spec|
|
|
16
16
|
|
17
17
|
spec.required_ruby_version = '>= 2.0.0'
|
18
18
|
spec.add_dependency 'activesupport'
|
19
|
-
spec.add_development_dependency 'bundler', '~> 1
|
19
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
20
|
+
spec.add_development_dependency 'rubocop'
|
20
21
|
spec.add_development_dependency 'rake', '~> 10.0'
|
21
22
|
spec.add_development_dependency 'minitest', '~> 5'
|
22
23
|
end
|
data/test/client_test.rb
CHANGED
data/test/file_compiler_test.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class FileCompilerTest < MiniTest::Test
|
@@ -7,7 +9,7 @@ class FileCompilerTest < MiniTest::Test
|
|
7
9
|
|
8
10
|
def test_confirm_compilation_matches_fixture
|
9
11
|
compiled = File.read(Rails.root.join('tmp', 'upcase.go')).to_s
|
10
|
-
valid = File.read(File.expand_path('
|
12
|
+
valid = File.read(File.expand_path('fixtures/valid_upcase.go', __dir__)).gsub(/HEADER/, RbConfig::CONFIG['rubyhdrdir']).gsub(/ARCH/, RbConfig::CONFIG['rubyarchhdrdir'])
|
11
13
|
assert_equal compiled, valid
|
12
14
|
end
|
13
15
|
end
|
data/test/performance_test.rb
CHANGED
data/test/rails_stub.rb
CHANGED
@@ -1,12 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'pathname'
|
4
|
+
require 'ostruct'
|
5
|
+
|
2
6
|
module Rails
|
3
|
-
Engine = {}
|
7
|
+
Engine = {}.freeze
|
8
|
+
|
4
9
|
def self.root
|
5
10
|
Pathname.new(File.join(Dir.pwd, 'test', 'dummy'))
|
6
11
|
end
|
12
|
+
|
7
13
|
class Railtie
|
8
14
|
def self.rake_tasks; end
|
9
15
|
|
16
|
+
def self.config
|
17
|
+
OpenStruct.new(to_prepare: {})
|
18
|
+
end
|
19
|
+
|
10
20
|
def self.initializer(_); end
|
11
21
|
end
|
12
22
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: malachite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zack Hubert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -30,14 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1
|
33
|
+
version: '2.1'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1
|
40
|
+
version: '2.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,8 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
133
|
- !ruby/object:Gem::Version
|
120
134
|
version: '0'
|
121
135
|
requirements: []
|
122
|
-
|
123
|
-
rubygems_version: 2.5.2
|
136
|
+
rubygems_version: 3.0.3
|
124
137
|
signing_key:
|
125
138
|
specification_version: 4
|
126
139
|
summary: A RubyGem which enables calling Go code from Rails
|