class Jsrb::Base

`Jsrb::Base` is a centralized class for Jsrb template. `js`, accessed from views (i.e. `*.jsrb` files), is an instance of Jsrb::Base.

`Jsrb::Base` provides the interface for pushing statements, constructing expressions and generating JavaScript outputs with handling an internal statement context properly.

Attributes

code_generator[W]

Public Class Methods

code_generator() click to toggle source

Shows JavaScript generator class name, `'Jsrb::NotFastGenerator'` by default.

### **Help wanted!**

*Jsrb::NotFastGenerator uses ExecJS and escodegen to generate JavaScript. It could be more efficient and get better error messages if we implement it in Ruby*.

@return [String] class name of a code generator

# File lib/jsrb/base.rb, line 218
def code_generator
  @code_generator || 'Jsrb::NotFastGenerator'
end
code_generator_class() click to toggle source

@private

# File lib/jsrb/base.rb, line 225
def code_generator_class
  @code_generator_class ||= Object.const_get(code_generator)
end
new() click to toggle source

@private

# File lib/jsrb/base.rb, line 12
def initialize
  @context = JSStatementContext.new
end

Public Instance Methods

do!(expr) click to toggle source

Pushes an ExpressionStatement to the current context

@example

js.do!(js.expr[:x].set(100))
# =>
#   x = 100;

@param [Jsrb::ExprChain] expr target expression. @return [nil]

# File lib/jsrb/base.rb, line 36
def do!(expr)
  ast = expr.object
  raise ArgumentError, 'Expression is empty' unless ast

  @context.push(
    type: 'ExpressionStatement',
    expression: ast
  )
end
expr(object = nil) click to toggle source

Constructs a new expression chain with a given JavaScript AST node.

@param [convertible ruby values] object represents JavaScript expression AST node @return [Jsrb::ExprChain] chainable instance

# File lib/jsrb/base.rb, line 203
def expr(object = nil)
  @context.new_expression(object)
end
generate_code() click to toggle source

Generates executable JavaScript code from current context.

@return [String] generated executable JavaScript code

# File lib/jsrb/base.rb, line 20
def generate_code
  generator = self.class.code_generator_class.new
  generator.call type: 'Program',
                 sourceType: 'script',
                 body: @context.stacks.first
end
if(cond_expr, &block) click to toggle source

Constructs a new conditional chain that represents a conditional expression at end.

@example

result = var!
js.do! result, js.if(expr1) {
  result_expr1
}.elsif(expr2) {
  result_expr2
}.else {
  result_expr3
}
# =>
#   // The actual output will have certain immediate functions
#   // that preserve variable scope for each case.
#   var _v1;
#   _v1 = (function() {
#     if (..expr1..) {
#       return ..result_expr1..;
#     } else if (..expr2..) {
#       return ..result_expr2..;
#     } else {
#       return ..result_expr3..;
#     }
#   })()

@param [Jsrb::ExprChain, convertible ruby values] cond_expr an expression for the test @yield new context block for the consequent case @return [Jsrb::CondChain] condition chainable instance

# File lib/jsrb/base.rb, line 194
def if(cond_expr, &block)
  CondChain.new(@context, true).elsif(cond_expr, &block)
end
if!(cond_expr, &block) click to toggle source

Starts a new conditional chain that pushes an IfStatement to the current context at end.

@example

js.if!(expr1) {
  # ..
}.elsif(expr2) {
  # ..
}.else {
  # ..
}
# =>
#   // The actual output will have certain immediate functions
#   // that preserve variable scope for each case.
#   if (..expr1..) {
#     // ..
#   } else if (..expr2..) {
#     // ..
#   } else {
#     // ..
#   }

# If you don't have else clause, close with `#end`.
js.if!(expr1) {
  # ..
}.elsif(expr2) {
  # ..
}.end
# =>
#   if (..expr1..) {
#     // ..
#   } else if (..expr2..) {
#     // ..
#   }

@param [Jsrb::ExprChain, convertible ruby values] cond_expr an expression for the test @yield new context block for the consequent case @return [Jsrb::CondChain] condition chainable instance

# File lib/jsrb/base.rb, line 161
def if!(cond_expr, &block)
  CondChain.new(@context, false).elsif(cond_expr, &block)
end
set!(lhs, rhs) click to toggle source

Pushes an assignment statement `lhs = rhs;`. This is a short hand of `js.do! lhs_expr.set(rhs_expr)`

@example

a = js.var! :a
js.set!(a, 'dog')
# =>
#   var a;
#   a = 'dog';

# directly pass a symbol of identifier name
js.set!(:x, 100)
# =>
#   x = 100;

@param [Jsrb::ExprChain, String, Symbol] expr target expression. @return [nil]

# File lib/jsrb/base.rb, line 63
def set!(lhs, rhs)
  lhs_expr = lhs.is_a?(ExprChain) ? lhs : expr(lhs)
  do! lhs_expr.set(rhs)
end
var!(id = nil) { || ... } click to toggle source

Pushes a VariableDeclaration to the current context and returns an access to the created identifier. @example

name = js.var!(:name) { 'foo' }
# var name = 'foo';

ary = js.var! :ary
# var ary;

obj = js.var! :obj
# var obj;

result = js.var!
# var _v1; //<- auto generate variable name

@param [Symbol] name a name of identifier, autogenerated if not given @yield optional block for initializer @yieldreturn an initializer expression @return [Jsrb::ExprChain] the expression which represents a newly created identifier

# File lib/jsrb/base.rb, line 87
def var!(id = nil)
  id ||= @context.gen_var_name!
  val_ast =
    if block_given?
      raw_expr = yield
      raw_expr.is_a?(ExprChain) ? raw_expr.unwrap : @context.ruby_to_js_ast(raw_expr)
    end
  if val_ast
    @context.push(
      type: 'VariableDeclaration',
      declarations: [{
        type: 'VariableDeclarator',
        id: {
          type: 'Identifier',
          name: id.to_s
        },
        init: val_ast
      }],
      kind: 'var'
    )
  else
    @context.push(
      type: 'VariableDeclaration',
      declarations: [{
        type: 'VariableDeclarator',
        id: {
          type: 'Identifier',
          name: id.to_s
        }
      }],
      kind: 'var'
    )
  end
  expr[id]
end