rusby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +51 -0
- data/LICENSE.txt +21 -0
- data/README.md +64 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/doc/img1.png +0 -0
- data/doc/slides.key +0 -0
- data/examples/Gemfile +3 -0
- data/examples/Gemfile.lock +31 -0
- data/examples/fanatic_greeter.rb +8 -0
- data/examples/fanatic_pluser.rb +8 -0
- data/examples/levenshtein_distance.rb +31 -0
- data/examples/quicksort.rb +32 -0
- data/examples/run_examples.rb +38 -0
- data/examples/weighted_random.rb +22 -0
- data/lib/rusby.rb +15 -0
- data/lib/rusby/builder.rb +149 -0
- data/lib/rusby/core.rb +113 -0
- data/lib/rusby/ffi/bridge.rb +42 -0
- data/lib/rusby/generators/assignments.rb +40 -0
- data/lib/rusby/generators/base.rb +66 -0
- data/lib/rusby/generators/conditionals.rb +38 -0
- data/lib/rusby/generators/loops.rb +54 -0
- data/lib/rusby/generators/misc.rb +26 -0
- data/lib/rusby/generators/strings.rb +10 -0
- data/lib/rusby/generators/types.rb +33 -0
- data/lib/rusby/postprocessor.rb +19 -0
- data/lib/rusby/preprocessor.rb +15 -0
- data/lib/rusby/profiler.rb +32 -0
- data/lib/rusby/proxy.rb +14 -0
- data/lib/rusby/rust.rb +69 -0
- data/lib/rusby/version.rb +3 -0
- data/rusby.gemspec +32 -0
- data/rust.yaml +38 -0
- metadata +223 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 220468d5f249c9e28f702ff82cc05857fec824a3
|
4
|
+
data.tar.gz: ac156b073759a711c1889f0d4cdb39fedc823ff7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: addbb61765e9957e47af6b79f28cbc17597144997e667728f71628d93a80c231e8e3ba0efc1b7806f851c194ab5560540c8de0dba746ad17ae8e4d1ee38e2ae2
|
7
|
+
data.tar.gz: 80795fd42665c369763f4d72ecba264a977ecd3c5cc808e08dc6aef13886770e597f93cbfebc1aaa6fee55a47ee359c7da59c5e7e166d7b412044867923b000e
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at akrasnoschekov@gmail.com. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rusby (0.1.0)
|
5
|
+
colorize
|
6
|
+
ffi
|
7
|
+
hashie
|
8
|
+
method_source
|
9
|
+
parser
|
10
|
+
ruby-prof
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
ast (2.2.0)
|
16
|
+
byebug (9.0.5)
|
17
|
+
colorize (0.7.7)
|
18
|
+
diff-lcs (1.2.5)
|
19
|
+
ffi (1.9.10)
|
20
|
+
hashie (3.4.4)
|
21
|
+
method_source (0.8.2)
|
22
|
+
parser (2.3.1.0)
|
23
|
+
ast (~> 2.2)
|
24
|
+
rake (10.5.0)
|
25
|
+
rspec (3.4.0)
|
26
|
+
rspec-core (~> 3.4.0)
|
27
|
+
rspec-expectations (~> 3.4.0)
|
28
|
+
rspec-mocks (~> 3.4.0)
|
29
|
+
rspec-core (3.4.4)
|
30
|
+
rspec-support (~> 3.4.0)
|
31
|
+
rspec-expectations (3.4.0)
|
32
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
33
|
+
rspec-support (~> 3.4.0)
|
34
|
+
rspec-mocks (3.4.1)
|
35
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
+
rspec-support (~> 3.4.0)
|
37
|
+
rspec-support (3.4.1)
|
38
|
+
ruby-prof (0.15.9)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
bundler (~> 1.12)
|
45
|
+
byebug
|
46
|
+
rake (~> 10.0)
|
47
|
+
rspec (~> 3.0)
|
48
|
+
rusby!
|
49
|
+
|
50
|
+
BUNDLED WITH
|
51
|
+
1.12.4
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Alexander Krasnoschekov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
## About
|
2
|
+
|
3
|
+
**Rusby** is a *Ruby* to *Rust* transpiler for simple performance-oriented methods.
|
4
|
+
|
5
|
+
Computations in plain Ruby are painfully slow.
|
6
|
+
Almost all internal methods in of Ruby are implemented in C, thus achieving acceptable performance on e.g. [Array#sort](https://github.com/ruby/ruby/blob/trunk/array.c).
|
7
|
+
|
8
|
+
On the other hand extension of ruby code with C or other low-level language functions is not to say hard... but at least is tricky. **Rusby** allows to write simple methods in plain ruby and convert them to rust with zero modifications.
|
9
|
+
|
10
|
+
Just mark method with `rusby!` and you are ready to rust :/
|
11
|
+
|
12
|
+
![Quicksort example](https://raw.githubusercontent.com/rambler-digital-solutions/rusby/master/doc/img1.png)
|
13
|
+
|
14
|
+
---
|
15
|
+
|
16
|
+
N.B. It's a research project, so at least test for edge cases (e.g. overflows) before production usage.
|
17
|
+
|
18
|
+
Transpilation was tested only on cases in `./examples` directory.
|
19
|
+
|
20
|
+
---
|
21
|
+
|
22
|
+
## How it works?
|
23
|
+
|
24
|
+
1. You prefix your method definition with `!rusby`.
|
25
|
+
1. Native Ruby method is ran for the first time.
|
26
|
+
1. Its arguments types and return type are recorded.
|
27
|
+
1. These data along with source code of the method (as AST tree) are passed to the Rusby::Builder.
|
28
|
+
1. Rusby::Builder calls Rusby::Rust, which recursively generates rust code based on AST tree (Rusby::Generators::\*).
|
29
|
+
1. Few hacks are applied along the way, see Rusby::Preprocessor, Rusby::Postrocessor.
|
30
|
+
1. Generated Rust code is dumped to file into `./lib` Dir
|
31
|
+
1. Rust code is prettified and compiled into dynamic lib.
|
32
|
+
1. At last we have ruby method and rust counterpart linked via [FFI](https://github.com/ffi/ffi).
|
33
|
+
1. Benchmark them and find the fastest one.
|
34
|
+
1. Link the winner into the source class.
|
35
|
+
1. Profit.
|
36
|
+
|
37
|
+
## Features
|
38
|
+
- In-place ruby/rust method swapping based on benchmarks
|
39
|
+
- Recursive calls transpiling
|
40
|
+
- Nested functions transpiling
|
41
|
+
- Limited string operations support
|
42
|
+
- Integer matrix manipulation support
|
43
|
+
|
44
|
+
## Quickstart
|
45
|
+
```
|
46
|
+
brew install rust # or similar
|
47
|
+
cd examples
|
48
|
+
bundle
|
49
|
+
ruby run_examples.rb
|
50
|
+
```
|
51
|
+
|
52
|
+
## Tests
|
53
|
+
```
|
54
|
+
rake spec
|
55
|
+
```
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rusby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
60
|
+
|
61
|
+
|
62
|
+
## License
|
63
|
+
|
64
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rusby"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/doc/img1.png
ADDED
Binary file
|
data/doc/slides.key
ADDED
Binary file
|
data/examples/Gemfile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
rusby (0.1.0)
|
5
|
+
colorize
|
6
|
+
ffi
|
7
|
+
hashie
|
8
|
+
method_source
|
9
|
+
parser
|
10
|
+
ruby-prof
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
ast (2.2.0)
|
16
|
+
colorize (0.7.7)
|
17
|
+
ffi (1.9.10)
|
18
|
+
hashie (3.4.4)
|
19
|
+
method_source (0.8.2)
|
20
|
+
parser (2.3.1.0)
|
21
|
+
ast (~> 2.2)
|
22
|
+
ruby-prof (0.15.9)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
rusby!
|
29
|
+
|
30
|
+
BUNDLED WITH
|
31
|
+
1.12.4
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class LevenshteinDistance
|
2
|
+
extend Rusby::Core
|
3
|
+
|
4
|
+
rusby!
|
5
|
+
def distance(s, t)
|
6
|
+
m = s.length
|
7
|
+
n = t.length
|
8
|
+
|
9
|
+
return m if n == 0
|
10
|
+
return n if m == 0
|
11
|
+
d = Array.new(m + 1) { Array.new(n + 1) }
|
12
|
+
|
13
|
+
(0..m).each { |i| d[i][0] = i }
|
14
|
+
(0..n).each { |j| d[0][j] = j }
|
15
|
+
|
16
|
+
(1..n).each do |j|
|
17
|
+
(1..m).each do |i|
|
18
|
+
d[i][j] = if s[i - 1] == t[j - 1] # adjust index into string
|
19
|
+
d[i - 1][j - 1] # no operation required
|
20
|
+
else
|
21
|
+
deletion = d[i - 1][j] + 1
|
22
|
+
insertion = d[i][j - 1] + 1
|
23
|
+
substitution = d[i - 1][j - 1] + 1
|
24
|
+
op = deletion < insertion ? deletion : insertion
|
25
|
+
op < substitution ? op : substitution
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return d[m][n]
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Quicksort
|
2
|
+
extend Rusby::Core
|
3
|
+
|
4
|
+
rusby!
|
5
|
+
def quicksort(a, lo, hi)
|
6
|
+
return a unless lo < hi
|
7
|
+
pivot = partition(a, lo, hi)
|
8
|
+
quicksort(a, lo, pivot)
|
9
|
+
quicksort(a, pivot + 1, hi)
|
10
|
+
a
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def partition(a, lo, hi)
|
16
|
+
pivot = a[lo]
|
17
|
+
i = lo - 1
|
18
|
+
j = hi + 1
|
19
|
+
loop do
|
20
|
+
begin
|
21
|
+
i += 1
|
22
|
+
end while a[i] < pivot
|
23
|
+
|
24
|
+
begin
|
25
|
+
j -= 1
|
26
|
+
end while a[j] > pivot
|
27
|
+
|
28
|
+
return j if i >= j
|
29
|
+
a[i], a[j] = [a[j], a[i]]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
Bundler.require
|
5
|
+
require "./fanatic_pluser"
|
6
|
+
require "./fanatic_greeter"
|
7
|
+
require "./quicksort"
|
8
|
+
require "./levenshtein_distance"
|
9
|
+
require "./weighted_random"
|
10
|
+
|
11
|
+
pluser = FanaticPluser.new
|
12
|
+
2.times do |i|
|
13
|
+
puts "== #{i + 1} - #{pluser.plusplus(77)}"
|
14
|
+
end
|
15
|
+
|
16
|
+
greeter = FanaticGreeter.new
|
17
|
+
2.times do |_i|
|
18
|
+
puts greeter.greet('Fred')
|
19
|
+
end
|
20
|
+
|
21
|
+
sorter = Quicksort.new
|
22
|
+
a = (1..50).map { |_i| rand(100_000) }
|
23
|
+
2.times do |i|
|
24
|
+
puts "=> #{i + 1} time method is being called".colorize(:light_black)
|
25
|
+
puts "== #{i + 1} - #{sorter.quicksort(a.clone, 0, a.size - 1)}"
|
26
|
+
end
|
27
|
+
|
28
|
+
measurer = LevenshteinDistance.new
|
29
|
+
params = %w(unimaginatively incomprehensibilities)
|
30
|
+
2.times do |i|
|
31
|
+
puts "#{i + 1}: #{measurer.distance(*params)}"
|
32
|
+
end
|
33
|
+
|
34
|
+
randomizer = WeightedRandom.new
|
35
|
+
weights = (1..1000).map { rand(1000).to_f }
|
36
|
+
2.times do |i|
|
37
|
+
puts "#{i + 1}: #{randomizer.pick(weights, rand())}"
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class WeightedRandom
|
2
|
+
extend Rusby::Core
|
3
|
+
|
4
|
+
rusby!
|
5
|
+
def pick(weights, seed)
|
6
|
+
sum = 0.0
|
7
|
+
left_bounds = []
|
8
|
+
right_bounds = []
|
9
|
+
weights.each do |item|
|
10
|
+
left_bounds << sum
|
11
|
+
sum = sum + item
|
12
|
+
right_bounds << sum
|
13
|
+
end
|
14
|
+
number = seed * sum
|
15
|
+
weights.each_with_index do |_, i|
|
16
|
+
if (number >= left_bounds[i] && number < right_bounds[i])
|
17
|
+
return i
|
18
|
+
end
|
19
|
+
end
|
20
|
+
return -1
|
21
|
+
end
|
22
|
+
end
|