jsrb 0.1.0 → 0.2.0
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 +5 -5
- data/.ruby-version +1 -0
- data/README.md +285 -5
- data/jsrb.gemspec +4 -1
- data/lib/jsrb/railtie.rb +26 -0
- data/lib/jsrb/version.rb +1 -1
- data/lib/jsrb.rb +1 -0
- metadata +25 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5b2cff3db7ac17a89b029bc7782e8735b7f9959c4595804c39537af8d6232077
|
4
|
+
data.tar.gz: b7700dc452ea93b9ba17cbf381bb79acfd00747f6e653b309cf24174811598d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 934089fa92db021a2d90e738286de40dbc094286a5f0f4ed281626bd6d666b66d25d643ac4f117289b616c3c4b8d173fac5dcb86d29a645df7cf415c8c4e4939
|
7
|
+
data.tar.gz: 9a1de7b3fd7a00e7facb9c633352e06a142ccb01680d819bba30d3f56c7be226682a00693098068ad85fee4a76ef83a3246377e2c85e5399553b6794adf6defb
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.5.1
|
data/README.md
CHANGED
@@ -1,14 +1,294 @@
|
|
1
|
-
[](https://circleci.com/gh/effective-spa/jsrb) [](https://codecov.io/gh/effective-spa/jsrb) [](https://codeclimate.com/github/effective-spa/jsrb/maintainability)
|
2
|
-
|
3
|
-
**This library is still development version. It's currently not recommended to be used in production environment.**
|
1
|
+
[](https://circleci.com/gh/effective-spa/jsrb) [](https://codecov.io/gh/effective-spa/jsrb) [](https://codeclimate.com/github/effective-spa/jsrb/maintainability) [](https://badge.fury.io/rb/jsrb)
|
4
2
|
|
5
3
|
# Jsrb
|
6
4
|
|
7
5
|
Jsrb is a template engine to generate JavaScript code in simple Ruby DSL.
|
8
6
|
|
9
|
-
|
7
|
+
# Getting Started
|
8
|
+
|
9
|
+
Jsrb handler works in jsrb files, which contain `.js.jsrb` extension. All ruby syntax is available and `jsrb` is provided in it. You can construct JavaScript code via `jsrb`.
|
10
|
+
|
11
|
+
```rb
|
12
|
+
name = jsrb.var!(:name) { 'foo' }
|
13
|
+
ary = jsrb.var! :ary
|
14
|
+
obj = jsrb.var! :obj
|
15
|
+
result = jsrb.var!
|
16
|
+
# var name = 'foo';
|
17
|
+
# var ary;
|
18
|
+
# var obj;
|
19
|
+
# var _v1; <- auto generate variable name
|
20
|
+
|
21
|
+
ary.set!([1, 2, 3])
|
22
|
+
# ary = [1, 2, 3];
|
23
|
+
|
24
|
+
obj.set!(
|
25
|
+
name: name,
|
26
|
+
profile: {
|
27
|
+
age: 20,
|
28
|
+
sex: 'm'
|
29
|
+
}
|
30
|
+
)
|
31
|
+
# obj = {
|
32
|
+
# name: name,
|
33
|
+
# profile: {
|
34
|
+
# age: 20,
|
35
|
+
# sex: 'm'
|
36
|
+
# }
|
37
|
+
# };
|
38
|
+
|
39
|
+
result.set! (obj.name + "(" + obj.profile.age + ")")
|
40
|
+
# _v1 = obj.name + "(" + obj.profile.age + ")";
|
41
|
+
|
42
|
+
ary.set! ary.map { |x| x * 2 }
|
43
|
+
# ary = ary.map(function(x) {
|
44
|
+
# return x * 2;
|
45
|
+
# });
|
46
|
+
|
47
|
+
jsrb.if!(ary[1] === 4) {
|
48
|
+
result.set! 'four'
|
49
|
+
}.elsif(ary[1] === 2) {
|
50
|
+
result.set! 'two'
|
51
|
+
}.else {
|
52
|
+
result.set! 'other'
|
53
|
+
}
|
54
|
+
# // the actual output doesn't looks like this, but will be better code in regard to variable scope.
|
55
|
+
# if (ary[1] === 4) {
|
56
|
+
# _v1 = 'four'
|
57
|
+
# } else if (ary[1] === 2) {
|
58
|
+
# _v1 = 'two'
|
59
|
+
# } else {
|
60
|
+
# _v1 = 'other'
|
61
|
+
# }
|
62
|
+
|
63
|
+
result.set! jsrb.expr.Date.new!
|
64
|
+
# _v1 = new Date;
|
65
|
+
|
66
|
+
jsrb.expr.console.log('hello').as_statement!
|
67
|
+
# console.log('hello');
|
68
|
+
```
|
69
|
+
|
70
|
+
# Usage
|
71
|
+
|
72
|
+
## Statements
|
73
|
+
|
74
|
+
### Variable declaration
|
75
|
+
|
76
|
+
`jsrb.var!` pushes a **VariableDeclaration** into current context.
|
77
|
+
|
78
|
+
```rb
|
79
|
+
# with variable name and initializer
|
80
|
+
jsrb.var!('varname') { 100 }
|
81
|
+
# var varname = 100;
|
82
|
+
|
83
|
+
# without initializer
|
84
|
+
jsrb.var!('varname')
|
85
|
+
# var varname;
|
86
|
+
|
87
|
+
# variable name is auto-generated if not specified
|
88
|
+
jsrb.var!
|
89
|
+
# var _v1;
|
90
|
+
|
91
|
+
# var! returns Jsrb::ExprChain instance, so that you can
|
92
|
+
# assign value with `.set!` method.
|
93
|
+
a = jsrb.var!
|
94
|
+
a.set! 100
|
95
|
+
# var _v1;
|
96
|
+
# v1 = 100;
|
97
|
+
```
|
98
|
+
|
99
|
+
### If statement, and conditional expression
|
100
|
+
|
101
|
+
`jsrb.if!` pushes an **IfStatement** into current context, `jsrb.if` to build **a conditional expression**.
|
102
|
+
|
103
|
+
```rb
|
104
|
+
# start with `#if!`
|
105
|
+
# and chain `#elsif` to add next case.
|
106
|
+
# Note that this is a statement, not expression.
|
107
|
+
jsrb.if!(v === 1) {
|
108
|
+
# ..
|
109
|
+
}.elsif(v === 2) {
|
110
|
+
# ..
|
111
|
+
}.else {
|
112
|
+
# ..
|
113
|
+
}
|
114
|
+
|
115
|
+
# if you don't need else clause, close with `#end`
|
116
|
+
jsrb.if!(v === 1) {
|
117
|
+
# ..
|
118
|
+
}.end
|
119
|
+
|
120
|
+
# if you want to regard this as an expression, use `#if` without exclamation.
|
121
|
+
v.set! jsrb.if(v === 1) {
|
122
|
+
# ..
|
123
|
+
}.else {
|
124
|
+
# ..
|
125
|
+
}
|
126
|
+
```
|
127
|
+
|
128
|
+
### Assignment statement
|
129
|
+
|
130
|
+
`ExprChain#set!` pushes an **assignment statement** (ExpressionStatement of AssignmentExpression).
|
131
|
+
|
132
|
+
```rb
|
133
|
+
a = jsrb.var! :a
|
134
|
+
a.set! 100
|
135
|
+
# var a;
|
136
|
+
# a = 100;
|
137
|
+
```
|
138
|
+
|
139
|
+
### Expression statement
|
140
|
+
|
141
|
+
`ExprChain#as_statement!` pushes an **ExpressionStatement** of the left hand side of chain.
|
142
|
+
|
143
|
+
```rb
|
144
|
+
get_elements = jsrb.expr['getElements']
|
145
|
+
get_elements.('.foo').forEach { |n| n.delete.() }.as_statement!
|
146
|
+
# getElements('.foo').forEach(function(n) { return n.delete(); });
|
147
|
+
```
|
148
|
+
|
149
|
+
## Expression chain
|
150
|
+
|
151
|
+
Expression chain (`ExprChain` class) is an utility class to construct JavaScript expressions.
|
152
|
+
|
153
|
+
### Initialize with wrapping a ruby value
|
154
|
+
|
155
|
+
`jsrb.expr` create a new `ExprChain` instance, taking an initial value optionally.
|
156
|
+
Some methods in jsrb automatically convert ruby expression to ExprChain.
|
157
|
+
|
158
|
+
```rb
|
159
|
+
x = jsrb.var! :x
|
160
|
+
|
161
|
+
x.set! jsrb.expr(100)
|
162
|
+
# x = 100;
|
163
|
+
# set! automatically wrap with ExprChain.
|
164
|
+
x.set! 100
|
165
|
+
# x = 100;
|
166
|
+
# If you need to compare by operator with another ExprChain,
|
167
|
+
# you have to wrap first.
|
168
|
+
x.set!(jsrb.expr(100) < jsrb.expr.y)
|
169
|
+
# x.set!(100 < jsrb.expr.y) will fail.
|
170
|
+
```
|
171
|
+
|
172
|
+
### Chains
|
173
|
+
|
174
|
+
#### Member expression
|
175
|
+
|
176
|
+
`ExprChain#[], #member!, #..` constructs **MemberExpression**.
|
177
|
+
`#[]` and `#member!` is safe. `#..` can be used only if the name has no conflict.
|
178
|
+
|
179
|
+
```rb
|
180
|
+
x = jsrb.var! :x
|
181
|
+
|
182
|
+
obj = jsrb.expr['someObj']
|
183
|
+
# jsrb.expr with no argument constructs empty chain,
|
184
|
+
# in which every member chain will be an identifier.
|
185
|
+
x.set! obj.field
|
186
|
+
# x = someObj['field'];
|
187
|
+
x.set! obj['field']
|
188
|
+
# x = someObj['field'];
|
189
|
+
x.set! obj.member! 'field'
|
190
|
+
# x = someObj['field'];
|
191
|
+
|
192
|
+
x.set! obj.send # NOTE that this is interpreted as a ruby Object's method, and causes an error.
|
193
|
+
```
|
194
|
+
|
195
|
+
#### Function Call
|
196
|
+
|
197
|
+
`ExprChain#call, so #.(), #.. with argument or block` constructs **CallExpression**.
|
198
|
+
|
199
|
+
```rb
|
200
|
+
x = jsrb.var! :x
|
201
|
+
console = jsrb.expr['console']
|
202
|
+
|
203
|
+
# using call method
|
204
|
+
console.log.('foo').as_statement!
|
205
|
+
# console.log('foo')
|
206
|
+
console.log.call('foo').as_statement!
|
207
|
+
# console.log('foo')
|
208
|
+
|
209
|
+
# using dynamic method
|
210
|
+
# if #..() has at least one argument or block, it will be a call expression.
|
211
|
+
console.log('foo').as_statement!
|
212
|
+
# console.log('foo')
|
213
|
+
x.map { |item| item.field }.as_statement!
|
214
|
+
# x.map(function(item) { return item.field; });
|
215
|
+
```
|
216
|
+
|
217
|
+
#### Operators
|
218
|
+
|
219
|
+
Any ruby-overridable and JS-existing operators are overridden for chaining.
|
220
|
+
Supported operators are: `** + - * / % >> << & ^ | <= < > >= == === != ! && ||`.
|
221
|
+
|
222
|
+
```rb
|
223
|
+
x = jsrb.var! :x
|
224
|
+
a = jsrb.expr['a']
|
225
|
+
|
226
|
+
x.set!(a === 1)
|
227
|
+
# x = a === 1;
|
228
|
+
|
229
|
+
x.set!(a * a)
|
230
|
+
# x = a * a;
|
231
|
+
|
232
|
+
x.set!(3 * a) # raises an error because Fixnum does not accept ExprChain as RHS.
|
233
|
+
```
|
234
|
+
|
235
|
+
#### New
|
236
|
+
|
237
|
+
`ExprChain#new!` constructs **NewExpression**.
|
238
|
+
|
239
|
+
```rb
|
240
|
+
x = jsrb.var! :x
|
241
|
+
|
242
|
+
x.set! jsrb.expr['Date'].new!
|
243
|
+
# x = new Date;
|
244
|
+
```
|
245
|
+
|
246
|
+
#### Function expression
|
247
|
+
|
248
|
+
`ExprChain#for_all!` constructs **FunctionExpression**. You can also construct it from Proc directly or passing a block.
|
249
|
+
|
250
|
+
```rb
|
251
|
+
ary = jsrb.var! :ary, [1, 2, 3]
|
252
|
+
|
253
|
+
ary.map((jsrb.expr['x'] * 2).for_all!('x')).as_statement!
|
254
|
+
# ary.map(function(x) { return x * 2; });
|
255
|
+
|
256
|
+
ary.map { |x| x * 2 }.as_statement!
|
257
|
+
# ary.map(function(x) { return x * 2; });
|
258
|
+
|
259
|
+
ary.map(->(x) { x * 2 }).as_statement!
|
260
|
+
# ary.map(function(x) { return x * 2; });
|
261
|
+
```
|
262
|
+
|
263
|
+
# Conversion
|
264
|
+
|
265
|
+
Every Ruby's generic value will be converted to Javascript value by following rule:
|
266
|
+
|
267
|
+
|Ruby value|JavaScript|
|
268
|
+
|---|---|
|
269
|
+
| finite `100` | `100` |
|
270
|
+
| NaN `Float::NAN` | `NaN` |
|
271
|
+
| +Infinity `Float::INFINITY` | `Number.POSITIVE_INFINITY` |
|
272
|
+
| -Infinity `Float::INFINITY` | `Number.NEGATIVE_INFINITY` |
|
273
|
+
| `true` | `true` |
|
274
|
+
| `false` | `false` |
|
275
|
+
| `:foo` | `"foo"` |
|
276
|
+
| `"foo"` | `"foo"` |
|
277
|
+
| `nil` | `null` |
|
278
|
+
| `[1, 2, 3]` | `[1, 2, 3]` |
|
279
|
+
| `{ foo: 'bar' }` | `{ "foo": "bar" }` |
|
280
|
+
| `->(x, y, z) { x + y + z }` | `function (x, y, z) { return x + y + z; }` |
|
281
|
+
|
282
|
+
# Customize Chain
|
283
|
+
|
284
|
+
You can add custom chain methods in `ExprChain` via `Jsrb::ExprChain.#add_custom_chain`.
|
285
|
+
|
286
|
+
```rb
|
287
|
+
Jsrb::ExprChain.add_custom_chain('log_here', '__tap_log__')
|
10
288
|
|
11
|
-
|
289
|
+
jsrb.expr['foo']['bar'].log_here.as_statement!
|
290
|
+
# __tap_log__(foo['bar']);
|
291
|
+
```
|
12
292
|
|
13
293
|
## Contributing
|
14
294
|
|
data/jsrb.gemspec
CHANGED
@@ -4,6 +4,7 @@ lib = File.expand_path('lib', __dir__)
|
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'jsrb/version'
|
6
6
|
|
7
|
+
# rubocop:disable Metrics/BlockLength
|
7
8
|
Gem::Specification.new do |spec|
|
8
9
|
spec.name = 'jsrb'
|
9
10
|
spec.version = Jsrb::VERSION
|
@@ -18,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
18
19
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
20
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
21
|
if spec.respond_to?(:metadata)
|
21
|
-
spec.metadata['allowed_push_host'] =
|
22
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
22
23
|
else
|
23
24
|
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
24
25
|
'public gem pushes.'
|
@@ -35,6 +36,8 @@ Gem::Specification.new do |spec|
|
|
35
36
|
spec.add_runtime_dependency 'stitch-rb', '~> 0.0.8'
|
36
37
|
|
37
38
|
spec.add_development_dependency 'bundler', '~> 1.13'
|
39
|
+
spec.add_development_dependency 'rails', '~> 5.0', '>= 5.0.0'
|
38
40
|
spec.add_development_dependency 'rake', '~> 10.0'
|
39
41
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
40
42
|
end
|
43
|
+
# rubocop:enable Metrics/BlockLength
|
data/lib/jsrb/railtie.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsrb
|
4
|
+
class Handler
|
5
|
+
cattr_accessor :default_format
|
6
|
+
self.default_format = Mime[:js]
|
7
|
+
|
8
|
+
def self.call(template)
|
9
|
+
%(jsrb = Jsrb::Base.new; #{template.source}; jsrb.generate_code)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Railtie < ::Rails::Railtie
|
14
|
+
initializer :server_component do
|
15
|
+
ActiveSupport.on_load :action_view do
|
16
|
+
ActionView::Template.register_template_handler :jsrb, Jsrb::Handler
|
17
|
+
end
|
18
|
+
|
19
|
+
ActiveSupport.on_load :action_controller do
|
20
|
+
ActionController::Renderers.add :jsrb do |obj, _options|
|
21
|
+
send_data obj.to_s, type: Mime[:js]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/jsrb/version.rb
CHANGED
data/lib/jsrb.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shun MIZUKAMI
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -58,6 +58,26 @@ dependencies:
|
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '1.13'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rails
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '5.0'
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 5.0.0
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '5.0'
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 5.0.0
|
61
81
|
- !ruby/object:Gem::Dependency
|
62
82
|
name: rake
|
63
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,6 +118,7 @@ files:
|
|
98
118
|
- ".gitignore"
|
99
119
|
- ".rspec"
|
100
120
|
- ".rubocop.yml"
|
121
|
+
- ".ruby-version"
|
101
122
|
- ".travis.yml"
|
102
123
|
- Gemfile
|
103
124
|
- LICENSE.txt
|
@@ -110,6 +131,7 @@ files:
|
|
110
131
|
- lib/jsrb/expr_chain.rb
|
111
132
|
- lib/jsrb/js_statement_context.rb
|
112
133
|
- lib/jsrb/not_fast_generator.rb
|
134
|
+
- lib/jsrb/railtie.rb
|
113
135
|
- lib/jsrb/vendor/escodegen.browser.js
|
114
136
|
- lib/jsrb/version.rb
|
115
137
|
homepage: https://github.com/effective-spa/jsrb
|
@@ -133,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
155
|
version: '0'
|
134
156
|
requirements: []
|
135
157
|
rubyforge_project:
|
136
|
-
rubygems_version: 2.
|
158
|
+
rubygems_version: 2.7.6
|
137
159
|
signing_key:
|
138
160
|
specification_version: 4
|
139
161
|
summary: generates JavaScript code with Ruby DSL
|