jsrb 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b2cff3db7ac17a89b029bc7782e8735b7f9959c4595804c39537af8d6232077
4
- data.tar.gz: b7700dc452ea93b9ba17cbf381bb79acfd00747f6e653b309cf24174811598d3
3
+ metadata.gz: 364d2bd1fb5aa8359d2396ab0cba0063fc7679a41e7dfd476cce1cf431ff9c33
4
+ data.tar.gz: d4b4bc5e5ae5de748f87e431ddcd325386116cc3771a830d3eb688b0ff4a0e5c
5
5
  SHA512:
6
- metadata.gz: 934089fa92db021a2d90e738286de40dbc094286a5f0f4ed281626bd6d666b66d25d643ac4f117289b616c3c4b8d173fac5dcb86d29a645df7cf415c8c4e4939
7
- data.tar.gz: 9a1de7b3fd7a00e7facb9c633352e06a142ccb01680d819bba30d3f56c7be226682a00693098068ad85fee4a76ef83a3246377e2c85e5399553b6794adf6defb
6
+ metadata.gz: 8f1f633f7475c81868867379eee537c7bdd8ca84502a0849e86cc79dead234ef0a96147018b492b8da4e6fa5f60089809e56d9cb929ab055a705238540d74928
7
+ data.tar.gz: 8c61e38d356b3a64cf37cc4a6200756d234baaddc6c4df1b110c1510bc898bc0f537d866d79a15ded681ce543f1db196ae9963124b6668ac5e240540133c3790
data/.rubocop.yml CHANGED
@@ -32,6 +32,9 @@ Style/LambdaCall:
32
32
  Exclude:
33
33
  - 'spec/**/*'
34
34
 
35
+ Style/MethodMissingSuper:
36
+ Enabled: false
37
+
35
38
  Metrics/BlockLength:
36
39
  Exclude:
37
40
  - 'spec/**/*'
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --markup-provider=redcarpet
2
+ --markup=markdown
data/Gemfile CHANGED
@@ -7,6 +7,8 @@ gemspec
7
7
 
8
8
  group :development, :test do
9
9
  gem 'pry-byebug'
10
+ gem 'redcarpet'
10
11
  gem 'rubocop', '~> 0.61.0'
11
12
  gem 'simplecov'
13
+ gem 'yard'
12
14
  end
data/README.md CHANGED
@@ -6,7 +6,7 @@ Jsrb is a template engine to generate JavaScript code in simple Ruby DSL.
6
6
 
7
7
  # Getting Started
8
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`.
9
+ Jsrb handler works in `.jsrb` view files. All ruby syntax is available and `jsrb` is provided in it. You can construct JavaScript code via `jsrb`.
10
10
 
11
11
  ```rb
12
12
  name = jsrb.var!(:name) { 'foo' }
data/jsrb.gemspec CHANGED
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
25
25
  'public gem pushes.'
26
26
  end
27
27
 
28
+ spec.metadata['yard.run'] = 'yri'
29
+
28
30
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
29
31
  f.match(%r{^(test|spec|features)/})
30
32
  end
data/lib/jsrb/base.rb CHANGED
@@ -1,11 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jsrb
4
+ # Base is a centralized class for Jsrb template.
5
+ # `jsrb`, accessed from views (i.e. `*.js.jsrb` files), is an instance of Jsrb::Base.
6
+ #
7
+ # Jsrb::Base provides some utilities to push statements,
8
+ # construct expressions and generate the final JavaScript code,
9
+ # with preserving a statement context to build the abstract syntax tree.
4
10
  class Base
5
11
  def initialize
6
12
  @context = JSStatementContext.new
7
13
  end
8
14
 
15
+ #
16
+ # Generates executable JavaScript code from current context.
17
+ #
18
+ # @return [String] generated executable JavaScript code
9
19
  def generate_code
10
20
  generator = self.class.code_generator_class.new
11
21
  generator.call type: 'Program',
@@ -13,6 +23,14 @@ module Jsrb
13
23
  body: @context.stacks.first
14
24
  end
15
25
 
26
+ #
27
+ # Pushes a VariableDeclaration to the current context
28
+ # and returns an access to created identifier.
29
+ #
30
+ # @param optional [Symbol] name a name of identifier, autogenerated if not specified.
31
+ # @yield optional block for initializer
32
+ # @yieldreturn an initializer expression (optional)
33
+ # @return [Jsrb::ExprChain] the expression that represents constructed new identifier
16
34
  def var!(id = nil)
