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 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
- Using opal
20
+ Installing opal
21
21
  ----------
22
22
 
23
- Opal can currently be used in three ways: through a distributed ruby gem,
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
- The `opal` command can also be used directly from this source repo, so
42
- to download and run opal:
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
- $ git clone https://github.com/adambeynon/opal.git
46
- $ cd opal
47
- $ bin/opal
42
+ opal init my_project
48
43
  ```
49
44
 
50
- ### Using rbp
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
- rbp installs dependencies locally to your project, so edit your
53
- package.yml file to add the following dependency:
49
+ ### Using opal in the browser
54
50
 
55
- ```yaml
56
- dev_dependencies:
57
- opal: "0.3.9"
58
- therubyracer: "0.9.4"
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
- Install them with:
59
+ ### Bundle
60
+
61
+ The Rakefile has a task to build your ruby project, so just run:
62
62
 
63
63
  ```
64
- $ rbp install
64
+ rake bundle
65
65
  ```
66
66
 
67
- This will install them into vendor/ ready to use. therubyracer is only
68
- needed if you want to run your ruby code, compiled into javascript,
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
- Running tests
73
- -------------
70
+ Project structure
71
+ -----------------
74
72
 
75
- To run tests, you need opaltest which is the testing framework for opal
76
- based on minitest. To get opaltest, run the following in the opal
77
- directory:
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
- $ rbp install
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
- This will put opaltest into `packages/opaltest` so it will be available
84
- for running. To test `array.rb` for example, run:
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
- $ rbp exec opal test/array.rb
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
- The results should be printed to the console.
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
- ### No method\_missing
97
+ ### Optional method\_missing
96
98
 
97
- To optimize method dispatch, `method_missing` is not supported in opal.
98
- It is supported in debug mode to improve readability of error messages
99
- from calling undefined methods, but should/will not be used in
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 'opal/parser'
2
- require 'opal/builder'
3
- require 'opal/context'
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 packages.
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}.rb', #{content});\n"
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
- src = Opal::Parser.new(src).parse!.generate_top
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
- # @return [Rbp::Package] the package this is bundling
13
- attr_reader :package
14
-
5
+ attr_accessor :name
6
+ attr_accessor :version
15
7
  attr_accessor :options
16
8
 
17
- def initialize(package)
18
- @package = package
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
- package_dir = @package.package_dir
27
-
28
- lib_files = @package.relative_lib_files.map do |lib|
29
- path = File.join package_dir, lib
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.package({\n]
37
- bundle << %[ name: "#{@package.name}",\n]
38
- bundle << %[ version: "#{@package.version}",\n]
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
- module Opal
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, *args
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
- # desc "irb", "Opens interactive opal/ruby repl"
25
- def irb
26
- ctx = Opal::Context.new
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
- def eval(path = nil)
31
- return "no path given for eval" unless path
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
- abort "path does not exist `#{path}'" unless File.exist? path
97
+ context = Context.new :method_missing => true,
98
+ :overload_arithmetic => true,
99
+ :overload_comparison => true,
100
+ :overload_bitwise => true
34
101
 
35
- ctx = Opal::Context.new
36
- ctx.require_file File.expand_path(path)
102
+ puts context.eval code
37
103
  end
38
104
 
39
- def compile(path)
40
- puts Opal::Parser.new(File.read(path)).parse!.generate_top
41
- end
42
-
43
- def install
44
- install = RBP::Install.new
45
- install.install
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