Class: Jsrb::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/jsrb/base.rb

Overview

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.

Class Attribute Summary collapse

Instance Method Summary collapse

Class Attribute Details

.code_generatorString

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.

Returns:

  • (String)

    class name of a code generator



218
219
220
# File 'lib/jsrb/base.rb', line 218

def code_generator
  @code_generator || 'Jsrb::NotFastGenerator'
end

Instance Method Details

#do!(expr) ⇒ nil

Pushes an ExpressionStatement to the current context

Examples:

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

Parameters:

Returns:

  • (nil)

Raises:

  • (ArgumentError)


36
37
38
39
40
41
42
43
44
# 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) ⇒ Jsrb::ExprChain

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

Parameters:

  • object (convertible ruby values) (defaults to: nil)

    represents JavaScript expression AST node

Returns:



203
204
205
# File 'lib/jsrb/base.rb', line 203

def expr(object = nil)
  @context.new_expression(object)
end

#generate_codeString

Generates executable JavaScript code from current context.

Returns:

  • (String)

    generated executable JavaScript code



20
21
22
23
24
25
# 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) { ... } ⇒ Jsrb::CondChain

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

Examples:

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..;
#     }
#   })()

Parameters:

  • cond_expr (Jsrb::ExprChain, convertible ruby values)

    an expression for the test

Yields:

  • new context block for the consequent case

Returns:



194
195
196
# File 'lib/jsrb/base.rb', line 194

def if(cond_expr, &block)
  CondChain.new(@context, true).elsif(cond_expr, &block)
end

#if!(cond_expr) { ... } ⇒ Jsrb::CondChain

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

Examples:

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..) {
#     // ..
#   }

Parameters:

  • cond_expr (Jsrb::ExprChain, convertible ruby values)

    an expression for the test

Yields:

  • new context block for the consequent case

Returns:



161
162
163
# File 'lib/jsrb/base.rb', line 161

def if!(cond_expr, &block)
  CondChain.new(@context, false).elsif(cond_expr, &block)
end

#set!(lhs, rhs) ⇒ nil

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

Examples:

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;

Parameters:

Returns:

  • (nil)


63
64
65
66
# 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) { ... } ⇒ Jsrb::ExprChain

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

Examples:

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

Parameters:

  • name (Symbol)

    a name of identifier, autogenerated if not given

Yields:

  • optional block for initializer

Yield Returns:

  • an initializer expression

Returns:

  • (Jsrb::ExprChain)

    the expression which represents a newly created identifier



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# 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