17
35
  id ||= @context.gen_var_name!
18
36
  if block_given?
@@ -25,28 +43,57 @@ module Jsrb
25
43
  expr.member!(id)
26
44
  end
27
45
 
46
+ #
47
+ # Constructs a new conditional chain that **pushes an IfStatement** to the current context
48
+ # after the chain ended.
49
+ #
50
+ # @param [Jsrb::ExprChain, convertible ruby values] cond_expr an expression for the test
51
+ # @yield new context block for the consequent case
52
+ # @return [Jsrb::CondChain] condition chainable instance
28
53
  def if!(cond_expr, &block)
29
54
  CondChain.new(@context, false).elsif(cond_expr, &block)
30
55
  end
31
56
 
57
+ #
58
+ # Constructs a new conditional chain that **returns a conditional expression** after the chain ended.
59
+ #
60
+ # @param [Jsrb::ExprChain, convertible ruby values] cond_expr an expression for the test
61
+ # @yield new context block for the consequent case
62
+ # @return [Jsrb::CondChain] condition chainable instance
32
63
  def if(cond_expr, &block)
33
64
  CondChain.new(@context, true).elsif(cond_expr, &block)
34
65
  end
35
66
 
67
+ #
68
+ # Constructs a new expression chain with a given JavaScript AST node.
69
+ #
70
+ # @param optional [convertible ruby values] object represents JavaScript expression AST node
71
+ # @return [Jsrb::ExprChain] chainable instance
36
72
  def expr(object = nil)
37
73
  @context.new_expression(object)
38
74
  end
39
75
 
40
76
  class << self
41
- def code_generator_class
42
- @code_generator_class ||= Object.const_get(code_generator)
43
- end
44
-
77
+ #
78
+ # Shows JavaScript generator class name, 'Jsrb::NotFastGenerator' by default.
79
+ #
80
+ # ### **Help wanted!**
81
+ #
82
+ # *Jsrb::NotFastGenerator uses ExecJS and escodegen to generate JavaScript.
83
+ # It could be more efficient and get better error messages if you
84
+ # rewrite in Ruby*.
85
+ #
45
86
  def code_generator
46
87
  @code_generator || 'Jsrb::NotFastGenerator'
47
88
  end
48
89
 
49
90
  attr_writer :code_generator
91
+
92
+ private
93
+
94
+ def code_generator_class
95
+ @code_generator_class ||= Object.const_get(code_generator)
96
+ end
50
97
  end
51
98
  end
52
99
  end
@@ -1,15 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jsrb
4
+ # ExprChain is a builder class that constructs JavaScript expressions
5
+ # in natural phrase by chain method.
4
6
  class ExprChain
5
7
  JS_LOGICAL_OPS = %w[&& ||].freeze
6
8
 
9
+ # Returns a new instance.
10
+ # @param [Jsrb::JSStatementContext] context statement context instance
11
+ # @param optional [Hash] object hash represents AST node
7
12
  def initialize(context, object = nil)
8
13
  @context = context
9
14
  @object = object
10
15
  end
11
16
 
12
- # rubocop:disable Style/MethodMissingSuper
17
+ # Responds arbitrary method name
18
+ #
19
+ # ### `#...`, the last letter is neither `=` nor `?`, and no argument and no block
20
+ # constructs a **MemberExpression**
21
+ #
22
+ # ```rb
23
+ # obj = jsrb.expr['obj']
24
+ # obj.foo # represents `obj.foo`
25
+ # ```
26
+ #
27
+ # ### `#...`, the last letter is neither `=` nor `?`, at least one argument or block
28
+ # constructs a **CallExpression** of MemberExpression
29
+ #
30
+ # ```rb
31
+ # obj = jsrb.expr['obj']
32
+ # obj.foo(100) # represents `obj.foo(100)`
33
+ # obj.foo { |x| x + 1 } # represents `obj.foo(function (x) { return x; })`
34
+ # ```
35
+ #
36
+ # ### `#...=`
37
+ # pushes **ExpressionStatement** of a member assignment expression
38
+ #
39
+ # ```rb
40
+ # obj = jsrb.expr['obj']
41
+ # obj.foo = 100 # pushes `obj.foo = 100;` in the current context
42
+ # ```
43
+ #
44
+ # ### `#...?`
45
+ # constructs **ConditionalExpression**
46
+ #
47
+ # ```rb
48
+ # obj = jsrb.expr['obj']
49
+ # obj.foo?(100, 200) # represents `obj.foo ? 100 : 200`
50
+ # ```
51
+ #
13
52
  def method_missing(name, *args, &block)
