opal 0.3.10 → 0.3.11
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +47 -46
- data/lib/opal.rb +11 -3
- data/lib/opal/builder.rb +4 -46
- data/lib/opal/bundle.rb +11 -25
- data/lib/opal/command.rb +101 -22
- data/lib/opal/context.rb +16 -50
- data/lib/opal/lexer.rb +21 -2
- data/lib/opal/nodes.rb +134 -20
- data/lib/opal/parser.rb +7 -7
- data/lib/opal/parser.y +7 -7
- data/lib/opal/rake/bundle_task.rb +24 -23
- data/lib/opal/version.rb +3 -0
- data/opal-parser.js +8343 -0
- data/opal.js +5685 -0
- data/stdlib/dev.rb +6 -4
- data/templates/init/Rakefile +7 -0
- data/templates/init/index.html +17 -0
- data/templates/init/lib/__NAME__.rb +2 -0
- metadata +9 -32
- data/corelib/array.rb +0 -1424
- data/corelib/boolean.rb +0 -20
- data/corelib/class.rb +0 -58
- data/corelib/core.rb +0 -66
- data/corelib/dir.rb +0 -22
- data/corelib/enumerable.rb +0 -33
- data/corelib/error.rb +0 -19
- data/corelib/file.rb +0 -60
- data/corelib/hash.rb +0 -729
- data/corelib/kernel.rb +0 -251
- data/corelib/load_order +0 -21
- data/corelib/match_data.rb +0 -33
- data/corelib/module.rb +0 -101
- data/corelib/nil_class.rb +0 -54
- data/corelib/numeric.rb +0 -352
- data/corelib/object.rb +0 -37
- data/corelib/proc.rb +0 -55
- data/corelib/range.rb +0 -27
- data/corelib/regexp.rb +0 -69
- data/corelib/string.rb +0 -300
- data/corelib/top_self.rb +0 -8
- data/runtime/class.js +0 -386
- data/runtime/fs.js +0 -199
- data/runtime/init.js +0 -556
- data/runtime/loader.js +0 -330
- data/runtime/module.js +0 -103
- data/runtime/post.js +0 -10
- data/runtime/pre.js +0 -7
- data/runtime/runtime.js +0 -345
data/README.md
CHANGED
@@ -17,16 +17,10 @@ Opal does not aim to be 100% comaptible with other ruby implementations,
|
|
17
17
|
but does so where the generated code can be efficient on all modern web
|
18
18
|
browsers - including older versions of IE and mobile devices.
|
19
19
|
|
20
|
-
|
20
|
+
Installing opal
|
21
21
|
----------
|
22
22
|
|
23
|
-
|
24
|
-
directly in the web browser or with rbp - a new package manager designed
|
25
|
-
for opal but usable for any ruby project.
|
26
|
-
|
27
|
-
### Using the gem
|
28
|
-
|
29
|
-
Install via ruby gems:
|
23
|
+
Install the gem:
|
30
24
|
|
31
25
|
```
|
32
26
|
$ gem install opal
|
@@ -38,66 +32,73 @@ The `opal` command should then be available. To run the simple repl use:
|
|
38
32
|
opal irb
|
39
33
|
```
|
40
34
|
|
41
|
-
|
42
|
-
|
35
|
+
Usage
|
36
|
+
-----
|
37
|
+
|
38
|
+
The quickest way to get opal running is to use the project generator.
|
39
|
+
Simply run the command:
|
43
40
|
|
44
41
|
```
|
45
|
-
|
46
|
-
$ cd opal
|
47
|
-
$ bin/opal
|
42
|
+
opal init my_project
|
48
43
|
```
|
49
44
|
|
50
|
-
|
45
|
+
replacing "my_project" with any name. This will make a "my_project"
|
46
|
+
directory with a Rakefile, html document and libs needed for running
|
47
|
+
opal in the browser.
|
51
48
|
|
52
|
-
|
53
|
-
package.yml file to add the following dependency:
|
49
|
+
### Using opal in the browser
|
54
50
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
51
|
+
Opal runs directly in the browser, and is distributed as two files,
|
52
|
+
`opal.js` and `opal-parser.js`. To just run precompiled code, just the
|
53
|
+
`opal.js` runtime is required which includes the runtime and opals
|
54
|
+
implementation of the ruby core library (pre compiled).
|
55
|
+
|
56
|
+
To evaluate ruby code directly in the browser, `opal-parser.js` is also
|
57
|
+
required which will also load any ruby code found in script tags.
|
60
58
|
|
61
|
-
|
59
|
+
### Bundle
|
60
|
+
|
61
|
+
The Rakefile has a task to build your ruby project, so just run:
|
62
62
|
|
63
63
|
```
|
64
|
-
|
64
|
+
rake bundle
|
65
65
|
```
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
directly on the commandline. If you are just compiling ruby then just
|
70
|
-
the opal package is sufficient.
|
67
|
+
Open `index.html` in a browser, and now it should run. Edit, build and
|
68
|
+
run to suit.
|
71
69
|
|
72
|
-
|
73
|
-
|
70
|
+
Project structure
|
71
|
+
-----------------
|
74
72
|
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
This repo contains the code for the opal gem as well as the opal core
|
74
|
+
library and runtime. Files inside `bin/` and `lib/` are the files that
|
75
|
+
are used as part of the gem and run directly on your ruby environment.
|
78
76
|
|
79
|
-
|
80
|
-
|
81
|
-
|
77
|
+
`corelib/` contains opal's core library implementation and is not used
|
78
|
+
directly by the gem. These files are precompiled during development
|
79
|
+
ready to be used in the gem or in a browser.
|
82
80
|
|
83
|
-
|
84
|
-
|
81
|
+
`runtime/` contains opal's runtime written in javascript. It is not used
|
82
|
+
directly by the gem, but is built ready to use in the js contexts that
|
83
|
+
opal runs.
|
85
84
|
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
`stdlib/` contains the stdlib files that opal comes packaged with. The
|
86
|
+
gem does use these, but only as required. Opal does not include the full
|
87
|
+
opal stdlib, and some parts are actually written in javascript for
|
88
|
+
optimal performance. These can be `require()` at runtime.
|
89
89
|
|
90
|
-
|
90
|
+
`opal.js` and `opal-parser.js` are included in the gem, but not the
|
91
|
+
source repo. They are the latest built versions of opal and its parser
|
92
|
+
which are built before the gem is published.
|
91
93
|
|
92
94
|
Differences from ruby
|
93
95
|
---------------------
|
94
96
|
|
95
|
-
###
|
97
|
+
### Optional method\_missing
|
96
98
|
|
97
|
-
To optimize method dispatch, `method_missing` is
|
98
|
-
|
99
|
-
|
100
|
-
production code.
|
99
|
+
To optimize method dispatch, `method_missing` is, by default, turned off
|
100
|
+
in opal. It can easily be enabled by passing `:method_missing => true`
|
101
|
+
in the parser options.
|
101
102
|
|
102
103
|
### Immutable strings and removed symbols
|
103
104
|
|
data/lib/opal.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "opal/parser"
|
2
|
+
require "opal/builder"
|
3
|
+
require "opal/context"
|
4
|
+
require "opal/version"
|
4
5
|
|
5
6
|
# Opal is a set of build tools and runtime utilies for compiling ruby
|
6
7
|
# source code into javascript. Opal can use therubyracer to provide a
|
7
8
|
# ruby context for evaluating the generated javascript against the
|
8
9
|
# provided runtime.
|
9
10
|
module Opal
|
11
|
+
# Root opal directory (root of gem)
|
10
12
|
OPAL_DIR = File.expand_path('../..', __FILE__)
|
13
|
+
|
14
|
+
# Full path to our opal.js runtime file
|
15
|
+
OPAL_JS_PATH = File.join OPAL_DIR, "opal.js"
|
16
|
+
|
17
|
+
# Full path to our opal-parser.js parser file
|
18
|
+
OPAL_PARSER_JS_PATH = File.join OPAL_DIR, "opal-parser.js"
|
11
19
|
end
|
12
20
|
|
data/lib/opal/builder.rb
CHANGED
@@ -1,21 +1,17 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'opal/parser'
|
3
|
+
require 'opal/version'
|
3
4
|
|
4
5
|
module Opal
|
5
|
-
|
6
6
|
# The Builder class is used for building single ruby sources, or
|
7
7
|
# building the core library ready for the browser/v8 context. It
|
8
|
-
# is not used directly for building
|
8
|
+
# is not used directly for building gem.
|
9
9
|
class Builder
|
10
10
|
|
11
11
|
OPAL_PATH = File.expand_path(File.join('..', '..', '..'), __FILE__)
|
12
12
|
|
13
13
|
STDLIB_PATH = File.join OPAL_PATH, 'stdlib'
|
14
14
|
|
15
|
-
RUNTIME_PATH = File.join OPAL_PATH, 'runtime'
|
16
|
-
|
17
|
-
CORE_PATH = File.join OPAL_PATH, 'corelib'
|
18
|
-
|
19
15
|
def initialize
|
20
16
|
@parser = Parser.new
|
21
17
|
end
|
@@ -43,7 +39,7 @@ module Opal
|
|
43
39
|
# relative_path = relative_path.sub(/\.rb/, '.js') if ext == '.rb'
|
44
40
|
content = compile_source full_path
|
45
41
|
|
46
|
-
"opal.lib('#{relative_path}
|
42
|
+
"opal.lib('#{relative_path}', #{content});\n"
|
47
43
|
end
|
48
44
|
|
49
45
|
# Simply compile the given source code at the given path. This is
|
@@ -61,51 +57,13 @@ module Opal
|
|
61
57
|
"function($rb, self, __FILE__) { #{src} }"
|
62
58
|
|
63
59
|
when '.rb'
|
64
|
-
|
65
|
-
"function($rb, self, __FILE__) { #{src} }"
|
60
|
+
return parse src
|
66
61
|
|
67
62
|
else
|
68
63
|
raise "Bad file type for wrapping. Must be ruby or javascript"
|
69
64
|
end
|
70
65
|
end
|
71
66
|
|
72
|
-
# Builds core opal runtime + core libs, and returns as a string.
|
73
|
-
# This can then just be used directly by any compiled code. The
|
74
|
-
# core lib is then auto loaded so it is ready for running.
|
75
|
-
def build_core
|
76
|
-
code = ''
|
77
|
-
|
78
|
-
%w[pre runtime init class module fs loader].each do |f|
|
79
|
-
code += File.read(File.join RUNTIME_PATH, f + '.js')
|
80
|
-
end
|
81
|
-
|
82
|
-
order = File.read(File.join(CORE_PATH, 'load_order')).strip.split
|
83
|
-
|
84
|
-
core = order.map do |o|
|
85
|
-
File.read File.join(CORE_PATH, o + '.rb')
|
86
|
-
end
|
87
|
-
|
88
|
-
code += "var core_lib = #{parse core.join};"
|
89
|
-
|
90
|
-
code + File.read(File.join RUNTIME_PATH, 'post.js')
|
91
|
-
end
|
92
|
-
|
93
|
-
# Builds the opal parser and dev.rb file, and returns as a string.
|
94
|
-
def build_parser
|
95
|
-
code = ''
|
96
|
-
|
97
|
-
%w[opal/nodes opal/lexer opal/parser].each do |src|
|
98
|
-
full = File.join OPAL_PATH, 'lib', src + '.rb'
|
99
|
-
compiled = compile_source full
|
100
|
-
code += "opal.lib('#{src}.rb', #{compiled});"
|
101
|
-
end
|
102
|
-
|
103
|
-
code += build_stdlib 'racc/parser', 'strscan', 'dev'
|
104
|
-
code += "opal.require('dev');"
|
105
|
-
|
106
|
-
code
|
107
|
-
end
|
108
|
-
|
109
67
|
# Build the given sources from the standard library. These can be
|
110
68
|
# globs. Returns a string of all content.
|
111
69
|
def build_stdlib(*files)
|
data/lib/opal/bundle.rb
CHANGED
@@ -1,41 +1,27 @@
|
|
1
1
|
require 'opal/builder'
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'rbp/package'
|
5
|
-
rescue LoadError
|
6
|
-
abort "You need to install rbp. `gem install rbp`."
|
7
|
-
end
|
8
|
-
|
9
3
|
module Opal
|
10
|
-
# Takes a package and builds it ready for the browser
|
11
4
|
class Bundle
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :version
|
15
7
|
attr_accessor :options
|
16
8
|
|
17
|
-
def initialize
|
18
|
-
@
|
19
|
-
@builder = Builder.new
|
9
|
+
def initialize
|
10
|
+
@builder = Builder.new
|
20
11
|
@options = {}
|
21
12
|
end
|
22
13
|
|
23
|
-
# Simple build - returns a string which can be written to a file
|
24
|
-
# FIXME: hardcoded lib directory to './lib'
|
25
14
|
def build
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
path
|
30
|
-
code = @builder.parse File.read(path), options
|
31
|
-
|
32
|
-
"\"#{lib}\": #{code}"
|
15
|
+
lib_files = Dir["{lib}/**/*.rb"].map do |lib|
|
16
|
+
code = @builder.parse File.read(lib), options
|
17
|
+
path = lib[4, lib.length - 7]
|
18
|
+
"\"#{path}\": #{code}"
|
33
19
|
end
|
34
20
|
|
35
21
|
bundle = []
|
36
|
-
bundle << %[opal.
|
37
|
-
bundle << %[ name: "#{@
|
38
|
-
bundle << %[ version: "#{@
|
22
|
+
bundle << %[opal.gem({\n]
|
23
|
+
bundle << %[ name: "#{@name}",\n]
|
24
|
+
bundle << %[ version: "#{@version}",\n]
|
39
25
|
bundle << %[ libs: {\n]
|
40
26
|
bundle << %[ #{lib_files.join ",\n "}\n]
|
41
27
|
bundle << %[ }\n]
|
data/lib/opal/command.rb
CHANGED
@@ -1,15 +1,20 @@
|
|
1
|
-
|
1
|
+
require 'optparse'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'opal/builder'
|
2
4
|
|
5
|
+
module Opal
|
6
|
+
# Command runner. When using the `opal` bin file, this class is used to
|
7
|
+
# delegate commands based on the options passed from the command line.
|
3
8
|
class Command
|
4
9
|
|
5
10
|
# Valid command line arguments
|
6
|
-
COMMANDS = [:help, :irb, :compile, :bundle, :exec, :eval, :install]
|
11
|
+
COMMANDS = [:help, :irb, :compile, :bundle, :exec, :eval, :install, :init]
|
7
12
|
|
8
13
|
def initialize(args)
|
9
14
|
command = args.shift
|
10
15
|
|
11
16
|
if command and COMMANDS.include?(command.to_sym)
|
12
|
-
__send__ command.to_sym
|
17
|
+
__send__ command.to_sym
|
13
18
|
elsif command and File.exists? command
|
14
19
|
eval command
|
15
20
|
else
|
@@ -17,36 +22,113 @@ module Opal
|
|
17
22
|
end
|
18
23
|
end
|
19
24
|
|
25
|
+
# Initialize a project either in current directory, or directory
|
26
|
+
# specified in ARGV.
|
27
|
+
def init
|
28
|
+
path = File.expand_path(ARGV.first || Dir.getwd)
|
29
|
+
base = File.basename(path)
|
30
|
+
template = File.join(OPAL_DIR, "templates", "init")
|
31
|
+
|
32
|
+
Dir.chdir(template) do
|
33
|
+
Dir["**/*"].each do |f|
|
34
|
+
next if File.directory? f
|
35
|
+
|
36
|
+
full = File.expand_path f, template
|
37
|
+
dest = File.join path, f.sub(/__NAME__/, base)
|
38
|
+
|
39
|
+
if File.exists? dest
|
40
|
+
puts "Skipping #{f}"
|
41
|
+
next
|
42
|
+
end
|
43
|
+
|
44
|
+
FileUtils.mkdir_p File.dirname(dest)
|
45
|
+
|
46
|
+
File.open(dest, 'w+') do |o|
|
47
|
+
o.write File.read(full).gsub(/__NAME__/, base)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
FileUtils.mkdir_p File.join(path, "js")
|
53
|
+
|
54
|
+
%w[opal.js opal-parser.js].each do |src|
|
55
|
+
File.open(File.join(path, "js", src), "w+") do |o|
|
56
|
+
o.write File.read(File.join(OPAL_DIR, src))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
20
61
|
def help
|
21
62
|
puts "need to print help"
|
22
63
|
end
|
23
64
|
|
24
|
-
#
|
25
|
-
|
26
|
-
|
65
|
+
# Starts an irb session using an inline v8 context. Commands can be
|
66
|
+
# entered just like IRB. Use Ctrl-C or type `exit` to quit.
|
67
|
+
def irb(*)
|
68
|
+
ctx = Context.new :method_missing => true,
|
69
|
+
:overload_arithmetic => true,
|
70
|
+
:overload_comparison => true,
|
71
|
+
:overload_bitwise => true
|
27
72
|
ctx.start_repl
|
28
73
|
end
|
29
74
|
|
30
|
-
|
31
|
-
|
75
|
+
# If the given arg exists as a file, then the source code is compiled
|
76
|
+
# and then run through a javascript context and the result printed out.
|
77
|
+
#
|
78
|
+
# If the arg isn't a file, then it is assumed to be raw ruby code and it
|
79
|
+
# is compiled and run directly with the result being printed out.
|
80
|
+
#
|
81
|
+
# Usage:
|
82
|
+
#
|
83
|
+
# opal eval path/to/some/file.rb
|
84
|
+
# # => "some result"
|
85
|
+
#
|
86
|
+
# opal eval "1.class"
|
87
|
+
# # => Numeric
|
88
|
+
#
|
89
|
+
# @param [String] code path or ruby code to eval
|
90
|
+
def eval(code = nil, *)
|
91
|
+
abort "Usage: opal eval [Ruby code or file path]" unless code
|
92
|
+
|
93
|
+
if File.exists? code
|
94
|
+
code = Parser.new.parse File.read(code)
|
95
|
+
end
|
32
96
|
|
33
|
-
|
97
|
+
context = Context.new :method_missing => true,
|
98
|
+
:overload_arithmetic => true,
|
99
|
+
:overload_comparison => true,
|
100
|
+
:overload_bitwise => true
|
34
101
|
|
35
|
-
|
36
|
-
ctx.require_file File.expand_path(path)
|
102
|
+
puts context.eval code
|
37
103
|
end
|
38
104
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
105
|
+
# If the given path exists, then compiles the source code of that
|
106
|
+
# file and spits out the generated javascript.
|
107
|
+
#
|
108
|
+
# If this file does not exist, then assumes the input is ruby code
|
109
|
+
# to compile and return.
|
110
|
+
#
|
111
|
+
# Usage:
|
112
|
+
#
|
113
|
+
# opal compile path/to/ruby.rb
|
114
|
+
# # => "generated code"
|
115
|
+
#
|
116
|
+
# opal compile "some ruby code"
|
117
|
+
# # => generated code
|
118
|
+
#
|
119
|
+
# @param [String] path file path or ruby code
|
120
|
+
def compile(path = nil, *)
|
121
|
+
abort "Usage: opal compile [Ruby code or file path]" unless path
|
122
|
+
|
123
|
+
if File.exists? path
|
124
|
+
puts Parser.new.parse File.read(path)
|
125
|
+
else
|
126
|
+
puts Parser.new.parse path
|
127
|
+
end
|
46
128
|
end
|
47
129
|
|
48
130
|
# Bundle the gem (browserify) ready for the browser
|
49
|
-
def bundle
|
131
|
+
def bundle(*)
|
50
132
|
# lazy load incase user does not have rbp installed
|
51
133
|
require 'opal/bundle'
|
52
134
|
|
@@ -54,9 +136,6 @@ module Opal
|
|
54
136
|
package = Rbp::Package.load_path path
|
55
137
|
bundle = Bundle.new package
|
56
138
|
|
57
|
-
puts bundle
|
58
|
-
puts bundle.package
|
59
|
-
|
60
139
|
puts bundle.build
|
61
140
|
end
|
62
141
|
end
|