opal 0.8.0 → 0.8.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +10 -0
- data/docs/compiled_ruby.md +425 -0
- data/docs/compiler.md +50 -0
- data/docs/compiler_directives.md +40 -34
- data/docs/configuring_gems.md +148 -0
- data/docs/encoding.md +13 -0
- data/docs/faq.md +17 -0
- data/docs/getting_started.md +30 -0
- data/docs/jquery.md +264 -0
- data/docs/libraries.md +36 -0
- data/docs/promises.md +64 -0
- data/docs/rails.md +116 -0
- data/docs/rspec.md +98 -0
- data/docs/sinatra.md +79 -0
- data/docs/source_maps.md +49 -0
- data/docs/static_applications.md +63 -0
- data/docs/templates.md +150 -0
- data/docs/unsupported_features.md +27 -0
- data/docs/using_sprockets.md +72 -0
- data/lib/opal/sprockets/processor.rb +15 -9
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/variables.rb +1 -1
- data/spec/lib/spec_helper.rb +2 -0
- data/spec/lib/sprockets/processor_spec.rb +11 -0
- metadata +22 -6
- data/lib/opal/sprockets/cache_key_fix.rb +0 -17
data/docs/libraries.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Using external libraries in your Opal app
|
2
|
+
|
3
|
+
As described in the getting started docs, opal uses a load path which works
|
4
|
+
with sprockets to create a set of locations which opal can require files
|
5
|
+
from. If you want to add a directory to this load path, you can add it to
|
6
|
+
either the global environment, or a sprockets instance.
|
7
|
+
|
8
|
+
### Global Environment
|
9
|
+
|
10
|
+
In the `Opal` module, a property `paths` is used to hold the load paths which
|
11
|
+
`Opal` uses to require files from. You can add a directory to this:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
Opal.append_path '../my_lib'
|
15
|
+
```
|
16
|
+
|
17
|
+
Now, any ruby files in this directory can be discovered.
|
18
|
+
|
19
|
+
### Sprockets instances
|
20
|
+
|
21
|
+
`Opal::Environment` is a subclass of the sprockets environment class which
|
22
|
+
can have instance specific paths added to it. This class will inherit all
|
23
|
+
global paths, but you can also add your instance paths as:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
env = Opal::Environment.new
|
27
|
+
env.append_path '../my_lib'
|
28
|
+
```
|
29
|
+
|
30
|
+
## with Opal::Builder
|
31
|
+
|
32
|
+
_WIP_
|
33
|
+
|
34
|
+
## With opal-sprockets
|
35
|
+
|
36
|
+
_WIP_
|
data/docs/promises.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# Promise
|
2
|
+
|
3
|
+
`Promise` is a class available in the Opal stdlib for helping structure asynchronous code.
|
4
|
+
|
5
|
+
It can be required inside any Opal applicaton:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require 'promise'
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
This example shows how to use a `HTTP` request from `opal-jquery` from a callback style, into a promise style handler.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
def get_json(url)
|
17
|
+
promise = Promise.new
|
18
|
+
|
19
|
+
HTTP.get(url) do |response|
|
20
|
+
if response.ok?
|
21
|
+
promise.resolve response.json
|
22
|
+
else
|
23
|
+
promise.reject response
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
promise
|
28
|
+
end
|
29
|
+
|
30
|
+
get_json('/users/1.json').then do |json|
|
31
|
+
puts "Got data: #{json}"
|
32
|
+
end.fail do |res|
|
33
|
+
alert "It didn't work :( #{res}"
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
A promise can only be resolved or rejected once.
|
38
|
+
|
39
|
+
### Chaining Promises
|
40
|
+
|
41
|
+
Promises become useful when chained together. The prevous example could be extended to get another object from the result of the first request.
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
get_json('/users/1.json').then do |json|
|
45
|
+
get_json("/posts/#{json[:post_id]}.json")
|
46
|
+
end.then do |post|
|
47
|
+
puts "got post: #{post}"
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
### Composing Promises
|
52
|
+
|
53
|
+
`Promise.when` can be used to wait for more than 1 promise to resolve (or reject). Lets assume we wanted to get 2 different users:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
first = get_json '/users/1.json'
|
57
|
+
second = get_json '/users/2.json'
|
58
|
+
|
59
|
+
Promise.when(first, second).then do |user1, user2|
|
60
|
+
puts "got users: #{user1}, #{user2}"
|
61
|
+
end.fail do
|
62
|
+
alert "Something bad happened"
|
63
|
+
end
|
64
|
+
```
|
data/docs/rails.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# Opal in a Rails application
|
2
|
+
|
3
|
+
Add Opal to your Gemfile:
|
4
|
+
|
5
|
+
``` ruby
|
6
|
+
gem 'opal-rails'
|
7
|
+
```
|
8
|
+
|
9
|
+
Or to start off with Opal when you build your new Rails app:
|
10
|
+
|
11
|
+
```bash
|
12
|
+
rails new <app-name> --javascript=opal
|
13
|
+
```
|
14
|
+
|
15
|
+
## Basic usage through the asset pipeline
|
16
|
+
|
17
|
+
```js
|
18
|
+
// app/assets/application.js.rb
|
19
|
+
|
20
|
+
//= require opal
|
21
|
+
//= require opal_ujs
|
22
|
+
//= require turbolinks
|
23
|
+
//= require_tree .
|
24
|
+
```
|
25
|
+
|
26
|
+
Opal requires are forwarded to the Asset Pipeline at compile time (similarly to what happens for RubyMotion). You can use either the `.rb` or `.opal` extension:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
# app/assets/javascripts/greeter.js.rb
|
30
|
+
|
31
|
+
puts "G'day world!" # check the console!
|
32
|
+
|
33
|
+
# Dom manipulation
|
34
|
+
require 'opal-jquery'
|
35
|
+
|
36
|
+
Document.ready? do
|
37
|
+
Element.find('body > header').html = '<h1>Hi there!</h1>'
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
### As a template
|
45
|
+
|
46
|
+
You can use it for your views too, it even inherits instance and local variables from actions:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
# app/controllers/posts_controller.rb
|
50
|
+
|
51
|
+
def create
|
52
|
+
@post = Post.create!(params[:post])
|
53
|
+
render type: :js, locals: {comments_html: render_to_string(@post.comments)}
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
Each assign is filtered through JSON so it's reduced to basic types:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# app/views/posts/create.js.opal
|
61
|
+
|
62
|
+
post = Element.find('.post')
|
63
|
+
post.find('.title').html = @post[:title]
|
64
|
+
post.find('.body').html = @post[:body]
|
65
|
+
post.find('.comments').html = comments_html
|
66
|
+
```
|
67
|
+
|
68
|
+
|
69
|
+
### As a Haml filter (optional)
|
70
|
+
|
71
|
+
Of course you need to require `haml-rails` separately since its presence is not assumed
|
72
|
+
|
73
|
+
```haml
|
74
|
+
-# app/views/posts/show.html.haml
|
75
|
+
|
76
|
+
%article.post
|
77
|
+
%h1.title= post.title
|
78
|
+
.body= post.body
|
79
|
+
|
80
|
+
%a#show-comments Display Comments!
|
81
|
+
|
82
|
+
.comments(style="display:none;")
|
83
|
+
- post.comments.each do |comment|
|
84
|
+
.comment= comment.body
|
85
|
+
|
86
|
+
:opal
|
87
|
+
Document.ready? do
|
88
|
+
Element.find('#show-comments').on :click do |click|
|
89
|
+
click.prevent_default
|
90
|
+
click.current_target.hide
|
91
|
+
Element.find('.comments').effect(:fade_in)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
|
97
|
+
### Spec!
|
98
|
+
|
99
|
+
Add specs into `app/assets/javascripts/spec`:
|
100
|
+
|
101
|
+
and then a spec folder with you specs!
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
# app/assets/javascripts/spec/example_spec.js.rb
|
105
|
+
|
106
|
+
describe 'a spec' do
|
107
|
+
it 'has successful examples' do
|
108
|
+
'I run'.should =~ /run/
|
109
|
+
end
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
Then visit `/opal_spec` from your app and **reload at will**.
|
114
|
+
|
115
|
+
![1 examples, 0 failures](http://f.cl.ly/items/001n0V0g0u0v14160W2G/Schermata%2007-2456110%20alle%201.06.29%20am.png)
|
116
|
+
|
data/docs/rspec.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# RSpec
|
2
|
+
|
3
|
+
`opal-rspec` allows opal to use rspec for running specs in javascript
|
4
|
+
environments. It comes with built-in support for running rspec with custom
|
5
|
+
`phantomjs` and standard web browser formatters. Also, async spec examples
|
6
|
+
are supported to reflect browser usage of ruby applications.
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
describe User do
|
10
|
+
it "can be created with a name" do
|
11
|
+
expect(User.new).to_not be_persisted
|
12
|
+
end
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
### Installation
|
17
|
+
|
18
|
+
Add the `opal-rspec` gem to your Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
# Gemfile
|
22
|
+
gem 'opal'
|
23
|
+
gem 'opal-rspec'
|
24
|
+
```
|
25
|
+
|
26
|
+
## Running specs
|
27
|
+
|
28
|
+
### phantomjs
|
29
|
+
|
30
|
+
To run specs, a rake task can be added which will load all spec files
|
31
|
+
from `spec/`:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
# Rakefile
|
35
|
+
require 'opal/rspec/rake_task'
|
36
|
+
Opal::RSpec::RakeTask.new(:default)
|
37
|
+
```
|
38
|
+
|
39
|
+
Then, to run your specs inside phantomjs, just run the rake task:
|
40
|
+
|
41
|
+
```sh
|
42
|
+
$ bundle exec rake
|
43
|
+
```
|
44
|
+
|
45
|
+
### In a Browser
|
46
|
+
|
47
|
+
`opal-rspec` can use sprockets to build and serve specs over a simple rack server. Add the following to a `config.ru` file:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# config.ru
|
51
|
+
require 'bundler'
|
52
|
+
Bundler.require
|
53
|
+
|
54
|
+
run Opal::Server.new { |s|
|
55
|
+
s.main = 'opal/rspec/sprockets_runner'
|
56
|
+
s.append_path 'spec'
|
57
|
+
s.debug = false
|
58
|
+
}
|
59
|
+
```
|
60
|
+
|
61
|
+
Then run the rack server bundle exec rackup and visit `http://localhost:9292` in any web browser.
|
62
|
+
|
63
|
+
## Async examples
|
64
|
+
|
65
|
+
`opal-rspec` adds support for async specs to rspec. These specs are defined using
|
66
|
+
`#async` instead of `#it`:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
describe MyClass do
|
70
|
+
# normal example
|
71
|
+
it 'does something' do
|
72
|
+
expect(:foo).to eq(:foo)
|
73
|
+
end
|
74
|
+
|
75
|
+
# async example
|
76
|
+
async 'does something else, too' do
|
77
|
+
# ...
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
This just marks the example as running async. To actually handle the async result,
|
83
|
+
you also need to use a `run_async` call inside some future handler:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
async 'HTTP requests should work' do
|
87
|
+
HTTP.get('/users/1.json') do |res|
|
88
|
+
run_async {
|
89
|
+
expect(res).to be_ok
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
The block passed to `run_async` informs the runner that this spec is finished
|
96
|
+
so it can move on. Any failures/expectations run inside this block will be run
|
97
|
+
in the context of the example.
|
98
|
+
|
data/docs/sinatra.md
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Using Opal with Sinatra
|
2
|
+
|
3
|
+
Add Opal to your Gemfile (or install using `gem`):
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
# Gemfile
|
7
|
+
gem 'sinatra'
|
8
|
+
gem 'opal', '~> 0.6.2'
|
9
|
+
```
|
10
|
+
|
11
|
+
Opal uses `sprockets` as its default build system, so the asset-pipeline
|
12
|
+
from rails can be mimicked here to map all ruby assets in the `/assets`
|
13
|
+
path to be compiled using opal.
|
14
|
+
|
15
|
+
## Basic Application
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# config.ru
|
19
|
+
require 'opal'
|
20
|
+
require 'sinatra'
|
21
|
+
|
22
|
+
opal = Opal::Server.new {|s|
|
23
|
+
s.append_path 'app'
|
24
|
+
s.main = 'application'
|
25
|
+
}
|
26
|
+
|
27
|
+
map opal.source_maps.prefix do
|
28
|
+
run opal.source_maps
|
29
|
+
end
|
30
|
+
|
31
|
+
map '/assets' do
|
32
|
+
run opal.sprockets
|
33
|
+
end
|
34
|
+
|
35
|
+
get '/' do
|
36
|
+
<<-HTML
|
37
|
+
<!doctype html>
|
38
|
+
<html>
|
39
|
+
<head>
|
40
|
+
<script src="/assets/application.js"></script>
|
41
|
+
</head>
|
42
|
+
</html>
|
43
|
+
HTML
|
44
|
+
end
|
45
|
+
|
46
|
+
run Sinatra::Application
|
47
|
+
```
|
48
|
+
|
49
|
+
This creates a simple sprockets instance under the `/assets` path. Opal
|
50
|
+
uses a set of load paths to compile assets using sprockets. The
|
51
|
+
`Opal::Environment` instance is a simple subclass of `Sprockets::Environment`
|
52
|
+
with all the custom opal paths added automatically.
|
53
|
+
|
54
|
+
This `env` object includes all the opal corelib and stdlib paths. To add
|
55
|
+
any custom application directories, you must add them to the load path using
|
56
|
+
`env.append_path`. You can now add an `app/application.rb` file into this
|
57
|
+
added path with some basic content:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# app/application.rb
|
61
|
+
require 'opal'
|
62
|
+
|
63
|
+
puts "wow, running ruby!"
|
64
|
+
```
|
65
|
+
|
66
|
+
It is necessary to require the opal corelib (seen in the `require` call) above.
|
67
|
+
This just makes the Opal runtime and corelib available. Then it is possible to
|
68
|
+
use all the corelib methods and classes, e.g. `Kernel#puts` as seen above.
|
69
|
+
|
70
|
+
### Running Application
|
71
|
+
|
72
|
+
As this is just a simple sinatra application, you can run it:
|
73
|
+
|
74
|
+
```sh
|
75
|
+
$ bundle exec rackup
|
76
|
+
```
|
77
|
+
|
78
|
+
And point your browser towards `http://localhost:9292/` and view the browser
|
79
|
+
debug console. You should see this message printed.
|
data/docs/source_maps.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Source maps
|
2
|
+
|
3
|
+
Source maps are available (on current stable release, v0.6.x) even without explicit support from Sprockets in a sort of hackish way.
|
4
|
+
|
5
|
+
_As such even if they generally work fine there are some limitations and edge case issues._
|
6
|
+
|
7
|
+
NOTE: Currently on `master` branch sourcemaps are work-in-progress and probably will integrate with the upcoming Sprockets 4 that has integrated support for them.
|
8
|
+
|
9
|
+
#### Processor `source_map_enabled` flag
|
10
|
+
To enable sourcemaps in the Sprockets processor you need to turn on the relative flag:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
Opal::Processor.source_map_enabled = true # default
|
14
|
+
```
|
15
|
+
|
16
|
+
|
17
|
+
#### Sprockets debug mode
|
18
|
+
|
19
|
+
The sourcemaps only work with Sprockets in debug mode because they are generated just for single files.
|
20
|
+
|
21
|
+
|
22
|
+
## Enable source maps
|
23
|
+
|
24
|
+
### Rails
|
25
|
+
|
26
|
+
Rails has debug mode already enabled in development environment with the following line from `config/environments/development.rb`:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
# Debug mode disables concatenation and preprocessing of assets.
|
30
|
+
# This option may cause significant delays in view rendering with a large
|
31
|
+
# number of complex assets.
|
32
|
+
config.assets.debug = true
|
33
|
+
```
|
34
|
+
|
35
|
+
`opal-rails` also enables sourcemaps in development so with the standard setup you ready to go.
|
36
|
+
|
37
|
+
|
38
|
+
### Sinatra
|
39
|
+
|
40
|
+
You can add `Opal::Server` as in the official example: [sinatra/config.ru](https://github.com/opal/opal/blob/0-6-stable/examples/sinatra/config.ru).
|
41
|
+
|
42
|
+
### Opal::Server
|
43
|
+
|
44
|
+
`Opal::Server` implements sourcemaps and can be used alone or with `Rack::Cascade` in conjunction with other apps.
|
45
|
+
|
46
|
+
### Opal::Environment
|
47
|
+
|
48
|
+
`Opal::Environment` is a bit lower level and doesn't support source maps by itself.
|
49
|
+
|