14
53
  if (matches = name.to_s.match(/\A(.+)\?\z/))
15
54
  member!(matches[1]).cond?(*args)
@@ -23,22 +62,50 @@ module Jsrb
23
62
  member!(name.to_s).call(*args, &block)
24
63
  end
25
64
  end
26
- # rubocop:enable Style/MethodMissingSuper
27
65
 
66
+ #
67
+ # Constructs a **MemberExpression**
68
+ #
69
+ # ```rb
70
+ # x = jsrb.var! :x
71
+ # obj = jsrb.expr['someObj']
72
+ # x.set! obj['field']
73
+ # ```
74
+ #
75
+ # will be
76
+ #
77
+ # ```js
78
+ # x = someObj['field'];
79
+ # ```
80
+ #
81
+ # @param [String, Symbol] value name of member
82
+ # @return [Jsrb::ExprChain] a chain represents **MemberExpression**
28
83
  def [](value)
29
84
  member!(value)
30
85
  end
31
86
 
32
- %i[** + - * / % >> << & ^ | <= < > >= == === != !].each do |operator|
33
- define_method(operator) do |*args|
34
- op!(operator, *args)
35
- end
36
- end
37
-
87
+ #
88
+ # Gets current wrapped AST node.
89
+ #
90
+ # @return [Hash, nil] current abstract syntax tree
38
91
  def unwrap!
39
92
  @object
40
93
  end
41
94
 
95
+ #
96
+ # pushes the current expression as a **ExpressionStatement** into the context.
97
+ #
98
+ # ```rb
99
+ # jsrb.expr['console'].log('hello').as_statement!
100
+ # ```
101
+ #
102
+ # will be
103
+ #
104
+ # ```js
105
+ # console.log('hello');
106
+ # ```
107
+ #
108
+ # @return [nil]
42
109
  def as_statement!
43
110
  raise ArgumentError, "Can't chain as_statement! on empty context" unless @object
44
111
 
@@ -49,6 +116,27 @@ module Jsrb
49
116
  nil # chain ends
50
117
  end
51
118
 
119
+ #
120
+ # pushes a **VariableDeclaration** whose initializer is the current expression into the context.
121
+ #
122
+ # ```rb
123
+ # name = jsrb.var!(:name) { 'foo' }
124
+ # ary = jsrb.var! :ary
125
+ # obj = jsrb.var! :obj
126
+ # result = jsrb.var!
127
+ # ```
128
+ #
129
+ # will be
130
+ #
131
+ # ```js
132
+ # var name = 'foo';
133
+ # var ary;
134
+ # var obj;
135
+ # var _v1; //<- auto generate variable name
136
+ # ```
137
+ #
138
+ # @param [String, Symbol] id variable name
139
+ # @return [nil]
52
140
  def as_variable_declaration!(id)
53
141
  if @object
