Full Code of johnlinvc/erruby for AI

develop 60df66495a01 cached
77 files
63.1 KB
21.1k tokens
33 symbols
1 requests
Download .txt
Repository: johnlinvc/erruby
Branch: develop
Commit: 60df66495a01
Files: 77
Total size: 63.1 KB

Directory structure:
gitextract_mz0uvchy/

├── .gitignore
├── .gitmodules
├── .travis.yml
├── COPYING.txt
├── Gemfile
├── Guardfile
├── README.md
├── TODO.md
├── erruby
├── erruby_test/
│   ├── pipe_dot.rb
│   └── undefined_method.rb
├── pre_compile
├── rb_src/
│   └── erruby.rb
├── rb_test/
│   ├── _load.rb
│   ├── _require_relative.rb
│   ├── and_dot.rb
│   ├── array_class.rb
│   ├── boolean_class.rb
│   ├── class_cross_call.rb
│   ├── class_def.rb
│   ├── class_inherent.rb
│   ├── class_method.rb
│   ├── const_def.rb
│   ├── file.rb
│   ├── fixnum.rb
│   ├── global_var.rb
│   ├── hello_world.rb
│   ├── integer_class.rb
│   ├── ivar.rb
│   ├── load.rb
│   ├── method_def.rb
│   ├── nested_block.rb
│   ├── nested_const.rb
│   ├── nil_class.rb
│   ├── require_relative.rb
│   ├── sysrb_out/
│   │   ├── .gitkeep
│   │   ├── and_dot.out
│   │   ├── array_class.out
│   │   ├── boolean_class.out
│   │   ├── class_cross_call.out
│   │   ├── class_def.out
│   │   ├── class_inherent.out
│   │   ├── class_method.out
│   │   ├── const_def.out
│   │   ├── file.out
│   │   ├── fixnum.out
│   │   ├── global_var.out
│   │   ├── hello_world.out
│   │   ├── integer_class.out
│   │   ├── ivar.out
│   │   ├── load.out
│   │   ├── method_def.out
│   │   ├── nested_block.out
│   │   ├── nested_const.out
│   │   ├── nil_class.out
│   │   ├── require_relative.out
│   │   └── var_assign.out
│   └── var_assign.rb
├── rebar.config
├── src/
│   ├── erb.erl
│   ├── erruby.app.src
│   ├── erruby.erl
│   ├── erruby_app.erl
│   ├── erruby_array.erl
│   ├── erruby_boolean.erl
│   ├── erruby_class.erl
│   ├── erruby_debug.erl
│   ├── erruby_fixnum.erl
│   ├── erruby_integer.erl
│   ├── erruby_lib/
│   │   └── erruby_file.erl
│   ├── erruby_nil.erl
│   ├── erruby_object.erl
│   ├── erruby_rb.erl
│   ├── erruby_sup.erl
│   ├── erruby_vm.erl
│   └── rb.hrl
└── test.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.eunit
deps
*.o
*.beam
*.plt
.*-*
erl_crash.dump
ebin
rel/example_project
.concrete/DEV_MODE
.rebar
rb_test/*.out


================================================
FILE: .gitmodules
================================================
[submodule "ext/ruby/spec"]
	path = ext/ruby/spec
	url = https://github.com/ruby/spec.git
[submodule "ext/ruby/mspec"]
	path = ext/ruby/mspec
	url = https://github.com/ruby/mspec.git


================================================
FILE: .travis.yml
================================================
language: erlang
otp_release:
   - 18.0
   - 18.1
before_script:
        - rvm install 2.3.1
        - rvm use 2.3.1
        - bundle install
script:
        - rebar compile && ./test.rb



================================================
FILE: COPYING.txt
================================================
The MIT License (MIT)

Copyright (c) 2015 Yu Hsiang Lin.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Gemfile
================================================
ruby "2.3.1"
source "https://rubygems.org"

gem 'erlport-ast_mapping', github: "johnlinvc/erlport-ast_mapping", branch: "ruby_2_3"
gem 'guard'
gem 'guard-shell'
gem 'guard-rebar', github: "johnlinvc/guard-rebar", branch: "feature/update_to_guard_2_13"


================================================
FILE: Guardfile
================================================
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

## Uncomment and set this to only include directories you want to watch
# directories %w(app lib config test spec features) \
#  .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}

## Note: if you are using the `directories` clause above and you are not
## watching the project directory ('.'), then you will want to move
## the Guardfile to a watched dir and symlink it back, e.g.
#
#  $ mkdir config
#  $ mv Guardfile config/
#  $ ln -s config/Guardfile .
#
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"

guard 'rebar-compile', all_on_start: true do
  watch(%r{src/.*\.erl})
  watch(%r{test/.*\.erl})
end

guard :shell do
  watch(/rb_test\/(.*)\.rb/) {|m| `./test.rb -v #{m[0]}` }
end


================================================
FILE: README.md
================================================
# ErRuby - an implementation of the Ruby language on Erlang
[![Build Status](https://travis-ci.org/johnlinvc/erruby.svg?branch=develop)](https://travis-ci.org/johnlinvc/erruby)
## About

ErRuby is an implementation of the Ruby language using Erlang.

It aims to bring some concurrency features to ruby by experimenting.

It's still a work in progress. So use it at your own risk.

## Install

### Prerequisites
 
- erlang vm
- rebar2
- ruby (2.3.1)

To install erlang & rebar on OS X, using homebrew

	brew install erlang rebar

### Building

After getting the source of ErRuby, get the gems for parser with bundler using:
	
	bundle install
	
 
Then get the deps of erlang modules by using:

	rebar get-deps
	
Last, compile ErRuby with:

	rebar compile
	
	
Test the build result with:

	./test.rb
	
It should output `everything pass`


## Goals

- Concurrent Features.
- Run mspec.
- GC.
- Friendly installation with rvm/rbenv

## Supported features

Currently it support some of the basic ruby constructs.

Supported features:

- `method` definition & calling.
- singleton methods, class methods.
- `class` and inheritance.
- `block` and `yield`.
- Constants.
- Local variables.
- Instance variables.
- `load` & `require_relative`.
- `Boolean` & `Integer` with basic methods.
- `String` literal.
- `Array` literal.

Unsupported core features

- class initializer, class instance variables.
- `module` definition, `include`, `extend`.
- variadic argument in function.
- keyword argument in function.
- GC.

### Class & inherentance
```ruby
class Foo
  def to_s
    "foo"
  end
end

class Bar < Foo
end

class Alice < Bar
  def to_s
    "i'm alice"
  end
  def self.name
    "Alice"
  end
end

puts Foo.new.to_s # "foo"
puts Bar.new.to_s # "foo"
puts Alice.new.to_s # "i'm alice"
puts Alice.name # "Alice"
```

### block
```ruby
def yield_with_arg(s,x)
  yield s,x
end

yield_with_arg("yield with","arg") do |ss, xx|
  puts ss # "yield with"
  puts xx # "arg"
end

3.times do |i|
  puts i.to_s
  4.times do |j|
    puts j.to_s
  end
end

([1,2,3]*1000).pmap do |x|
  x+1
end


```


## License

ErRuby is licensed to you under MIT license. See the [COPYING.txt](COPYING.txt) file for more details.


================================================
FILE: TODO.md
================================================
restructure to standard erlang style
design the object system of ruby in erlang
- everything is object, just like ruby
- every object is a process. message invoke with message passing using the actor model.
use otp to run the code


================================================
FILE: erruby
================================================
#!/bin/bash
pushd `dirname $0` > /dev/null
export ERRUBY_PATH=`pwd`
popd > /dev/null
if [[ $* == *"-f"* ]]
then
escript "${ERRUBY_PATH}/ebin/erruby.beam" $*
else
erl -noshell +P 134217727 -pa ebin -s erruby main "{$*}" -s init stop
fi


================================================
FILE: erruby_test/pipe_dot.rb
================================================
def cal
  1 + 1
end
x = self|.cal
puts(x.to_s)
puts(x.to_s)
puts(1|.to_s)
1|.to_s

def str
  "hello future"
end
puts(self|.str)


================================================
FILE: erruby_test/undefined_method.rb
================================================
class Foo
end
f = Foo.new
f.bar


================================================
FILE: pre_compile
================================================
#!/bin/bash
pushd ./deps/erlport > /dev/null
make > /dev/null
popd > /dev/null

pushd ./deps/plists > /dev/null
./make.sh
popd > /dev/null


================================================
FILE: rb_src/erruby.rb
================================================
#!/usr/bin/env ruby

require 'rubygems'
require 'bundler/setup'
require 'erlport/ast_mapping'

def parse(src)
  ErlPort::AstMapping.parse(src)
end

def install_encoder
  ErlPort::AstMapping.install_encoder
end

if __FILE__ == $0
  p parse("[1,2,3]".each_char.map(&:ord))
end


================================================
FILE: rb_test/_load.rb
================================================
puts "loaded"


================================================
FILE: rb_test/_require_relative.rb
================================================
puts "required file"


================================================
FILE: rb_test/and_dot.rb
================================================
puts(1&.to_s)
nil&.not_exist_method


================================================
FILE: rb_test/array_class.rb
================================================
[true, false]
[nil, nil]
["a","b","c"]
[1,2].map{|x| puts(x.to_s)}
puts "mul"
([1,2,3] * 3).map{|x| puts x.to_s}
#a = 0
#[1,2,3].map do |x|
  #a = a + x
#end
#puts a
puts ["a","b","c"].at(1)
puts ["a","b","c"].first
puts ["a","b","c"].last

puts [false].empty?.to_s
puts [].empty?.to_s
puts [1, 2, 3].length.to_s
puts [1, 2, 3].size.to_s
ary = ["a","b"]
ary.concat ["c", "d"]
puts ary.last
ary2 = ary + ["e", "f"]
puts ary2.last
ary = ["a","b","c"]
ary.push "d"
puts ary.last
ary << "e" << "f"
puts ary.last
array = ["b", "c"]
array.unshift("a")
puts array.first
puts array.shift
puts array.first

puts [1, 2, 3, 4, 5].drop(1).length.to_s
puts [1, 2, 3, 4, 5].drop(3).length.to_s
puts [1, 2, 3, 4, 5].drop(0).length.to_s
puts [1, 2, 3, 4, 5].drop(5).length.to_s
puts [1, 2, 3, 4, 5].drop(10).length.to_s


================================================
FILE: rb_test/boolean_class.rb
================================================
puts (true).to_s
puts (false).to_s

puts (!true).to_s
puts (!false).to_s

puts (true == false).to_s
puts (true == true).to_s
puts (false == true).to_s
puts (false == false).to_s

puts (true & true).to_s
puts (true & false).to_s
puts (false & true).to_s
puts (false & false).to_s

puts (true ^ true).to_s
puts (true ^ false).to_s
puts (false ^ true).to_s
puts (false ^ false).to_s

puts (true | true).to_s
puts (true | false).to_s
puts (false | true).to_s
puts (false | false).to_s

puts true.to_s
puts false.to_s

puts true.inspect
puts false.inspect


================================================
FILE: rb_test/class_cross_call.rb
================================================
class Foo
  def msg
    "hello"
  end
end

class Bar
  def say
    puts Foo.new.msg
  end
end

Bar.new.say


================================================
FILE: rb_test/class_def.rb
================================================
class Foo
  def message
    "hello world"
  end
  def hello
    puts message
  end
end
class Bar
  def message
    "hello bar"
  end
  def hello
    puts message
  end
end
f = Foo.new
f.hello
ff = Foo.new

Bar.new.hello


================================================
FILE: rb_test/class_inherent.rb
================================================
class Foo
  def to_s
    "foo"
  end
end

class Bar < Foo
end

class Alice < Bar
  def to_s
    "i'm alice"
  end
end

puts Foo.new.to_s # "foo"
puts Bar.new.to_s # "foo"
puts Alice.new.to_s # "i'm alice"


================================================
FILE: rb_test/class_method.rb
================================================
class Foo
  def self.bar
    puts "bar"
  end
end

Foo.bar


================================================
FILE: rb_test/const_def.rb
================================================
HELLO_CONST = "hello const"
puts HELLO_CONST


================================================
FILE: rb_test/file.rb
================================================
puts __FILE__
puts File.expand_path('../../../erruby/rb_test', __FILE__)


================================================
FILE: rb_test/fixnum.rb
================================================
puts 1.to_s
puts 2.to_s
puts -1.to_s
puts 0.to_s
puts 576460752303423488.to_s
puts -576460752303423489.to_s
puts (1+1).to_s
puts (2-1).to_s
puts (-(1)).to_s
puts (3 % 2).to_s
puts (4 * 2).to_s
puts (3 / 2).to_s
puts (4 ** 2).to_s
puts (1 < 2).to_s
puts (2 < 2).to_s
puts (3 < 2).to_s
puts (1 <= 2).to_s
puts (2 <= 2).to_s
puts (3 <= 2).to_s
puts (1 > 2).to_s
puts (2 > 2).to_s
puts (3 > 2).to_s
puts (1 >= 2).to_s
puts (2 >= 2).to_s
puts (3 >= 2).to_s
puts (1 == 2).to_s
puts (2 == 2).to_s
puts (3 == 2).to_s
puts (1 <=> 2).to_s
puts (2 <=> 2).to_s
puts (3 <=> 2).to_s


================================================
FILE: rb_test/global_var.rb
================================================
$Gvar = "hello gvar"
puts $Gvar


================================================
FILE: rb_test/hello_world.rb
================================================
puts "hello world"


================================================
FILE: rb_test/integer_class.rb
================================================
puts 5.to_i.to_s
puts 5.to_int.to_s
puts 5.floor.to_s
puts 5.ceil.to_s
puts 5.truncate.to_s
puts 5.numerator.to_s
puts 5.ord.to_s
puts 56.denominator.to_s
puts 2.even?.to_s
puts 3.even?.to_s
puts 2.odd?.to_s
puts 3.odd?.to_s
puts 2.gcd(2).to_s
puts 6.gcd(8).to_s
puts 8.gcd(6).to_s
puts 0.gcd(8).to_s
puts 0.gcd(0).to_s
puts 6.gcd(0).to_s
puts 2.lcm(2).to_s
puts 6.lcm(8).to_s
puts 8.lcm(6).to_s
puts 0.lcm(8).to_s
puts 6.lcm(0).to_s
puts 1.integer?.to_s
puts 1.next.to_s
puts (-1).next.to_s
puts 1.succ.to_s
puts (-1).succ.to_s
puts "times"
puts 5.times {|i| puts i.to_s}.to_s
puts 0.times {|i| puts i.to_s}.to_s
puts (-5).times {|i| puts i.to_s}.to_s
puts "upto"
puts (-2).upto(2){|i| puts i.to_s}.to_s
puts (2).upto(2){|i| puts i.to_s}.to_s
puts (3).upto(2){|i| puts i.to_s}.to_s
puts "downto"
puts (2).downto(-2){|i| puts i.to_s}.to_s
puts (2).downto(2){|i| puts i.to_s}.to_s
puts (5).downto(6){|i| puts i.to_s}.to_s
puts "abs"
puts (2).abs.to_s
puts (-2).abs.to_s
puts "magnitude"
puts (2).magnitude.to_s
puts (-2).magnitude.to_s


================================================
FILE: rb_test/ivar.rb
================================================
class Foo
  def setup
    @ivar = "hello"
  end
  def ivar
    @ivar
  end
end
foo = Foo.new
foo.setup
puts foo.ivar


================================================
FILE: rb_test/load.rb
================================================
load 'rb_test/_load.rb'
load 'rb_test/_load.rb'


================================================
FILE: rb_test/method_def.rb
================================================
str = "not this"
def hello_world_method_0
  "hello world no arg"
end

def hello_world_method_1(name)
  str = name
  str
end

def hello_world_method_block(n)
  puts n
  puts yield
end

def yield_with_arg(s,x)
  yield s,x
end

yield_with_arg("yield with","arg") do |ss, xx|
  puts ss # "yield with"
  puts xx # "arg"
end

puts hello_world_method_0
puts hello_world_method_1("my name is erruby")
hello_world_method_block("arg") { "hello block" }

#hello_world_method_block(4){"hello"}.block1{"this"}.block2{"world"}


================================================
FILE: rb_test/nested_block.rb
================================================
3.times do |i|
  puts i.to_s
  4.times do |j|
    puts j.to_s
  end
end


================================================
FILE: rb_test/nested_const.rb
================================================
class Foo
  Bar = "hello nested"
  class Alice
  end
end
Bob = "outside bob"
puts "Foo::Bar"
puts Foo::Bar
Foo::Alice::Bob = "inside Bob"
puts Foo::Alice::Bob
puts Bob


================================================
FILE: rb_test/nil_class.rb
================================================
nil

nil & nil
nil & true
nil & false
nil & ""

nil ^ nil
nil ^ true
nil ^ false
nil ^ ""

nil | nil
nil | true
nil | false
nil | ""

nil.inspect

nil.nil?

nil.to_s


================================================
FILE: rb_test/require_relative.rb
================================================
require_relative "_require_relative"
require_relative "_require_relative"


================================================
FILE: rb_test/sysrb_out/.gitkeep
================================================


================================================
FILE: rb_test/sysrb_out/and_dot.out
================================================
1


================================================
FILE: rb_test/sysrb_out/array_class.out
================================================
1
2
mul
1
2
3
1
2
3
1
2
3
b
a
c
false
true
3
3
d
f
d
f
a
a
b
4
2
5
0
0


================================================
FILE: rb_test/sysrb_out/boolean_class.out
================================================
true
false
false
true
false
true
false
true
true
false
false
false
false
true
true
false
true
true
true
false
true
false
true
false


================================================
FILE: rb_test/sysrb_out/class_cross_call.out
================================================
hello


================================================
FILE: rb_test/sysrb_out/class_def.out
================================================
hello world
hello bar


================================================
FILE: rb_test/sysrb_out/class_inherent.out
================================================
foo
foo
i'm alice


================================================
FILE: rb_test/sysrb_out/class_method.out
================================================
bar


================================================
FILE: rb_test/sysrb_out/const_def.out
================================================
hello const


================================================
FILE: rb_test/sysrb_out/file.out
================================================
rb_test/file.rb
/Users/johnlinvc/Projs/erruby/erruby/rb_test


================================================
FILE: rb_test/sysrb_out/fixnum.out
================================================
1
2
-1
0
576460752303423488
-576460752303423489
2
1
-1
1
8
1
16
true
false
false
true
true
false
false
false
true
false
true
true
false
true
false
-1
0
1


================================================
FILE: rb_test/sysrb_out/global_var.out
================================================
hello gvar


================================================
FILE: rb_test/sysrb_out/hello_world.out
================================================
hello world


================================================
FILE: rb_test/sysrb_out/integer_class.out
================================================
5
5
5
5
5
5
5
1
true
false
false
true
2
2
2
8
0
6
2
24
24
0
0
true
2
0
2
0
times
0
1
2
3
4
5
0
-5
upto
-2
-1
0
1
2
-2
2
2
3
downto
2
1
0
-1
-2
2
2
2
5
abs
2
2
magnitude
2
2


================================================
FILE: rb_test/sysrb_out/ivar.out
================================================
hello


================================================
FILE: rb_test/sysrb_out/load.out
================================================
loaded
loaded


================================================
FILE: rb_test/sysrb_out/method_def.out
================================================
yield with
arg
hello world no arg
my name is erruby
arg
hello block


================================================
FILE: rb_test/sysrb_out/nested_block.out
================================================
0
0
1
2
3
1
0
1
2
3
2
0
1
2
3


================================================
FILE: rb_test/sysrb_out/nested_const.out
================================================
Foo::Bar
hello nested
inside Bob
outside bob


================================================
FILE: rb_test/sysrb_out/nil_class.out
================================================


================================================
FILE: rb_test/sysrb_out/require_relative.out
================================================
required file


================================================
FILE: rb_test/sysrb_out/var_assign.out
================================================
hello world


================================================
FILE: rb_test/var_assign.rb
================================================
hello = "hello world"
puts hello


================================================
FILE: rebar.config
================================================
{deps, [
        {erlport, ".*", {git, "https://github.com/johnlinvc/erlport.git", {branch, "erruby"}}, [raw]},
        {plists, ".*", {git, "https://github.com/johnlinvc/plists.git", {branch, "master"}}, [raw]},
        {getopt, "0.8.2", {git, "https://github.com/jcomellas/getopt.git", {tag, "v0.8.2"}}}
       ]
}.
{pre_hooks, [{compile, "./pre_compile"}]}.


================================================
FILE: src/erb.erl
================================================
-module(erb).
-export([find_or_init_class/2]).

find_or_init_class(Name, InitFun) ->
  case whereis(Name) of
    undefined -> InitFun();
    Pid -> {ok, Pid}
  end.


================================================
FILE: src/erruby.app.src
================================================
{application, erruby,
 [
  {description, ""},
  {vsn, "1"},
  {registered, []},
  {applications, [
                  kernel,
                  stdlib
                 ]},
  {mod, { erruby_app, []}},
  {env, []}
 ]}.


================================================
FILE: src/erruby.erl
================================================
-module(erruby).
-include("rb.hrl").
-export([eruby/1, start_ruby/0, stop_ruby/1, parse_ast/2, main/1]).

opt_spec_list() ->
  [
   {debug, $d, "debug", {integer, 0}, "Verbose level for debugging"},
   {verbose, $v, "verbose", undefined, "print version number and enter verbose mode"},
   {fast, $f, "fast", undefined, "use escript instead of erl for faster bootup"},
   {help, $h, "help", undefined, "Show this help"}
  ].

handle_opts({debug, DebugLevel}) ->
  erruby_debug:set_debug_level(DebugLevel);
handle_opts(help ) ->
  show_help();
handle_opts(verbose) ->
  io:format("erruby 0.1.0~n"),
  erruby_debug:set_debug_level(2);
handle_opts(_Opts) ->
  ok.

parse_args([ArgsAtom]) when is_atom(ArgsAtom) ->
  ArgsString = atom_to_list(ArgsAtom),
  ArgsUntokened = string:centre(ArgsString,length(ArgsString)-2),
  string:tokens(ArgsUntokened, " ");

parse_args(Args) ->
  Args.

main(RawArgs) ->
  Args = parse_args(RawArgs),
  add_lib_path(),
  erruby_debug:start_link(0),
  {ok, {Opts, Extra}} = getopt(Args),
  lists:foreach(fun handle_opts/1, Opts),
  [SrcFileName | RubyArgs] = Extra,
  try
    erruby_debug:debug_2("input file name ~s\n", [SrcFileName]),
    erruby_debug:debug_2("input args ~s\n", [RubyArgs]),
    eruby(SrcFileName)
  catch
    _:known_error ->
      erruby_debug:debug_1("known error ~n", []),
      erruby_debug:debug_1("~p~n",[erlang:get_stacktrace()]);
    _:E ->
      io:format("error ~p ~n", [E]),
      erlang:display(erlang:get_stacktrace())
  end.

eruby(SrcFileName) ->
  {ok, Binary} = file:read_file(SrcFileName),
  FileLines = binary:bin_to_list(Binary),
  Ruby = start_ruby(),
  Ast = parse_ast(Ruby, FileLines),
  stop_ruby(Ruby),
  erruby_vm:eval_file(Ast, SrcFileName).

getopt(Args) ->
  getopt:parse(opt_spec_list(), Args).

show_help() ->
  getopt:usage(opt_spec_list(), "erruby", "[programfile] [arguments]"),
  halt(1).


install_encoder(Ruby) ->
  ruby:call(Ruby, erruby_rb_path() , 'install_encoder',[]).

erruby_path() ->
  os:getenv("ERRUBY_PATH") ++ "/ebin".

relative_path(Path) ->
  erruby_path() ++ Path.

erruby_rb_path() ->
  list_to_atom(relative_path("/../rb_src/erruby.rb")).

parse_ast(Ruby, String) ->
  ruby:call(Ruby, erruby_rb_path(),'parse', [String]).

add_lib_path() ->
  code:add_path(relative_path("/../deps/erlport/ebin")),
  code:add_path(relative_path("/../deps/getopt/ebin")),
  code:add_path(relative_path("/../deps/plists/ebin")),
  code:add_path(erruby_path()).

stop_ruby(Ruby) ->
  ruby:stop(Ruby).

start_ruby() ->
  {ok, Ruby} = ruby:start(),
  install_encoder(Ruby),
  Ruby.



================================================
FILE: src/erruby_app.erl
================================================
-module(erruby_app).

-behaviour(application).

%% Application callbacks
-export([start/2, stop/1]).

%% ===================================================================
%% Application callbacks
%% ===================================================================

start(_StartType, _StartArgs) ->
    erruby_sup:start_link().

stop(_State) ->
    ok.


================================================
FILE: src/erruby_array.erl
================================================
-module(erruby_array).
-include("rb.hrl").
-export([install_array_classes/0, new_array/2, new_array/1]).
-export([array_to_list/1, push/2]).

%TODO find a way to define module_function
install_array_classes() ->
  {ok, ArrayClass} = erruby_class:new_class(),
  'Array' = erruby_object:def_global_const('Array', ArrayClass),
  erruby_object:def_method(ArrayClass, map, fun method_map/1),
  erruby_object:def_method(ArrayClass, pmap, fun method_pmap/1),
  erruby_object:def_method(ArrayClass, '*' , fun method_multiplication/2),
  erruby_object:def_method(ArrayClass, '+', fun method_plus/2),
  erruby_object:def_method(ArrayClass, 'concat', fun method_concat/2),
  erruby_object:def_method(ArrayClass, 'at' , fun method_at/2),
  erruby_object:def_method(ArrayClass, 'first' , fun method_first/1),
  erruby_object:def_method(ArrayClass, 'last' , fun method_last/1),
  erruby_object:def_method(ArrayClass, 'empty?', fun method_empty_q/1),
  erruby_object:def_method(ArrayClass, 'length', fun method_length/1),
  erruby_object:def_method(ArrayClass, 'size', fun method_length/1),
  erruby_object:def_method(ArrayClass, 'push' , fun method_push/2),
  erruby_object:def_method(ArrayClass, '<<' , fun method_push/2),
  erruby_object:def_method(ArrayClass, 'unshift' , fun method_unshift/2),
  erruby_object:def_method(ArrayClass, 'shift' , fun method_shift/1),
  erruby_object:def_method(ArrayClass, 'drop' , fun method_drop/2),
  ok.

drop_elements(_List, Count) when Count =< 0 ->
  _List;
drop_elements([Head | Tail], Count) ->
  drop_elements(Tail, Count - 1).

method_drop(#{self := Self}=Env, IntObj) ->
  Int = erruby_fixnum:fix_to_int(IntObj),
  List = array_to_list(Self),
  if
    length(List) < Int ->
      new_array(Env, []);
    true ->
      ResultList = drop_elements(List, Int),
      new_array(Env, ResultList)
  end.

method_map(#{self := Self}=Env) ->
  List = array_to_list(Self),
  FoldFun = fun(X, EnvAcc) -> erruby_vm:yield(EnvAcc, [X]) end,
  Envs = erruby_vm:scanl(FoldFun, Env, List),
  Results = lists:map(fun erruby_rb:ret_val/1, Envs),
  erruby_rb:return(Results, lists:last(Envs)).

repeat_list(_List, Count) when Count =< 0 ->
  new_array([]);
repeat_list(List, 1) ->
  List;
repeat_list(List, Count) ->
  lists:append(List, repeat_list(List, Count-1)).

method_multiplication(#{self := Self}=Env, IntObj) ->
  Int = erruby_fixnum:fix_to_int(IntObj),
  List = array_to_list(Self),
  ResultList = repeat_list(List, Int),
  new_array(Env, ResultList).

method_plus(#{self := Self}=Env, Another) ->
  Elements = array_to_list(Self),
  AnotherElements = array_to_list(Another),
  NewElements = Elements ++ AnotherElements,
  new_array(Env, NewElements).

method_concat(#{self := Self}=Env, Another) ->
  Elements = array_to_list(Self),
  AnotherElements = array_to_list(Another),
  NewElements = Elements ++ AnotherElements,
  Properties = erruby_object:get_properties(Self),
  NewProperties = Properties#{ elements := NewElements},
  erruby_object:set_properties(Self, NewProperties),
  erruby_rb:return(Self, Env).

method_pmap(#{self := Self}=Env) ->
  List = array_to_list(Self),
  MapFun = fun(X) -> erruby_vm:yield(Env, [X]) end,
  Envs = plists:map(MapFun, List, {processes, erlang:system_info(schedulers_online)}),
  Results = lists:map(fun erruby_rb:ret_val/1, Envs),
  erruby_rb:return(Results, lists:last(Envs)).

method_at(#{self := Self}=Env, IntObj) ->
  Int = erruby_fixnum:fix_to_int(IntObj),
  erruby_rb:return(at(Self, Int), Env).

method_first(#{self := Self}=Env) ->
  List = array_to_list(Self),
  [ Head | _Tail ] = List,
  erruby_rb:return(Head, Env).

method_last(#{self := Self}=Env) ->
  List = array_to_list(Self),
  erruby_rb:return(lists:last(List), Env).

method_empty_q(#{self := Self}=Env) ->
  List = array_to_list(Self),
  case  length(List) < 1 of
    true -> erruby_boolean:new_true(Env);
    false -> erruby_boolean:new_false(Env)
  end.
method_length(#{self := Self}=Env) ->
  List = array_to_list(Self),
  erruby_fixnum:new_fixnum(Env, length(List)).

method_push(#{self := Self}=Env, Append) ->
  push(Self, Append),
  erruby_rb:return(Self, Env).

method_unshift(#{self := Self}=Env, Head) ->
  Elements = array_to_list(Self),
  NewElements = [Head | Elements],
  Properties = erruby_object:get_properties(Self),
  NewProperties = Properties#{ elements := NewElements} ,
  erruby_object:set_properties(Self, NewProperties),
  erruby_rb:return(Self, Env).

method_shift(#{self := Self}=Env) ->
  Elements = array_to_list(Self),
  [Head | Rest] = Elements,
  Properties = erruby_object:get_properties(Self),
  NewProperties = Properties#{ elements := Rest} ,
  erruby_object:set_properties(Self, NewProperties),
  erruby_rb:return(Head, Env).

%TODO maybe use pid to find class
new_array(Env, Elements) ->
  erruby_rb:return(new_array(Elements), Env).

new_array(Elements) ->
  ArrayClass = erruby_object:find_global_const('Array'),
  Properties = #{elements => Elements},
  {ok, Array} = erruby_object:new_object(ArrayClass, Properties),
  Array.

%% @doc the Index is 0-based, not the 1-based of usual erlang
at(Array, Index) ->
  Properties = erruby_object:get_properties(Array),
  #{ elements := Elements} = Properties,
  lists:nth(Index+1, Elements).

push(Array, Elem) ->
  Elements = array_to_list(Array),
  NewElements = Elements ++ [Elem],
  Properties = erruby_object:get_properties(Array),
  NewProperties = Properties#{ elements := NewElements} ,
  erruby_object:set_properties(Array, NewProperties).

array_to_list(Array) ->
  Properties = erruby_object:get_properties(Array),
  #{ elements := Elements} = Properties,
  Elements.


================================================
FILE: src/erruby_boolean.erl
================================================
-module(erruby_boolean).
-export([install_boolean_classes/0,new_true/1,new_false/1,true_instance/0,false_instance/0]).
%TODO register the True & False class in Const

install_boolean_classes() ->
  {ok, TrueClass} = erruby_class:new_class(),
  {ok, FalseClass} = erruby_class:new_class(),
  'TrueClass' = erruby_object:def_global_const('TrueClass', TrueClass),
  'FalseClass' = erruby_object:def_global_const('FalseClass', FalseClass),
  install_method(TrueClass, FalseClass, '!', fun method_not/1),
  install_method(TrueClass, FalseClass, '&', fun method_and/2),
  install_method(TrueClass, FalseClass, '^', fun method_xor/2),
  install_method(TrueClass, FalseClass, '|', fun method_or/2),
  erruby_object:def_method(TrueClass, to_s, fun method_true_to_s/1),
  erruby_object:def_method(FalseClass, to_s, fun method_false_to_s/1),
  erruby_object:def_method(TrueClass, inspect, fun method_true_to_s/1),
  erruby_object:def_method(FalseClass, inspect, fun method_false_to_s/1),
  erruby_object:new_object_with_pid_symbol(erruby_boolean_true, TrueClass),
  erruby_object:new_object_with_pid_symbol(erruby_boolean_false, FalseClass),
  ok.

install_method(TC, FC, Name, Func) ->
  erruby_object:def_method(TC, Name, Func),
  erruby_object:def_method(FC, Name, Func).

new_true(Env) -> erruby_rb:return(true_instance(), Env).
new_false(Env) -> erruby_rb:return(false_instance(), Env).

true_instance() ->
  whereis(erruby_boolean_true).

false_instance() ->
  whereis(erruby_boolean_false).

method_not(#{self := Self} = Env) ->
  True = true_instance(),
  False = false_instance(),
  RetVal = case Self of
    True -> False;
    False -> True
  end,
  erruby_rb:return(RetVal, Env).

method_and(#{self := Self} = Env, Object) ->
  Another = object_to_boolean(Object),
  RetVal = and_op(Self, Another),
  erruby_rb:return(RetVal, Env).

object_to_boolean(Object) ->
  NilObject = erruby_nil:nil_instance(),
  False = false_instance(),
  case Object of
    NilObject -> false_instance();
    False -> false_instance();
    _ -> true_instance()
  end.


and_op(B1,B2) ->
  True = true_instance(),
  False = false_instance(),
  case B1 of
    True -> B2;
    False -> False
  end.

or_op(B1,B2) ->
  True = true_instance(),
  False = false_instance(),
  case B1 of
    True -> True;
    False -> B2
  end.

not_op(Boolean) ->
  True = true_instance(),
  False = false_instance(),
  case Boolean of
    True -> False;
    False -> True
  end.

method_or(#{self := Self} = Env, Object) ->
  Another = object_to_boolean(Object),
  RetVal = or_op(Self, Another),
  erruby_rb:return(RetVal, Env).

method_xor(#{self := Self} = Env, Object) ->
  Another = object_to_boolean(Object),
  NotAandB = and_op(not_op(Self),Another),
  AandNotB = and_op(Self, not_op(Another)),
  RetVal = or_op(NotAandB, AandNotB),
  erruby_rb:return(RetVal, Env).

method_true_to_s(Env) ->
  erruby_vm:new_string("true", Env).

method_false_to_s(Env) ->
  erruby_vm:new_string("false",Env).


================================================
FILE: src/erruby_class.erl
================================================
-module(erruby_class).
-export([new_class/0, new_named_class/1, new_class/1, install_class_class_methods/0, init_class_class/0, class_name/1]).

%TODO return self when calling method_class on self
%TODO add name parameter
%TODO should call initialize method when new

new_class() ->
  new_named_class(undefined).

new_named_class(Name) ->
  Properties = #{name => Name},
  erruby_object:start_link(class_class(), Properties).

class_name(Self) ->
  Properties = erruby_object:get_properties(Self),
  #{name := Name} = Properties,
  Name.

new_class(SuperClass) ->
  Properties = #{superclass => SuperClass},
  erruby_object:start_link(class_class(), Properties).

install_class_class_methods() ->
  erruby_object:def_method(class_class(), 'new', fun method_new/1),
  ok.

%FIXME new a real class
method_new(#{self := Klass}=Env) ->
  {ok, NewObject} = erruby_object:start_link(Klass),
  erruby_rb:return(NewObject, Env).

init_class_class() ->
  erb:find_or_init_class(erruby_class_class, fun init_class_class_internal/0).

init_class_class_internal() ->
  Properties = #{superclass => erruby_object:object_class()},
  {ok, Pid} = erruby_object:new_object_with_pid_symbol(erruby_class_class, erruby_object:object_class()),
  ok = install_class_class_methods(),
  {ok, Pid}.

class_class() ->
  whereis(erruby_class_class).



================================================
FILE: src/erruby_debug.erl
================================================
-module(erruby_debug).
-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).
-export([start_link/1, debug/3, debug_1/2,debug_2/2, debug_tmp/2, set_debug_level/1]).
-export([print_env/1]).

init([DebugLevel]) ->
  {ok, #{debug_level => DebugLevel}}.

terminate(_Arg, _State) -> {ok, dead}.

code_change(_OldVsn, State, _Extra) -> {ok, State}.

debug(Format, Args, Level) ->
  FullFormat = lists:concat(["debug level ", Level, ": ", Format]),
  gen_server:call(erruby_debug_pid, #{level => Level, format => FullFormat, args => Args}).

debug_1(Format, Args) ->
  debug(Format, Args, 1).

debug_2(Format, Args) ->
  debug(Format, Args, 2).

debug_tmp(Format, Args) ->
  io:format(Format, Args).

set_debug_level(Level) ->
  gen_server:cast(erruby_debug_pid, #{new_level => Level}).

start_link(DebugLevel) -> gen_server:start_link({local, erruby_debug_pid} ,?MODULE, [DebugLevel], []).

handle_info(Info, State) ->
  io:format("Got unkwon info:~n~p~n", [Info]),
  {ok, State}.

handle_call(#{level := Level, format := Format, args := Args}, _From, #{debug_level := DebugLevel} = State) when DebugLevel >= Level ->
  io:format(Format, Args),
  {reply, ok, State};

handle_call(#{level := Level}, _From, #{debug_level := DebugLevel} = State) when DebugLevel < Level ->
  {reply, ok, State};

handle_call(_Req, _From, State) ->
  io:format("handle unknow call ~p ~p ~p ~n",[_Req, _From, State]),
  NewState = State,
  {reply, done, NewState}.

handle_cast(#{new_level := NewLevel}, State) ->
  {noreply, State#{ debug_level => NewLevel } };

handle_cast(_Req, State) ->
  io:format("handle unknown cast ~p ~p ~n",[_Req, State]),
  NewState = State,
  {noreply, NewState}.

print_env(Env) ->
  debug_1("Env: ~p ~n",[Env]).


================================================
FILE: src/erruby_fixnum.erl
================================================
-module(erruby_fixnum).
-export([install_fixnum_class/0, new_fixnum/2, fix_to_int/1]).

%%
%% @TODO inherent from integer & numeric
install_fixnum_class() ->
  IntegerClass = erruby_object:find_global_const('Integer'),
  {ok, FixnumClass} = erruby_class:new_class(IntegerClass),
  'Fixnum' = erruby_object:def_global_const('Fixnum', FixnumClass),
  erruby_object:def_method(FixnumClass, to_s, fun method_to_s/1),
  erruby_object:def_method(FixnumClass, '-@', fun method_neg/1),
  erruby_object:def_method(FixnumClass, '+', fun method_add/2),
  erruby_object:def_method(FixnumClass, '-', fun method_minus/2),
  erruby_object:def_method(FixnumClass, '*', fun method_multiplication/2),
  erruby_object:def_method(FixnumClass, '**', fun method_power/2),
  erruby_object:def_method(FixnumClass, '<', fun method_less/2),
  erruby_object:def_method(FixnumClass, '>', fun method_greater/2),
  erruby_object:def_method(FixnumClass, '<=', fun method_less_equal/2),
  erruby_object:def_method(FixnumClass, '>=', fun method_greater_equal/2),
  erruby_object:def_method(FixnumClass, '==', fun method_equal/2),
  erruby_object:def_method(FixnumClass, '<=>', fun method_cmp/2),
  erruby_object:def_method(FixnumClass, '/', fun method_division/2),
  erruby_object:def_method(FixnumClass, '%', fun method_module/2),
  ok.

fixnum_class() ->
  erruby_object:find_global_const('Fixnum').

new_fixnum(Env, N) ->
  {ok, Obj} = erruby_object:new_object(fixnum_class(), #{val => N}),
  erruby_rb:return(Obj, Env).

fix_to_int(Fixnum) ->
  get_val(Fixnum).

get_val(Fixnum) ->
  #{val := Val} = erruby_object:get_properties(Fixnum),
  Val.

binary_op(#{self := Self}=Env, AnotherFixnum, Fun) ->
  Val = Fun(get_val(Self), get_val(AnotherFixnum)),
  new_fixnum(Env, Val).

%% @TODO use new_string instead
method_to_s(#{self := Self}=Env) ->
  Val = get_val(Self),
  erruby_rb:return(integer_to_list(Val), Env).

%% TODO handle case where the other is not Fixnum
method_add(Env, AnotherFixnum) ->
  binary_op(Env, AnotherFixnum, fun (A,B) -> A+B end).

method_minus(Env, AnotherFixnum) ->
  binary_op(Env, AnotherFixnum, fun (A,B) -> A-B end).

method_multiplication(Env, AnotherFixnum) ->
  binary_op(Env, AnotherFixnum, fun (A,B) -> A*B end).

method_division(Env, AnotherFixnum) ->
  binary_op(Env, AnotherFixnum, fun (A,B) -> trunc(A/B) end).

method_power(Env, AnotherFixnum) ->
  binary_op(Env, AnotherFixnum, fun (A,B) -> trunc(math:pow(A,B)) end).

method_neg(#{self := Self}=Env) ->
  Val = - get_val(Self),
  new_fixnum(Env, Val).

method_module(Env, AnotherFixnum) ->
  binary_op(Env, AnotherFixnum, fun (A,B) -> A rem B end).

binary_cmp(#{self := Self}=Env, AnotherFixnum, Fun) ->
  Val = get_val(Self),
  AnotherVal = get_val(AnotherFixnum),
  case Fun(Val,AnotherVal) of
    true -> erruby_boolean:new_true(Env);
    false -> erruby_boolean:new_false(Env)
  end.

%%TODO move these to the comparator module
method_less(Env, AnotherFixnum) ->
  binary_cmp(Env, AnotherFixnum, fun (X,Y) -> X < Y end).

method_less_equal(Env, AnotherFixnum) ->
  binary_cmp(Env, AnotherFixnum, fun (X,Y) -> X =< Y end).

method_greater(Env, AnotherFixnum) ->
  binary_cmp(Env, AnotherFixnum, fun (X,Y) -> X > Y end).

method_greater_equal(Env, AnotherFixnum) ->
  binary_cmp(Env, AnotherFixnum, fun (X,Y) -> X >= Y end).

method_equal(Env, AnotherFixnum) ->
  binary_cmp(Env, AnotherFixnum, fun (X,Y) -> X =:= Y end).


cmp_helper(X,Y) when X < Y ->
  -1;
cmp_helper(X,Y) when X =:= Y ->
  0;
cmp_helper(X,Y) when X > Y ->
  1.

method_cmp(Env, AnotherFixnum) ->
  binary_op(Env, AnotherFixnum, fun cmp_helper/2).



================================================
FILE: src/erruby_integer.erl
================================================
-module(erruby_integer).
-export([install_integer_class/0]).

install_integer_class() ->
  {ok, IntegerClass} = erruby_class:new_class(),
  'Integer' = erruby_object:def_global_const('Integer', IntegerClass),
  erruby_object:def_method(IntegerClass, to_i, fun method_to_i/1),
  erruby_object:def_method(IntegerClass, to_int, fun method_to_i/1),
  erruby_object:def_method(IntegerClass, floor, fun method_to_i/1),
  erruby_object:def_method(IntegerClass, ceil, fun method_to_i/1),
  erruby_object:def_method(IntegerClass, truncate, fun method_to_i/1),
  erruby_object:def_method(IntegerClass, numerator, fun method_to_i/1),
  erruby_object:def_method(IntegerClass, ord, fun method_to_i/1),
  erruby_object:def_method(IntegerClass, denominator, fun method_denominator/1),
  erruby_object:def_method(IntegerClass, 'even?', fun method_even_q/1),
  erruby_object:def_method(IntegerClass, 'odd?', fun method_odd_q/1),
  erruby_object:def_method(IntegerClass, 'gcd', fun method_gcd/2),
  erruby_object:def_method(IntegerClass, 'lcm', fun method_lcm/2),
  erruby_object:def_method(IntegerClass, 'integer?', fun method_integer_q/1),
  erruby_object:def_method(IntegerClass, 'succ', fun method_succ/1),
  erruby_object:def_method(IntegerClass, 'next', fun method_succ/1),
  erruby_object:def_method(IntegerClass, 'times', fun method_times/1),
  erruby_object:def_method(IntegerClass, 'upto', fun method_upto/2),
  erruby_object:def_method(IntegerClass, 'downto', fun method_downto/2),
  erruby_object:def_method(IntegerClass, 'abs', fun method_abs/1),
  erruby_object:def_method(IntegerClass, 'magnitude', fun method_abs/1),
  ok.

method_to_i(#{self := Self}=Env) -> erruby_rb:return(Self, Env).

method_denominator(Env) ->
  erruby_fixnum:new_fixnum(Env, 1).

%%TODO handle Bignum
method_even_q(#{self := Self}=Env) ->
  Int = erruby_fixnum:fix_to_int(Self),
  case Int rem 2 of
    0 -> erruby_boolean:new_true(Env);
    1 -> erruby_boolean:new_false(Env)
  end.
method_odd_q(#{self := Self}=Env) ->
  Int = erruby_fixnum:fix_to_int(Self),
  case Int rem 2 of
    1 -> erruby_boolean:new_true(Env);
    0 -> erruby_boolean:new_false(Env)
  end.

%%TODO use binary gcd algo instead
%%TODO move this to rational
gcd(X,Y) when X < Y -> gcd(Y,X);
gcd(X,Y) when Y =:= 0 -> X;
gcd(X,Y) -> gcd(Y, X rem Y).

method_gcd(#{self := Self}=Env, AnotherInt) ->
  X = abs(erruby_fixnum:fix_to_int(Self)),
  Y = abs(erruby_fixnum:fix_to_int(AnotherInt)),
  case min(X,Y) of
    0 -> erruby_fixnum:new_fixnum(Env, max(X,Y));
    _ -> erruby_fixnum:new_fixnum(Env, gcd(X,Y))
  end.

lcm(0,_Y) -> 0;
lcm(_X,0) -> 0;
lcm(X,Y) -> trunc(X / gcd(X,Y) * Y).

method_lcm(#{self := Self}=Env, AnotherInt) ->
  X = abs(erruby_fixnum:fix_to_int(Self)),
  Y = abs(erruby_fixnum:fix_to_int(AnotherInt)),
  case min(X,Y) of
    0 -> erruby_fixnum:new_fixnum(Env, 0);
    _ -> erruby_fixnum:new_fixnum(Env, lcm(X,Y))
  end.

method_integer_q(Env) ->
  erruby_boolean:new_true(Env).

method_succ(#{self := Self}=Env) ->
  erruby_fixnum:new_fixnum(Env, erruby_fixnum:fix_to_int(Self)+1).


yield_in_range(#{self := Self} = Env,Range) ->
  FoldFun = fun (X, EnvAcc) ->
                IntEnv = erruby_fixnum:new_fixnum(EnvAcc, X),
                FixInt = erruby_rb:ret_val(IntEnv),
                erruby_vm:yield(IntEnv, [FixInt]) end,
  LastEnv = lists:foldl(FoldFun, Env, Range),
  erruby_rb:return(Self, LastEnv).

times_range(X) when X =< 0 -> [];
times_range(X) -> lists:seq(0, X-1).

%%TODO handle empty block case
%%TODO handle Bigdecimal
method_times(#{self := Self}=Env) ->
  Int = erruby_fixnum:fix_to_int(Self),
  Range = times_range(Int),
  yield_in_range(Env,Range).

upto_range(Start,End) when Start > End -> [];
upto_range(Start,End) -> lists:seq(Start,End).

method_upto(#{self := Self}=Env, AnotherInteger) ->
  Int = erruby_fixnum:fix_to_int(Self),
  AnotherInt = erruby_fixnum:fix_to_int(AnotherInteger),
  Range = upto_range(Int,AnotherInt),
  yield_in_range(Env,Range).

downto_range(Start,End) -> lists:reverse(upto_range(End,Start)).

method_downto(#{self := Self}=Env, AnotherInteger) ->
  Int = erruby_fixnum:fix_to_int(Self),
  AnotherInt = erruby_fixnum:fix_to_int(AnotherInteger),
  Range = downto_range(Int,AnotherInt),
  yield_in_range(Env,Range).

method_abs(#{self := Self}=Env) ->
  erruby_fixnum:new_fixnum(Env, abs(erruby_fixnum:fix_to_int(Self))).


================================================
FILE: src/erruby_lib/erruby_file.erl
================================================
-module(erruby_file).
-include("../rb.hrl").
-export([install_file_classes/0]).

install_file_classes() ->
  {ok, FileClass} = erruby_class:new_class(),
  'File' = erruby_object:def_global_const('File', FileClass),
  erruby_object:def_singleton_method(FileClass, 'expand_path', fun method_expand_path/3),
  ok.

method_expand_path(Env, Filename, RelativeDirOrFileName) ->
  {ok, Cwd} = file:get_cwd(),
  DirOrFileName = filename:absname_join(Cwd, RelativeDirOrFileName),
  ExpanedPath = filename:absname_join(DirOrFileName, Filename),
  FlattenedPath = flatten_path(ExpanedPath),
  erruby_vm:new_string(FlattenedPath, Env).

flatten_path(Path)->
  Components = filename:split(Path),
  FlattenedComponents = flatten_path_components(Components,[]),
  filename:join(FlattenedComponents).

flatten_path_components([], Acc) -> lists:reverse(Acc);
flatten_path_components([".."|T], [])->
  flatten_path_components(T, []);
flatten_path_components([".."|T], ["/"])->
  flatten_path_components(T, ["/"]);
flatten_path_components([".."|T], [_H|Acc])->
  flatten_path_components(T, Acc);
flatten_path_components([H|T], Acc)->
  flatten_path_components(T, [H|Acc]).


================================================
FILE: src/erruby_nil.erl
================================================
-module(erruby_nil).
-export([new_nil/1, install_nil_class/0, nil_instance/0]).

install_nil_class() ->
  {ok, NilClass} = erruby_class:new_class(),
  'NilClass' = erruby_object:def_global_const('NilClass', NilClass),
  erruby_object:def_method(NilClass, '&', fun method_and/2),
  erruby_object:def_method(NilClass, '^', fun method_xor/2),
  erruby_object:def_method(NilClass, '|', fun method_xor/2),
  erruby_object:def_method(NilClass, inspect, fun method_inspect/1),
  erruby_object:def_method(NilClass, 'nil?', fun 'method_nil_q'/1),
  erruby_object:def_method(NilClass, 'to_s', fun 'method_to_s'/1),
  erruby_object:new_object_with_pid_symbol(erruby_nil, NilClass),
  ok.

new_nil(Env) ->
  erruby_rb:return(nil_instance(), Env).

nil_instance() -> whereis(erruby_nil).

method_and(Env, _Obj) -> erruby_boolean:new_false(Env).

method_xor(Env, Obj) ->
  Nil = nil_instance(),
  False = erruby_boolean:false_instance(),
  case Obj of
    Nil -> erruby_boolean:new_false(Env);
    False -> erruby_boolean:new_false(Env);
    _ -> erruby_boolean:new_true(Env)
  end.

method_inspect(Env) -> erruby_vm:new_string("nil",Env).

method_nil_q(Env) -> erruby_boolean:new_true(Env).

method_to_s(Env) -> erruby_vm:new_string("",Env).


================================================
FILE: src/erruby_object.erl
================================================
-module(erruby_object).
-include("rb.hrl").
-behavior(gen_server).
-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).
%for vm
-export([def_method/4, find_instance_method/2, def_global_const/2, find_global_const/1, def_const/3, find_const/2, init_object_class/0,object_class/0]).
-export([def_singleton_method/4, def_singleton_method/3]).
-export([def_global_var/2, find_global_var/1]).
%for other buildtin class
-export([def_method/3, new_object_with_pid_symbol/2, new_object/2]).
-export([def_ivar/3, find_ivar/2]).
-export([init_main_object/0, main_object/0]).
-export([start_link/2, start_link/1]).
-export([get_properties/1, set_properties/2]).
-export([get_class/1]).

init([#{class := Class, properties := Properties}]) ->
  DefaultState = default_state(),
  StateWithClass = add_class_to_state(DefaultState, Class),
  {ok, add_property_to_state(StateWithClass, Properties)};

init([#{class := Class}]) ->
  DefaultState = default_state(),
  {ok, add_class_to_state(DefaultState, Class)};

init([]) ->
  {ok, default_state()}.

add_class_to_state(State, Class) ->
  State#{class => Class}.

add_property_to_state(State, Properties) ->
  State#{properties => Properties}.

%TODO in method_class return defalut object_class if no class is present
default_state() ->
  Methods = #{},
  IVars = #{},
  Consts = #{},
  #{self => self(),
    methods => Methods,
    ivars => IVars,
    properties => #{},
    consts => Consts}.


%TODO unify these?
start_link(Class) ->
  gen_server:start_link(?MODULE, [#{class => Class }], []).

start_link(Class, Properties) ->
  gen_server:start_link(?MODULE, [#{class => Class, properties => Properties}], []).

terminate(_Arg, _State) ->
  {ok, dead}.

code_change(_OldVsn, State, _Extra) -> {ok, State}.

get_class(Self) ->
  gen_server:call(Self, #{type => get_class}).

find_instance_method(Self, Name) ->
  SingletonMethod = find_instance_method_in_singleton_class(Self, Name),
  case SingletonMethod of
    {ok, Method} -> Method;
    {not_found, _} ->
      find_instance_method_in_class(Self, Name)
  end.

find_instance_method_in_singleton_class(Self, Name) ->
  SingletonClass = singleton_class(Self),
  case SingletonClass of
    not_found -> {not_found, Name};
    _ ->
      Result = gen_server:call(SingletonClass, #{type => find_method, name => Name}),
      case Result of
        not_found -> {not_found, Name};
        _ -> {ok, Result}
      end
  end.

find_instance_method_in_class(Self, Name) ->
  %erruby_debug:debug_tmp("finding instance method ~p in ~p",[ Name, Self]),
  Klass = get_class(Self),
  Result = gen_server:call(Klass, #{type => find_method, name => Name}),
  case Result of
    not_found -> {not_found, Name};
    _ -> Result
  end.

find_method(Self, Name) ->
  gen_server:call(Self, #{type => find_method, name => Name}).

self_or_object_class(Self) ->
  MainObject = main_object(),
  case Self of
    MainObject -> object_class();
    _ -> Self
  end.


singleton_class(Self) ->
  Properties = get_properties(Self),
  maps:get(singleton_class, Properties, not_found).

get_or_create_singleton_class(Self) ->
  SingletonClass = singleton_class(Self),
  case SingletonClass of
    not_found ->
      {ok, NewSingletonClass} = erruby_class:new_named_class("singleton class"),
      Properties = get_properties(Self),
      NewProperties = Properties#{ singleton_class => NewSingletonClass },
      set_properties(Self, NewProperties),
      NewSingletonClass;
    _ ->
      SingletonClass
  end.


def_method(Self, Name, Args, Body) ->
  Receiver = self_or_object_class(Self),
  gen_server:call(Receiver, #{type => def_method, name => Name, args => Args, body => Body}).

def_method(Self,Name,Func) when is_function(Func) ->
  Receiver = self_or_object_class(Self),
  gen_server:call(Receiver, #{type => def_method, name => Name, func => Func}).

def_singleton_method(Self, Name, Args, Body) ->
  Receiver = get_or_create_singleton_class(Self),
  gen_server:call(Receiver, #{type => def_method, name => Name, args => Args, body => Body}).

def_singleton_method(Self,Name,Func) when is_function(Func) ->
  Receiver = get_or_create_singleton_class(Self),
  gen_server:call(Receiver, #{type => def_method, name => Name, func => Func}).

%TODO call def_const instead
def_global_const(Name, Value) ->
  gen_server:call(object_class(), #{type => def_const, name => Name, value => Value}).

find_global_const(Name) ->
  find_const(object_class(), Name).


%TODO define on basic object instead
%TODO ability to use custom getter/setter
def_global_var(Name, Value) ->
  Msg = #{type => def_global_var, name => Name, value => Value},
  gen_server:call(object_class(), Msg).

find_global_var(Name) ->
  gen_server:call(object_class(), #{type => find_global_var, name => Name}).

def_const(Self, Name, Value) ->
  Receiver = self_or_object_class(Self),
  gen_server:call(Receiver, #{type => def_const, name => Name, value => Value}).

find_const(Self, Name) ->
  erruby_debug:debug_2("finding on ~p for const:~p~n",[Self, Name]),
  gen_server:call(Self, #{type => find_const, name => Name}).

def_ivar(Self, Name, Value)->
  gen_server:call(Self, #{type => def_ivar, name => Name, value => Value}).

find_ivar(Self, Name) ->
  erruby_debug:debug_2("finding on ~p for ivar:~p~n",[Self, Name]),
  gen_server:call(Self, #{type => find_ivar, name => Name}).

get_properties(Self) ->
  gen_server:call(Self, #{type => get_properties}).

set_properties(Self, Properties) ->
  gen_server:call(Self, #{type => set_properties, properties => Properties}).


handle_info(Info, State) ->
  io:format("Got unkwon info:~n~p~n", [Info]),
  {ok, State}.

handle_call(#{ type := def_method , name := Name, body := Body, args := Args}=_Msg, _From, #{methods := Methods} =State) ->
  NewMethods = Methods#{ Name => #{ args => Args, body => Body, argc => length(Args) } },
  NewState = State#{ methods := NewMethods},
  {reply, Name, NewState};

handle_call(#{ type := def_method, name := Name, func := Func}=_Msg, _From, #{methods := Methods} = State) ->
  NewMethods = Methods#{ Name => Func },
  NewState = State#{ methods := NewMethods},
  {reply, Name, NewState};

handle_call(#{ type := find_method, name := Name }, _From, #{methods := Methods} = State) ->
  erruby_debug:debug_2("finding method:~p~n in State:~p~n",[Name, State]),
  case maps:is_key(Name,Methods) of
    true ->
      #{Name := Method} = Methods,
      {reply, Method, State};
    false ->
      %TODO use error classes
      %io:format("Method ~p not found~n",[Name]),
      erruby_debug:debug_2("finding in ancestors:~p~n",[ancestors(State)]),
      Method = find_method_in_ancestors(ancestors(State), Name),
      {reply, Method, State}
  end;

handle_call(#{ type := get_properties }, _From, #{properties := Properties}=State) ->
  {reply, Properties, State};

handle_call(#{ type := set_properties, properties := Properties }, _From, State) ->
  NewState = State#{ properties := Properties},
  {reply, NewState, NewState};

handle_call(#{ type := def_ivar, name := Name, value := Value }, _From, #{ivars := IVars}=State) ->
  NewIvars = IVars#{Name => Value},
  NewState = State#{ivars := NewIvars},
  {reply, Name, NewState};

handle_call(#{ type := find_ivar, name := Name }, _From, #{ivars := IVars}=State) ->
  erruby_debug:debug_2("finding ivar:~p~nin State:~p~n",[Name, State]),
  Value = maps:get(Name, IVars, erruby_nil:nil_instance()),
  {reply, Value, State};

handle_call(#{ type := def_const, name := Name, value := Value }, _From, #{consts := Consts}=State) ->
  NewConsts = Consts#{Name => Value},
  NewState = State#{consts := NewConsts},
  {reply, Name, NewState};

handle_call(#{ type := find_const, name := Name }, _From, #{consts := Consts}=State) ->
  erruby_debug:debug_2("finding const:~p~nin State:~p~n",[Name, State]),
  Value = maps:get(Name, Consts, not_found),
  {reply, Value, State};

handle_call(#{ type := def_global_var, name := Name, value := Value}, _From,
            #{properties := #{global_var_tbl := GVarTbl} } = State) ->
  NewGVarTbl = GVarTbl#{ Name => Value},
  #{properties := Properties} = State,
  NewProperties = Properties#{ global_var_tbl := NewGVarTbl },
  NewState = State#{ properties :=  NewProperties},
  {reply, Name, NewState};

handle_call(#{ type := find_global_var, name := Name}, _From,
            #{properties := #{global_var_tbl := GVarTbl} } = State) ->
  Value = maps:get(Name, GVarTbl, not_found),
  {reply, Value, State};


handle_call(#{ type := get_class}, _From, State) ->
  Value = maps:get(class, State, object_class()),
  {reply, Value, State};


handle_call(_Req, _From, State) ->
  io:format("handle unknow call ~p ~n ~p ~n ~p ~n",[_Req, _From, State]),
  NewState = State,
  {reply, done, NewState}.

handle_cast(_Req, State) ->
  io:format("handle unknown cast ~p ~p ~n",[_Req, State]),
  NewState = State,
  {reply, done, NewState}.

%TODO support va args
method_puts(Env, String) ->
  io:format("~s~n", [String]),
  erruby_nil:new_nil(Env).

append_rb_extension(FileName) ->
  case filename:extension(FileName) of
    [] -> string:concat(FileName, ".rb");
    _ -> FileName
  end.

%TODO extract to Kernal
%TODO raise error if file not found
method_require_relative(Env, FileName) ->
  RelativeFileName = relativeFileName(Env, FileName),
  RelativeFileNameWithExt = append_rb_extension(RelativeFileName),
  LoadedFeatures = find_global_var("$LOADED_FEATURES"),
  LoadedFeaturesList = erruby_array:array_to_list(LoadedFeatures),
  Contains = lists:member( RelativeFileNameWithExt, LoadedFeaturesList),
  case Contains of
    true -> erruby_boolean:new_false(Env);
    _ ->
      load_file(Env, RelativeFileNameWithExt),
      erruby_array:push(LoadedFeatures, RelativeFileNameWithExt),
      erruby_boolean:new_true(Env)
  end.

relativeFileName(Env, FileName) ->
  SrcFile = erruby_vm:file_name(Env),
  SrcDir = filename:dirname(SrcFile),
  filename:join([SrcDir, FileName]).

load_file(Env, RelativeFileNameWithExt) ->
  try
    erruby:eruby(RelativeFileNameWithExt),
    erruby_boolean:new_true(Env)
  catch
    _:_E ->
      erruby_debug:debug_2("cant require_relative file ~p~n", [RelativeFileNameWithExt]),
      erruby_boolean:new_false(Env)
  end.

%TODO raise error if file not found
% @TODO find a better way to get filename
method_load(Env, FileName)->
  Pwd = os:getenv("PWD"),
  RelativeFileNameWithExt = filename:join([Pwd, FileName]),
  load_file(Env, RelativeFileNameWithExt).

method_self(#{self := Self}=Env) ->
  erruby_rb:return(Self, Env).

method_inspect(#{self := Self}=Env) ->
  S = io_lib:format("#<Object:~p>",[Self]),
  erruby_vm:new_string(S,Env).

method_to_s(#{self := Self}=Env) ->
  S = io_lib:format("~p",[Self]),
  erruby_vm:new_string(S,Env).

%TODO support property?
new_object_with_pid_symbol(Symbol, Class) ->
  gen_server:start_link({local, Symbol}, ?MODULE, [#{class => Class}], []).

new_object(Class, Payload) when is_map(Payload) ->
  start_link(Class, Payload).

init_object_class() ->
  erb:find_or_init_class(erruby_object_class, fun init_object_class_internal/0).

init_object_class_internal() ->
  {ok, Pid} = gen_server:start_link({local, erruby_object_class}, ?MODULE, [],[]),
  install_object_class_methods(),
  'Object' = def_const(Pid, 'Object', Pid),
  set_properties(object_class(), #{global_var_tbl => #{}}),
  def_global_var("$LOADED_FEATURES", erruby_array:new_array([])),
  {ok, Pid}.

init_main_object() ->
  erb:find_or_init_class(erruby_main_object, fun init_main_object_internal/0).

init_main_object_internal() ->
  new_object_with_pid_symbol(erruby_main_object, object_class()).

object_class() ->
  whereis(erruby_object_class).

main_object() ->
  whereis(erruby_main_object).

install_object_class_methods() ->
  %TODO use this after inherent is done
  %def_method(object_class(), '==', fun method_eq/2).
  def_method(object_class(), 'puts', fun method_puts/2),
  def_method(object_class(), 'self', fun method_self/1),
  def_method(object_class(), 'inspect', fun method_inspect/1),
  def_method(object_class(), 'to_s', fun method_to_s/1),
  def_method(object_class(), '==', fun method_eq/2),
  def_method(object_class(), 'require_relative', fun method_require_relative/2),
  def_method(object_class(), 'load', fun method_load/2),
  ok.


method_eq(#{self := Self}=Env, Object) ->
  case Object of
    Self -> erruby_boolean:new_true(Env);
    _ -> erruby_boolean:new_false(Env)
  end.

super_class(#{properties := Properties}=_State) ->
  maps:get(superclass, Properties, object_class()).

%TODO handle include & extend
ancestors(State) ->
  SuperClass = super_class(State),
  ObjectClass = object_class(),
  case self() of
    ObjectClass -> [];
    _ -> [SuperClass, ObjectClass]
  end.

find_method_in_ancestors([], _Name) ->
  not_found;

find_method_in_ancestors(Ancestors, Name) ->
  [Klass | Rest] = Ancestors,
  Method = find_method(Klass, Name),
  case Method of
    not_found -> find_method_in_ancestors(Rest, Name);
    _ -> Method
  end.



================================================
FILE: src/erruby_rb.erl
================================================
%%% TODO move general runtime api to here
-module(erruby_rb).
-export([ret_self/1,ret_val/1,return/2]).

ret_self( #{self := Self} = Env ) ->
  Env#{ret_val => Self}.

ret_val( #{ret_val := RetVal} ) -> RetVal.
return(Value, Env) -> Env#{ret_val => Value}.


================================================
FILE: src/erruby_sup.erl
================================================
-module(erruby_sup).

-behaviour(supervisor).

%% API
-export([start_link/0]).

%% Supervisor callbacks
-export([init/1]).

%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).

%% ===================================================================
%% API functions
%% ===================================================================

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

%% ===================================================================
%% Supervisor callbacks
%% ===================================================================

init([]) ->
    {ok, { {one_for_one, 5, 10}, []} }.



================================================
FILE: src/erruby_vm.erl
================================================
-module(erruby_vm).
-include("rb.hrl").
-export([eval_file/2, scanl/3]).
-export([new_nil/1, new_string/2]).
-export([eval_method_with_exit/5, yield/2]).
-export([file_name/1]).

print_ast(Ast) ->
  erruby_debug:debug_1("Ast: ~p ~n",[Ast]).

print_env(Env) ->
  erruby_debug:debug_1("Env: ~p ~n",[Env]).

scanl(_F, Acc, []) ->
  [Acc];
scanl(F, Acc0, [H | T]) ->
  Acc = apply(F, [H, Acc0]),
  [Acc0 | scanl(F, Acc, T)].

eval_file(Ast, FileName) ->
  DefaultEnv = default_env(),
  Env = set_filename(DefaultEnv, FileName),
  eval_ast(Ast, Env).

set_filename(Env, FileName) ->
  Env#{'FileName' => FileName}.

file_name(Env) ->
  case maps:find('FileName', Env) of
    {ok, Value} -> Value;
    error ->
      file_name(find_prev_frame(Env))
  end.

eval_ast({ast,type,'begin',children, Children}, Env) ->
  erruby_debug:debug_2("eval begin~n",[]),
  lists:foldl(fun eval_ast/2, Env, Children);

eval_ast({ast, type, self, children, []}, Env) ->
  #{ self := Self } = Env,
  erruby_rb:return(Self, Env);

eval_ast({ast, type, str, children, Children}, Env) ->
  [SBin|_T] = Children,
  new_string(binary_to_list(SBin), Env);

eval_ast({ast, type, nil, children, []}, Env) ->
  erruby_nil:new_nil(Env);

eval_ast({ast, type, true, children, []}, Env) ->
  erruby_boolean:new_true(Env);

eval_ast({ast, type, false, children, []}, Env) ->
  erruby_boolean:new_false(Env);

eval_ast({ast, type, array, children, Args}, Env) ->
  {EvaledArgs, LastEnv} = eval_args(Args, Env),
  erruby_array:new_array(LastEnv, EvaledArgs);

eval_ast({ast, type, int, children, [N]}, Env) ->
  erruby_fixnum:new_fixnum(Env, N);

eval_ast({ast, type, '__FILE__', children, []}, #{'FileName' := Filename } = Env) ->
  new_string(Filename, Env);

eval_ast({ast, type, csend, children, Children}, Env)->
  erruby_debug:debug_1("csend~n",[]),
  [print_ast(Ast) || Ast <- Children],
  [Receiver | [Msg | Args]] = Children,
  ReceiverFrame = receiver_or_self(Receiver, Env),
  UnresolvedTarget = erruby_rb:ret_val(ReceiverFrame),
  Target = resolve_future(UnresolvedTarget),
  Nil = erruby_nil:nil_instance(),
  case Target of
    Nil -> Nil;
    _ ->
      {EvaledArgs, LastEnv} = eval_args(Args, ReceiverFrame),
      Method = erruby_object:find_instance_method(Target, Msg),
      eval_method(Target,Method, EvaledArgs, LastEnv)
  end;

eval_ast({ast, type, psend, children, Children}, Env)->
  erruby_debug:debug_1("psend~n",[]),
  [print_ast(Ast) || Ast <- Children],
  [Receiver | [Msg | Args]] = Children,
  ReceiverFrame = receiver_or_self(Receiver, Env),
  UnresolvedTarget = erruby_rb:ret_val(ReceiverFrame),
  Target = resolve_future(UnresolvedTarget),
  {EvaledArgs, LastEnv} = eval_args(Args, ReceiverFrame),
  Method = erruby_object:find_instance_method(Target, Msg),
  process_eval_method(Target,Method, EvaledArgs, LastEnv);

%TODO call method using method object
eval_ast({ast,type,send, children, Children}, Env) ->
  erruby_debug:debug_1("send~n",[]),
  [print_ast(Ast) || Ast <- Children],
  [Receiver | [Msg | Args]] = Children,
  ReceiverFrame = receiver_or_self(Receiver, Env),
  UnresolvedTarget = erruby_rb:ret_val(ReceiverFrame),
  Target = resolve_future(UnresolvedTarget),
  {EvaledArgs, LastEnv} = eval_args(Args, ReceiverFrame),
  Method = erruby_object:find_instance_method(Target, Msg),
  eval_method(Target,Method, EvaledArgs, LastEnv);

eval_ast({ast, type, block, children, [Method | [Args | [Body]]]= _Children}, Env) ->
  Block = #{body => Body, args => Args},
  BlockEnv = Env#{block => Block},
  Result = eval_ast(Method, BlockEnv),
  Result#{block => not_exist};

eval_ast({ast, type, yield, children, Args}, Env) ->
  {EvaledArgs, LastEnv} = eval_args(Args, Env),
  yield(LastEnv, EvaledArgs);

%FIXME return the value
eval_ast({ast, type, lvasgn, children, Children}, Env) ->
  [Name, ValAst] = Children,
  NewEnv = eval_ast(ValAst, Env),
  RetVal = erruby_rb:ret_val(NewEnv),
  bind_lvar(Name, RetVal, NewEnv);

eval_ast({ast, type, lvar, children, [Name]}, Env) ->
  erruby_debug:debug_1("searching lvar ~p~n in frame~p~n", [Name, Env]),
  #{ lvars := #{Name := Val}} = Env,
  erruby_rb:return(Val, Env);

%FIXME return the value
eval_ast({ast, type, ivasgn, children, Children}, #{self := Self}=Env) ->
  [Name, ValAst] = Children,
  NewEnv = eval_ast(ValAst, Env),
  RetVal = erruby_rb:ret_val(NewEnv),
  erruby_object:def_ivar(Self, Name, RetVal),
  erruby_rb:return(RetVal, Env);

eval_ast({ast, type, ivar, children, [Name]}, #{self := Self}=Env) ->
  Val = erruby_object:find_ivar(Self, Name),
  erruby_rb:return(Val, Env);

eval_ast({ast, type, gvasgn, children, Children}, Env) ->
  [Name, ValAst] = Children,
  NewEnv = eval_ast(ValAst, Env),
  RetVal = erruby_rb:ret_val(NewEnv),
  erruby_object:def_global_var(Name, RetVal),
  erruby_rb:return(Name, NewEnv);

eval_ast({ast, type, gvar, children, [Name]}, Env) ->
  Val = erruby_object:find_global_var(Name),
  erruby_rb:return(Val, Env);


eval_ast({ast, type, defs, children, Children}, Env) ->
  [ReceiverAst , Name , {ast, type, args, children, Args}, Body] = Children,
  ReceiverEnv = eval_ast(ReceiverAst, Env),
  Receiver = erruby_rb:ret_val(ReceiverEnv),
  erruby_object:def_singleton_method(Receiver, Name, Args, Body),
  new_symbol(Name, Env);


eval_ast({ast, type, def, children, Children}, Env) ->
  [Name | [ {ast, type, args, children, Args} , Body ] ] = Children,
  #{ self := Self } = Env,
  erruby_object:def_method(Self, Name, Args, Body),
  new_symbol(Name, Env);

%TODO figure out the Unknown field in AST
%TODO impl ancestors
eval_ast({ast, type, class, children,
          [NameAst,undefined,Body] = _Children}, #{ self := Self } = Env) ->
  {_,_,const,_,[_,Name]} = NameAst,
  NameEnv = eval_ast(NameAst,Env),
  ClassConst = erruby_rb:ret_val(NameEnv),
  Class = case ClassConst of
    not_found -> {ok, NewClass} = erruby_class:new_named_class(Name),
           erruby_object:def_const(Self, Name, NewClass),
           NewClass;
      _ -> ClassConst
    end,
  case Body of
    undefined -> NameEnv;
    _ ->
      NewFrame = new_frame(NameEnv, Class),
      ResultFrame = eval_ast(Body,NewFrame),
      pop_frame(ResultFrame)
  end;

%TODO refactor with the one without SupperClass
eval_ast({ast, type, class, children,
          [NameAst,SuperClassAst,Body] = _Children}, #{ self := Self } = Env) ->
  {_,_,const,_,[_,Name]} = NameAst,
  NameEnv = eval_ast(NameAst,Env),
  ClassConst = erruby_rb:ret_val(NameEnv),
  SuperClassEnv = eval_ast(SuperClassAst,NameEnv),
  SuperClassConst = erruby_rb:ret_val(SuperClassEnv),
  %TODO should fail when SuperClassConst is not defined
  Class = case ClassConst of
            not_found -> {ok, NewClass} = erruby_class:new_class(SuperClassConst),
                   erruby_object:def_const(Self, Name, NewClass),
                   NewClass;
            _ -> ClassConst
          end,
  case Body of
    undefined -> SuperClassEnv;
    _ ->
      NewFrame = new_frame(SuperClassEnv, Class),
      ResultFrame = eval_ast(Body,NewFrame),
      pop_frame(ResultFrame)
  end;



eval_ast({ast, type, casgn, children, [ParentConstAst, Name, ValAst] }, Env) ->
  ParentConstEnv = parent_const_env(ParentConstAst, Env),
  ParentConst = erruby_rb:ret_val(ParentConstEnv),
  NewEnv = eval_ast(ValAst, ParentConstEnv),
  Val = erruby_rb:ret_val(NewEnv),
  erruby_object:def_const(ParentConst, Name, Val),
  NewEnv;

%TODO throw error when not_found
eval_ast({ast, type, const, children, [ParentConstAst, Name]}, Env) ->
  ParentConstEnv = parent_const_env(ParentConstAst, Env),
  ParentConst = erruby_rb:ret_val(ParentConstEnv),
  LocalConst = erruby_object:find_const(ParentConst, Name),
  Const = case LocalConst of
            not_found -> erruby_object:find_const(erruby_object:object_class(), Name);
            _ -> LocalConst
          end,
  erruby_rb:return(Const, Env);


eval_ast(Ast, Env) ->
  erruby_debug:debug_1("Unhandled eval~n",[]),
  print_ast(Ast),
  print_env(Env).


process_eval_method(Target,Method,Args,Env) ->
  Pid = spawn(?MODULE, eval_method_with_exit, [Target,Method,Args,Env, self()]),
  erruby_rb:return({future, Pid}, Env).

resolve_future({future, Pid}) ->
  receive
    {future, Pid, Result} ->
      print_env(Result),
      %erruby_debug:debug_tmp("resolve_future future ~p~n", [Result]),
      self() ! {future, Pid, Result},
      erruby_rb:ret_val(Result)
  end;

resolve_future(Any) ->
  print_env(Any),
  %erruby_debug:debug_tmp("resolve_future Any ~p~n", [Any]),
  Any.

eval_method_with_exit(Target,Method,Args,Env, Sender) ->
  try
    Result = eval_method(Target, Method, Args, Env),
    Respond = {future, self(),Result},
    Sender ! Respond
  catch
    _:E ->
      io:format("error ~p ~n", [E]),
      erlang:display(erlang:get_stacktrace())
  end,
  exit(normal).

eval_method(Target,Method, UnresolvedArgs, Env) when is_function(Method) ->
  NewFrame = new_frame(Env,Target),
  Args = lists:map(fun resolve_future/1, UnresolvedArgs),
  MethodArgs = [NewFrame | Args],
  ResultFrame = apply(Method, MethodArgs),
  pop_frame(ResultFrame);

eval_method(Target, {not_found, Name}, _, _) ->
  %TODO raise exception instead
  TargetClass = erruby_object:get_class(Target),
  TargetClassName = erruby_class:class_name(TargetClass),
  io:format("Undefined Method ~s for ~p~n", [Name, TargetClassName]),
  exit(known_error);

eval_method(Target,#{body := Body, args := ArgNamesAst} = _Method, Args, Env) ->
  NewFrame = new_frame(Env,Target),
  ArgNames = [ArgName || {ast, type, arg, children, [ArgName]} <- ArgNamesAst],
  NameWithArgs = lists:zip( ArgNames, Args),
  NewFrameWithArgs = lists:foldl(fun ({Name, Arg}, EnvAcc) ->  bind_lvar(Name, Arg, EnvAcc) end, NewFrame, NameWithArgs),
  pop_frame( eval_ast(Body, NewFrameWithArgs)).


bind_lvar(Name, Val, #{ lvars := LVars } = Env) ->
  Env#{ lvars := LVars#{ Name => Val }}.

receiver_or_self(undefined, Env) ->
  #{ self := Self } = Env,
  erruby_rb:return(Self, Env);
receiver_or_self(Receiver, Env) ->
  eval_ast(Receiver,Env).


new_string(String, Env) ->
  erruby_rb:return(String, Env).

new_symbol(Symbol, Env) ->
  erruby_rb:return(Symbol, Env).

new_frame(Env, Self) ->
  Env#{lvars => #{}, ret_val => not_exist, self => Self, prev_frame => Env}.

new_nil(Env) ->
  erruby_nil:new_nil(Env).

%TODO move to another place
find_prev_frame(Env) ->
  case maps:get(prev_frame, Env, no_prev_frame) of
    no_prev_frame -> throw(cant_find_block);
    Frame -> Frame
  end.

find_block(Env) ->
  case maps:get(block, Env) of
    not_exist -> find_block(find_prev_frame(Env));
    Block -> Block
  end.

parent_const_env(ParentConstAst, Env) ->
  case ParentConstAst of
    undefined -> erruby_rb:ret_self(Env);
    {ast, type, const, children, _} -> eval_ast(ParentConstAst, Env)
  end.

eval_args(ArgAsts, Env) ->
  [_ |Envs] = scanl(fun eval_ast/2, Env, ArgAsts),
  EvaledArgs = lists:map( fun erruby_rb:ret_val/1, Envs),
  LastEnv = case Envs of
              [] -> Env;
              _ -> lists:last(Envs)
            end,
  {EvaledArgs, LastEnv}.


yield(Env, Args)->
  Block = find_block(Env),
  #{body := Body, args := {ast, type, args, children, ArgNamesAst}} = Block,
  ArgNames = [ArgName || {ast, type, arg, children, [ArgName]} <- ArgNamesAst],
  NameWithArgs = lists:zip( ArgNames, Args),
  NewFrameWithArgs = lists:foldl(fun ({Name, Arg}, EnvAcc) ->  bind_lvar(Name, Arg, EnvAcc) end, Env, NameWithArgs),
  Result = eval_ast(Body,NewFrameWithArgs),
  Result.

pop_frame(Frame) ->
  #{ret_val := RetVal, prev_frame := PrevFrame} = Frame,
  erruby_rb:return(RetVal, PrevFrame).

default_env() ->
  {ok, _ObjectClass} = erruby_object:init_object_class(),
  {ok, _ClassClass} = erruby_class:init_class_class(),
  {ok, MainObject} = erruby_object:init_main_object(),
  init_builtin_class(),
  #{self => MainObject, lvars => #{}}.

init_builtin_class() ->
  ok = erruby_nil:install_nil_class(),
  ok = erruby_array:install_array_classes(),
  ok = erruby_integer:install_integer_class(),
  ok = erruby_fixnum:install_fixnum_class(),
  ok = erruby_boolean:install_boolean_classes(),
  ok = erruby_file:install_file_classes(),
  ok.


================================================
FILE: src/rb.hrl
================================================
-define(RB_DEBUG_T(T),erruby_debug:debug_tmp("~s:~p~n",[??T,T])).


================================================
FILE: test.rb
================================================
#!/usr/bin/env ruby
require 'optparse'

options = {}

OptionParser.new do |opts|
  opts.banner = "Usage: test.rb [options] test_case.rb"
  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    options[:verbose] = v
  end
  opts.on("-h", "--help", "Print this help") do
    puts(opts)
    exit 1
  end
end.parse!

verbose = options[:verbose]

def run_single_mri_test(fn, verbose:false)
  basename = File.basename(fn,'.rb')
  outname = "rb_test/sysrb_out/#{basename}.out"
  puts "testing #{fn}" if verbose
  system("ruby #{fn} > #{outname}")
  system("./erruby #{fn} | diff #{outname} -")
end

def run_mri_tests(verbose:)
  fail_case = []
  if ARGV[0] && File.exist?(ARGV[0])
    fn = ARGV[0]
    basename = File.basename(fn,'.rb')
    test_result = run_single_mri_test(fn, verbose: verbose)
    fail_case << fn unless test_result
  else
    Dir.glob("rb_test/*.rb") do |fn|
      basename = File.basename(fn,'.rb')
      next if basename.start_with?("_")
      unless run_single_mri_test(fn, verbose: verbose)
        fail_case << fn
      end
    end
  end
  fail_case
end

fail_case = run_mri_tests(verbose: verbose)

if fail_case.empty?
  puts "everything pass"
  exit 0
else
  fail_case.each do |fn|
      puts "test #{fn} failed"
  end
  exit 1
end
Download .txt
gitextract_mz0uvchy/

├── .gitignore
├── .gitmodules
├── .travis.yml
├── COPYING.txt
├── Gemfile
├── Guardfile
├── README.md
├── TODO.md
├── erruby
├── erruby_test/
│   ├── pipe_dot.rb
│   └── undefined_method.rb
├── pre_compile
├── rb_src/
│   └── erruby.rb
├── rb_test/
│   ├── _load.rb
│   ├── _require_relative.rb
│   ├── and_dot.rb
│   ├── array_class.rb
│   ├── boolean_class.rb
│   ├── class_cross_call.rb
│   ├── class_def.rb
│   ├── class_inherent.rb
│   ├── class_method.rb
│   ├── const_def.rb
│   ├── file.rb
│   ├── fixnum.rb
│   ├── global_var.rb
│   ├── hello_world.rb
│   ├── integer_class.rb
│   ├── ivar.rb
│   ├── load.rb
│   ├── method_def.rb
│   ├── nested_block.rb
│   ├── nested_const.rb
│   ├── nil_class.rb
│   ├── require_relative.rb
│   ├── sysrb_out/
│   │   ├── .gitkeep
│   │   ├── and_dot.out
│   │   ├── array_class.out
│   │   ├── boolean_class.out
│   │   ├── class_cross_call.out
│   │   ├── class_def.out
│   │   ├── class_inherent.out
│   │   ├── class_method.out
│   │   ├── const_def.out
│   │   ├── file.out
│   │   ├── fixnum.out
│   │   ├── global_var.out
│   │   ├── hello_world.out
│   │   ├── integer_class.out
│   │   ├── ivar.out
│   │   ├── load.out
│   │   ├── method_def.out
│   │   ├── nested_block.out
│   │   ├── nested_const.out
│   │   ├── nil_class.out
│   │   ├── require_relative.out
│   │   └── var_assign.out
│   └── var_assign.rb
├── rebar.config
├── src/
│   ├── erb.erl
│   ├── erruby.app.src
│   ├── erruby.erl
│   ├── erruby_app.erl
│   ├── erruby_array.erl
│   ├── erruby_boolean.erl
│   ├── erruby_class.erl
│   ├── erruby_debug.erl
│   ├── erruby_fixnum.erl
│   ├── erruby_integer.erl
│   ├── erruby_lib/
│   │   └── erruby_file.erl
│   ├── erruby_nil.erl
│   ├── erruby_object.erl
│   ├── erruby_rb.erl
│   ├── erruby_sup.erl
│   ├── erruby_vm.erl
│   └── rb.hrl
└── test.rb
Download .txt
SYMBOL INDEX (33 symbols across 11 files)

FILE: erruby_test/pipe_dot.rb
  function cal (line 1) | def cal
  function str (line 10) | def str

FILE: erruby_test/undefined_method.rb
  class Foo (line 1) | class Foo

FILE: rb_src/erruby.rb
  function parse (line 7) | def parse(src)
  function install_encoder (line 11) | def install_encoder

FILE: rb_test/class_cross_call.rb
  class Foo (line 1) | class Foo
    method msg (line 2) | def msg
  class Bar (line 7) | class Bar
    method say (line 8) | def say

FILE: rb_test/class_def.rb
  class Foo (line 1) | class Foo
    method message (line 2) | def message
    method hello (line 5) | def hello
  class Bar (line 9) | class Bar
    method message (line 10) | def message
    method hello (line 13) | def hello

FILE: rb_test/class_inherent.rb
  class Foo (line 1) | class Foo
    method to_s (line 2) | def to_s
  class Bar (line 7) | class Bar < Foo
  class Alice (line 10) | class Alice < Bar
    method to_s (line 11) | def to_s

FILE: rb_test/class_method.rb
  class Foo (line 1) | class Foo
    method bar (line 2) | def self.bar

FILE: rb_test/ivar.rb
  class Foo (line 1) | class Foo
    method setup (line 2) | def setup
    method ivar (line 5) | def ivar

FILE: rb_test/method_def.rb
  function hello_world_method_0 (line 2) | def hello_world_method_0
  function hello_world_method_1 (line 6) | def hello_world_method_1(name)
  function hello_world_method_block (line 11) | def hello_world_method_block(n)
  function yield_with_arg (line 16) | def yield_with_arg(s,x)

FILE: rb_test/nested_const.rb
  class Foo (line 1) | class Foo
    class Alice (line 3) | class Alice

FILE: test.rb
  function run_single_mri_test (line 19) | def run_single_mri_test(fn, verbose:false)
  function run_mri_tests (line 27) | def run_mri_tests(verbose:)
Condensed preview — 77 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (71K chars).
[
  {
    "path": ".gitignore",
    "chars": 114,
    "preview": ".eunit\ndeps\n*.o\n*.beam\n*.plt\n.*-*\nerl_crash.dump\nebin\nrel/example_project\n.concrete/DEV_MODE\n.rebar\nrb_test/*.out\n"
  },
  {
    "path": ".gitmodules",
    "chars": 183,
    "preview": "[submodule \"ext/ruby/spec\"]\n\tpath = ext/ruby/spec\n\turl = https://github.com/ruby/spec.git\n[submodule \"ext/ruby/mspec\"]\n\t"
  },
  {
    "path": ".travis.yml",
    "chars": 188,
    "preview": "language: erlang\notp_release:\n   - 18.0\n   - 18.1\nbefore_script:\n        - rvm install 2.3.1\n        - rvm use 2.3.1\n   "
  },
  {
    "path": "COPYING.txt",
    "chars": 1081,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Yu Hsiang Lin.\n\nPermission is hereby granted, free of charge, to any person ob"
  },
  {
    "path": "Gemfile",
    "chars": 252,
    "preview": "ruby \"2.3.1\"\nsource \"https://rubygems.org\"\n\ngem 'erlport-ast_mapping', github: \"johnlinvc/erlport-ast_mapping\", branch: "
  },
  {
    "path": "Guardfile",
    "chars": 813,
    "preview": "# A sample Guardfile\n# More info at https://github.com/guard/guard#readme\n\n## Uncomment and set this to only include dir"
  },
  {
    "path": "README.md",
    "chars": 2197,
    "preview": "# ErRuby - an implementation of the Ruby language on Erlang\n[![Build Status](https://travis-ci.org/johnlinvc/erruby.svg?"
  },
  {
    "path": "TODO.md",
    "chars": 231,
    "preview": "restructure to standard erlang style\ndesign the object system of ruby in erlang\n- everything is object, just like ruby\n-"
  },
  {
    "path": "erruby",
    "chars": 235,
    "preview": "#!/bin/bash\npushd `dirname $0` > /dev/null\nexport ERRUBY_PATH=`pwd`\npopd > /dev/null\nif [[ $* == *\"-f\"* ]]\nthen\nescript "
  },
  {
    "path": "erruby_test/pipe_dot.rb",
    "chars": 128,
    "preview": "def cal\n  1 + 1\nend\nx = self|.cal\nputs(x.to_s)\nputs(x.to_s)\nputs(1|.to_s)\n1|.to_s\n\ndef str\n  \"hello future\"\nend\nputs(sel"
  },
  {
    "path": "erruby_test/undefined_method.rb",
    "chars": 32,
    "preview": "class Foo\nend\nf = Foo.new\nf.bar\n"
  },
  {
    "path": "pre_compile",
    "chars": 139,
    "preview": "#!/bin/bash\npushd ./deps/erlport > /dev/null\nmake > /dev/null\npopd > /dev/null\n\npushd ./deps/plists > /dev/null\n./make.s"
  },
  {
    "path": "rb_src/erruby.rb",
    "chars": 275,
    "preview": "#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'bundler/setup'\nrequire 'erlport/ast_mapping'\n\ndef parse(src)\n  ErlPort:"
  },
  {
    "path": "rb_test/_load.rb",
    "chars": 14,
    "preview": "puts \"loaded\"\n"
  },
  {
    "path": "rb_test/_require_relative.rb",
    "chars": 21,
    "preview": "puts \"required file\"\n"
  },
  {
    "path": "rb_test/and_dot.rb",
    "chars": 36,
    "preview": "puts(1&.to_s)\nnil&.not_exist_method\n"
  },
  {
    "path": "rb_test/array_class.rb",
    "chars": 804,
    "preview": "[true, false]\n[nil, nil]\n[\"a\",\"b\",\"c\"]\n[1,2].map{|x| puts(x.to_s)}\nputs \"mul\"\n([1,2,3] * 3).map{|x| puts x.to_s}\n#a = 0\n"
  },
  {
    "path": "rb_test/boolean_class.rb",
    "chars": 551,
    "preview": "puts (true).to_s\nputs (false).to_s\n\nputs (!true).to_s\nputs (!false).to_s\n\nputs (true == false).to_s\nputs (true == true)."
  },
  {
    "path": "rb_test/class_cross_call.rb",
    "chars": 107,
    "preview": "class Foo\n  def msg\n    \"hello\"\n  end\nend\n\nclass Bar\n  def say\n    puts Foo.new.msg\n  end\nend\n\nBar.new.say\n"
  },
  {
    "path": "rb_test/class_def.rb",
    "chars": 220,
    "preview": "class Foo\n  def message\n    \"hello world\"\n  end\n  def hello\n    puts message\n  end\nend\nclass Bar\n  def message\n    \"hell"
  },
  {
    "path": "rb_test/class_inherent.rb",
    "chars": 205,
    "preview": "class Foo\n  def to_s\n    \"foo\"\n  end\nend\n\nclass Bar < Foo\nend\n\nclass Alice < Bar\n  def to_s\n    \"i'm alice\"\n  end\nend\n\np"
  },
  {
    "path": "rb_test/class_method.rb",
    "chars": 59,
    "preview": "class Foo\n  def self.bar\n    puts \"bar\"\n  end\nend\n\nFoo.bar\n"
  },
  {
    "path": "rb_test/const_def.rb",
    "chars": 45,
    "preview": "HELLO_CONST = \"hello const\"\nputs HELLO_CONST\n"
  },
  {
    "path": "rb_test/file.rb",
    "chars": 73,
    "preview": "puts __FILE__\nputs File.expand_path('../../../erruby/rb_test', __FILE__)\n"
  },
  {
    "path": "rb_test/fixnum.rb",
    "chars": 569,
    "preview": "puts 1.to_s\nputs 2.to_s\nputs -1.to_s\nputs 0.to_s\nputs 576460752303423488.to_s\nputs -576460752303423489.to_s\nputs (1+1).t"
  },
  {
    "path": "rb_test/global_var.rb",
    "chars": 32,
    "preview": "$Gvar = \"hello gvar\"\nputs $Gvar\n"
  },
  {
    "path": "rb_test/hello_world.rb",
    "chars": 19,
    "preview": "puts \"hello world\"\n"
  },
  {
    "path": "rb_test/integer_class.rb",
    "chars": 1035,
    "preview": "puts 5.to_i.to_s\nputs 5.to_int.to_s\nputs 5.floor.to_s\nputs 5.ceil.to_s\nputs 5.truncate.to_s\nputs 5.numerator.to_s\nputs 5"
  },
  {
    "path": "rb_test/ivar.rb",
    "chars": 117,
    "preview": "class Foo\n  def setup\n    @ivar = \"hello\"\n  end\n  def ivar\n    @ivar\n  end\nend\nfoo = Foo.new\nfoo.setup\nputs foo.ivar\n"
  },
  {
    "path": "rb_test/load.rb",
    "chars": 48,
    "preview": "load 'rb_test/_load.rb'\nload 'rb_test/_load.rb'\n"
  },
  {
    "path": "rb_test/method_def.rb",
    "chars": 513,
    "preview": "str = \"not this\"\ndef hello_world_method_0\n  \"hello world no arg\"\nend\n\ndef hello_world_method_1(name)\n  str = name\n  str\n"
  },
  {
    "path": "rb_test/nested_block.rb",
    "chars": 72,
    "preview": "3.times do |i|\n  puts i.to_s\n  4.times do |j|\n    puts j.to_s\n  end\nend\n"
  },
  {
    "path": "rb_test/nested_const.rb",
    "chars": 168,
    "preview": "class Foo\n  Bar = \"hello nested\"\n  class Alice\n  end\nend\nBob = \"outside bob\"\nputs \"Foo::Bar\"\nputs Foo::Bar\nFoo::Alice::B"
  },
  {
    "path": "rb_test/nil_class.rb",
    "chars": 166,
    "preview": "nil\n\nnil & nil\nnil & true\nnil & false\nnil & \"\"\n\nnil ^ nil\nnil ^ true\nnil ^ false\nnil ^ \"\"\n\nnil | nil\nnil | true\nnil | fa"
  },
  {
    "path": "rb_test/require_relative.rb",
    "chars": 74,
    "preview": "require_relative \"_require_relative\"\nrequire_relative \"_require_relative\"\n"
  },
  {
    "path": "rb_test/sysrb_out/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "rb_test/sysrb_out/and_dot.out",
    "chars": 2,
    "preview": "1\n"
  },
  {
    "path": "rb_test/sysrb_out/array_class.out",
    "chars": 71,
    "preview": "1\n2\nmul\n1\n2\n3\n1\n2\n3\n1\n2\n3\nb\na\nc\nfalse\ntrue\n3\n3\nd\nf\nd\nf\na\na\nb\n4\n2\n5\n0\n0\n"
  },
  {
    "path": "rb_test/sysrb_out/boolean_class.out",
    "chars": 132,
    "preview": "true\nfalse\nfalse\ntrue\nfalse\ntrue\nfalse\ntrue\ntrue\nfalse\nfalse\nfalse\nfalse\ntrue\ntrue\nfalse\ntrue\ntrue\ntrue\nfalse\ntrue\nfalse"
  },
  {
    "path": "rb_test/sysrb_out/class_cross_call.out",
    "chars": 6,
    "preview": "hello\n"
  },
  {
    "path": "rb_test/sysrb_out/class_def.out",
    "chars": 22,
    "preview": "hello world\nhello bar\n"
  },
  {
    "path": "rb_test/sysrb_out/class_inherent.out",
    "chars": 18,
    "preview": "foo\nfoo\ni'm alice\n"
  },
  {
    "path": "rb_test/sysrb_out/class_method.out",
    "chars": 4,
    "preview": "bar\n"
  },
  {
    "path": "rb_test/sysrb_out/const_def.out",
    "chars": 12,
    "preview": "hello const\n"
  },
  {
    "path": "rb_test/sysrb_out/file.out",
    "chars": 61,
    "preview": "rb_test/file.rb\n/Users/johnlinvc/Projs/erruby/erruby/rb_test\n"
  },
  {
    "path": "rb_test/sysrb_out/fixnum.out",
    "chars": 154,
    "preview": "1\n2\n-1\n0\n576460752303423488\n-576460752303423489\n2\n1\n-1\n1\n8\n1\n16\ntrue\nfalse\nfalse\ntrue\ntrue\nfalse\nfalse\nfalse\ntrue\nfalse\n"
  },
  {
    "path": "rb_test/sysrb_out/global_var.out",
    "chars": 11,
    "preview": "hello gvar\n"
  },
  {
    "path": "rb_test/sysrb_out/hello_world.out",
    "chars": 12,
    "preview": "hello world\n"
  },
  {
    "path": "rb_test/sysrb_out/integer_class.out",
    "chars": 173,
    "preview": "5\n5\n5\n5\n5\n5\n5\n1\ntrue\nfalse\nfalse\ntrue\n2\n2\n2\n8\n0\n6\n2\n24\n24\n0\n0\ntrue\n2\n0\n2\n0\ntimes\n0\n1\n2\n3\n4\n5\n0\n-5\nupto\n-2\n-1\n0\n1\n2\n-2\n2\n"
  },
  {
    "path": "rb_test/sysrb_out/ivar.out",
    "chars": 6,
    "preview": "hello\n"
  },
  {
    "path": "rb_test/sysrb_out/load.out",
    "chars": 14,
    "preview": "loaded\nloaded\n"
  },
  {
    "path": "rb_test/sysrb_out/method_def.out",
    "chars": 68,
    "preview": "yield with\narg\nhello world no arg\nmy name is erruby\narg\nhello block\n"
  },
  {
    "path": "rb_test/sysrb_out/nested_block.out",
    "chars": 30,
    "preview": "0\n0\n1\n2\n3\n1\n0\n1\n2\n3\n2\n0\n1\n2\n3\n"
  },
  {
    "path": "rb_test/sysrb_out/nested_const.out",
    "chars": 45,
    "preview": "Foo::Bar\nhello nested\ninside Bob\noutside bob\n"
  },
  {
    "path": "rb_test/sysrb_out/nil_class.out",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "rb_test/sysrb_out/require_relative.out",
    "chars": 14,
    "preview": "required file\n"
  },
  {
    "path": "rb_test/sysrb_out/var_assign.out",
    "chars": 12,
    "preview": "hello world\n"
  },
  {
    "path": "rb_test/var_assign.rb",
    "chars": 33,
    "preview": "hello = \"hello world\"\nputs hello\n"
  },
  {
    "path": "rebar.config",
    "chars": 361,
    "preview": "{deps, [\n        {erlport, \".*\", {git, \"https://github.com/johnlinvc/erlport.git\", {branch, \"erruby\"}}, [raw]},\n        "
  },
  {
    "path": "src/erb.erl",
    "chars": 165,
    "preview": "-module(erb).\n-export([find_or_init_class/2]).\n\nfind_or_init_class(Name, InitFun) ->\n  case whereis(Name) of\n    undefin"
  },
  {
    "path": "src/erruby.app.src",
    "chars": 216,
    "preview": "{application, erruby,\n [\n  {description, \"\"},\n  {vsn, \"1\"},\n  {registered, []},\n  {applications, [\n                  ker"
  },
  {
    "path": "src/erruby.erl",
    "chars": 2562,
    "preview": "-module(erruby).\n-include(\"rb.hrl\").\n-export([eruby/1, start_ruby/0, stop_ruby/1, parse_ast/2, main/1]).\n\nopt_spec_list("
  },
  {
    "path": "src/erruby_app.erl",
    "chars": 357,
    "preview": "-module(erruby_app).\n\n-behaviour(application).\n\n%% Application callbacks\n-export([start/2, stop/1]).\n\n%% ==============="
  },
  {
    "path": "src/erruby_array.erl",
    "chars": 5603,
    "preview": "-module(erruby_array).\n-include(\"rb.hrl\").\n-export([install_array_classes/0, new_array/2, new_array/1]).\n-export([array_"
  },
  {
    "path": "src/erruby_boolean.erl",
    "chars": 2955,
    "preview": "-module(erruby_boolean).\n-export([install_boolean_classes/0,new_true/1,new_false/1,true_instance/0,false_instance/0]).\n%"
  },
  {
    "path": "src/erruby_class.erl",
    "chars": 1324,
    "preview": "-module(erruby_class).\n-export([new_class/0, new_named_class/1, new_class/1, install_class_class_methods/0, init_class_c"
  },
  {
    "path": "src/erruby_debug.erl",
    "chars": 1754,
    "preview": "-module(erruby_debug).\n-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).\n-expo"
  },
  {
    "path": "src/erruby_fixnum.erl",
    "chars": 3585,
    "preview": "-module(erruby_fixnum).\n-export([install_fixnum_class/0, new_fixnum/2, fix_to_int/1]).\n\n%%\n%% @TODO inherent from intege"
  },
  {
    "path": "src/erruby_integer.erl",
    "chars": 4345,
    "preview": "-module(erruby_integer).\n-export([install_integer_class/0]).\n\ninstall_integer_class() ->\n  {ok, IntegerClass} = erruby_c"
  },
  {
    "path": "src/erruby_lib/erruby_file.erl",
    "chars": 1154,
    "preview": "-module(erruby_file).\n-include(\"../rb.hrl\").\n-export([install_file_classes/0]).\n\ninstall_file_classes() ->\n  {ok, FileCl"
  },
  {
    "path": "src/erruby_nil.erl",
    "chars": 1229,
    "preview": "-module(erruby_nil).\n-export([new_nil/1, install_nil_class/0, nil_instance/0]).\n\ninstall_nil_class() ->\n  {ok, NilClass}"
  },
  {
    "path": "src/erruby_object.erl",
    "chars": 12962,
    "preview": "-module(erruby_object).\n-include(\"rb.hrl\").\n-behavior(gen_server).\n-export([init/1, terminate/2, code_change/3, handle_c"
  },
  {
    "path": "src/erruby_rb.erl",
    "chars": 257,
    "preview": "%%% TODO move general runtime api to here\n-module(erruby_rb).\n-export([ret_self/1,ret_val/1,return/2]).\n\nret_self( #{sel"
  },
  {
    "path": "src/erruby_sup.erl",
    "chars": 712,
    "preview": "-module(erruby_sup).\n\n-behaviour(supervisor).\n\n%% API\n-export([start_link/0]).\n\n%% Supervisor callbacks\n-export([init/1]"
  },
  {
    "path": "src/erruby_vm.erl",
    "chars": 12075,
    "preview": "-module(erruby_vm).\n-include(\"rb.hrl\").\n-export([eval_file/2, scanl/3]).\n-export([new_nil/1, new_string/2]).\n-export([ev"
  },
  {
    "path": "src/rb.hrl",
    "chars": 66,
    "preview": "-define(RB_DEBUG_T(T),erruby_debug:debug_tmp(\"~s:~p~n\",[??T,T])).\n"
  },
  {
    "path": "test.rb",
    "chars": 1259,
    "preview": "#!/usr/bin/env ruby\nrequire 'optparse'\n\noptions = {}\n\nOptionParser.new do |opts|\n  opts.banner = \"Usage: test.rb [option"
  }
]

About this extraction

This page contains the full source code of the johnlinvc/erruby GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 77 files (63.1 KB), approximately 21.1k tokens, and a symbol index with 33 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!