opal 0.8.0 → 0.8.1.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+

|
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
|
+
|