54
142
  @context.push(
@@ -78,6 +166,20 @@ module Jsrb
78
166
  end
79
167
  end
80
168
 
169
+ #
170
+ # pushes a **ReturnStatement** whose argument is the current expression into the context.
171
+ #
172
+ # ```rb
173
+ # jsrb.expr['getItems'].().as_return!
174
+ # ```
175
+ #
176
+ # will be
177
+ #
178
+ # ```js
179
+ # return getItems();
180
+ # ```
181
+ #
182
+ # @return [nil]
81
183
  def as_return!
82
184
  @context.push(
83
185
  type: 'ReturnStatement',
@@ -85,6 +187,23 @@ module Jsrb
85
187
  )
86
188
  end
87
189
 
190
+ #
191
+ # Constructs a **MemberExpression**
192
+ #
193
+ # ```rb
194
+ # x = jsrb.var! :x
195
+ # obj = jsrb.expr['someObj']
196
+ # x.set! obj.member! 'field'
197
+ # ```
198
+ #
199
+ # will be
200
+ #
201
+ # ```js
202
+ # x = someObj['field'];
203
+ # ```
204
+ #
205
+ # @param [String, Symbol] value name of member
206
+ # @return [Jsrb::ExprChain] a chain represents **MemberExpression**
88
207
  def member!(value)
89
208
  if @object
90
209
  self.class.new @context, type: 'MemberExpression',
@@ -97,6 +216,25 @@ module Jsrb
97
216
  end
98
217
  end
99
218
 
219
+ #
220
+ # Constructs a **AssignmentExpression** whose left is current expression.
221
+ #
222
+ # ```rb
223
+ # x = jsrb.var! :x
224
+ # y = jsrb.var! :y
225
+ # y.assign!(x.assign! 100).as_statement!
226
+ # ```
227
+ #
228
+ # will be
229
+ #
230
+ # ```js
231
+ # var x;
232
+ # var y;
233
+ # y = x = 100;
234
+ # ```
235
+ #
236
+ # @param [Jsrb::ExprChain, convertible ruby values] value RHS value of assignment
237
+ # @return [Jsrb::ExprChain] a chain represents **AssignmentExpression**
100
238
  def assign!(value)
101
239
  raise ArgumentError, "Can't chain assign! on empty context" unless @object
102
240
 
@@ -106,10 +244,47 @@ module Jsrb
106
244
  right: @context.ruby_to_js_ast(value)
107
245
  end
108
246
 
247
+ #
248
+ # Pushes an **ExpressionStatement** of the assignment expression.
249
+ #
250
+ # ```rb
251
+ # x = jsrb.var! :x
252
+ # x.set! 100
253
+ # ```
254
+ #
255
+ # will be
256
+ #
257
+ # ```js
258
+ # var x;
259
+ # x = 100;
260
+ # ```
261
+ #
262
+ # @param [Jsrb::ExprChain, convertible ruby values] value RHS value of assignment
263
+ # @return [nil]
109
264
  def set!(value)
110
265
  assign!(value).as_statement!
111
266
  end
112
267
 
268
+ #
269
+ # Constructs a **CallExpression**.
270
+ #
271
+ # ```rb
272
+ # x = jsrb.var! :x
273
+ # console = jsrb.expr['console']
274
+ # console.log.('foo').as_statement!
275
+ # console.log.call('bar').as_statement!
276
+ # ```
277
+ #
278
+ # will be
279
+ #
280
+ # ```js
281
+ # console.log('foo');
282
+ # console.log('bar');
283
+ # ```
284
+ #
285
+ # @param [Jsrb::ExprChain, convertible ruby values] args arguments
286
+ # @yield optional block represents final argument
287
+ # @return [Jsrb::ExprChain] a chain represents **CallExpression**
113
288
  def call(*args, &block)
114
289
  raise ArgumentError, "Can't chain call on empty context" unless @object
115
290
 
@@ -122,6 +297,22 @@ module Jsrb
122
297
  arguments: js_args
123
298
  end
124
299
 
300
+ #
301
+ # Constructs a **NewExpression**.
302
+ #
303
+ # ```rb
304
+ # x = jsrb.var! :x
305
+ # x.set! jsrb.expr['Date'].new!
306
+ # ```
307
+ #
308
+ # will be
309
+ #
310
+ # ```js
311
+ # x = new Date;
312
+ # ```
313
+ #
314
+ # @param [Jsrb::ExprChain, convertible ruby values] args arguments
315
+ # @return [Jsrb::ExprChain] a chain represents **NewExpression**
125
316
  def new!(*args)
126
317
  raise ArgumentError, "Can't chain new! on empty context" unless @object
127
318
 
@@ -133,6 +324,26 @@ module Jsrb
133
324
  arguments: arguments
134
325
  end
135
326
 
327
+ #
328
+ # Constructs a **UnaryExpression**, **BinaryExpression** or **LogicalExpression**.
329
+ #
330
+ # All ruby-overridable operators can also be used:
331
+ # `** + - * / % >> << & ^ | <= < > >= == === != ! && ||`
332
+ #
333
+ # ```rb
334
+ # x = jsrb.var! :x
335
+ # x.set!(jsrb.expr['a'] < 100)
336
+ # ```
337
+ #
338
+ # will be
339
+ #
340
+ # ```js
341
+ # x = a < 100;
342
+ # ```
343
+ #
344
+ # @param [String, Symbol] operator operator
345
+ # @param optional [Jsrb::ExprChain, convertible ruby values] args arguments contains RHS value
346
+ # @return [Jsrb::ExprChain] a chain represents **UnaryExpression**, **BinaryExpression** or **LogicalExpression**
136
347
  def op!(operator, *args)
137
348
  raise ArgumentError, "Can't chain op! on empty context" unless @object
138
349
 
@@ -146,6 +357,12 @@ module Jsrb
146
357
  end
147
358
  end
148
359
 
360
+ %i[** + - * / % >> << & ^ | <= < > >= == === != !].each do |operator|
361
+ define_method(operator) do |*args|
362
+ op!(operator, *args)
363
+ end
364
+ end
365
+
149
366
  private def _binary_op!(opstr, arg)
150
367
  if JS_LOGICAL_OPS.include? opstr
151
368
  self.class.new @context, type: 'LogicalExpression',
@@ -167,6 +384,23 @@ module Jsrb
167
384
  prefix: true
168
385
  end
169
386
 
387
+ #
388
+ # Constructs a **ConditionalExpression** whose test expression is the current expression.
389
+ #
390
+ # ```rb
391
+ # x = jsrb.var! :x
392
+ # x.set! (jsrb.expr['height'] < 300).cond?('lo', 'hi')
393
+ # ```
394
+ #
395
+ # will be
396
+ #
397
+ # ```js
398
+ # x = (height < 300) ? 'lo' : 'hi';
399
+ # ```
400
+ #
401
+ # @param [Jsrb::ExprChain, convertible ruby values] consequent expression used in consequent
402
+ # @param [Jsrb::ExprChain, convertible ruby values] alternate expression used in alternate
403
+ # @return [Jsrb::ExprChain] a chain represents **ConditionalExpression**
170
404
  def cond?(consequent, alternate)
171
405
  raise ArgumentError, "Can't chain cond? on empty context" unless @object
172
406
 
@@ -176,12 +410,33 @@ module Jsrb
176
410
  alternate: @context.ruby_to_js_ast(alternate)
177
411
  end
178
412
 
413
+ #
414
+ # Constructs a **FunctionExpression** whose returned body is the current context.
415
+ #
416
+ # ```rb
417
+ # f = jsrb.var! :f
418
+ # f.set! (jsrb.expr['x'] * 2).for_all(:x)
419
+ # ```
420
+ #
421
+ # will be
422
+ #
423
+ # ```js
424
+ # f = function (x) { return x * 2; };
425
+ # ```
426
+ #
427
+ # @param [String, Symbol] args argument identifiers
428
+ # @return [Jsrb::ExprChain] a chain represents **FunctionExpression**
179
429
  def for_all!(*args)
180
430
  raise ArgumentError, "Can't chain for_all! on empty context" unless @object
181
431
 
182
432
  self.class.new @context, type: 'FunctionExpression',
183
433
  id: nil,
184
- params: args.map { |arg| @context.ruby_to_js_ast(arg) },
434
+ params: args.map { |arg|
435
+ {
436
+ type: 'Identifier',
437
+ name: arg.to_s
438
+ }
439
+ },
185
440
  body: {
186
441
  type: 'BlockStatement',
187
442
  body: [
@@ -207,11 +462,31 @@ module Jsrb
207
462
  end
208
463
 
209
464
  class << self
465
+ #
466
+ # Adds a new chain method.
467
+ #
468
+ # ```rb
469
+ # Jsrb::ExprChain.add_custom_chain('log_here', '__tap_log__')
470
+ #
471
+ # jsrb.expr['foo']['bar'].log_here.as_statement!
472
+ # ```
473
+ #
474
+ # will be
475
+ #
476
+ # ```js
477
+ # __tap_log__(foo['bar']);
478
+ # ```
479
+ #
480
+ # @param [Symbol] chain_method_name name of a chain method
481
+ # @param [Symbol] function_name name of wrapper function
210
482
  def add_custom_chain(chain_method_name, function_name)
211
483
  @_custom_chains ||= {}
212
484
  @_custom_chains[chain_method_name] = function_name
213
485
  end
214
486
 
487
+ #
488
+ # Show custom chains.
489
+ #
215
490
  def custom_chains
216
491
  @_custom_chains || {}
217
492
  end
data/lib/jsrb/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jsrb
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.1'
5
5
  end
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.2.0
4
+ version: 0.2.1
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-10 00:00:00.000000000 Z
11
+ date: 2019-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execjs
@@ -120,6 +120,7 @@ files:
120
120
  - ".rubocop.yml"
121
121
  - ".ruby-version"
122
122
  - ".travis.yml"
123
+ - ".yardopts"
123
124
  - Gemfile
124
125
  - LICENSE.txt
125
126
  - README.md
@@ -139,6 +140,7 @@ licenses:
139
140
  - MIT
140
141
  metadata:
141
142
  allowed_push_host: https://rubygems.org
143
+ yard.run: yri
142
144
  post_install_message:
143
145
  rdoc_options: []
144
146
  require_paths: